diff --git a/.github/workflows/codecoverage.yml b/.github/workflows/codecoverage.yml index 935631aacee..a98cf0d2ce0 100644 --- a/.github/workflows/codecoverage.yml +++ b/.github/workflows/codecoverage.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-20.04 services: elggdb: - image: 'mysql:5.7' + image: 'mysql:8.0' env: MYSQL_DATABASE: elgg MYSQL_ROOT_PASSWORD: password @@ -24,7 +24,7 @@ jobs: fail-fast: false matrix: # Keep number of suites inline with Scrutinizer waiting for the same amount of coverage runs - testsuite: ['unit', 'integration-a-to-d', 'integration-e-to-s', 'integration-t-to-all', 'plugins-unit', 'plugins-integration'] + testsuite: ['unit', 'integration-a-to-d', 'integration-e-to-s', 'integration-t-to-all', 'plugins-unit', 'plugins-integration-generic', 'plugins-integration'] steps: - name: Check if run on the Elgg repo @@ -34,13 +34,13 @@ jobs: - name: Install PHP uses: shivammathur/setup-php@v2 with: - php-version: '8.0' + php-version: '8.1' coverage: xdebug extensions: gd,pdo,xml,json,mysqli,pdo_mysql,libxml,mbstring,intl - ini-values: max_execution_time=180 + ini-values: max_execution_time=180,zend.enable_gc=0 - name: Code checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: # Fetch 10 commits or Scrutinizer will throw ("Failed to retrieve commit parents. If you use a shallow git checkout, please checkout at least a depth of one."), see: RepositoryIntrospector at scrutinizer-ci/ocular GitHub repository # 10 commits is an arbitrary value that is more than 1 commit @@ -51,7 +51,7 @@ jobs: run: echo "dir=$(composer config cache-files-dir)" >> ${GITHUB_OUTPUT} - name: Restore Composer Cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} @@ -65,7 +65,7 @@ jobs: - name: Enable Elgg plugins run: | - php ./elgg-cli plugins:activate activity blog bookmarks ckeditor dashboard developers discussions externalpages file friends friends_collections garbagecollector groups invitefriends likes members messageboard messages pages profile reportedcontent search site_notifications system_log tagcloud thewire uservalidationbyemail web_services custom_index:last --no-ansi + php ./elgg-cli plugins:activate activity blog bookmarks ckeditor dashboard developers discussions externalpages file friends friends_collections garbagecollector groups invitefriends likes members messageboard messages pages profile reportedcontent search site_notifications system_log tagcloud theme_sandbox thewire uservalidationbyemail web_services custom_index:last --no-ansi php ./elgg-cli plugins:list --no-ansi - name: Generate code coverage diff --git a/.github/workflows/create-zip-release.yml b/.github/workflows/create-zip-release.yml index eb86f3bc8e6..6959321fa92 100644 --- a/.github/workflows/create-zip-release.yml +++ b/.github/workflows/create-zip-release.yml @@ -17,10 +17,10 @@ jobs: echo ZIP_FILE=elgg-${GITHUB_REF#refs/tags/}.zip >> $GITHUB_OUTPUT - name: Checkout Starter Project - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: Elgg/starter-project - ref: master + ref: 6.x path: ${{ steps.branch.outputs.ZIP_FOLDER }} - name: Composer Install diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 3fb2345d943..7aaf7729ced 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -6,7 +6,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Code checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Build HTML documentation uses: ammaraskar/sphinx-action@master diff --git a/.github/workflows/javascript.yml b/.github/workflows/javascript.yml deleted file mode 100644 index 266a87044dc..00000000000 --- a/.github/workflows/javascript.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: Javascript test suite -on: [pull_request] -jobs: - karma: - name: Karma tests - runs-on: ubuntu-20.04 - - steps: - - name: Install PHP - uses: shivammathur/setup-php@v2 - with: - php-version: '8.0' - coverage: none - extensions: gd,pdo,xml,json,mysqli,pdo_mysql,libxml,mbstring - - - name: Install NodeJS - uses: actions/setup-node@v2 - with: - node-version: 8 - - - name: Code checkout - uses: actions/checkout@v3 - - - name: Restore NPM cache - uses: actions/cache@v3 - with: - path: ~/.npm - key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} - restore-keys: ${{ runner.os }}-node- - - - name: Get Composer Cache Directory - id: composer-cache - run: echo "dir=$(composer config cache-files-dir)" >> ${GITHUB_OUTPUT} - - - name: Restore Composer Cache - uses: actions/cache@v3 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} - restore-keys: ${{ runner.os }}-composer- - - - name: Composer install - run: composer install - - - name: Yarn install - run: yarn install - - - name: Yarn check - continue-on-error: true - run: yarn check - - - name: Run Karma tests - run: yarn test diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 132ad81e639..8401c993f6a 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -6,7 +6,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Code checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Check format uses: gsactions/commit-message-checker@v2 @@ -48,19 +48,19 @@ jobs: - name: Install PHP uses: shivammathur/setup-php@v2 with: - php-version: '8.0' + php-version: '8.1' coverage: none extensions: gd,pdo,xml,json,mysqli,pdo_mysql - name: Code checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Get Composer Cache Directory id: composer-cache run: echo "dir=$(composer config cache-files-dir)" >> ${GITHUB_OUTPUT} - name: Restore Composer Cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} @@ -81,7 +81,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Code checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Check encoding of Core language files run: echo '! find ./languages/ -name "*.php" -type f -exec file --mime {} \; | grep -v "charset=utf-8$" | grep -v "charset=us-ascii$"' | bash diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 1b3a09fa03a..7e0e4ec587b 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -38,42 +38,42 @@ jobs: strategy: fail-fast: false matrix: - php-versions: ['8.0', '8.1', '8.2'] + php-versions: ['8.1', '8.2', '8.3'] experimental: [false] extra-title: [''] memcache: [0] - db-image: ['mysql:5.7'] + db-image: ['mysql:8.0'] redis: [0] include: - - php-versions: '8.0' + - php-versions: '8.1' experimental: false extra-title: '- Memcache' memcache: 1 - db-image: 'mysql:5.7' + db-image: 'mysql:8.0' redis: 0 - - php-versions: '8.0' + - php-versions: '8.1' experimental: false extra-title: '- Redis' memcache: 0 - db-image: 'mysql:5.7' + db-image: 'mysql:8.0' redis: 1 - - php-versions: '8.0' + - php-versions: '8.1' experimental: false extra-title: '' memcache: 0 - db-image: 'mysql:8.0' + db-image: 'mysql:8.2' redis: 0 - - php-versions: '8.0' + - php-versions: '8.1' experimental: false extra-title: '' memcache: 0 - db-image: 'mariadb:10.3' + db-image: 'mariadb:10.6' redis: 0 - - php-versions: '8.0' + - php-versions: '8.1' experimental: false extra-title: '' memcache: 0 - db-image: 'mariadb:10.6' + db-image: 'mariadb:10.11' redis: 0 env: ELGG_MEMCACHE: ${{ matrix.memcache }} @@ -86,17 +86,17 @@ jobs: php-version: ${{ matrix.php-versions }} coverage: none extensions: gd,pdo,xml,json,memcached,redis-5.3.7,mysqli,pdo_mysql,libxml,mbstring,intl - ini-values: max_execution_time=180 + ini-values: max_execution_time=180,zend.enable_gc=0 - name: Code checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Get Composer Cache Directory id: composer-cache run: echo "dir=$(composer config cache-files-dir)" >> ${GITHUB_OUTPUT} - name: Restore Composer Cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} @@ -110,21 +110,11 @@ jobs: - name: Enable Elgg plugins run: | - php ./elgg-cli plugins:activate activity blog bookmarks ckeditor dashboard developers discussions externalpages file friends friends_collections garbagecollector groups invitefriends likes members messageboard messages pages profile reportedcontent search site_notifications system_log tagcloud thewire uservalidationbyemail web_services custom_index:last --no-ansi + php ./elgg-cli plugins:activate activity blog bookmarks ckeditor dashboard developers discussions externalpages file friends friends_collections garbagecollector groups invitefriends likes members messageboard messages pages profile reportedcontent search site_notifications system_log tagcloud theme_sandbox thewire uservalidationbyemail web_services custom_index:last --no-ansi php ./elgg-cli plugins:list --no-ansi - name: Seed Elgg database - run: php ./elgg-cli database:seed --limit=5 --image_folder=./.scripts/seeder/images/ -vv --no-ansi - - - name: Start Elgg webserver - # there is some weird issue with the PHP cli-server in PHP 8.1, so skipping this - if: ${{ !contains(fromJSON('["8.1", "8.2"]'), matrix.php-versions) }} - run: | - php -S localhost:8888 -c ./.scripts/ci/local_php_server.ini index.php & - # give Web server some time to bind to sockets, etc - sleep 3 - # check if the webserver is running - curl -s http://localhost:8888/ | tac | tac | grep -q "Elgg CI Site" + run: php ./elgg-cli database:seed --limit=5 --image_folder=./.scripts/seeder/images/ -vv --no-ansi --no-interaction - name: Run PHPUnit - Core unit run: ./vendor/bin/phpunit --testsuite unit @@ -135,6 +125,9 @@ jobs: - name: Run PHPUnit - Plugins unit run: ./vendor/bin/phpunit --testsuite plugins-unit + - name: Run PHPUnit - Plugins integration generic + run: ./vendor/bin/phpunit --testsuite plugins-integration-generic + - name: Run PHPUnit - Plugins integration run: ./vendor/bin/phpunit --testsuite plugins-integration diff --git a/.github/workflows/upgrade.yml b/.github/workflows/upgrade.yml index 2e021f15e76..b64eb289c46 100644 --- a/.github/workflows/upgrade.yml +++ b/.github/workflows/upgrade.yml @@ -10,11 +10,11 @@ env: jobs: upgrade: - name: Upgrade from 2.3 + name: Upgrade from 4.3 runs-on: ubuntu-20.04 services: elggdb: - image: mysql:5.7 + image: 'mysql:8.0' env: MYSQL_DATABASE: elgg MYSQL_ROOT_PASSWORD: password @@ -25,100 +25,72 @@ jobs: - name: Install PHP uses: shivammathur/setup-php@v2 with: - php-version: '7.4' + php-version: '8.0' coverage: none extensions: gd,pdo,xml,json,mysqli,pdo_mysql,libxml,mbstring - - - name: Install Composer v1 - run: composer self-update --1 - - - name: Code checkout Elgg 2.3 - uses: actions/checkout@v3 + + - name: Code checkout Elgg 4.3 + uses: actions/checkout@v4 with: repository: 'Elgg/Elgg' - ref: '2.3' + ref: '4.3' - name: Get Composer Cache Directory id: composer-cache run: echo "dir=$(composer config cache-files-dir)" >> ${GITHUB_OUTPUT} - - name: Restore Composer Cache for 2.3 - uses: actions/cache@v3 + - name: Restore Composer Cache for 4.3 + uses: actions/cache@v4 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} restore-keys: ${{ runner.os }}-composer- - - - name: Composer install - run: | - composer global require fxp/composer-asset-plugin:^1.1.4 --prefer-dist - composer install - - - name: Install Elgg 2.3 - run: | - mkdir ${HOME}/elgg_data - php -f ./install/cli/ci_installer.php - - - name: Enable Elgg 2.3 plugins - run: php -f ./.scripts/ci/enable_plugins.php - - - name: Seed Elgg 2.3 database - run: php -f ./.scripts/seeder/seed.php - - - name: Code checkout Elgg 3.3 - uses: actions/checkout@v3 - with: - repository: 'Elgg/Elgg' - ref: '3.3' - clean: false - - name: Composer install Elgg 3.3 dependencies - run: composer install --prefer-dist --no-suggest + - name: Composer install Elgg 4.3 dependencies + run: composer install - - name: Elgg CLI upgrade to 3.3 - run: php ./elgg-cli upgrade async --verbose + - name: Elgg CLI install Elgg 4.3 + run: php ./elgg-cli install --config ./install/cli/testing_app.php --verbose --no-ansi - - name: Enable Elgg 3.3 plugins + - name: Enable Elgg 4.3 plugins run: php -f ./.scripts/ci/enable_plugins.php - - name: Install Composer v2 - # make sure to remove the global fxp/composer-asset-plugin package as it's no longer needed - # also remove the elgg/login_as plugin because after the Composer update it has a hard time removing it - run: | - composer global remove fxp/composer-asset-plugin - composer remove elgg/login_as - composer self-update --2 - - - name: Code checkout Elgg 4.3 - uses: actions/checkout@v3 + - name: Seed Elgg 4.3 database + run: php ./elgg-cli database:seed --limit=5 --image_folder=./.scripts/seeder/images/ -vv --no-ansi + + - name: Code checkout Elgg 5.1 + uses: actions/checkout@v4 with: repository: 'Elgg/Elgg' - ref: '4.3' + ref: '5.1' clean: false - - name: Composer install Elgg 4.3 dependencies + - name: Composer install Elgg 5.1 dependencies run: composer install --prefer-dist --no-suggest - - name: Elgg CLI upgrade to 4.3 + - name: Elgg CLI upgrade to 5.1 run: php ./elgg-cli upgrade async --verbose - - name: Enable Elgg 4.3 plugins - run: php -f ./.scripts/ci/enable_plugins.php + - name: Enable Elgg 5.1 plugins + run: | + php ./elgg-cli plugins:activate activity blog bookmarks ckeditor dashboard developers discussions externalpages file friends friends_collections garbagecollector groups invitefriends likes members messageboard messages pages profile reportedcontent search site_notifications system_log tagcloud theme_sandbox thewire uservalidationbyemail web_services custom_index:last --no-ansi + php ./elgg-cli plugins:list --no-ansi - - name: Update PHP + - name: Update PHP to 8.1 uses: shivammathur/setup-php@v2 with: - php-version: '8.0' + php-version: '8.1' coverage: none extensions: gd,pdo,xml,json,mysqli,pdo_mysql,libxml,mbstring + ini-values: zend.enable_gc=0 - name: Code checkout PR - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: clean: false - name: Restore Composer Cache for PR - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} @@ -133,17 +105,9 @@ jobs: - name: Activate current plugins run: | - php ./elgg-cli plugins:activate activity blog bookmarks ckeditor dashboard developers discussions externalpages file friends friends_collections garbagecollector groups invitefriends likes members messageboard messages pages profile reportedcontent search site_notifications system_log tagcloud thewire uservalidationbyemail web_services custom_index:last --no-ansi + php ./elgg-cli plugins:activate activity blog bookmarks ckeditor dashboard developers discussions externalpages file friends friends_collections garbagecollector groups invitefriends likes members messageboard messages pages profile reportedcontent search site_notifications system_log tagcloud theme_sandbox thewire uservalidationbyemail web_services custom_index:last --no-ansi php ./elgg-cli plugins:list --no-ansi - - name: Start Elgg webserver - run: | - php -S localhost:8888 -c ./.scripts/ci/local_php_server.ini index.php & - # give Web server some time to bind to sockets, etc - sleep 3 - # check if the webserver is running - curl -s http://localhost:8888/ | tac | tac | grep -q "Elgg CI Site" - - name: Run PHPUnit - Core unit run: ./vendor/bin/phpunit --testsuite unit @@ -153,6 +117,9 @@ jobs: - name: Run PHPUnit - Plugins unit run: ./vendor/bin/phpunit --testsuite plugins-unit + - name: Run PHPUnit - Plugins integration generic + run: ./vendor/bin/phpunit --testsuite plugins-integration-generic + - name: Run PHPUnit - Plugins integration run: ./vendor/bin/phpunit --testsuite plugins-integration diff --git a/.gitignore b/.gitignore index af1cfb1c8ef..bb09198e628 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,7 @@ !/mod/site_notifications/ !/mod/system_log/ !/mod/tagcloud/ +!/mod/theme_sandbox/ !/mod/thewire/ !/mod/uservalidationbyemail/ !/mod/web_services/ diff --git a/.readthedocs.yml b/.readthedocs.yml index abfabe60deb..646914ed6e3 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -5,6 +5,11 @@ # Required version: 2 +build: + os: ubuntu-22.04 + tools: + python: "3.7" + # Build documentation in the docs/ directory with Sphinx sphinx: builder: html @@ -20,6 +25,5 @@ formats: all # Optionally set the version of Python and requirements required to build your docs python: - version: 3.7 install: - requirements: docs/pip-requirements.txt \ No newline at end of file diff --git a/.scripts/release.php b/.scripts/release.php index 814b520bb91..bd50c2b1be5 100644 --- a/.scripts/release.php +++ b/.scripts/release.php @@ -20,14 +20,21 @@ $matches = []; if (!preg_match($regexp, $version, $matches)) { - echo 'Bad version format. You must follow the format of X.Y.Z with an optional suffix of' - . ' -alpha.N, -beta.N, or -rc.N (where N is a number).' . PHP_EOL; + echo 'Bad version format. You must follow the format of X.Y.Z with an optional suffix of'; + echo ' -alpha.N, -beta.N, or -rc.N (where N is a number).' . PHP_EOL; exit(1); } require_once dirname(__DIR__) . '/vendor/autoload.php'; -function run_commands($commands) { +/** + * Execute a command in the commandline + * + * @param array $commands all commands to execute + * + * @return void + */ +function run_commands(array $commands): void { foreach ($commands as $command) { echo $command . PHP_EOL; @@ -62,16 +69,18 @@ function run_commands($commands) { $json = json_encode($composer_config, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . PHP_EOL; file_put_contents($composer_path, $json); +// write the changelog +$changelog = new \Elgg\Project\ChangelogWriter([ + 'version' => $version, +]); +$changelog(); + // make the new release -run_commands(array( +run_commands([ // update hash in composer.lock, because version was updated and now there is a mismatch between .json and .lock 'composer update --lock', - // Generate changelog - 'yarn install', - 'node .scripts/write-changelog.js', - // commit everything to GitHub 'git add .', "git commit -am \"chore(release): v{$version}\"", -)); +]); diff --git a/.scripts/write-changelog.js b/.scripts/write-changelog.js deleted file mode 100755 index 160abec5fa9..00000000000 --- a/.scripts/write-changelog.js +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env node - -var pkg = require('../composer.json'); -var fs = require('fs'); -var changelog = require('elgg-conventional-changelog'); - -changelog({ - version: pkg.version, - repository: 'https://github.com/Elgg/Elgg', - types: { - feat: 'Features', - feature: 'Features', - perf: 'Performance', - performance: 'Performance', - doc: 'Documentation', - docs: 'Documentation', - fix: 'Bug Fixes', - fixes: 'Bug Fixes', - fixed: 'Bug Fixes', - deprecate: 'Deprecations', - deprecates: 'Deprecations', - deprecated: 'Deprecations', - break: 'Breaking Changes', - breaks: 'Breaking Changes', - removed: 'Removed' - } -}, function (err, log) { - if (err) - throw new Error(err); - fs.writeFileSync('CHANGELOG.md', log); -}); - diff --git a/.tx/config b/.tx/config index f2e9a7ec0ab..8c6dcaf5485 100644 --- a/.tx/config +++ b/.tx/config @@ -2,235 +2,241 @@ host = https://www.transifex.com lang_map = pt_BR: pt_br, ro_RO: ro_ro, zh-Hans: zh_hans -[o:elgg:p:elgg-core-5:r:engine] +[o:elgg:p:elgg-core-6:r:engine] file_filter = languages/.php source_file = languages/en.php source_lang = en type = PHP_ARRAY -[o:elgg:p:elgg-core-5:r:install] +[o:elgg:p:elgg-core-6:r:install] file_filter = install/languages/.php source_file = install/languages/en.php source_lang = en type = PHP_ARRAY -[o:elgg:p:elgg-core-5:r:activity] +[o:elgg:p:elgg-core-6:r:activity] file_filter = mod/activity/languages/.php source_file = mod/activity/languages/en.php source_lang = en type = PHP_ARRAY -[o:elgg:p:elgg-core-5:r:blog] +[o:elgg:p:elgg-core-6:r:blog] file_filter = mod/blog/languages/.php source_file = mod/blog/languages/en.php source_lang = en type = PHP_ARRAY -[o:elgg:p:elgg-core-5:r:bookmarks] +[o:elgg:p:elgg-core-6:r:bookmarks] file_filter = mod/bookmarks/languages/.php source_file = mod/bookmarks/languages/en.php source_lang = en type = PHP_ARRAY -[o:elgg:p:elgg-core-5:r:ckeditor] +[o:elgg:p:elgg-core-6:r:ckeditor] file_filter = mod/ckeditor/languages/.php source_file = mod/ckeditor/languages/en.php source_lang = en type = PHP_ARRAY -[o:elgg:p:elgg-core-5:r:custom_index] +[o:elgg:p:elgg-core-6:r:custom_index] file_filter = mod/custom_index/languages/.php source_file = mod/custom_index/languages/en.php source_lang = en type = PHP_ARRAY -[o:elgg:p:elgg-core-5:r:developers] +[o:elgg:p:elgg-core-6:r:developers] file_filter = mod/developers/languages/.php source_file = mod/developers/languages/en.php source_lang = en type = PHP_ARRAY -[o:elgg:p:elgg-core-5:r:discussions] +[o:elgg:p:elgg-core-6:r:discussions] file_filter = mod/discussions/languages/.php source_file = mod/discussions/languages/en.php source_lang = en type = PHP_ARRAY -[o:elgg:p:elgg-core-5:r:externalpages] +[o:elgg:p:elgg-core-6:r:externalpages] file_filter = mod/externalpages/languages/.php source_file = mod/externalpages/languages/en.php source_lang = en type = PHP_ARRAY -[o:elgg:p:elgg-core-5:r:file] +[o:elgg:p:elgg-core-6:r:file] file_filter = mod/file/languages/.php source_file = mod/file/languages/en.php source_lang = en type = PHP_ARRAY -[o:elgg:p:elgg-core-5:r:friends] +[o:elgg:p:elgg-core-6:r:friends] file_filter = mod/friends/languages/.php source_file = mod/friends/languages/en.php source_lang = en type = PHP_ARRAY -[o:elgg:p:elgg-core-5:r:friends_collections] +[o:elgg:p:elgg-core-6:r:friends_collections] file_filter = mod/friends_collections/languages/.php source_file = mod/friends_collections/languages/en.php source_lang = en type = PHP_ARRAY -[o:elgg:p:elgg-core-5:r:garbagecollector] +[o:elgg:p:elgg-core-6:r:garbagecollector] file_filter = mod/garbagecollector/languages/.php source_file = mod/garbagecollector/languages/en.php source_lang = en type = PHP_ARRAY -[o:elgg:p:elgg-core-5:r:groups] +[o:elgg:p:elgg-core-6:r:groups] file_filter = mod/groups/languages/.php source_file = mod/groups/languages/en.php source_lang = en type = PHP_ARRAY -[o:elgg:p:elgg-core-5:r:invitefriends] +[o:elgg:p:elgg-core-6:r:invitefriends] file_filter = mod/invitefriends/languages/.php source_file = mod/invitefriends/languages/en.php source_lang = en type = PHP_ARRAY -[o:elgg:p:elgg-core-5:r:likes] +[o:elgg:p:elgg-core-6:r:likes] file_filter = mod/likes/languages/.php source_file = mod/likes/languages/en.php source_lang = en type = PHP_ARRAY -[o:elgg:p:elgg-core-5:r:members] +[o:elgg:p:elgg-core-6:r:members] file_filter = mod/members/languages/.php source_file = mod/members/languages/en.php source_lang = en type = PHP_ARRAY -[o:elgg:p:elgg-core-5:r:messageboard] +[o:elgg:p:elgg-core-6:r:messageboard] file_filter = mod/messageboard/languages/.php source_file = mod/messageboard/languages/en.php source_lang = en type = PHP_ARRAY -[o:elgg:p:elgg-core-5:r:messages] +[o:elgg:p:elgg-core-6:r:messages] file_filter = mod/messages/languages/.php source_file = mod/messages/languages/en.php source_lang = en type = PHP_ARRAY -[o:elgg:p:elgg-core-5:r:pages] +[o:elgg:p:elgg-core-6:r:pages] file_filter = mod/pages/languages/.php source_file = mod/pages/languages/en.php source_lang = en type = PHP_ARRAY -[o:elgg:p:elgg-core-5:r:profile] +[o:elgg:p:elgg-core-6:r:profile] file_filter = mod/profile/languages/.php source_file = mod/profile/languages/en.php source_lang = en type = PHP_ARRAY -[o:elgg:p:elgg-core-5:r:reportedcontent] +[o:elgg:p:elgg-core-6:r:reportedcontent] file_filter = mod/reportedcontent/languages/.php source_file = mod/reportedcontent/languages/en.php source_lang = en type = PHP_ARRAY -[o:elgg:p:elgg-core-5:r:search] +[o:elgg:p:elgg-core-6:r:search] file_filter = mod/search/languages/.php source_file = mod/search/languages/en.php source_lang = en type = PHP_ARRAY -[o:elgg:p:elgg-core-5:r:site_notifications] +[o:elgg:p:elgg-core-6:r:site_notifications] file_filter = mod/site_notifications/languages/.php source_file = mod/site_notifications/languages/en.php source_lang = en type = PHP_ARRAY -[o:elgg:p:elgg-core-5:r:system_log] +[o:elgg:p:elgg-core-6:r:system_log] file_filter = mod/system_log/languages/.php source_file = mod/system_log/languages/en.php source_lang = en type = PHP_ARRAY -[o:elgg:p:elgg-core-5:r:tagcloud] +[o:elgg:p:elgg-core-6:r:tagcloud] file_filter = mod/tagcloud/languages/.php source_file = mod/tagcloud/languages/en.php source_lang = en type = PHP_ARRAY -[o:elgg:p:elgg-core-5:r:thewire] +[o:elgg:p:elgg-core-6:r:theme_sandbox] +file_filter = mod/theme_sandbox/languages/.php +source_file = mod/theme_sandbox/languages/en.php +source_lang = en +type = PHP_ARRAY + +[o:elgg:p:elgg-core-6:r:thewire] file_filter = mod/thewire/languages/.php source_file = mod/thewire/languages/en.php source_lang = en type = PHP_ARRAY -[o:elgg:p:elgg-core-5:r:uservalidationbyemail] +[o:elgg:p:elgg-core-6:r:uservalidationbyemail] file_filter = mod/uservalidationbyemail/languages/.php source_file = mod/uservalidationbyemail/languages/en.php source_lang = en type = PHP_ARRAY -[o:elgg:p:elgg-core-5:r:web_services] +[o:elgg:p:elgg-core-6:r:web_services] file_filter = mod/web_services/languages/.php source_file = mod/web_services/languages/en.php source_lang = en type = PHP_ARRAY -[o:elgg:p:elgg-core-5:r:docs-index] +[o:elgg:p:elgg-core-6:r:docs-index] file_filter = docs/locale//LC_MESSAGES/index.po source_file = docs/locale/pot/index.pot source_lang = en type = PO -[o:elgg:p:elgg-core-5:r:docs-admin] +[o:elgg:p:elgg-core-6:r:docs-admin] file_filter = docs/locale//LC_MESSAGES/admin.po source_file = docs/locale/pot/admin.pot source_lang = en type = PO -[o:elgg:p:elgg-core-5:r:docs-appendix] +[o:elgg:p:elgg-core-6:r:docs-appendix] file_filter = docs/locale//LC_MESSAGES/appendix.po source_file = docs/locale/pot/appendix.pot source_lang = en type = PO -[o:elgg:p:elgg-core-5:r:docs-contribute] +[o:elgg:p:elgg-core-6:r:docs-contribute] file_filter = docs/locale//LC_MESSAGES/contribute.po source_file = docs/locale/pot/contribute.pot source_lang = en type = PO -[o:elgg:p:elgg-core-5:r:docs-design] +[o:elgg:p:elgg-core-6:r:docs-design] file_filter = docs/locale//LC_MESSAGES/design.po source_file = docs/locale/pot/design.pot source_lang = en type = PO -[o:elgg:p:elgg-core-5:r:docs-guides] +[o:elgg:p:elgg-core-6:r:docs-guides] file_filter = docs/locale//LC_MESSAGES/guides.po source_file = docs/locale/pot/guides.pot source_lang = en type = PO -[o:elgg:p:elgg-core-5:r:docs-intro] +[o:elgg:p:elgg-core-6:r:docs-intro] file_filter = docs/locale//LC_MESSAGES/intro.po source_file = docs/locale/pot/intro.pot source_lang = en type = PO -[o:elgg:p:elgg-core-5:r:docs-plugins] +[o:elgg:p:elgg-core-6:r:docs-plugins] file_filter = docs/locale//LC_MESSAGES/plugins.po source_file = docs/locale/pot/plugins.pot source_lang = en type = PO -[o:elgg:p:elgg-core-5:r:docs-tutorials] +[o:elgg:p:elgg-core-6:r:docs-tutorials] file_filter = docs/locale//LC_MESSAGES/tutorials.po source_file = docs/locale/pot/tutorials.pot source_lang = en diff --git a/CHANGELOG.md b/CHANGELOG.md index bd75be537ec..79fb792b238 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,296 @@ + +### 6.0.0-beta.1 (2024-04-18) + +#### Contributors + +* Jeroen Dalsem (63) +* Jerôme Bakker (28) + +#### Features + +* **ckeditor:** updated to ckeditor v41.3 [c30beef28](https://github.com/Elgg/Elgg//commit/c30beef28eeaa745bd3369653ad1dc661e93e45a) +* **db:** updated to doctrine/dbal v4 [c3776a7a7](https://github.com/Elgg/Elgg//commit/c3776a7a73c6e01ce48949ff3e6a988ee53cbd57) +* **core:** added temporary bin [ea8939719](https://github.com/Elgg/Elgg//commit/ea893971959e370c11a63f2ac3bd418db4eea2df) closes [#5172](https://github.com/Elgg/Elgg//commit/5172) +* **views:** + * restructured various page elements and improved css [c5c46637a](https://github.com/Elgg/Elgg//commit/c5c46637ad6137509a70422198e36808d127239e) + * improve various sidebar search forms [172ada402](https://github.com/Elgg/Elgg//commit/172ada402d6dd5a97a1a59f2ceb5299cdb2a1b40) + * improved usage of headings in various parts of a page [df7e1eaac](https://github.com/Elgg/Elgg//commit/df7e1eaac91d664125e6fc173e8945e3f768fd07) closes [#14435](https://github.com/Elgg/Elgg//commit/14435) +* **session:** login event has been reintroduced for logging purposes [34819950d](https://github.com/Elgg/Elgg//commit/34819950d0a8f1c783c15d9da5db2ef767fb23d4) +* **js:** dropped RequireJS in favor of ECMAScript modules [e2e998c2c](https://github.com/Elgg/Elgg//commit/e2e998c2c6c42759518829be0ba0182aee9a411b) +* **icons:** uniform storage of entity icon cropping coordinates [cee682c2f](https://github.com/Elgg/Elgg//commit/cee682c2f0cd0e4bb1c05393ca47dfb01e398d04) +* **php:** require php intl module [5b5ddccb6](https://github.com/Elgg/Elgg//commit/5b5ddccb6e53cc369430a32beb2b6bcb2293fda9) closes [#13901](https://github.com/Elgg/Elgg//commit/13901) +* **tests:** updated to PHPUnit 10.5 [b01996b60](https://github.com/Elgg/Elgg//commit/b01996b6036c626f4ad131777a9020af987dc832) +* **responses:** response forward urls are now secure by default [afe18fb3b](https://github.com/Elgg/Elgg//commit/afe18fb3b32b3c852dfdbf70bf6bb637d3c33edf) + + +#### Bug fixes + +* **core:** + * correctly determine if plugins need reindexing [84e72f296](https://github.com/Elgg/Elgg//commit/84e72f2964e5deb8c8cbd9eb66ad3940da79c829) + * correctly check for the need for a default order by [72d015033](https://github.com/Elgg/Elgg//commit/72d0150334302143458f137b75c1c972e3ad00a7) +* **groups:** + * only show group owner transfer if there are other members [3f8a4f1bf](https://github.com/Elgg/Elgg//commit/3f8a4f1bf4f0a4ed57a7a1e108fa7084c3d6ff22) + * only show edit form sections if there is content [28673a1f7](https://github.com/Elgg/Elgg//commit/28673a1f7bbbb615662a37ff0ac82266bedaa3d7) +* **webservices:** + * set correct response header during exception [7a1322631](https://github.com/Elgg/Elgg//commit/7a132263188f9570cdc7e25ece1cda593be53e86) closes [#14506](https://github.com/Elgg/Elgg//commit/14506) + * improved calculation of POST hash [64522a17f](https://github.com/Elgg/Elgg//commit/64522a17fce912311aa615757dbc6723251b73f7) closes [#14233](https://github.com/Elgg/Elgg//commit/14233) +* **upgrades:** show correct count in the admin upgrade listing [adc8b9028](https://github.com/Elgg/Elgg//commit/adc8b9028049996e2b0a5b243a2402dbe3eb009b) closes [#14520](https://github.com/Elgg/Elgg//commit/14520) +* **database:** allow both metadata and annotations [67962755c](https://github.com/Elgg/Elgg//commit/67962755ceae392c21a2396552db8f563d984cad) closes [#14405](https://github.com/Elgg/Elgg//commit/14405) + + +#### Removed + +* **filesystem:** removed flysystem wrapper [537b90a1d](https://github.com/Elgg/Elgg//commit/537b90a1d24c9a9182dbf34e0a9e4e71b3d9035d) +* **db:** the enabled column for annotations has been removed [bdd17b413](https://github.com/Elgg/Elgg//commit/bdd17b413b6f925d24e60a21c3289bf92817f3bc) +* **core:** the \ElggEntity->getTags() function has been removed [d3bbe25d0](https://github.com/Elgg/Elgg//commit/d3bbe25d0ff29a94cf920b67a8a804359124317b) +* **icons:** icontime metadata is no longer available [7e139b935](https://github.com/Elgg/Elgg//commit/7e139b9352908407bf48edec343c96fbf317df35) + + + +### 5.1.5 (2024-03-22) + +#### Contributors + +* Jerôme Bakker (7) +* Jeroen Dalsem (1) + +#### Bug fixes + +* **core:** + * improved friendly title for multibyte characters [6d80fa23f](https://github.com/Elgg/Elgg//commit/6d80fa23ff800e4aa67913dd9c76ab157804120a) closes [#14577](https://github.com/Elgg/Elgg//commit/14577) + * no longer set dynamic property on exceptions [21b41a6a6](https://github.com/Elgg/Elgg//commit/21b41a6a693479fa93a7dca24bac71d323eb5dfe) +* **ckeditor:** do not limit html elements in ckeditor [01bacfc51](https://github.com/Elgg/Elgg//commit/01bacfc515e60c6abf3bc299d89f89150458e811) +* **plugins:** improved handling of composer version constraints [8dd38c0b7](https://github.com/Elgg/Elgg//commit/8dd38c0b7929de6d5d3e0aba6704fe50316538c6) closes [#14580](https://github.com/Elgg/Elgg//commit/14580) +* **pages:** correctly disable parent page option [02a4f3bfa](https://github.com/Elgg/Elgg//commit/02a4f3bfa372ec5d103ba48d8b27af23d3b134e8) + + + +### 5.1.4 (2024-01-12) + +#### Contributors + +* Jerôme Bakker (3) +* Jeroen Dalsem (2) + +#### Bug fixes + +* **comments:** only load comment form when needed [1eaa55b48](https://github.com/Elgg/Elgg//commit/1eaa55b48bd3fc55ac00580627e254e0f8124fa5) +* **session:** allow samesite cookie configuration [1dcb96c26](https://github.com/Elgg/Elgg//commit/1dcb96c2688da0b7e6cb87d78de12043f05dc8c0) +* **notifications:** prevent unneeded content subscriptions [3ffedc0ad](https://github.com/Elgg/Elgg//commit/3ffedc0ad92992f930377e5261a24ba51580e61c) closes [#14301](https://github.com/Elgg/Elgg//commit/14301) + + + +### 5.1.3 (2023-12-15) + +#### Contributors + +* Jeroen Dalsem (5) +* Jerôme Bakker (2) + +#### Bug fixes + +* **cli:** database seed command no longer queues notifications [7fb4139fe](https://github.com/Elgg/Elgg//commit/7fb4139fea6b61243838adf31beccd09812c453c) +* **uservalidationbyemail:** only allow confirm link for logged out users [89ba96f5d](https://github.com/Elgg/Elgg//commit/89ba96f5da04ec392d027d4b26c75b6a8946e273) +* **users:** prevent ban/unban notifications for users during disable [623a2fe6a](https://github.com/Elgg/Elgg//commit/623a2fe6acfa1104414b57cc88ce4ab408c715e1) + + + +### 5.1.2 (2023-11-30) + +#### Contributors + +* Jeroen Dalsem (4) +* Jerôme Bakker (4) + +#### Bug fixes + +* **output:** link must have discernible text [8ed45c12d](https://github.com/Elgg/Elgg//commit/8ed45c12d49365306c463a461af7a10ae74bbb1d) +* **web_services:** only create new tokens on initial save [a1904fc7c](https://github.com/Elgg/Elgg//commit/a1904fc7c64a5ee88ddb65aa5467528b58fde4db) closes [#14516](https://github.com/Elgg/Elgg//commit/14516) +* **developers:** removed metadata enabled column in entity explorer [4256e4dd7](https://github.com/Elgg/Elgg//commit/4256e4dd7c6fac502de9c6fbc8b6432720667f57) + + + +### 5.1.1 (2023-11-17) + +#### Contributors + +* Jerôme Bakker (9) +* Jeroen Dalsem (5) + +#### Bug fixes + +* **webservices:** no longer expose parts of the system during an error [a0db26a40](https://github.com/Elgg/Elgg//commit/a0db26a40fb9b42a9794516890f9efd6a54f1f18) +* **cli:** provide readable feedback when using incorrect cron interval [c658dd2b7](https://github.com/Elgg/Elgg//commit/c658dd2b7ba4d9c46a0229b8810862110c677b33) +* **pages:** don't allow a page to be its own parent [f029d1e69](https://github.com/Elgg/Elgg//commit/f029d1e69b1a36b758348c104985ff9c4eaff757) +* **views:** don't output a summary title if no display name [385475469](https://github.com/Elgg/Elgg//commit/385475469ea96ca3f7034811305fbbde866fc1af) +* **css:** improved elgg-level behaviour on limited viewports [a1482000f](https://github.com/Elgg/Elgg//commit/a1482000fb9e509f4aa9082d52fd3bc0977ad6e4) +* **routes:** correctly deprecate the comment/edit route [04bed5687](https://github.com/Elgg/Elgg//commit/04bed5687bb33b65fe8cd00caf03b61a7cd56f5b) + + + +## 5.1.0 (2023-10-24) + +#### Contributors + +* Jeroen Dalsem (37) +* Jerôme Bakker (36) + +#### Features + +* **ckeditor:** + * updated to v40.0.0 [441c0f442](https://github.com/Elgg/Elgg//commit/441c0f442f87f43eef5c277708316f33a3a8091d) + * ctrl+enter in the editor field will submit the form [5b0bd6a8d](https://github.com/Elgg/Elgg//commit/5b0bd6a8d72e2872e447fb3e331356aa5b4f095b) +* **css:** allow theme variables to be configured by the site admin [3eb7fe354](https://github.com/Elgg/Elgg//commit/3eb7fe3549ef2c7758541c4080d6914bf131815d) +* **cron:** added custom cron logger class [6535d386b](https://github.com/Elgg/Elgg//commit/6535d386b22d27e8631e59c6cbcaf258e63f7b3e) +* **a11y:** + * added menu aria labels [19869cfc9](https://github.com/Elgg/Elgg//commit/19869cfc9f3e1ddc90f5e15babcb3974dad083be) + * added aria search forms [091202e4a](https://github.com/Elgg/Elgg//commit/091202e4a0445d7d2fc37c3b217628f8e0e2f022) + * added header, main, footer aria landmarks [61315fe7e](https://github.com/Elgg/Elgg//commit/61315fe7edbb11a13f049517ac13631c57859ed1) +* **views:** support a title on an imprint element [2ebfccb09](https://github.com/Elgg/Elgg//commit/2ebfccb096dba500bf2f496bd1807b923ca9cb63) +* **breadcrumbs:** + * improved usability of elgg_push_collection_breadcrumb [68c6d069e](https://github.com/Elgg/Elgg//commit/68c6d069e785eeb56446b1db84c4f4bf402e471c) + * last item pointing to current page will be removed [95b305458](https://github.com/Elgg/Elgg//commit/95b3054585ca07c85de328a28e0346a51385ead6) + * added a home icon as a first item [e78e7ee68](https://github.com/Elgg/Elgg//commit/e78e7ee68519cd44c07721c9a1c95fd6080eea17) +* **blog:** prevent double submit of the blog form [0a23cd09b](https://github.com/Elgg/Elgg//commit/0a23cd09b2d388a300b48f928b560a36fd9dcc5f) +* **cli:** + * interactively set number of seeded items per seeder [337b1bd71](https://github.com/Elgg/Elgg//commit/337b1bd71040b0d83c41a70a745069b1fbe6f6fd) + * added database seeders command [12baa7c68](https://github.com/Elgg/Elgg//commit/12baa7c68317859257d7286ce14e399189d658ed) + * activate plugins CLI command supports plugin priority [160fcaf69](https://github.com/Elgg/Elgg//commit/160fcaf69b38e9c7596756708a4cfeb954af0e1f) + * installer now has the option to prevent plugin activation [1a20e79ef](https://github.com/Elgg/Elgg//commit/1a20e79eff94503081e29c63b6a1ebee9002126d) +* **security:** add support for security.txt [2709c2db4](https://github.com/Elgg/Elgg//commit/2709c2db45a455c1e52ec3cc1e438b2155a4627a) closes [#14315](https://github.com/Elgg/Elgg//commit/14315) +* **admin:** reorganized admin and configure utilities menu items [de1959ad5](https://github.com/Elgg/Elgg//commit/de1959ad580b6e4ea49fdd9f7a7560c0b02bea74) +* **widgets:** the widget edit form now shows in a lightbox [15e68df90](https://github.com/Elgg/Elgg//commit/15e68df9056284cd3f6c4056be30081433a08dfd) +* **input:** the value output view for an userpicker can be set [585903bb9](https://github.com/Elgg/Elgg//commit/585903bb94ecb97983bd0754e471fb5d3123cab0) +* **developers:** + * the theme sandbox is now a separated plugin [22cd62e89](https://github.com/Elgg/Elgg//commit/22cd62e897c7c5760246926da24494069168b7d7) + * added inspection page for the database CLI seeders [e8255d3f6](https://github.com/Elgg/Elgg//commit/e8255d3f661b1e50d19252da32dbe54e5f9dc12d) +* **html:** added a scroll to top button [58b1ae7d1](https://github.com/Elgg/Elgg//commit/58b1ae7d12eae286a48fde8afb1bd6e16704e26b) +* **js:** client side validate max file size for file input [3b19a7071](https://github.com/Elgg/Elgg//commit/3b19a7071591f766fa51706f590c3255ecf3d086) closes [#7059](https://github.com/Elgg/Elgg//commit/7059) + + +#### Bug fixes + +* **css:** fixed some margin issues on elgg-field form elements [1565a6d47](https://github.com/Elgg/Elgg//commit/1565a6d475d17124dcc84a77438180d2fb549cbb) closes [#14354](https://github.com/Elgg/Elgg//commit/14354) +* **a11y:** + * topbar sub menu items are now keyboard accessible [6326c3902](https://github.com/Elgg/Elgg//commit/6326c39020e6421ecfbcb3d1890bbb17c610da90) closes [#6759](https://github.com/Elgg/Elgg//commit/6759) + * make sure widget edit/delete actions are keyboard accessible [d7b61ed15](https://github.com/Elgg/Elgg//commit/d7b61ed15952556ff394340fa38df16bbc5ba353) closes [#14471](https://github.com/Elgg/Elgg//commit/14471) + * tab to first item in opened dropdown menu [487d7370a](https://github.com/Elgg/Elgg//commit/487d7370a2edb4971ab6a66e1cb08d75c9dc0d84) + * edit comment form sets focus to comment textarea [477646730](https://github.com/Elgg/Elgg//commit/47764673071fd8301042569f672cd9d92c37578b) + * keep focus on toggled menu item [a18ad0057](https://github.com/Elgg/Elgg//commit/a18ad0057c4d79286768e77c14943315350c350d) +* **cache:** report HTTP 410 Gone on stale cache urls [cfd488361](https://github.com/Elgg/Elgg//commit/cfd488361b7e2eb1783afcf7dd16f00127897c6b) closes [#14086](https://github.com/Elgg/Elgg//commit/14086) +* **views:** + * prevent duplicate ids on widget layouts [b17877975](https://github.com/Elgg/Elgg//commit/b17877975ee5550d7c29b236e2252dacda59d22e) closes [#14428](https://github.com/Elgg/Elgg//commit/14428) + * do not use rel to track related hover menu placeholders [972f40873](https://github.com/Elgg/Elgg//commit/972f4087373cc5700a7cd7bd707d29f7193d522a) closes [#14430](https://github.com/Elgg/Elgg//commit/14430) +* **breadcrumbs:** no longer add a breadcrumb if link to self is false [7a44a533c](https://github.com/Elgg/Elgg//commit/7a44a533c2d68f7402abb0b124698934e6626b75) + + +#### Deprecations + +* **views:** resource and route for comment edit are not in use [84deb0e54](https://github.com/Elgg/Elgg//commit/84deb0e54ed887c883f67c5538f0d8d095efd19b) + + + +### 5.0.7 (2023-10-10) + +#### Contributors + +* Jeroen Dalsem (5) +* Jerôme Bakker (2) + +#### Bug Fixes + +* **forms:** prevent double submit on comment forms ([1b057186](https://github.com/Elgg/Elgg/commit/1b057186899ceb119b461613f65ac4b1f82e9b3b)) +* **icons:** retry icon resize after failure ([e04e396b](https://github.com/Elgg/Elgg/commit/e04e396b428b850b173fbcc42f3ac4efeb4d08d1)) + + + +### 5.0.6 (2023-09-07) + +#### Contributors + +* Jerôme Bakker (2) +* Nikolai Shcherbin (1) + +#### Bug Fixes + +* **ckeditor:** early abort object mentions on closing bracket ([b397601c](https://github.com/Elgg/Elgg/commit/b397601cd21212698c16e0ab00eb96d0e9f9679f)) +* **docs:** document correct function ([e9ba84a1](https://github.com/Elgg/Elgg/commit/e9ba84a15c4aeaeb9892ec252bdb5543135251fe)) + + + +### 5.0.5 (2023-08-16) + +#### Contributors + +* Jeroen Dalsem (1) +* Jerôme Bakker (1) + +#### Bug Fixes + +* **rss:** invalid atom link href in rss channel ([0467cf87](https://github.com/Elgg/Elgg/commit/0467cf8703bb3ea4936bd73bfbb3813a434d9275)) + + + +### 5.0.4 (2023-07-26) + +#### Contributors + +* Jerôme Bakker (9) +* Jeroen Dalsem (1) + +#### Bug Fixes + +* **ckeditor:** added all block level image alignments to toolbar ([6fff9429](https://github.com/Elgg/Elgg/commit/6fff94290017df4a9bf879236b73c1f0be92c62e)) +* **icons:** prevent racing condition when saving cropping coordinates ([b4993528](https://github.com/Elgg/Elgg/commit/b499352814c45d8fbfc1eefa3fa5294e27de68cb)) +* **notifications:** processing delayed emails could cause OOM issues ([5e0fcab1](https://github.com/Elgg/Elgg/commit/5e0fcab17eb701474d1d121933474eefa52b7aca)) +* **views:** + * input/button and output/url must have discernible text ([924b2cdc](https://github.com/Elgg/Elgg/commit/924b2cdcae2a97447a2094b7389fe9ebb1d2f74e)) + * make sure the icon cropper img has an alt text ([0cc105c8](https://github.com/Elgg/Elgg/commit/0cc105c8b684ed756b4839c1d72df714f17a1865)) + * allow mobile devices to zoom ([1cee1be1](https://github.com/Elgg/Elgg/commit/1cee1be17474da910172dd5cc829f10a67c7fd0b)) + * correctly set iframe width for PHPInfo ([e72f476e](https://github.com/Elgg/Elgg/commit/e72f476eb62ce5e8253deaf7ea9ca71fe70c79c5)) + * only generate listing ID when using pagination ([ffe94eab](https://github.com/Elgg/Elgg/commit/ffe94eab174e0984cf288585fd91d24ac8d07a55)) + + + +### 5.0.3 (2023-07-14) + +#### Contributors + +* Jerôme Bakker (7) +* Jeroen Dalsem (3) + +#### Bug Fixes + +* **admin:** admin layout now gets correct layout class ([f0c348c0](https://github.com/Elgg/Elgg/commit/f0c348c03973328f07918894d5cbe65ed8a0e9af)) +* **composer:** no longer try to symlink the mods on Windows ([5319f0ea](https://github.com/Elgg/Elgg/commit/5319f0eaf69071602b410a88857511ca80e8358a)) +* **database:** execute delayed queries immediately during CLI ([d2d23209](https://github.com/Elgg/Elgg/commit/d2d2320984994cbfe0cdcd2ec42d6cf1f277f9dc)) +* **email:** image styles will be converted to attributes if possible ([f306388b](https://github.com/Elgg/Elgg/commit/f306388b51d08aeb2a28154a83793775315423a8)) +* **http:** maintain set redirect code in response ([c4ad5037](https://github.com/Elgg/Elgg/commit/c4ad5037bbaa04343c733358931f513765932a19)) +* **icons:** make sure transparent images have a white background ([25d039b2](https://github.com/Elgg/Elgg/commit/25d039b258ad14f77b0193222193deaccc375f9b)) +* **settings:** prevent setting changes from being added to the systemlog ([708cb7ff](https://github.com/Elgg/Elgg/commit/708cb7ff51e8a98b946124f2bcf0c7f38b67f01c)) +* **site_notifications:** return correct actor ([a2ee148f](https://github.com/Elgg/Elgg/commit/a2ee148f954432c3ce876c257c9da15b5671ffaa)) +* **user:** prevent logging of changes to last_login and prev_last_login ([ba28f760](https://github.com/Elgg/Elgg/commit/ba28f760f562e1c493d757d49c2f7b36b1ccc8ba)) + + + +### 5.0.2 (2023-07-03) + +#### Contributors + +* Jerôme Bakker (5) + +#### Performance + +* **site_notifications:** simplify site_notification removal query ([ad8bd918](https://github.com/Elgg/Elgg/commit/ad8bd918edad2c312a4f6bbac042119b446cdc12)) + + +#### Bug Fixes + +* **thewire:** improved hashtag matching ([67277b2f](https://github.com/Elgg/Elgg/commit/67277b2fe84201b43637cca001be55da5e5faff8)) +* **user:** return correct type for getOwnerGuid ([72856546](https://github.com/Elgg/Elgg/commit/72856546ba14139efa355398514e751b08c5c97b)) +* **views:** correctly handle errors in mention parsing ([92dc5d6d](https://github.com/Elgg/Elgg/commit/92dc5d6df4b1afdd5359211711ec9d66a1dcbc7e)) + + ### 5.0.1 (2023-06-19) @@ -152,6 +445,31 @@ * **widgets:** class function saveSettings has been removed ([3c58daee](https://github.com/Elgg/Elgg/commit/3c58daeea8bfc48c099827733cbe167462043d5f)) + +### 4.3.10 (2023-11-17) + +#### Contributors + +* Jerôme Bakker (2) + +#### Bug Fixes + +* **session:** correctly invalidate session on privilege elevation ([6357da49](https://github.com/Elgg/Elgg/commit/6357da49080c1d339e57300ae111208fa95220e4)) + + + +### 4.3.9 (2023-07-26) + +#### Contributors + +* Jerôme Bakker (2) +* Nikolai Shcherbin (1) + +#### Bug Fixes + +* **admin:** use correct params for memcache and redis server information ([6ee26b94](https://github.com/Elgg/Elgg/commit/6ee26b94637a384af133187afb9fab766ef324da)) + + ### 4.3.8 (2023-04-04) diff --git a/README.md b/README.md index b41eeafb9b9..f546c0fc629 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ Elgg ==== -[![PHPUnit test suites](https://github.com/Elgg/Elgg/actions/workflows/phpunit.yml/badge.svg?branch=5.0)](https://github.com/Elgg/Elgg/actions/workflows/phpunit.yml) -[![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/Elgg/Elgg/badges/quality-score.png?s=5.0)](https://scrutinizer-ci.com/g/Elgg/Elgg/?branch=5.0) -[![Scrutinizer Code Coverage](https://scrutinizer-ci.com/g/Elgg/Elgg/badges/coverage.png?b=5.0)](https://scrutinizer-ci.com/g/Elgg/Elgg/?branch=5.0) -[![Read the docs build status](https://readthedocs.org/projects/elgg/badge/?badge=5.0)](http://learn.elgg.org/en/5.0/) +[![PHPUnit test suites](https://github.com/Elgg/Elgg/actions/workflows/phpunit.yml/badge.svg?branch=5.1)](https://github.com/Elgg/Elgg/actions/workflows/phpunit.yml) +[![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/Elgg/Elgg/badges/quality-score.png?s=5.1)](https://scrutinizer-ci.com/g/Elgg/Elgg/?branch=5.1) +[![Scrutinizer Code Coverage](https://scrutinizer-ci.com/g/Elgg/Elgg/badges/coverage.png?b=5.1)](https://scrutinizer-ci.com/g/Elgg/Elgg/?branch=5.1) +[![Read the docs build status](https://readthedocs.org/projects/elgg/badge/?badge=5.1)](http://learn.elgg.org/en/5.1/) Elgg is an open source rapid development framework for socially aware web applications. @@ -18,7 +18,7 @@ Features - **Cacheable system of static assets** that allows themes and plugins to serve images, stylesheets, fonts and scripts bypassing the engine - **User authentication** is powered by pluggable auth modules, which allow applications to implement custom authentication protocols - **Security** is ensured by built-in anti CSRF validation, strict XSS filters, HMAC signatures, latest cryptographic approaches to password hashing -- **Client-side API** powered by asynchronous JavaScript modules via RequireJS and a build-in Ajax service for easy communication with the server +- **Client-side API** powered by asynchronous ES modules and a built-in Ajax service for easy communication with the server - **Flexible entity system** that allows applications to prototype new types of content and user interactions - **Opinionated data model** with a consolidated API layer that allows the developers to easily interface with the database - **Access control system** that allows applications to build granular content access policies, as well as create private networks and intranets @@ -34,14 +34,14 @@ Under the hood: - Elgg is a modular OOP framework that is driven by DI services - NGINX or Apache compatible - Symfony2 HTTP Foundation handles requests and responses -- RequireJS handles AMD +- modular javascript with ECMAScript modules - Laminas Mail handles outgoing email - htmLawed XSS filters - DBAL - Phinx database migrations - CSS-Crush for CSS preprocessing - Imagine for image manipulation -* Persistent caching with Memcached and/or Redis +- Persistent caching with Memcached and/or Redis - Error handling with Monolog Elgg Foundation diff --git a/actions/admin/security/security_txt.php b/actions/admin/security/security_txt.php new file mode 100644 index 00000000000..a95691d5e4c --- /dev/null +++ b/actions/admin/security/security_txt.php @@ -0,0 +1,33 @@ + true, + 'expires' => true, + 'encryption' => false, + 'acknowledgments' => false, + 'language' => false, + 'canonical' => false, + 'policy' => false, + 'hiring' => false, + 'csaf' => false, +]; + +// first validate all required inputs +foreach ($fields as $name => $required) { + $value = get_input($name); + if (!$required || !empty($value)) { + continue; + } + + return elgg_error_response(elgg_echo('error:missing_data')); +} + +// save all data +foreach ($fields as $name => $required) { + elgg_save_config("security_txt_{$name}", get_input($name) ?: null); +} + +return elgg_ok_response('', elgg_echo('save:success')); diff --git a/actions/admin/site/icons.php b/actions/admin/site/icons.php index d3020de3c3b..57d921b3b6a 100644 --- a/actions/admin/site/icons.php +++ b/actions/admin/site/icons.php @@ -48,4 +48,4 @@ elgg_save_config('font_awesome_zip', $zip->getClientOriginalName()); } -return elgg_ok_response(elgg_echo('save:success')); +return elgg_ok_response('', elgg_echo('save:success')); diff --git a/actions/admin/site/settings.php b/actions/admin/site/settings.php index ccfe6361477..0c4e81c58d7 100644 --- a/actions/admin/site/settings.php +++ b/actions/admin/site/settings.php @@ -76,6 +76,14 @@ elgg_save_config('pagination_behaviour', get_input('pagination_behaviour', 'ajax-replace')); elgg_save_config('mentions_display_format', get_input('mentions_display_format')); +$trash_retention = (int) get_input('trash_retention', 30); +if ($trash_retention < 0) { + $trash_retention = 30; +} + +elgg_save_config('trash_retention', $trash_retention); +elgg_save_config('trash_enabled', (bool) get_input('trash_enabled')); + elgg_save_config('user_joined_river', get_input('user_joined_river') === 'on'); elgg_save_config('can_change_username', get_input('can_change_username') === 'on'); diff --git a/actions/admin/site/theme.php b/actions/admin/site/theme.php new file mode 100644 index 00000000000..ac782805d88 --- /dev/null +++ b/actions/admin/site/theme.php @@ -0,0 +1,34 @@ +cssCompiler->getCssVars([], false); +foreach ($vars as $name => $value) { + if (empty($value)) { + unset($vars[$name]); + continue; + } + + if (!array_key_exists($name, $available_config)) { + unset($vars[$name]); + continue; + } + + if (strtolower($value) === strtolower((string) $available_config[$name])) { + unset($vars[$name]); + continue; + } +} + +if (empty($vars)) { + elgg_remove_config('custom_theme_vars'); +} else { + elgg_save_config('custom_theme_vars', $vars); +} + +elgg_invalidate_caches(); + +return elgg_ok_response('', elgg_echo('save:success')); diff --git a/actions/admin/user/bulk/delete.php b/actions/admin/user/bulk/delete.php index 08b3ffdd65a..961d39391bc 100644 --- a/actions/admin/user/bulk/delete.php +++ b/actions/admin/user/bulk/delete.php @@ -8,7 +8,7 @@ return elgg_error_response(elgg_echo('error:missing_data')); } -elgg_call(ELGG_SHOW_DISABLED_ENTITIES, function() use ($user_guids) { +elgg_call(ELGG_SHOW_DISABLED_ENTITIES | ELGG_SHOW_DELETED_ENTITIES, function() use ($user_guids) { foreach ($user_guids as $user_guid) { $user = get_user($user_guid); if (empty($user)) { diff --git a/actions/admin/user/delete.php b/actions/admin/user/delete.php index d34051892e4..8bea01b5403 100644 --- a/actions/admin/user/delete.php +++ b/actions/admin/user/delete.php @@ -12,7 +12,7 @@ return elgg_error_response(elgg_echo('admin:user:self:delete:no')); } -$user = elgg_call(ELGG_SHOW_DISABLED_ENTITIES, function() use ($guid) { +$user = elgg_call(ELGG_SHOW_DISABLED_ENTITIES | ELGG_SHOW_DELETED_ENTITIES, function() use ($guid) { return get_user($guid); }); if (!$user || !$user->canDelete()) { @@ -22,7 +22,7 @@ $name = $user->getDisplayName(); $username = $user->username; -$deleted = elgg_call(ELGG_SHOW_DISABLED_ENTITIES, function() use ($user) { +$deleted = elgg_call(ELGG_SHOW_DISABLED_ENTITIES | ELGG_SHOW_DELETED_ENTITIES, function() use ($user) { return $user->delete(); }); if (!$deleted) { diff --git a/actions/entity/chooserestoredestination.php b/actions/entity/chooserestoredestination.php new file mode 100644 index 00000000000..b3de81c0369 --- /dev/null +++ b/actions/entity/chooserestoredestination.php @@ -0,0 +1,63 @@ +isDeleted()) { + return elgg_error_response(elgg_echo('entity:restore:item_not_found')); +} + +$new_container = get_entity($destination_container_guid[0]); +if (!$new_container instanceof \ElggEntity) { + return elgg_error_response(elgg_echo('error:missing_data')); +} + +if (!$new_container->canWriteToContainer(0, $entity->type, $entity->subtype)) { + return elgg_error_response(elgg_echo('entity:restore:container_permission', [$new_container->getDisplayName()])); +} + +// determine what name to show on success +$display_name = $entity->getDisplayName() ?: elgg_echo('entity:restore:item'); + +if (!$entity->restore()) { + return elgg_error_response(elgg_echo('entity:restore:fail', [$display_name])); +} + +$entity->container_guid = $new_container->guid; +if (!$entity->save()) { + return elgg_error_response(elgg_echo('entity:restore:fail', [$display_name])); +} + +$success_keys = [ + "entity:restore:{$entity->type}:{$entity->subtype}:success", + "entity:restore:{$entity->type}:success", + 'entity:restore:success', +]; + +$message = ''; +if (get_input('show_success', true)) { + foreach ($success_keys as $success_key) { + if (elgg_language_key_exists($success_key)) { + $message = elgg_echo($success_key, [$display_name]); + break; + } + } +} + +return elgg_ok_response('', $message); diff --git a/actions/entity/delete.php b/actions/entity/delete.php index 136b1d351f4..1e2121e1e37 100644 --- a/actions/entity/delete.php +++ b/actions/entity/delete.php @@ -4,8 +4,9 @@ */ $guid = (int) get_input('guid'); - -$entity = get_entity($guid); +$entity = elgg_call(ELGG_SHOW_DISABLED_ENTITIES | ELGG_SHOW_DELETED_ENTITIES, function() use ($guid) { + return get_entity($guid); +}); if (!$entity instanceof \ElggEntity) { return elgg_error_response(elgg_echo('entity:delete:item_not_found')); } @@ -14,8 +15,6 @@ return elgg_error_response(elgg_echo('entity:delete:permission_denied')); } -set_time_limit(0); - // determine what name to show on success $display_name = $entity->getDisplayName() ?: elgg_echo('entity:delete:item'); @@ -23,7 +22,7 @@ $subtype = $entity->getSubtype(); $container = $entity->getContainerEntity(); -if (!$entity->delete()) { +if (!$entity->delete(true, true)) { return elgg_error_response(elgg_echo('entity:delete:fail', [$display_name])); } diff --git a/actions/entity/restore.php b/actions/entity/restore.php new file mode 100644 index 00000000000..f33e2eb4705 --- /dev/null +++ b/actions/entity/restore.php @@ -0,0 +1,41 @@ +isDeleted()) { + return elgg_error_response(elgg_echo('entity:restore:item_not_found')); +} + +if (!$entity->canEdit()) { + return elgg_error_response(elgg_echo('entity:restore:permission_denied')); +} + +// determine what name to show on success +$display_name = $entity->getDisplayName() ?: elgg_echo('entity:restore:item'); + +if (!$entity->restore()) { + return elgg_error_response(elgg_echo('entity:restore:fail', [$display_name])); +} + +$success_keys = [ + "entity:restore:{$entity->type}:{$entity->subtype}:success", + "entity:restore:{$entity->type}:success", + 'entity:restore:success', +]; + +$message = ''; +if (get_input('show_success', true)) { + foreach ($success_keys as $success_key) { + if (elgg_language_key_exists($success_key)) { + $message = elgg_echo($success_key, [$display_name]); + break; + } + } +} + +return elgg_ok_response('', $message); diff --git a/actions/entity/trash.php b/actions/entity/trash.php new file mode 100644 index 00000000000..e708e83462b --- /dev/null +++ b/actions/entity/trash.php @@ -0,0 +1,94 @@ +canDelete() || !$entity->hasCapability('restorable') || $entity instanceof \ElggPlugin || $entity instanceof \ElggSite || $entity instanceof \ElggUser) { + return elgg_error_response(elgg_echo('entity:delete:permission_denied')); +} + +// determine what name to show on success +$display_name = $entity->getDisplayName() ?: elgg_echo('entity:delete:item'); + +$type = $entity->getType(); +$subtype = $entity->getSubtype(); +$container = $entity->getContainerEntity(); + +if (!$entity->delete(true, false)) { + return elgg_error_response(elgg_echo('entity:delete:fail', [$display_name])); +} + +// determine forward URL +$forward_url = get_input('forward_url'); +if (!empty($forward_url)) { + $forward_url = elgg_normalize_site_url((string) $forward_url); +} + +if (empty($forward_url)) { + $forward_url = REFERRER; + $referrer_url = elgg_extract('HTTP_REFERER', $_SERVER, ''); + $site_url = elgg_get_site_url(); + + $find_forward_url = function (\ElggEntity $container = null) use ($type, $subtype) { + $routes = _elgg_services()->routes; + + // check if there is a collection route (eg. blog/owner/username) + $route_name = false; + if ($container instanceof \ElggUser) { + $route_name = "collection:{$type}:{$subtype}:owner"; + } elseif ($container instanceof \ElggGroup) { + $route_name = "collection:{$type}:{$subtype}:group"; + } + + if ($route_name && $routes->get($route_name)) { + $params = $routes->resolveRouteParameters($route_name, $container); + + return elgg_generate_url($route_name, $params); + } + + // no route found, fallback to container url + if ($container instanceof \ElggEntity) { + return $container->getURL(); + } + + // no container + return ''; + }; + + if (!empty($referrer_url) && elgg_strpos($referrer_url, $site_url) === 0) { + // referer is on current site + $referrer_path = elgg_substr($referrer_url, elgg_strlen($site_url)); + $segments = explode('/', $referrer_path); + + if (in_array($guid, $segments)) { + // referrer URL contains a reference to the entity that will be deleted + $forward_url = $find_forward_url($container); + } + } elseif ($container instanceof \ElggEntity) { + $forward_url = $find_forward_url($container); + } +} + +$success_keys = [ + "entity:delete:{$type}:{$subtype}:success", + "entity:delete:{$type}:success", + 'entity:delete:success', +]; + +$message = ''; +if (get_input('show_success', true)) { + foreach ($success_keys as $success_key) { + if (elgg_language_key_exists($success_key)) { + $message = elgg_echo($success_key, [$display_name]); + break; + } + } +} + +return elgg_ok_response('', $message, $forward_url); diff --git a/composer.json b/composer.json index 9d0690ee0f7..c939e1350ac 100644 --- a/composer.json +++ b/composer.json @@ -1,65 +1,62 @@ { "name": "elgg/elgg", - "version": "5.0.1", + "version": "6.0.0-beta.1", "description": "Elgg is an award-winning social networking engine, delivering the building blocks that enable businesses, schools, universities and associations to create their own fully-featured social networks and applications.", "license": "GPL-2.0-only", "minimum-stability": "dev", "prefer-stable": true, "type": "project", "require": { - "php": ">=8.0", - "ext-pdo": "*", - "ext-gd": "*", + "php": ">=8.1", + "ext-intl": "*", "ext-json": "*", + "ext-gd": "*", + "ext-pdo": "*", "ext-xml": "*", - "ckeditor/ckeditor": "~4.20.0", - "composer/semver": "~3.3.0", + "composer/installers": ">=1.0.8", + "composer/semver": "~3.4.0", "css-crush/css-crush": "~4.1.0", - "doctrine/dbal": "~3.4.4", + "doctrine/dbal": "~4.0.1", "eloquent/composer-config-reader": "~3.0.0", - "fakerphp/faker": "~1.20.0", + "fakerphp/faker": "~1.23.0", "fortawesome/font-awesome": "~5.14", - "guzzlehttp/guzzle": "~7.5.0", + "guzzlehttp/guzzle": "~7.8.0", "hackzilla/password-generator": "~1.6.0", "imagine/imagine": "~1.3.0", "laminas/laminas-mail": "~2.4", - "laminas/laminas-mime": "2.11.0", + "laminas/laminas-mime": "2.12.0", "laminas/laminas-servicemanager": "^3.3.1", - "league/flysystem": "~2.5.0", - "league/flysystem-memory": "~2.0.0", "matthiasmullie/minify": "~1.3.0", "michelf/php-markdown": "~2.0.0", "misd/linkify": "~1.1.2", - "monolog/monolog": "~2.8.0", - "npm-asset/cropperjs": "~1.5.9", - "npm-asset/jquery": "~3.6.0", + "monolog/monolog": "~3.6.0", + "npm-asset/cropperjs": "~1.6.1", + "npm-asset/jquery": "~3.7.1", "npm-asset/jquery-cropper": "~1.0.0", "npm-asset/jquery-colorbox": "^1.6.4", "npm-asset/jquery-ui": "~1.13.1", "npm-asset/jquery-ui-touch-punch": "~0.2.3", "npm-asset/normalize.css": "~8.0.1", - "npm-asset/requirejs": "^2.3.6", - "npm-asset/requirejs-text": "^2.0.4", "npm-asset/sprintf-js": "~1.1.2", - "npm-asset/yaireo--tagify": "~4.16.0", - "pelago/emogrifier": "~7.0.0", + "npm-asset/yaireo--tagify": "~4.22.0", + "pelago/emogrifier": "~7.2.0", "peppeocchi/php-cron-scheduler": "~4.0", - "php-di/php-di": "~6.4.0", - "phpfastcache/phpfastcache": "~9.1.3", - "react/promise": "^2.5", + "php-di/php-di": "~7.0.6", + "phpfastcache/phpfastcache": "~9.2.3", + "react/promise": "~3.1.0", "roave/security-advisories": "dev-master", - "robmorgan/phinx": "~0.12.7", - "symfony/console": "~5.3", - "symfony/http-foundation": "~5.3", - "symfony/mime": "~5.3", - "symfony/routing": "~5.3", - "symfony/var-dumper": "~5.3", - "vanilla/htmlawed": "~2.2.0" + "robmorgan/phinx": "~0.16.0", + "symfony/console": "~6.4", + "symfony/http-foundation": "~6.4", + "symfony/mime": "~6.4", + "symfony/routing": "~6.4", + "symfony/var-dumper": "~6.4", + "vanilla/htmlawed": "~2.2.15" }, "config": { "process-timeout": 0, "platform": { - "php": "8.0" + "php": "8.1" }, "fxp-asset": { "enabled": false @@ -100,7 +97,7 @@ }, "require-dev": { "elgg/sniffs": "dev-master", - "phpunit/phpunit": "~9.5", + "phpunit/phpunit": "~10.5", "phpdocumentor/reflection-docblock": "^5.2", "scrutinizer/ocular": "^1.9" }, diff --git a/composer.lock b/composer.lock index 092959ca5d4..9e893902c3c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,28 +4,85 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b9eab7643708c13503988a75b1aea24f", + "content-hash": "09a4acdb6cafe03a79af9ca5c119648a", "packages": [ + { + "name": "cakephp/chronos", + "version": "3.0.4", + "source": { + "type": "git", + "url": "https://github.com/cakephp/chronos.git", + "reference": "9cb035acd10152a6b74df936986f15c4e6015bd3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cakephp/chronos/zipball/9cb035acd10152a6b74df936986f15c4e6015bd3", + "reference": "9cb035acd10152a6b74df936986f15c4e6015bd3", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "cakephp/cakephp-codesniffer": "^5.0", + "phpunit/phpunit": "^10.1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Cake\\Chronos\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Brian Nesbitt", + "email": "brian@nesbot.com", + "homepage": "http://nesbot.com" + }, + { + "name": "The CakePHP Team", + "homepage": "https://cakephp.org" + } + ], + "description": "A simple API extension for DateTime.", + "homepage": "https://cakephp.org", + "keywords": [ + "date", + "datetime", + "time" + ], + "support": { + "issues": "https://github.com/cakephp/chronos/issues", + "source": "https://github.com/cakephp/chronos" + }, + "time": "2023-10-17T07:41:48+00:00" + }, { "name": "cakephp/core", - "version": "4.4.14", + "version": "5.0.7", "source": { "type": "git", "url": "https://github.com/cakephp/core.git", - "reference": "ded708dbeb10a27ffcb4e3a87d1ceec33614ad63" + "reference": "163ba348b96870de24b7cf34abdcd8d0c3794ed7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/core/zipball/ded708dbeb10a27ffcb4e3a87d1ceec33614ad63", - "reference": "ded708dbeb10a27ffcb4e3a87d1ceec33614ad63", + "url": "https://api.github.com/repos/cakephp/core/zipball/163ba348b96870de24b7cf34abdcd8d0c3794ed7", + "reference": "163ba348b96870de24b7cf34abdcd8d0c3794ed7", "shasum": "" }, "require": { - "cakephp/utility": "^4.0", - "php": ">=7.4.0" + "cakephp/utility": "^5.0", + "league/container": "^4.2", + "php": ">=8.1", + "psr/container": "^1.1 || ^2.0" }, "provide": { - "psr/container-implementation": "^1.0 || ^2.0" + "psr/container-implementation": "^2.0" }, "suggest": { "cakephp/cache": "To use Configure::store() and restore().", @@ -64,29 +121,36 @@ "issues": "https://github.com/cakephp/cakephp/issues", "source": "https://github.com/cakephp/core" }, - "time": "2023-05-16T13:58:50+00:00" + "time": "2024-03-13T17:13:27+00:00" }, { "name": "cakephp/database", - "version": "4.4.14", + "version": "5.0.7", "source": { "type": "git", "url": "https://github.com/cakephp/database.git", - "reference": "752e3dfa61be055bf9d360880f00ab4ccfea6d1e" + "reference": "218f60271f65d1808272f785ce64a15491796648" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/database/zipball/752e3dfa61be055bf9d360880f00ab4ccfea6d1e", - "reference": "752e3dfa61be055bf9d360880f00ab4ccfea6d1e", + "url": "https://api.github.com/repos/cakephp/database/zipball/218f60271f65d1808272f785ce64a15491796648", + "reference": "218f60271f65d1808272f785ce64a15491796648", "shasum": "" }, "require": { - "cakephp/core": "^4.0", - "cakephp/datasource": "^4.0", - "php": ">=7.4.0" + "cakephp/chronos": "^3.0.2", + "cakephp/core": "^5.0", + "cakephp/datasource": "^5.0", + "php": ">=8.1", + "psr/log": "^3.0" + }, + "require-dev": { + "cakephp/i18n": "^5.0", + "cakephp/log": "^5.0", + "phpstan/phpstan": "^1.10" }, "suggest": { - "cakephp/i18n": "If you are using locale-aware datetime formats or Chronos types.", + "cakephp/i18n": "If you are using locale-aware datetime formats.", "cakephp/log": "If you want to use query logging without providing a logger yourself." }, "type": "library", @@ -120,27 +184,32 @@ "issues": "https://github.com/cakephp/cakephp/issues", "source": "https://github.com/cakephp/database" }, - "time": "2023-04-28T21:24:39+00:00" + "time": "2024-03-04T21:01:09+00:00" }, { "name": "cakephp/datasource", - "version": "4.4.14", + "version": "5.0.7", "source": { "type": "git", "url": "https://github.com/cakephp/datasource.git", - "reference": "faec70c6e0f78bb5a1db287f9b46a8b2a6fdbb13" + "reference": "3b3a70d0d8ae0daf55535f45b99ef109639ed1ec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/datasource/zipball/faec70c6e0f78bb5a1db287f9b46a8b2a6fdbb13", - "reference": "faec70c6e0f78bb5a1db287f9b46a8b2a6fdbb13", + "url": "https://api.github.com/repos/cakephp/datasource/zipball/3b3a70d0d8ae0daf55535f45b99ef109639ed1ec", + "reference": "3b3a70d0d8ae0daf55535f45b99ef109639ed1ec", "shasum": "" }, "require": { - "cakephp/core": "^4.0", - "php": ">=7.4.0", - "psr/log": "^1.0 || ^2.0", - "psr/simple-cache": "^1.0 || ^2.0" + "cakephp/core": "^5.0", + "php": ">=8.1", + "psr/simple-cache": "^2.0 || ^3.0" + }, + "require-dev": { + "cakephp/cache": "^5.0", + "cakephp/collection": "^5.0", + "cakephp/utility": "^5.0", + "phpstan/phpstan": "^1.10" }, "suggest": { "cakephp/cache": "If you decide to use Query caching.", @@ -178,25 +247,25 @@ "issues": "https://github.com/cakephp/cakephp/issues", "source": "https://github.com/cakephp/datasource" }, - "time": "2023-04-22T08:15:33+00:00" + "time": "2024-03-11T18:07:04+00:00" }, { "name": "cakephp/utility", - "version": "4.4.14", + "version": "5.0.7", "source": { "type": "git", "url": "https://github.com/cakephp/utility.git", - "reference": "a6a17c556d02c57259e21127a4f3d3ec5cd8481f" + "reference": "6d624cefc3e005ebf9bd2e7d8a1d35f5f4601ff8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/utility/zipball/a6a17c556d02c57259e21127a4f3d3ec5cd8481f", - "reference": "a6a17c556d02c57259e21127a4f3d3ec5cd8481f", + "url": "https://api.github.com/repos/cakephp/utility/zipball/6d624cefc3e005ebf9bd2e7d8a1d35f5f4601ff8", + "reference": "6d624cefc3e005ebf9bd2e7d8a1d35f5f4601ff8", "shasum": "" }, "require": { - "cakephp/core": "^4.0", - "php": ">=7.4.0" + "cakephp/core": "^5.0", + "php": ">=8.1" }, "suggest": { "ext-intl": "To use Text::transliterate() or Text::slug()", @@ -237,68 +306,165 @@ "issues": "https://github.com/cakephp/cakephp/issues", "source": "https://github.com/cakephp/utility" }, - "time": "2023-02-24T22:07:16+00:00" + "time": "2024-02-24T04:42:47+00:00" }, { - "name": "ckeditor/ckeditor", - "version": "4.20.2", + "name": "composer/installers", + "version": "v2.2.0", "source": { "type": "git", - "url": "https://github.com/ckeditor/ckeditor4-releases.git", - "reference": "8cc8f1b065f93d90c305c2609fec4e4215dd20ba" + "url": "https://github.com/composer/installers.git", + "reference": "c29dc4b93137acb82734f672c37e029dfbd95b35" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ckeditor/ckeditor4-releases/zipball/8cc8f1b065f93d90c305c2609fec4e4215dd20ba", - "reference": "8cc8f1b065f93d90c305c2609fec4e4215dd20ba", + "url": "https://api.github.com/repos/composer/installers/zipball/c29dc4b93137acb82734f672c37e029dfbd95b35", + "reference": "c29dc4b93137acb82734f672c37e029dfbd95b35", "shasum": "" }, - "type": "library", + "require": { + "composer-plugin-api": "^1.0 || ^2.0", + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "composer/composer": "1.6.* || ^2.0", + "composer/semver": "^1 || ^3", + "phpstan/phpstan": "^0.12.55", + "phpstan/phpstan-phpunit": "^0.12.16", + "symfony/phpunit-bridge": "^5.3", + "symfony/process": "^5" + }, + "type": "composer-plugin", + "extra": { + "class": "Composer\\Installers\\Plugin", + "branch-alias": { + "dev-main": "2.x-dev" + }, + "plugin-modifies-install-path": true + }, + "autoload": { + "psr-4": { + "Composer\\Installers\\": "src/Composer/Installers" + } + }, "notification-url": "https://packagist.org/downloads/", "license": [ - "GPL-2.0+", - "LGPL-2.1+", - "MPL-1.1+" + "MIT" ], "authors": [ { - "name": "CKSource", - "homepage": "https://cksource.com" + "name": "Kyle Robinson Young", + "email": "kyle@dontkry.com", + "homepage": "https://github.com/shama" } ], - "description": "JavaScript WYSIWYG web text editor.", - "homepage": "https://ckeditor.com/ckeditor-4/", + "description": "A multi-framework Composer library installer", + "homepage": "https://composer.github.io/installers/", "keywords": [ - "CKEditor", - "ckeditor4", - "editor", - "fckeditor", - "html", - "javascript", - "richtext", - "text", - "wysiwyg" + "Dolibarr", + "Eliasis", + "Hurad", + "ImageCMS", + "Kanboard", + "Lan Management System", + "MODX Evo", + "MantisBT", + "Mautic", + "Maya", + "OXID", + "Plentymarkets", + "Porto", + "RadPHP", + "SMF", + "Starbug", + "Thelia", + "Whmcs", + "WolfCMS", + "agl", + "annotatecms", + "attogram", + "bitrix", + "cakephp", + "chef", + "cockpit", + "codeigniter", + "concrete5", + "croogo", + "dokuwiki", + "drupal", + "eZ Platform", + "elgg", + "expressionengine", + "fuelphp", + "grav", + "installer", + "itop", + "known", + "kohana", + "laravel", + "lavalite", + "lithium", + "magento", + "majima", + "mako", + "matomo", + "mediawiki", + "miaoxing", + "modulework", + "modx", + "moodle", + "osclass", + "pantheon", + "phpbb", + "piwik", + "ppi", + "processwire", + "puppet", + "pxcms", + "reindex", + "roundcube", + "shopware", + "silverstripe", + "sydes", + "sylius", + "tastyigniter", + "wordpress", + "yawik", + "zend", + "zikula" ], "support": { - "forum": "https://stackoverflow.com/tags/ckeditor", - "issues": "https://github.com/ckeditor/ckeditor4/issues", - "source": "https://github.com/ckeditor/ckeditor4", - "wiki": "https://ckeditor.com/docs/ckeditor4/latest/" + "issues": "https://github.com/composer/installers/issues", + "source": "https://github.com/composer/installers/tree/v2.2.0" }, - "time": "2023-02-15T12:55:37+00:00" + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2022-08-20T06:45:11+00:00" }, { "name": "composer/semver", - "version": "3.3.2", + "version": "3.4.0", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9" + "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9", - "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9", + "url": "https://api.github.com/repos/composer/semver/zipball/35e8d0af4486141bc745f23a29cc2091eb624a32", + "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32", "shasum": "" }, "require": { @@ -348,9 +514,9 @@ "versioning" ], "support": { - "irc": "irc://irc.freenode.org/composer", + "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.3.2" + "source": "https://github.com/composer/semver/tree/3.4.0" }, "funding": [ { @@ -366,7 +532,7 @@ "type": "tidelift" } ], - "time": "2022-04-01T19:23:25+00:00" + "time": "2023-08-31T09:50:34+00:00" }, { "name": "css-crush/css-crush", @@ -428,140 +594,44 @@ }, "time": "2022-09-05T10:24:14+00:00" }, - { - "name": "doctrine/cache", - "version": "2.2.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/cache.git", - "reference": "1ca8f21980e770095a31456042471a57bc4c68fb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/cache/zipball/1ca8f21980e770095a31456042471a57bc4c68fb", - "reference": "1ca8f21980e770095a31456042471a57bc4c68fb", - "shasum": "" - }, - "require": { - "php": "~7.1 || ^8.0" - }, - "conflict": { - "doctrine/common": ">2.2,<2.4" - }, - "require-dev": { - "cache/integration-tests": "dev-master", - "doctrine/coding-standard": "^9", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "psr/cache": "^1.0 || ^2.0 || ^3.0", - "symfony/cache": "^4.4 || ^5.4 || ^6", - "symfony/var-exporter": "^4.4 || ^5.4 || ^6" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" - } - }, - "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": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.", - "homepage": "https://www.doctrine-project.org/projects/cache.html", - "keywords": [ - "abstraction", - "apcu", - "cache", - "caching", - "couchdb", - "memcached", - "php", - "redis", - "xcache" - ], - "support": { - "issues": "https://github.com/doctrine/cache/issues", - "source": "https://github.com/doctrine/cache/tree/2.2.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%2Fcache", - "type": "tidelift" - } - ], - "time": "2022-05-20T20:07:39+00:00" - }, { "name": "doctrine/dbal", - "version": "3.4.6", + "version": "4.0.1", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "3ce132f7c0b83d33b26ab6ed308e9e9260699bc4" + "reference": "9e588fe1f38a443cb17de6b86b803d9e028e2156" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/3ce132f7c0b83d33b26ab6ed308e9e9260699bc4", - "reference": "3ce132f7c0b83d33b26ab6ed308e9e9260699bc4", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/9e588fe1f38a443cb17de6b86b803d9e028e2156", + "reference": "9e588fe1f38a443cb17de6b86b803d9e028e2156", "shasum": "" }, "require": { - "composer-runtime-api": "^2", - "doctrine/cache": "^1.11|^2.0", "doctrine/deprecations": "^0.5.3|^1", - "doctrine/event-manager": "^1.0", - "php": "^7.4 || ^8.0", + "php": "^8.1", "psr/cache": "^1|^2|^3", "psr/log": "^1|^2|^3" }, "require-dev": { - "doctrine/coding-standard": "10.0.0", - "jetbrains/phpstorm-stubs": "2022.2", - "phpstan/phpstan": "1.8.10", - "phpstan/phpstan-strict-rules": "^1.4", - "phpunit/phpunit": "9.5.25", - "psalm/plugin-phpunit": "0.17.0", - "squizlabs/php_codesniffer": "3.7.1", - "symfony/cache": "^5.4|^6.0", - "symfony/console": "^4.4|^5.4|^6.0", - "vimeo/psalm": "4.29.0" + "doctrine/coding-standard": "12.0.0", + "fig/log-test": "^1", + "jetbrains/phpstorm-stubs": "2023.2", + "phpstan/phpstan": "1.10.58", + "phpstan/phpstan-phpunit": "1.3.15", + "phpstan/phpstan-strict-rules": "^1.5", + "phpunit/phpunit": "10.5.9", + "psalm/plugin-phpunit": "0.18.4", + "slevomat/coding-standard": "8.13.1", + "squizlabs/php_codesniffer": "3.9.0", + "symfony/cache": "^6.3.8|^7.0", + "symfony/console": "^5.4|^6.3|^7.0", + "vimeo/psalm": "5.21.1" }, "suggest": { "symfony/console": "For helpful console commands such as SQL execution and import of files." }, - "bin": [ - "bin/doctrine-dbal" - ], "type": "library", "autoload": { "psr-4": { @@ -614,7 +684,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/3.4.6" + "source": "https://github.com/doctrine/dbal/tree/4.0.1" }, "funding": [ { @@ -630,20 +700,20 @@ "type": "tidelift" } ], - "time": "2022-10-21T14:38:43+00:00" + "time": "2024-03-03T15:59:11+00:00" }, { "name": "doctrine/deprecations", - "version": "v1.1.1", + "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", - "reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3" + "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/612a3ee5ab0d5dd97b7cf3874a6efe24325efac3", - "reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", + "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", "shasum": "" }, "require": { @@ -675,114 +745,22 @@ "homepage": "https://www.doctrine-project.org/", "support": { "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/v1.1.1" - }, - "time": "2023-06-03T09:27:29+00:00" - }, - { - "name": "doctrine/event-manager", - "version": "1.2.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/event-manager.git", - "reference": "95aa4cb529f1e96576f3fda9f5705ada4056a520" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/event-manager/zipball/95aa4cb529f1e96576f3fda9f5705ada4056a520", - "reference": "95aa4cb529f1e96576f3fda9f5705ada4056a520", - "shasum": "" - }, - "require": { - "doctrine/deprecations": "^0.5.3 || ^1", - "php": "^7.1 || ^8.0" - }, - "conflict": { - "doctrine/common": "<2.9" - }, - "require-dev": { - "doctrine/coding-standard": "^9 || ^10", - "phpstan/phpstan": "~1.4.10 || ^1.8.8", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "vimeo/psalm": "^4.24" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Common\\": "src" - } + "source": "https://github.com/doctrine/deprecations/tree/1.1.3" }, - "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" - }, - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com" - } - ], - "description": "The Doctrine Event Manager is a simple PHP event system that was built to be used with the various Doctrine projects.", - "homepage": "https://www.doctrine-project.org/projects/event-manager.html", - "keywords": [ - "event", - "event dispatcher", - "event manager", - "event system", - "events" - ], - "support": { - "issues": "https://github.com/doctrine/event-manager/issues", - "source": "https://github.com/doctrine/event-manager/tree/1.2.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%2Fevent-manager", - "type": "tidelift" - } - ], - "time": "2022-10-12T20:51:15+00:00" + "time": "2024-01-30T19:34:25+00:00" }, { "name": "dragonmantank/cron-expression", - "version": "v3.3.2", + "version": "v3.3.3", "source": { "type": "git", "url": "https://github.com/dragonmantank/cron-expression.git", - "reference": "782ca5968ab8b954773518e9e49a6f892a34b2a8" + "reference": "adfb1f505deb6384dc8b39804c5065dd3c8c8c0a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/782ca5968ab8b954773518e9e49a6f892a34b2a8", - "reference": "782ca5968ab8b954773518e9e49a6f892a34b2a8", + "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/adfb1f505deb6384dc8b39804c5065dd3c8c8c0a", + "reference": "adfb1f505deb6384dc8b39804c5065dd3c8c8c0a", "shasum": "" }, "require": { @@ -822,7 +800,7 @@ ], "support": { "issues": "https://github.com/dragonmantank/cron-expression/issues", - "source": "https://github.com/dragonmantank/cron-expression/tree/v3.3.2" + "source": "https://github.com/dragonmantank/cron-expression/tree/v3.3.3" }, "funding": [ { @@ -830,7 +808,7 @@ "type": "github" } ], - "time": "2022-09-10T18:51:20+00:00" + "time": "2023-08-10T19:36:49+00:00" }, { "name": "eloquent/composer-config-reader", @@ -891,6 +869,7 @@ "issues": "https://github.com/eloquent/composer-config-reader/issues", "source": "https://github.com/eloquent/composer-config-reader/tree/3.0.0" }, + "abandoned": true, "time": "2020-11-16T06:11:04+00:00" }, { @@ -944,24 +923,25 @@ "issues": "https://github.com/eloquent/enumeration/issues", "source": "https://github.com/eloquent/enumeration/tree/master" }, + "abandoned": true, "time": "2018-11-22T02:45:56+00:00" }, { "name": "fakerphp/faker", - "version": "v1.20.0", + "version": "v1.23.1", "source": { "type": "git", "url": "https://github.com/FakerPHP/Faker.git", - "reference": "37f751c67a5372d4e26353bd9384bc03744ec77b" + "reference": "bfb4fe148adbf78eff521199619b93a52ae3554b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/37f751c67a5372d4e26353bd9384bc03744ec77b", - "reference": "37f751c67a5372d4e26353bd9384bc03744ec77b", + "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/bfb4fe148adbf78eff521199619b93a52ae3554b", + "reference": "bfb4fe148adbf78eff521199619b93a52ae3554b", "shasum": "" }, "require": { - "php": "^7.1 || ^8.0", + "php": "^7.4 || ^8.0", "psr/container": "^1.0 || ^2.0", "symfony/deprecation-contracts": "^2.2 || ^3.0" }, @@ -972,7 +952,8 @@ "bamarni/composer-bin-plugin": "^1.4.1", "doctrine/persistence": "^1.3 || ^2.0", "ext-intl": "*", - "symfony/phpunit-bridge": "^4.4 || ^5.2" + "phpunit/phpunit": "^9.5.26", + "symfony/phpunit-bridge": "^5.4.16" }, "suggest": { "doctrine/orm": "Required to use Faker\\ORM\\Doctrine", @@ -982,11 +963,6 @@ "ext-mbstring": "Required for multibyte Unicode string functionality." }, "type": "library", - "extra": { - "branch-alias": { - "dev-main": "v1.20-dev" - } - }, "autoload": { "psr-4": { "Faker\\": "src/Faker/" @@ -1009,9 +985,9 @@ ], "support": { "issues": "https://github.com/FakerPHP/Faker/issues", - "source": "https://github.com/FakerPHP/Faker/tree/v1.20.0" + "source": "https://github.com/FakerPHP/Faker/tree/v1.23.1" }, - "time": "2022-07-20T13:12:54+00:00" + "time": "2024-01-02T13:46:09+00:00" }, { "name": "fortawesome/font-awesome", @@ -1084,22 +1060,22 @@ }, { "name": "guzzlehttp/guzzle", - "version": "7.5.3", + "version": "7.8.1", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "584d1f06b5caa07b0587f5054d551ed65460ce5d" + "reference": "41042bc7ab002487b876a0683fc8dce04ddce104" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/584d1f06b5caa07b0587f5054d551ed65460ce5d", - "reference": "584d1f06b5caa07b0587f5054d551ed65460ce5d", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/41042bc7ab002487b876a0683fc8dce04ddce104", + "reference": "41042bc7ab002487b876a0683fc8dce04ddce104", "shasum": "" }, "require": { "ext-json": "*", - "guzzlehttp/promises": "^1.5", - "guzzlehttp/psr7": "^1.9.1 || ^2.4.5", + "guzzlehttp/promises": "^1.5.3 || ^2.0.1", + "guzzlehttp/psr7": "^1.9.1 || ^2.5.1", "php": "^7.2.5 || ^8.0", "psr/http-client": "^1.0", "symfony/deprecation-contracts": "^2.2 || ^3.0" @@ -1108,10 +1084,11 @@ "psr/http-client-implementation": "1.0" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.1", + "bamarni/composer-bin-plugin": "^1.8.2", "ext-curl": "*", - "php-http/client-integration-tests": "^3.0", - "phpunit/phpunit": "^8.5.29 || ^9.5.23", + "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999", + "php-http/message-factory": "^1.1", + "phpunit/phpunit": "^8.5.36 || ^9.6.15", "psr/log": "^1.1 || ^2.0 || ^3.0" }, "suggest": { @@ -1189,7 +1166,7 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.5.3" + "source": "https://github.com/guzzle/guzzle/tree/7.8.1" }, "funding": [ { @@ -1205,33 +1182,37 @@ "type": "tidelift" } ], - "time": "2023-05-15T20:42:18+00:00" + "time": "2023-12-03T20:35:24+00:00" }, { "name": "guzzlehttp/promises", - "version": "1.5.3", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "67ab6e18aaa14d753cc148911d273f6e6cb6721e" + "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/67ab6e18aaa14d753cc148911d273f6e6cb6721e", - "reference": "67ab6e18aaa14d753cc148911d273f6e6cb6721e", + "url": "https://api.github.com/repos/guzzle/promises/zipball/bbff78d96034045e58e13dedd6ad91b5d1253223", + "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223", "shasum": "" }, "require": { - "php": ">=5.5" + "php": "^7.2.5 || ^8.0" }, "require-dev": { - "symfony/phpunit-bridge": "^4.4 || ^5.1" + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.36 || ^9.6.15" }, "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, "autoload": { - "files": [ - "src/functions_include.php" - ], "psr-4": { "GuzzleHttp\\Promise\\": "src/" } @@ -1268,7 +1249,7 @@ ], "support": { "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/1.5.3" + "source": "https://github.com/guzzle/promises/tree/2.0.2" }, "funding": [ { @@ -1284,20 +1265,20 @@ "type": "tidelift" } ], - "time": "2023-05-21T12:31:43+00:00" + "time": "2023-12-03T20:19:20+00:00" }, { "name": "guzzlehttp/psr7", - "version": "2.5.0", + "version": "2.6.2", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "b635f279edd83fc275f822a1188157ffea568ff6" + "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/b635f279edd83fc275f822a1188157ffea568ff6", - "reference": "b635f279edd83fc275f822a1188157ffea568ff6", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/45b30f99ac27b5ca93cb4831afe16285f57b8221", + "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221", "shasum": "" }, "require": { @@ -1311,9 +1292,9 @@ "psr/http-message-implementation": "1.0" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.1", + "bamarni/composer-bin-plugin": "^1.8.2", "http-interop/http-factory-tests": "^0.9", - "phpunit/phpunit": "^8.5.29 || ^9.5.23" + "phpunit/phpunit": "^8.5.36 || ^9.6.15" }, "suggest": { "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" @@ -1384,7 +1365,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.5.0" + "source": "https://github.com/guzzle/psr7/tree/2.6.2" }, "funding": [ { @@ -1400,7 +1381,7 @@ "type": "tidelift" } ], - "time": "2023-04-17T16:11:26+00:00" + "time": "2023-12-03T20:05:35+00:00" }, { "name": "hackzilla/password-generator", @@ -1510,16 +1491,16 @@ }, { "name": "justinrainbow/json-schema", - "version": "5.2.12", + "version": "v5.2.13", "source": { "type": "git", "url": "https://github.com/justinrainbow/json-schema.git", - "reference": "ad87d5a5ca981228e0e205c2bc7dfb8e24559b60" + "reference": "fbbe7e5d79f618997bc3332a6f49246036c45793" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/ad87d5a5ca981228e0e205c2bc7dfb8e24559b60", - "reference": "ad87d5a5ca981228e0e205c2bc7dfb8e24559b60", + "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/fbbe7e5d79f618997bc3332a6f49246036c45793", + "reference": "fbbe7e5d79f618997bc3332a6f49246036c45793", "shasum": "" }, "require": { @@ -1574,26 +1555,26 @@ ], "support": { "issues": "https://github.com/justinrainbow/json-schema/issues", - "source": "https://github.com/justinrainbow/json-schema/tree/5.2.12" + "source": "https://github.com/justinrainbow/json-schema/tree/v5.2.13" }, - "time": "2022-04-13T08:02:27+00:00" + "time": "2023-09-26T02:20:38+00:00" }, { "name": "laminas/laminas-loader", - "version": "2.9.0", + "version": "2.10.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-loader.git", - "reference": "51ed9c3fa42d1098a9997571730c0cbf42d078d3" + "reference": "e6fe952304ef40ce45cd814751ab35d42afdad12" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-loader/zipball/51ed9c3fa42d1098a9997571730c0cbf42d078d3", - "reference": "51ed9c3fa42d1098a9997571730c0cbf42d078d3", + "url": "https://api.github.com/repos/laminas/laminas-loader/zipball/e6fe952304ef40ce45cd814751ab35d42afdad12", + "reference": "e6fe952304ef40ce45cd814751ab35d42afdad12", "shasum": "" }, "require": { - "php": "~8.0.0 || ~8.1.0 || ~8.2.0" + "php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0" }, "conflict": { "zendframework/zend-loader": "*" @@ -1632,46 +1613,44 @@ "type": "community_bridge" } ], - "time": "2022-10-16T12:50:49+00:00" + "time": "2023-10-18T09:58:51+00:00" }, { "name": "laminas/laminas-mail", - "version": "2.22.0", + "version": "2.25.1", "source": { "type": "git", "url": "https://github.com/laminas/laminas-mail.git", - "reference": "1d307ff65328c00117c6d90ba0084fdd0fc2bd5c" + "reference": "110e04497395123998220e244cceecb167cc6dda" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-mail/zipball/1d307ff65328c00117c6d90ba0084fdd0fc2bd5c", - "reference": "1d307ff65328c00117c6d90ba0084fdd0fc2bd5c", + "url": "https://api.github.com/repos/laminas/laminas-mail/zipball/110e04497395123998220e244cceecb167cc6dda", + "reference": "110e04497395123998220e244cceecb167cc6dda", "shasum": "" }, "require": { "ext-iconv": "*", - "laminas/laminas-loader": "^2.8.0", - "laminas/laminas-mime": "^2.10.0", - "laminas/laminas-stdlib": "^3.11.0", - "laminas/laminas-validator": "^2.23.0", - "php": "~8.0.0 || ~8.1.0 || ~8.2.0", - "symfony/polyfill-intl-idn": "^1.26.0", - "symfony/polyfill-mbstring": "^1.16.0", + "laminas/laminas-loader": "^2.9.0", + "laminas/laminas-mime": "^2.11.0", + "laminas/laminas-stdlib": "^3.17.0", + "laminas/laminas-validator": "^2.31.0", + "php": "~8.1.0 || ~8.2.0 || ~8.3.0", + "symfony/polyfill-intl-idn": "^1.27.0", + "symfony/polyfill-mbstring": "^1.27.0", "webmozart/assert": "^1.11.0" }, "require-dev": { "laminas/laminas-coding-standard": "~2.5.0", - "laminas/laminas-crypt": "^3.9.0", - "laminas/laminas-db": "^2.16", - "laminas/laminas-servicemanager": "^3.20", - "phpunit/phpunit": "^9.5.26", + "laminas/laminas-db": "^2.18", + "laminas/laminas-servicemanager": "^3.22.1", + "phpunit/phpunit": "^10.4.2", "psalm/plugin-phpunit": "^0.18.4", - "symfony/process": "^6.0.11", - "vimeo/psalm": "^5.1" + "symfony/process": "^6.3.4", + "vimeo/psalm": "^5.15" }, "suggest": { - "laminas/laminas-crypt": "^3.8 Crammd5 support in SMTP Auth", - "laminas/laminas-servicemanager": "^3.16 when using SMTP to deliver messages" + "laminas/laminas-servicemanager": "^3.21 when using SMTP to deliver messages" }, "type": "library", "extra": { @@ -1709,25 +1688,25 @@ "type": "community_bridge" } ], - "time": "2023-01-18T08:33:48+00:00" + "time": "2023-11-02T10:32:34+00:00" }, { "name": "laminas/laminas-mime", - "version": "2.11.0", + "version": "2.12.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-mime.git", - "reference": "60ec04b755821c79c1987ce291b44e69f2c0831f" + "reference": "08cc544778829b7d68d27a097885bd6e7130135e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-mime/zipball/60ec04b755821c79c1987ce291b44e69f2c0831f", - "reference": "60ec04b755821c79c1987ce291b44e69f2c0831f", + "url": "https://api.github.com/repos/laminas/laminas-mime/zipball/08cc544778829b7d68d27a097885bd6e7130135e", + "reference": "08cc544778829b7d68d27a097885bd6e7130135e", "shasum": "" }, "require": { "laminas/laminas-stdlib": "^2.7 || ^3.0", - "php": "~8.0.0 || ~8.1.0 || ~8.2.0" + "php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0" }, "conflict": { "zendframework/zend-mime": "*" @@ -1770,30 +1749,30 @@ "type": "community_bridge" } ], - "time": "2022-10-18T08:38:15+00:00" + "time": "2023-11-02T16:47:19+00:00" }, { "name": "laminas/laminas-servicemanager", - "version": "3.20.0", + "version": "3.22.1", "source": { "type": "git", "url": "https://github.com/laminas/laminas-servicemanager.git", - "reference": "bc2c2cbe2dd90db8b9d16b0618f542692b76ab59" + "reference": "de98d297d4743956a0558a6d71616979ff779328" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-servicemanager/zipball/bc2c2cbe2dd90db8b9d16b0618f542692b76ab59", - "reference": "bc2c2cbe2dd90db8b9d16b0618f542692b76ab59", + "url": "https://api.github.com/repos/laminas/laminas-servicemanager/zipball/de98d297d4743956a0558a6d71616979ff779328", + "reference": "de98d297d4743956a0558a6d71616979ff779328", "shasum": "" }, "require": { - "laminas/laminas-stdlib": "^3.2.1", - "php": "~8.0.0 || ~8.1.0 || ~8.2.0", + "laminas/laminas-stdlib": "^3.17", + "php": "~8.1.0 || ~8.2.0 || ~8.3.0", "psr/container": "^1.0" }, "conflict": { "ext-psr": "*", - "laminas/laminas-code": "<3.3.1", + "laminas/laminas-code": "<4.10.0", "zendframework/zend-code": "<3.3.1", "zendframework/zend-servicemanager": "*" }, @@ -1805,18 +1784,18 @@ }, "require-dev": { "composer/package-versions-deprecated": "^1.11.99.5", - "laminas/laminas-coding-standard": "~2.4.0", + "friendsofphp/proxy-manager-lts": "^1.0.14", + "laminas/laminas-code": "^4.10.0", + "laminas/laminas-coding-standard": "~2.5.0", "laminas/laminas-container-config-test": "^0.8", - "laminas/laminas-dependency-plugin": "^2.2", - "mikey179/vfsstream": "^1.6.11@alpha", - "ocramius/proxy-manager": "^2.14.1", - "phpbench/phpbench": "^1.2.7", - "phpunit/phpunit": "^9.5.26", - "psalm/plugin-phpunit": "^0.18.0", - "vimeo/psalm": "^5.0.0" + "mikey179/vfsstream": "^1.6.11", + "phpbench/phpbench": "^1.2.9", + "phpunit/phpunit": "^10.4", + "psalm/plugin-phpunit": "^0.18.4", + "vimeo/psalm": "^5.8.0" }, "suggest": { - "ocramius/proxy-manager": "ProxyManager ^2.1.1 to handle lazy initialization of services" + "friendsofphp/proxy-manager-lts": "ProxyManager ^2.1.1 to handle lazy initialization of services" }, "bin": [ "bin/generate-deps-for-config-factory", @@ -1860,34 +1839,34 @@ "type": "community_bridge" } ], - "time": "2022-12-01T17:03:38+00:00" + "time": "2023-10-24T11:19:47+00:00" }, { "name": "laminas/laminas-stdlib", - "version": "3.16.1", + "version": "3.19.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-stdlib.git", - "reference": "f4f773641807c7ccee59b758bfe4ac4ba33ecb17" + "reference": "6a192dd0882b514e45506f533b833b623b78fff3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-stdlib/zipball/f4f773641807c7ccee59b758bfe4ac4ba33ecb17", - "reference": "f4f773641807c7ccee59b758bfe4ac4ba33ecb17", + "url": "https://api.github.com/repos/laminas/laminas-stdlib/zipball/6a192dd0882b514e45506f533b833b623b78fff3", + "reference": "6a192dd0882b514e45506f533b833b623b78fff3", "shasum": "" }, "require": { - "php": "~8.0.0 || ~8.1.0 || ~8.2.0" + "php": "~8.1.0 || ~8.2.0 || ~8.3.0" }, "conflict": { "zendframework/zend-stdlib": "*" }, "require-dev": { - "laminas/laminas-coding-standard": "^2.4.0", - "phpbench/phpbench": "^1.2.7", - "phpunit/phpunit": "^9.5.26", - "psalm/plugin-phpunit": "^0.18.0", - "vimeo/psalm": "^5.0.0" + "laminas/laminas-coding-standard": "^2.5", + "phpbench/phpbench": "^1.2.15", + "phpunit/phpunit": "^10.5.8", + "psalm/plugin-phpunit": "^0.18.4", + "vimeo/psalm": "^5.20.0" }, "type": "library", "autoload": { @@ -1919,44 +1898,43 @@ "type": "community_bridge" } ], - "time": "2022-12-03T18:48:01+00:00" + "time": "2024-01-19T12:39:49+00:00" }, { "name": "laminas/laminas-validator", - "version": "2.27.0", + "version": "2.53.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-validator.git", - "reference": "451f5e24574a99b86e8e22f0431ccfc6d5c7318b" + "reference": "dbcfc19cb7f2e3eb3a27ba5d059c200e8404d72c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-validator/zipball/451f5e24574a99b86e8e22f0431ccfc6d5c7318b", - "reference": "451f5e24574a99b86e8e22f0431ccfc6d5c7318b", + "url": "https://api.github.com/repos/laminas/laminas-validator/zipball/dbcfc19cb7f2e3eb3a27ba5d059c200e8404d72c", + "reference": "dbcfc19cb7f2e3eb3a27ba5d059c200e8404d72c", "shasum": "" }, "require": { - "laminas/laminas-servicemanager": "^3.12.0", + "laminas/laminas-servicemanager": "^3.21.0", "laminas/laminas-stdlib": "^3.13", - "php": "~8.0.0 || ~8.1.0 || ~8.2.0" + "php": "~8.1.0 || ~8.2.0 || ~8.3.0", + "psr/http-message": "^1.0.1 || ^2.0.0" }, "conflict": { "zendframework/zend-validator": "*" }, "require-dev": { - "laminas/laminas-coding-standard": "^2.4.0", - "laminas/laminas-db": "^2.15.0", - "laminas/laminas-filter": "^2.23.0", - "laminas/laminas-http": "^2.17.0", - "laminas/laminas-i18n": "^2.19", - "laminas/laminas-session": "^2.13.0", - "laminas/laminas-uri": "^2.10.0", - "phpunit/phpunit": "^9.5.25", - "psalm/plugin-phpunit": "^0.18.0", - "psr/http-client": "^1.0.1", - "psr/http-factory": "^1.0.1", - "psr/http-message": "^1.0.1", - "vimeo/psalm": "^4.28" + "laminas/laminas-coding-standard": "^2.5", + "laminas/laminas-db": "^2.19", + "laminas/laminas-filter": "^2.34", + "laminas/laminas-i18n": "^2.26.0", + "laminas/laminas-session": "^2.20", + "laminas/laminas-uri": "^2.11.0", + "phpunit/phpunit": "^10.5.15", + "psalm/plugin-phpunit": "^0.19.0", + "psr/http-client": "^1.0.3", + "psr/http-factory": "^1.0.2", + "vimeo/psalm": "^5.23.1" }, "suggest": { "laminas/laminas-db": "Laminas\\Db component, required by the (No)RecordExists validator", @@ -1982,199 +1960,62 @@ }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" - ], - "description": "Validation classes for a wide range of domains, and the ability to chain validators to create complex validation criteria", - "homepage": "https://laminas.dev", - "keywords": [ - "laminas", - "validator" - ], - "support": { - "chat": "https://laminas.dev/chat", - "docs": "https://docs.laminas.dev/laminas-validator/", - "forum": "https://discourse.laminas.dev", - "issues": "https://github.com/laminas/laminas-validator/issues", - "rss": "https://github.com/laminas/laminas-validator/releases.atom", - "source": "https://github.com/laminas/laminas-validator" - }, - "funding": [ - { - "url": "https://funding.communitybridge.org/projects/laminas-project", - "type": "community_bridge" - } - ], - "time": "2022-11-12T21:00:53+00:00" - }, - { - "name": "laravel/serializable-closure", - "version": "v1.3.0", - "source": { - "type": "git", - "url": "https://github.com/laravel/serializable-closure.git", - "reference": "f23fe9d4e95255dacee1bf3525e0810d1a1b0f37" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/f23fe9d4e95255dacee1bf3525e0810d1a1b0f37", - "reference": "f23fe9d4e95255dacee1bf3525e0810d1a1b0f37", - "shasum": "" - }, - "require": { - "php": "^7.3|^8.0" - }, - "require-dev": { - "nesbot/carbon": "^2.61", - "pestphp/pest": "^1.21.3", - "phpstan/phpstan": "^1.8.2", - "symfony/var-dumper": "^5.4.11" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Laravel\\SerializableClosure\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Taylor Otwell", - "email": "taylor@laravel.com" - }, - { - "name": "Nuno Maduro", - "email": "nuno@laravel.com" - } - ], - "description": "Laravel Serializable Closure provides an easy and secure way to serialize closures in PHP.", - "keywords": [ - "closure", - "laravel", - "serializable" - ], - "support": { - "issues": "https://github.com/laravel/serializable-closure/issues", - "source": "https://github.com/laravel/serializable-closure" - }, - "time": "2023-01-30T18:31:20+00:00" - }, - { - "name": "league/flysystem", - "version": "2.5.0", - "source": { - "type": "git", - "url": "https://github.com/thephpleague/flysystem.git", - "reference": "8aaffb653c5777781b0f7f69a5d937baf7ab6cdb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/8aaffb653c5777781b0f7f69a5d937baf7ab6cdb", - "reference": "8aaffb653c5777781b0f7f69a5d937baf7ab6cdb", - "shasum": "" - }, - "require": { - "ext-json": "*", - "league/mime-type-detection": "^1.0.0", - "php": "^7.2 || ^8.0" - }, - "conflict": { - "guzzlehttp/ringphp": "<1.1.1" - }, - "require-dev": { - "async-aws/s3": "^1.5", - "async-aws/simple-s3": "^1.0", - "aws/aws-sdk-php": "^3.132.4", - "composer/semver": "^3.0", - "ext-fileinfo": "*", - "ext-ftp": "*", - "friendsofphp/php-cs-fixer": "^3.2", - "google/cloud-storage": "^1.23", - "phpseclib/phpseclib": "^2.0", - "phpstan/phpstan": "^0.12.26", - "phpunit/phpunit": "^8.5 || ^9.4", - "sabre/dav": "^4.1" - }, - "type": "library", - "autoload": { - "psr-4": { - "League\\Flysystem\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Frank de Jonge", - "email": "info@frankdejonge.nl" - } + "BSD-3-Clause" ], - "description": "File storage abstraction for PHP", + "description": "Validation classes for a wide range of domains, and the ability to chain validators to create complex validation criteria", + "homepage": "https://laminas.dev", "keywords": [ - "WebDAV", - "aws", - "cloud", - "file", - "files", - "filesystem", - "filesystems", - "ftp", - "s3", - "sftp", - "storage" + "laminas", + "validator" ], "support": { - "issues": "https://github.com/thephpleague/flysystem/issues", - "source": "https://github.com/thephpleague/flysystem/tree/2.5.0" + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-validator/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-validator/issues", + "rss": "https://github.com/laminas/laminas-validator/releases.atom", + "source": "https://github.com/laminas/laminas-validator" }, "funding": [ { - "url": "https://ecologi.com/frankdejonge", - "type": "custom" - }, - { - "url": "https://github.com/frankdejonge", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/league/flysystem", - "type": "tidelift" + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" } ], - "time": "2022-09-17T21:02:32+00:00" + "time": "2024-04-01T09:26:32+00:00" }, { - "name": "league/flysystem-memory", - "version": "2.0.6", + "name": "laravel/serializable-closure", + "version": "v1.3.3", "source": { "type": "git", - "url": "https://github.com/thephpleague/flysystem-memory.git", - "reference": "f644026c705b8a501543f38cb8b745a603aa4952" + "url": "https://github.com/laravel/serializable-closure.git", + "reference": "3dbf8a8e914634c48d389c1234552666b3d43754" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem-memory/zipball/f644026c705b8a501543f38cb8b745a603aa4952", - "reference": "f644026c705b8a501543f38cb8b745a603aa4952", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/3dbf8a8e914634c48d389c1234552666b3d43754", + "reference": "3dbf8a8e914634c48d389c1234552666b3d43754", "shasum": "" }, "require": { - "ext-fileinfo": "*", - "league/flysystem": "^2.0.0", - "php": "^7.2 || ^8.0" + "php": "^7.3|^8.0" + }, + "require-dev": { + "nesbot/carbon": "^2.61", + "pestphp/pest": "^1.21.3", + "phpstan/phpstan": "^1.8.2", + "symfony/var-dumper": "^5.4.11" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, "autoload": { "psr-4": { - "League\\Flysystem\\InMemory\\": "" + "Laravel\\SerializableClosure\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2183,51 +2024,72 @@ ], "authors": [ { - "name": "Frank de Jonge", - "email": "info@frankdejonge.nl" + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + }, + { + "name": "Nuno Maduro", + "email": "nuno@laravel.com" } ], - "description": "In-memory filesystem adapter for Flysystem.", + "description": "Laravel Serializable Closure provides an easy and secure way to serialize closures in PHP.", "keywords": [ - "Flysystem", - "file", - "files", - "filesystem", - "memory" + "closure", + "laravel", + "serializable" ], "support": { - "issues": "https://github.com/thephpleague/flysystem-memory/issues", - "source": "https://github.com/thephpleague/flysystem-memory/tree/2.0.6" + "issues": "https://github.com/laravel/serializable-closure/issues", + "source": "https://github.com/laravel/serializable-closure" }, - "time": "2021-02-12T19:24:17+00:00" + "time": "2023-11-08T14:08:06+00:00" }, { - "name": "league/mime-type-detection", - "version": "1.11.0", + "name": "league/container", + "version": "4.2.2", "source": { "type": "git", - "url": "https://github.com/thephpleague/mime-type-detection.git", - "reference": "ff6248ea87a9f116e78edd6002e39e5128a0d4dd" + "url": "https://github.com/thephpleague/container.git", + "reference": "ff346319ca1ff0e78277dc2311a42107cc1aab88" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/ff6248ea87a9f116e78edd6002e39e5128a0d4dd", - "reference": "ff6248ea87a9f116e78edd6002e39e5128a0d4dd", + "url": "https://api.github.com/repos/thephpleague/container/zipball/ff346319ca1ff0e78277dc2311a42107cc1aab88", + "reference": "ff346319ca1ff0e78277dc2311a42107cc1aab88", "shasum": "" }, "require": { - "ext-fileinfo": "*", - "php": "^7.2 || ^8.0" + "php": "^7.2 || ^8.0", + "psr/container": "^1.1 || ^2.0" + }, + "provide": { + "psr/container-implementation": "^1.0" + }, + "replace": { + "orno/di": "~2.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.2", - "phpstan/phpstan": "^0.12.68", - "phpunit/phpunit": "^8.5.8 || ^9.3" + "nette/php-generator": "^3.4", + "nikic/php-parser": "^4.10", + "phpstan/phpstan": "^0.12.47", + "phpunit/phpunit": "^8.5.17", + "roave/security-advisories": "dev-latest", + "scrutinizer/ocular": "^1.8", + "squizlabs/php_codesniffer": "^3.6" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.x-dev", + "dev-4.x": "4.x-dev", + "dev-3.x": "3.x-dev", + "dev-2.x": "2.x-dev", + "dev-1.x": "1.x-dev" + } + }, "autoload": { "psr-4": { - "League\\MimeTypeDetection\\": "src" + "League\\Container\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -2236,39 +2098,46 @@ ], "authors": [ { - "name": "Frank de Jonge", - "email": "info@frankdejonge.nl" + "name": "Phil Bennett", + "email": "mail@philbennett.co.uk", + "role": "Developer" } ], - "description": "Mime-type detection for Flysystem", + "description": "A fast and intuitive dependency injection container.", + "homepage": "https://github.com/thephpleague/container", + "keywords": [ + "container", + "dependency", + "di", + "injection", + "league", + "provider", + "service" + ], "support": { - "issues": "https://github.com/thephpleague/mime-type-detection/issues", - "source": "https://github.com/thephpleague/mime-type-detection/tree/1.11.0" + "issues": "https://github.com/thephpleague/container/issues", + "source": "https://github.com/thephpleague/container/tree/4.2.2" }, "funding": [ { - "url": "https://github.com/frankdejonge", + "url": "https://github.com/philipobenito", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/league/flysystem", - "type": "tidelift" } ], - "time": "2022-04-17T13:12:02+00:00" + "time": "2024-03-13T13:12:53+00:00" }, { "name": "matthiasmullie/minify", - "version": "1.3.71", + "version": "1.3.73", "source": { "type": "git", "url": "https://github.com/matthiasmullie/minify.git", - "reference": "ae42a47d7fecc1fbb7277b2f2d84c37a33edc3b1" + "reference": "cb7a9297b4ab070909cefade30ee95054d4ae87a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/matthiasmullie/minify/zipball/ae42a47d7fecc1fbb7277b2f2d84c37a33edc3b1", - "reference": "ae42a47d7fecc1fbb7277b2f2d84c37a33edc3b1", + "url": "https://api.github.com/repos/matthiasmullie/minify/zipball/cb7a9297b4ab070909cefade30ee95054d4ae87a", + "reference": "cb7a9297b4ab070909cefade30ee95054d4ae87a", "shasum": "" }, "require": { @@ -2318,7 +2187,7 @@ ], "support": { "issues": "https://github.com/matthiasmullie/minify/issues", - "source": "https://github.com/matthiasmullie/minify/tree/1.3.71" + "source": "https://github.com/matthiasmullie/minify/tree/1.3.73" }, "funding": [ { @@ -2326,7 +2195,7 @@ "type": "github" } ], - "time": "2023-04-25T20:33:03+00:00" + "time": "2024-03-15T10:27:10+00:00" }, { "name": "matthiasmullie/path-converter", @@ -2488,42 +2357,41 @@ }, { "name": "monolog/monolog", - "version": "2.8.0", + "version": "3.6.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "720488632c590286b88b80e62aa3d3d551ad4a50" + "reference": "4b18b21a5527a3d5ffdac2fd35d3ab25a9597654" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/720488632c590286b88b80e62aa3d3d551ad4a50", - "reference": "720488632c590286b88b80e62aa3d3d551ad4a50", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/4b18b21a5527a3d5ffdac2fd35d3ab25a9597654", + "reference": "4b18b21a5527a3d5ffdac2fd35d3ab25a9597654", "shasum": "" }, "require": { - "php": ">=7.2", - "psr/log": "^1.0.1 || ^2.0 || ^3.0" + "php": ">=8.1", + "psr/log": "^2.0 || ^3.0" }, "provide": { - "psr/log-implementation": "1.0.0 || 2.0.0 || 3.0.0" + "psr/log-implementation": "3.0.0" }, "require-dev": { - "aws/aws-sdk-php": "^2.4.9 || ^3.0", + "aws/aws-sdk-php": "^3.0", "doctrine/couchdb": "~1.0@dev", "elasticsearch/elasticsearch": "^7 || ^8", "ext-json": "*", - "graylog2/gelf-php": "^1.4.2", - "guzzlehttp/guzzle": "^7.4", + "graylog2/gelf-php": "^1.4.2 || ^2.0", + "guzzlehttp/guzzle": "^7.4.5", "guzzlehttp/psr7": "^2.2", "mongodb/mongodb": "^1.8", "php-amqplib/php-amqplib": "~2.4 || ^3", - "phpspec/prophecy": "^1.15", - "phpstan/phpstan": "^0.12.91", - "phpunit/phpunit": "^8.5.14", - "predis/predis": "^1.1 || ^2.0", - "rollbar/rollbar": "^1.3 || ^2 || ^3", + "phpstan/phpstan": "^1.9", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-strict-rules": "^1.4", + "phpunit/phpunit": "^10.5.17", + "predis/predis": "^1.1 || ^2", "ruflin/elastica": "^7", - "swiftmailer/swiftmailer": "^5.3|^6.0", "symfony/mailer": "^5.4 || ^6", "symfony/mime": "^5.4 || ^6" }, @@ -2546,7 +2414,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "2.x-dev" + "dev-main": "3.x-dev" } }, "autoload": { @@ -2574,7 +2442,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/2.8.0" + "source": "https://github.com/Seldaek/monolog/tree/3.6.0" }, "funding": [ { @@ -2586,14 +2454,14 @@ "type": "tidelift" } ], - "time": "2022-07-24T11:55:47+00:00" + "time": "2024-04-12T21:02:21+00:00" }, { "name": "npm-asset/cropperjs", - "version": "1.5.13", + "version": "1.6.1", "dist": { "type": "tar", - "url": "https://registry.npmjs.org/cropperjs/-/cropperjs-1.5.13.tgz" + "url": "https://registry.npmjs.org/cropperjs/-/cropperjs-1.6.1.tgz" }, "type": "npm-asset", "license": [ @@ -2602,10 +2470,10 @@ }, { "name": "npm-asset/jquery", - "version": "3.6.4", + "version": "3.7.1", "dist": { "type": "tar", - "url": "https://registry.npmjs.org/jquery/-/jquery-3.6.4.tgz" + "url": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz" }, "type": "npm-asset", "license": [ @@ -2678,30 +2546,6 @@ "MIT" ] }, - { - "name": "npm-asset/requirejs", - "version": "2.3.6", - "dist": { - "type": "tar", - "url": "https://registry.npmjs.org/requirejs/-/requirejs-2.3.6.tgz" - }, - "type": "npm-asset", - "license": [ - "MIT" - ] - }, - { - "name": "npm-asset/requirejs-text", - "version": "2.0.16", - "dist": { - "type": "tar", - "url": "https://registry.npmjs.org/requirejs-text/-/requirejs-text-2.0.16.tgz" - }, - "type": "npm-asset", - "license": [ - "MIT" - ] - }, { "name": "npm-asset/sprintf-js", "version": "1.1.2", @@ -2716,10 +2560,10 @@ }, { "name": "npm-asset/yaireo--tagify", - "version": "4.16.4", + "version": "4.22.2", "dist": { "type": "tar", - "url": "https://registry.npmjs.org/@yaireo/tagify/-/tagify-4.16.4.tgz" + "url": "https://registry.npmjs.org/@yaireo/tagify/-/tagify-4.22.2.tgz" }, "type": "npm-asset", "license": [ @@ -2728,29 +2572,29 @@ }, { "name": "pelago/emogrifier", - "version": "v7.0.0", + "version": "v7.2.0", "source": { "type": "git", "url": "https://github.com/MyIntervals/emogrifier.git", - "reference": "547b8c814794aec871e3c98b1c712f416755f4eb" + "reference": "727bdf7255b51798307f17dec52ff8a91f1c7de3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/MyIntervals/emogrifier/zipball/547b8c814794aec871e3c98b1c712f416755f4eb", - "reference": "547b8c814794aec871e3c98b1c712f416755f4eb", + "url": "https://api.github.com/repos/MyIntervals/emogrifier/zipball/727bdf7255b51798307f17dec52ff8a91f1c7de3", + "reference": "727bdf7255b51798307f17dec52ff8a91f1c7de3", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", - "php": "~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0", + "php": "~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0", "sabberworm/php-css-parser": "^8.4.0", - "symfony/css-selector": "^4.4.23 || ^5.4.0 || ^6.0.0" + "symfony/css-selector": "^4.4.23 || ^5.4.0 || ^6.0.0 || ^7.0.0" }, "require-dev": { - "php-parallel-lint/php-parallel-lint": "^1.3.2", - "phpunit/phpunit": "^9.5.25", - "rawr/cross-data-providers": "^2.3.0" + "php-parallel-lint/php-parallel-lint": "1.3.2", + "phpunit/phpunit": "9.6.11", + "rawr/cross-data-providers": "2.4.0" }, "type": "library", "extra": { @@ -2802,7 +2646,7 @@ "issues": "https://github.com/MyIntervals/emogrifier/issues", "source": "https://github.com/MyIntervals/emogrifier" }, - "time": "2022-11-01T17:53:29+00:00" + "time": "2023-12-06T02:00:20+00:00" }, { "name": "peppeocchi/php-cron-scheduler", @@ -2865,16 +2709,16 @@ }, { "name": "php-di/invoker", - "version": "2.3.3", + "version": "2.3.4", "source": { "type": "git", "url": "https://github.com/PHP-DI/Invoker.git", - "reference": "cd6d9f267d1a3474bdddf1be1da079f01b942786" + "reference": "33234b32dafa8eb69202f950a1fc92055ed76a86" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-DI/Invoker/zipball/cd6d9f267d1a3474bdddf1be1da079f01b942786", - "reference": "cd6d9f267d1a3474bdddf1be1da079f01b942786", + "url": "https://api.github.com/repos/PHP-DI/Invoker/zipball/33234b32dafa8eb69202f950a1fc92055ed76a86", + "reference": "33234b32dafa8eb69202f950a1fc92055ed76a86", "shasum": "" }, "require": { @@ -2908,7 +2752,7 @@ ], "support": { "issues": "https://github.com/PHP-DI/Invoker/issues", - "source": "https://github.com/PHP-DI/Invoker/tree/2.3.3" + "source": "https://github.com/PHP-DI/Invoker/tree/2.3.4" }, "funding": [ { @@ -2916,43 +2760,40 @@ "type": "github" } ], - "time": "2021-12-13T09:22:56+00:00" + "time": "2023-09-08T09:24:21+00:00" }, { "name": "php-di/php-di", - "version": "6.4.0", + "version": "7.0.6", "source": { "type": "git", "url": "https://github.com/PHP-DI/PHP-DI.git", - "reference": "ae0f1b3b03d8b29dff81747063cbfd6276246cc4" + "reference": "8097948a89f6ec782839b3e958432f427cac37fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-DI/PHP-DI/zipball/ae0f1b3b03d8b29dff81747063cbfd6276246cc4", - "reference": "ae0f1b3b03d8b29dff81747063cbfd6276246cc4", + "url": "https://api.github.com/repos/PHP-DI/PHP-DI/zipball/8097948a89f6ec782839b3e958432f427cac37fd", + "reference": "8097948a89f6ec782839b3e958432f427cac37fd", "shasum": "" }, "require": { "laravel/serializable-closure": "^1.0", - "php": ">=7.4.0", + "php": ">=8.0", "php-di/invoker": "^2.0", - "php-di/phpdoc-reader": "^2.0.1", - "psr/container": "^1.0" + "psr/container": "^1.1 || ^2.0" }, "provide": { "psr/container-implementation": "^1.0" }, "require-dev": { - "doctrine/annotations": "~1.10", - "friendsofphp/php-cs-fixer": "^2.4", - "mnapoli/phpunit-easymock": "^1.2", - "ocramius/proxy-manager": "^2.11.2", - "phpstan/phpstan": "^0.12", - "phpunit/phpunit": "^9.5" + "friendsofphp/php-cs-fixer": "^3", + "friendsofphp/proxy-manager-lts": "^1", + "mnapoli/phpunit-easymock": "^1.3", + "phpunit/phpunit": "^9.5", + "vimeo/psalm": "^4.6" }, "suggest": { - "doctrine/annotations": "Install it if you want to use annotations (version ~1.2)", - "ocramius/proxy-manager": "Install it if you want to use lazy injection (version ~2.0)" + "friendsofphp/proxy-manager-lts": "Install it if you want to use lazy injection (version ^1)" }, "type": "library", "autoload": { @@ -2980,7 +2821,7 @@ ], "support": { "issues": "https://github.com/PHP-DI/PHP-DI/issues", - "source": "https://github.com/PHP-DI/PHP-DI/tree/6.4.0" + "source": "https://github.com/PHP-DI/PHP-DI/tree/7.0.6" }, "funding": [ { @@ -2992,62 +2833,20 @@ "type": "tidelift" } ], - "time": "2022-04-09T16:46:38+00:00" - }, - { - "name": "php-di/phpdoc-reader", - "version": "2.2.1", - "source": { - "type": "git", - "url": "https://github.com/PHP-DI/PhpDocReader.git", - "reference": "66daff34cbd2627740ffec9469ffbac9f8c8185c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHP-DI/PhpDocReader/zipball/66daff34cbd2627740ffec9469ffbac9f8c8185c", - "reference": "66daff34cbd2627740ffec9469ffbac9f8c8185c", - "shasum": "" - }, - "require": { - "php": ">=7.2.0" - }, - "require-dev": { - "mnapoli/hard-mode": "~0.3.0", - "phpunit/phpunit": "^8.5|^9.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "PhpDocReader\\": "src/PhpDocReader" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PhpDocReader parses @var and @param values in PHP docblocks (supports namespaced class names with the same resolution rules as PHP)", - "keywords": [ - "phpdoc", - "reflection" - ], - "support": { - "issues": "https://github.com/PHP-DI/PhpDocReader/issues", - "source": "https://github.com/PHP-DI/PhpDocReader/tree/2.2.1" - }, - "time": "2020-10-12T12:39:22+00:00" + "time": "2023-11-02T10:04:50+00:00" }, { "name": "phpfastcache/phpfastcache", - "version": "9.1.3", + "version": "9.2.3", "source": { "type": "git", "url": "https://github.com/PHPSocialNetwork/phpfastcache.git", - "reference": "8614c5624e56b6f41fa666fdec3dc746b52df6b4" + "reference": "372d62e0bbab5bcfac6404dc912040b038a3afb7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPSocialNetwork/phpfastcache/zipball/8614c5624e56b6f41fa666fdec3dc746b52df6b4", - "reference": "8614c5624e56b6f41fa666fdec3dc746b52df6b4", + "url": "https://api.github.com/repos/PHPSocialNetwork/phpfastcache/zipball/372d62e0bbab5bcfac6404dc912040b038a3afb7", + "reference": "372d62e0bbab5bcfac6404dc912040b038a3afb7", "shasum": "" }, "require": { @@ -3057,46 +2856,46 @@ "psr/cache": "^2.0||^3.0", "psr/simple-cache": "^2.0||^3.0" }, - "conflict": { - "doctrine/couchdb": "=5.4.0" + "php": ">=7.1.0" }, "require-dev": { - "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.36" + "phpstan/phpstan": "1.10.39 || 1.4.10", + "phpunit/phpunit": "^9.6 || ^7.5" }, "type": "library", "autoload": { @@ -3627,7 +3432,7 @@ ], "support": { "issues": "https://github.com/reactphp/promise/issues", - "source": "https://github.com/reactphp/promise/tree/v2.10.0" + "source": "https://github.com/reactphp/promise/tree/v3.1.0" }, "funding": [ { @@ -3635,7 +3440,7 @@ "type": "open_collective" } ], - "time": "2023-05-02T15:15:43+00:00" + "time": "2023-11-16T16:21:57+00:00" }, { "name": "roave/security-advisories", @@ -3643,56 +3448,66 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "601b276d21df95e49f1802c7432b788cfaac15a8" + "reference": "db80e362f762211062612ae92774a7ea93bb713e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/601b276d21df95e49f1802c7432b788cfaac15a8", - "reference": "601b276d21df95e49f1802c7432b788cfaac15a8", + "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/db80e362f762211062612ae92774a7ea93bb713e", + "reference": "db80e362f762211062612ae92774a7ea93bb713e", "shasum": "" }, "conflict": { "3f/pygmentize": "<1.2", - "admidio/admidio": "<4.2.8", + "admidio/admidio": "<4.2.13", "adodb/adodb-php": "<=5.20.20|>=5.21,<=5.21.3", - "aheinze/cockpit": "<=2.2.1", + "aheinze/cockpit": "<2.2", + "aimeos/aimeos-typo3": "<19.10.12|>=20,<20.10.5", + "airesvsg/acf-to-rest-api": "<=3.1", "akaunting/akaunting": "<2.1.13", "akeneo/pim-community-dev": "<5.0.119|>=6,<6.0.53", "alextselegidis/easyappointments": "<1.5", "alterphp/easyadmin-extension-bundle": ">=1.2,<1.2.11|>=1.3,<1.3.1", "amazing/media2click": ">=1,<1.3.3", "amphp/artax": "<1.0.6|>=2,<2.0.6", - "amphp/http": "<1.0.1", + "amphp/http": "<=1.7.2|>=2,<=2.1", "amphp/http-client": ">=4,<4.4", "anchorcms/anchor-cms": "<=0.12.7", "andreapollastri/cipi": "<=3.1.15", - "andrewhaine/silverstripe-form-capture": ">=0.2,<=0.2.3|>=1,<=1.0.1|>=2,<=2.2.4", + "andrewhaine/silverstripe-form-capture": ">=0.2,<=0.2.3|>=1,<1.0.2|>=2,<2.2.5", + "apache-solr-for-typo3/solr": "<2.8.3", "apereo/phpcas": "<1.6", "api-platform/core": ">=2.2,<2.2.10|>=2.3,<2.3.6|>=2.6,<2.7.10|>=3,<3.0.12|>=3.1,<3.1.3", "appwrite/server-ce": "<=1.2.1", "arc/web": "<3", "area17/twill": "<1.2.5|>=2,<2.5.3", - "asymmetricrypt/asymmetricrypt": ">=0,<9.9.99", - "automad/automad": "<1.8", + "artesaos/seotools": "<0.17.2", + "asymmetricrypt/asymmetricrypt": "<9.9.99", + "athlon1600/php-proxy": "<=5.1", + "athlon1600/php-proxy-app": "<=3", + "austintoddj/canvas": "<=3.4.2", + "automad/automad": "<=1.10.9", "awesome-support/awesome-support": "<=6.0.7", - "aws/aws-sdk-php": ">=3,<3.2.1", + "aws/aws-sdk-php": "<3.288.1", "azuracast/azuracast": "<0.18.3", "backdrop/backdrop": "<1.24.2", + "backpack/crud": "<3.4.9", + "bacula-web/bacula-web": "<8.0.0.0-RC2-dev", "badaso/core": "<2.7", - "bagisto/bagisto": "<0.1.5", + "bagisto/bagisto": "<2.1", "barrelstrength/sprout-base-email": "<1.2.7", "barrelstrength/sprout-forms": "<3.9", "barryvdh/laravel-translation-manager": "<0.6.2", "barzahlen/barzahlen-php": "<2.0.1", - "baserproject/basercms": "<4.7.5", + "baserproject/basercms": "<5.0.9", "bassjobsen/bootstrap-3-typeahead": ">4.0.2", - "bigfork/silverstripe-form-capture": ">=3,<=3.1", - "billz/raspap-webgui": "<=2.6.6", + "bigfork/silverstripe-form-capture": ">=3,<3.1.1", + "billz/raspap-webgui": "<2.9.5", "bk2k/bootstrap-package": ">=7.1,<7.1.2|>=8,<8.0.8|>=9,<9.0.4|>=9.1,<9.1.3|>=10,<10.0.10|>=11,<11.0.3", "bmarshall511/wordpress_zero_spam": "<5.2.13", "bolt/bolt": "<3.7.2", "bolt/core": "<=4.2", "bottelet/flarepoint": "<2.2.1", + "bref/bref": "<2.1.17", "brightlocal/phpwhois": "<=4.2.5", "brotkrueml/codehighlight": "<2.7", "brotkrueml/schema": "<1.13.1|>=2,<2.5.1", @@ -3701,85 +3516,103 @@ "bugsnag/bugsnag-laravel": ">=2,<2.0.2", "bytefury/crater": "<6.0.2", "cachethq/cachet": "<2.5.1", - "cakephp/cakephp": "<3.10.3|>=4,<4.0.10|>=4.2,<4.2.12|>=4.3,<4.3.11|>=4.4,<4.4.10|= 1.3.7|>=4.1,<4.1.4", + "cakephp/cakephp": "<3.10.3|>=4,<4.0.10|>=4.1,<4.1.4|>=4.2,<4.2.12|>=4.3,<4.3.11|>=4.4,<4.4.10", "cakephp/database": ">=4.2,<4.2.12|>=4.3,<4.3.11|>=4.4,<4.4.10", "cardgate/magento2": "<2.0.33", + "cardgate/woocommerce": "<=3.1.15", "cart2quote/module-quotation": ">=4.1.6,<=4.4.5|>=5,<5.4.4", "cartalyst/sentry": "<=2.1.6", "catfan/medoo": "<1.7.5", - "centreon/centreon": "<22.10-beta.1", + "causal/oidc": "<2.1", + "cecil/cecil": "<7.47.1", + "centreon/centreon": "<22.10.15", "cesnet/simplesamlphp-module-proxystatistics": "<3.1", - "cockpit-hq/cockpit": "<2.4.1", + "chriskacerguis/codeigniter-restserver": "<=2.7.1", + "civicrm/civicrm-core": ">=4.2,<4.2.9|>=4.3,<4.3.3", + "ckeditor/ckeditor": "<4.24", + "cockpit-hq/cockpit": "<=2.6.3|==2.7", "codeception/codeception": "<3.1.3|>=4,<4.1.22", - "codeigniter/framework": "<=3.0.6", - "codeigniter4/framework": "<4.3.5", - "codeigniter4/shield": "<1-beta.4|= 1.0.0-beta", + "codeigniter/framework": "<3.1.9", + "codeigniter4/framework": "<4.4.7", + "codeigniter4/shield": "<1.0.0.0-beta8", "codiad/codiad": "<=2.8.4", - "composer/composer": "<1.10.26|>=2-alpha.1,<2.2.12|>=2.3,<2.3.5", - "concrete5/concrete5": "<9.2|>= 9.0.0RC1, < 9.1.3", + "composer/composer": "<1.10.27|>=2,<2.2.23|>=2.3,<2.7", + "concrete5/concrete5": "<9.2.8", "concrete5/core": "<8.5.8|>=9,<9.1", "contao-components/mediaelement": ">=2.14.2,<2.21.1", + "contao/comments-bundle": ">=2,<4.13.40|>=5.0.0.0-RC1-dev,<5.3.4", "contao/contao": ">=4,<4.4.56|>=4.5,<4.9.40|>=4.10,<4.11.7|>=4.13,<4.13.21|>=5.1,<5.1.4", "contao/core": ">=2,<3.5.39", - "contao/core-bundle": "<4.9.40|>=4.10,<4.11.7|>=4.13,<4.13.21|>=5.1,<5.1.4|= 4.10.0", + "contao/core-bundle": "<4.13.40|>=5,<5.3.4", "contao/listing-bundle": ">=4,<4.4.8", "contao/managed-edition": "<=1.5", - "craftcms/cms": "<4.4.6|>= 4.0.0-RC1, < 4.4.12|>= 4.0.0-RC1, <= 4.4.5|>= 4.0.0-RC1, <= 4.4.6|>= 4.0.0-RC1, < 4.4.6|>= 4.0.0-RC1, < 4.3.7|>= 4.0.0-RC1, < 4.2.1", - "croogo/croogo": "<3.0.7", + "corveda/phpsandbox": "<1.3.5", + "cosenary/instagram": "<=2.3", + "craftcms/cms": "<4.6.2", + "croogo/croogo": "<4", "cuyz/valinor": "<0.12", "czproject/git-php": "<4.0.3", "darylldoyle/safe-svg": "<1.9.10", "datadog/dd-trace": ">=0.30,<0.30.2", + "datatables/datatables": "<1.10.10", "david-garcia/phpwhois": "<=4.3.1", "dbrisinajumi/d2files": "<1", - "dcat/laravel-admin": "<=2.1.3-beta", + "dcat/laravel-admin": "<=2.1.3.0-beta", "derhansen/fe_change_pwd": "<2.0.5|>=3,<3.0.3", - "derhansen/sf_event_mgt": "<4.3.1|>=5,<5.1.1", - "directmailteam/direct-mail": "<5.2.4", - "doctrine/annotations": ">=1,<1.2.7", + "derhansen/sf_event_mgt": "<4.3.1|>=5,<5.1.1|>=7,<7.4", + "desperado/xml-bundle": "<=0.1.7", + "directmailteam/direct-mail": "<6.0.3|>=7,<7.0.3|>=8,<9.5.2", + "doctrine/annotations": "<1.2.7", "doctrine/cache": ">=1,<1.3.2|>=1.4,<1.4.2", - "doctrine/common": ">=2,<2.4.3|>=2.5,<2.5.1", + "doctrine/common": "<2.4.3|>=2.5,<2.5.1", "doctrine/dbal": ">=2,<2.0.8|>=2.1,<2.1.2|>=3,<3.1.4", "doctrine/doctrine-bundle": "<1.5.2", "doctrine/doctrine-module": "<=0.7.1", - "doctrine/mongodb-odm": ">=1,<1.0.2", - "doctrine/mongodb-odm-bundle": ">=2,<3.0.1", + "doctrine/mongodb-odm": "<1.0.2", + "doctrine/mongodb-odm-bundle": "<3.0.1", "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1|>=2.8.3,<2.8.4", - "dolibarr/dolibarr": "<17.0.1|= 12.0.5|>= 3.3.beta1, < 13.0.2", - "dompdf/dompdf": "<2.0.2|= 2.0.2", - "drupal/core": ">=7,<7.96|>=8,<9.4.14|>=9.5,<9.5.8|>=10,<10.0.8", - "drupal/drupal": ">=7,<7.80|>=8,<8.9.16|>=9,<9.1.12|>=9.2,<9.2.4", + "dolibarr/dolibarr": "<=19", + "dompdf/dompdf": "<2.0.4", + "doublethreedigital/guest-entries": "<3.1.2", + "drupal/core": ">=6,<6.38|>=7,<7.96|>=8,<10.1.8|>=10.2,<10.2.2", + "drupal/drupal": ">=5,<5.11|>=6,<6.38|>=7,<7.80|>=8,<8.9.16|>=9,<9.1.12|>=9.2,<9.2.4", + "duncanmcclean/guest-entries": "<3.1.2", "dweeves/magmi": "<=0.7.24", + "ec-cube/ec-cube": "<2.4.4", "ecodev/newsletter": "<=4", "ectouch/ectouch": "<=2.7.2", - "elefant/cms": "<1.3.13", + "elefant/cms": "<2.0.7", "elgg/elgg": "<3.3.24|>=4,<4.0.5", + "elijaa/phpmemcacheadmin": "<=1.3", "encore/laravel-admin": "<=1.8.19", "endroid/qr-code-bundle": "<3.4.2", + "enhavo/enhavo-app": "<=0.13.1", "enshrined/svg-sanitize": "<0.15", "erusev/parsedown": "<1.7.2", "ether/logs": "<3.0.4", + "evolutioncms/evolution": "<=3.2.3", "exceedone/exment": "<4.4.3|>=5,<5.0.3", - "exceedone/laravel-admin": "= 3.0.0|<2.2.3", - "ezsystems/demobundle": ">=5.4,<5.4.6.1", + "exceedone/laravel-admin": "<2.2.3|==3", + "ezsystems/demobundle": ">=5.4,<5.4.6.1-dev", "ezsystems/ez-support-tools": ">=2.2,<2.2.3", - "ezsystems/ezdemo-ls-extension": ">=5.4,<5.4.2.1", - "ezsystems/ezfind-ls": ">=5.3,<5.3.6.1|>=5.4,<5.4.11.1|>=2017.12,<2017.12.0.1", + "ezsystems/ezdemo-ls-extension": ">=5.4,<5.4.2.1-dev", + "ezsystems/ezfind-ls": ">=5.3,<5.3.6.1-dev|>=5.4,<5.4.11.1-dev|>=2017.12,<2017.12.0.1-dev", "ezsystems/ezplatform": "<=1.13.6|>=2,<=2.5.24", "ezsystems/ezplatform-admin-ui": ">=1.3,<1.3.5|>=1.4,<1.4.6|>=1.5,<1.5.29|>=2.3,<2.3.26", "ezsystems/ezplatform-admin-ui-assets": ">=4,<4.2.1|>=5,<5.0.1|>=5.1,<5.1.1", - "ezsystems/ezplatform-graphql": ">=1-rc.1,<1.0.13|>=2-beta.1,<2.3.12", - "ezsystems/ezplatform-kernel": "<1.2.5.1|>=1.3,<1.3.26", + "ezsystems/ezplatform-graphql": ">=1.0.0.0-RC1-dev,<1.0.13|>=2.0.0.0-beta1,<2.3.12", + "ezsystems/ezplatform-kernel": "<1.2.5.1-dev|>=1.3,<1.3.35", "ezsystems/ezplatform-rest": ">=1.2,<=1.2.2|>=1.3,<1.3.8", - "ezsystems/ezplatform-richtext": ">=2.3,<2.3.7.1", + "ezsystems/ezplatform-richtext": ">=2.3,<2.3.7.1-dev", + "ezsystems/ezplatform-solr-search-engine": ">=1.7,<1.7.12|>=2,<2.0.2|>=3.3,<3.3.15", "ezsystems/ezplatform-user": ">=1,<1.0.1", - "ezsystems/ezpublish-kernel": "<6.13.8.2|>=7,<7.5.30", - "ezsystems/ezpublish-legacy": "<=2017.12.7.3|>=2018.6,<=2019.3.5.1", + "ezsystems/ezpublish-kernel": "<6.13.8.2-dev|>=7,<7.5.31", + "ezsystems/ezpublish-legacy": "<=2017.12.7.3|>=2018.6,<=2019.03.5.1", "ezsystems/platform-ui-assets-bundle": ">=4.2,<4.2.3", - "ezsystems/repository-forms": ">=2.3,<2.3.2.1|>=2.5,<2.5.15", + "ezsystems/repository-forms": ">=2.3,<2.3.2.1-dev|>=2.5,<2.5.15", "ezyang/htmlpurifier": "<4.1.1", "facade/ignition": "<1.16.15|>=2,<2.4.2|>=2.5,<2.5.2", - "facturascripts/facturascripts": "<=2022.8", + "facturascripts/facturascripts": "<=2022.08", "feehi/cms": "<=2.1.1", "feehi/feehicms": "<=2.1.1", "fenom/fenom": "<=2.12.1", @@ -3787,43 +3620,54 @@ "firebase/php-jwt": "<6", "fixpunkt/fp-masterquiz": "<2.2.1|>=3,<3.5.2", "fixpunkt/fp-newsletter": "<1.1.1|>=2,<2.1.2|>=2.2,<3.2.6", - "flarum/core": "<1.7", + "flarum/core": "<1.8.5", + "flarum/framework": "<1.8.5", "flarum/mentions": "<1.6.3", - "flarum/sticky": ">=0.1-beta.14,<=0.1-beta.15", - "flarum/tags": "<=0.1-beta.13", + "flarum/sticky": ">=0.1.0.0-beta14,<=0.1.0.0-beta15", + "flarum/tags": "<=0.1.0.0-beta13", + "floriangaerber/magnesium": "<0.3.1", "fluidtypo3/vhs": "<5.1.1", - "fof/byobu": ">=0.3-beta.2,<1.1.7", + "fof/byobu": ">=0.3.0.0-beta2,<1.1.7", "fof/upload": "<1.2.3", + "foodcoopshop/foodcoopshop": ">=3.2,<3.6.1", "fooman/tcpdf": "<6.2.22", "forkcms/forkcms": "<5.11.1", "fossar/tcpdf-parser": "<6.2.22", - "francoisjacquet/rosariosis": "<11", + "francoisjacquet/rosariosis": "<=11.5.1", "frappant/frp-form-answers": "<3.1.2|>=4,<4.0.2", "friendsofsymfony/oauth2-php": "<1.3", "friendsofsymfony/rest-bundle": ">=1.2,<1.2.2", "friendsofsymfony/user-bundle": ">=1.2,<1.3.5", + "friendsofsymfony1/symfony1": ">=1.1,<1.5.19", "friendsoftypo3/mediace": ">=7.6.2,<7.6.5", - "froala/wysiwyg-editor": "<3.2.7", - "froxlor/froxlor": "<2.1", + "friendsoftypo3/openid": ">=4.5,<4.5.31|>=4.7,<4.7.16|>=6,<6.0.11|>=6.1,<6.1.6", + "froala/wysiwyg-editor": "<3.2.7|>=4.0.1,<=4.1.3", + "froxlor/froxlor": "<=2.1.1", "fuel/core": "<1.8.1", - "funadmin/funadmin": "<=3.2", + "funadmin/funadmin": "<=3.2|>=3.3.2,<=3.3.3", "gaoming13/wechat-php-sdk": "<=1.10.2", "genix/cms": "<=1.1.11", - "getgrav/grav": "<1.7.42", - "getkirby/cms": "= 3.8.0|<3.5.8.2|>=3.6,<3.6.6.2|>=3.7,<3.7.5.1", + "getgrav/grav": "<1.7.45", + "getkirby/cms": "<4.1.1", + "getkirby/kirby": "<=2.5.12", "getkirby/panel": "<2.5.14", "getkirby/starterkit": "<=3.7.0.2", - "gilacms/gila": "<=1.11.4", + "gilacms/gila": "<=1.15.4", + "gleez/cms": "<=1.2|==2", "globalpayments/php-sdk": "<2", + "gogentooss/samlbase": "<1.2.7", "google/protobuf": "<3.15", "gos/web-socket-bundle": "<1.10.4|>=2,<2.6.1|>=3,<3.3", "gree/jose": "<2.2.1", "gregwar/rst": "<1.0.3", - "grumpydictator/firefly-iii": "<6", + "grumpydictator/firefly-iii": "<6.1.7", + "gugoan/economizzer": "<=0.9.0.0-beta1", "guzzlehttp/guzzle": "<6.5.8|>=7,<7.4.5", "guzzlehttp/psr7": "<1.9.1|>=2,<2.4.5", + "haffner/jh_captcha": "<=2.1.3|>=3,<=3.0.2", "harvesthq/chosen": "<1.8.7", - "helloxz/imgurl": "= 2.31|<=2.31", + "helloxz/imgurl": "<=2.31", + "hhxsv5/laravel-s": "<3.7.36", "hillelcoren/invoice-ninja": "<5.3.35", "himiklab/yii2-jqgrid-widget": "<1.0.8", "hjue/justwriting": "<=1", @@ -3831,208 +3675,266 @@ "httpsoft/http-message": "<1.0.12", "hyn/multi-tenant": ">=5.6,<5.7.2", "ibexa/admin-ui": ">=4.2,<4.2.3", - "ibexa/core": ">=4,<4.0.7|>=4.1,<4.1.4|>=4.2,<4.2.3", + "ibexa/core": ">=4,<4.0.7|>=4.1,<4.1.4|>=4.2,<4.2.3|>=4.5,<4.5.6|>=4.6,<4.6.2", "ibexa/graphql": ">=2.5,<2.5.31|>=3.3,<3.3.28|>=4.2,<4.2.3", "ibexa/post-install": "<=1.0.4", + "ibexa/solr": ">=4.5,<4.5.4", "ibexa/user": ">=4,<4.4.3", "icecoder/icecoder": "<=8.1", "idno/known": "<=1.3.1", - "illuminate/auth": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.10", + "ilicmiljan/secure-props": ">=1.2,<1.2.2", + "illuminate/auth": "<5.5.10", "illuminate/cookie": ">=4,<=4.0.11|>=4.1,<=4.1.99999|>=4.2,<=4.2.99999|>=5,<=5.0.99999|>=5.1,<=5.1.99999|>=5.2,<=5.2.99999|>=5.3,<=5.3.99999|>=5.4,<=5.4.99999|>=5.5,<=5.5.49|>=5.6,<=5.6.99999|>=5.7,<=5.7.99999|>=5.8,<=5.8.99999|>=6,<6.18.31|>=7,<7.22.4", "illuminate/database": "<6.20.26|>=7,<7.30.5|>=8,<8.40", "illuminate/encryption": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.40|>=5.6,<5.6.15", "illuminate/view": "<6.20.42|>=7,<7.30.6|>=8,<8.75", - "impresscms/impresscms": "<=1.4.3", - "in2code/femanager": "<5.5.3|>=6,<6.3.4|>=7,<7.1", + "impresscms/impresscms": "<=1.4.5", + "impresspages/impresspages": "<=1.0.12", + "in2code/femanager": "<5.5.3|>=6,<6.3.4|>=7,<7.2.3", "in2code/ipandlanguageredirect": "<5.1.2", "in2code/lux": "<17.6.1|>=18,<24.0.2", "innologi/typo3-appointments": "<2.0.6", - "intelliants/subrion": "<=4.2.1", + "intelliants/subrion": "<4.2.2", "islandora/islandora": ">=2,<2.4.1", "ivankristianto/phpwhois": "<=4.3", "jackalope/jackalope-doctrine-dbal": "<1.7.4", "james-heinrich/getid3": "<1.9.21", + "james-heinrich/phpthumb": "<1.7.12", "jasig/phpcas": "<1.3.3", + "jcbrand/converse.js": "<3.3.3", + "johnbillion/wp-crontrol": "<1.16.2", + "joomla/application": "<1.0.13", "joomla/archive": "<1.1.12|>=2,<2.0.1", "joomla/filesystem": "<1.6.2|>=2,<2.0.1", "joomla/filter": "<1.4.4|>=2,<2.0.1", + "joomla/framework": "<1.5.7|>=2.5.4,<=3.8.12", "joomla/input": ">=2,<2.0.2", + "joomla/joomla-cms": ">=2.5,<3.9.12", "joomla/session": "<1.3.1", "joyqi/hyper-down": "<=2.4.27", "jsdecena/laracom": "<2.0.9", "jsmitty12/phpwhois": "<5.1", + "juzaweb/cms": "<=3.4", "kazist/phpwhois": "<=4.2.6", "kelvinmo/simplexrd": "<3.1.1", "kevinpapst/kimai2": "<1.16.7", - "kimai/kimai": "<1.1", - "kitodo/presentation": "<3.1.2", + "khodakhah/nodcms": "<=3", + "kimai/kimai": "<2.13", + "kitodo/presentation": "<3.2.3|>=3.3,<3.3.4", "klaviyo/magento2-extension": ">=1,<3", - "knplabs/knp-snappy": "<1.4.2", + "knplabs/knp-snappy": "<=1.4.2", + "kohana/core": "<3.3.3", "krayin/laravel-crm": "<1.2.2", "kreait/firebase-php": ">=3.2,<3.8.1", "la-haute-societe/tcpdf": "<6.2.22", - "laminas/laminas-diactoros": "<2.18.1|>=2.24,<2.24.2|>=2.25,<2.25.2|= 2.23.0|= 2.22.0|= 2.21.0|= 2.20.0|= 2.19.0", + "laminas/laminas-diactoros": "<2.18.1|==2.19|==2.20|==2.21|==2.22|==2.23|>=2.24,<2.24.2|>=2.25,<2.25.2", "laminas/laminas-form": "<2.17.1|>=3,<3.0.2|>=3.1,<3.1.1", "laminas/laminas-http": "<2.14.2", "laravel/fortify": "<1.11.1", - "laravel/framework": "<6.20.42|>=7,<7.30.6|>=8,<8.75", + "laravel/framework": "<6.20.44|>=7,<7.30.6|>=8,<8.75", "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", "latte/latte": "<2.10.8", "lavalite/cms": "<=9", "lcobucci/jwt": ">=3.4,<3.4.6|>=4,<4.0.4|>=4.1,<4.1.5", "league/commonmark": "<0.18.3", "league/flysystem": "<1.1.4|>=2,<2.1.1", + "league/oauth2-server": ">=8.3.2,<8.4.2|>=8.5,<8.5.3", "lexik/jwt-authentication-bundle": "<2.10.7|>=2.11,<2.11.3", - "librenms/librenms": "<22.10", + "librenms/librenms": "<2017.08.18", "liftkit/database": "<2.13.2", "limesurvey/limesurvey": "<3.27.19", "livehelperchat/livehelperchat": "<=3.91", - "livewire/livewire": ">2.2.4,<2.2.6", + "livewire/livewire": ">2.2.4,<2.2.6|>=3.3.5,<3.4.9", "lms/routes": "<2.1.1", "localizationteam/l10nmgr": "<7.4|>=8,<8.7|>=9,<9.2", "luyadev/yii-helpers": "<1.2.1", - "magento/community-edition": ">=2,<2.2.10|>=2.3,<2.3.3", - "magento/magento1ce": "<1.9.4.3", - "magento/magento1ee": ">=1,<1.14.4.3", - "magento/product-community-edition": ">=2,<2.2.10|>=2.3,<2.3.2-p.2", + "magento/community-edition": "<2.4.3.0-patch3|>=2.4.4,<2.4.5", + "magento/core": "<=1.9.4.5", + "magento/magento1ce": "<1.9.4.3-dev", + "magento/magento1ee": ">=1,<1.14.4.3-dev", + "magento/product-community-edition": ">=2,<2.2.10|>=2.3,<2.3.2.0-patch2", + "magneto/core": "<1.9.4.4-dev", "maikuolan/phpmussel": ">=1,<1.6", - "mantisbt/mantisbt": "<=2.25.5", + "mainwp/mainwp": "<=4.4.3.3", + "mantisbt/mantisbt": "<2.26.1", "marcwillmann/turn": "<0.3.3", "matyhtf/framework": "<3.0.6", - "mautic/core": "<4.3|= 2.13.1", - "mediawiki/core": ">=1.27,<1.27.6|>=1.29,<1.29.3|>=1.30,<1.30.2|>=1.31,<1.31.9|>=1.32,<1.32.6|>=1.32.99,<1.33.3|>=1.33.99,<1.34.3|>=1.34.99,<1.35", + "mautic/core": "<4.4.12|>=5.0.0.0-alpha,<5.0.4", + "mediawiki/core": "<1.36.2", "mediawiki/matomo": "<2.4.3", + "mediawiki/semantic-media-wiki": "<4.0.2", "melisplatform/melis-asset-manager": "<5.0.1", "melisplatform/melis-cms": "<5.0.1", "melisplatform/melis-front": "<5.0.1", "mezzio/mezzio-swoole": "<3.7|>=4,<4.3", "mgallegos/laravel-jqgrid": "<=1.3", - "microweber/microweber": "<=1.3.4", + "microsoft/microsoft-graph": ">=1.16,<1.109.1|>=2,<2.0.1", + "microsoft/microsoft-graph-beta": "<2.0.1", + "microsoft/microsoft-graph-core": "<2.0.2", + "microweber/microweber": "<=2.0.4", "miniorange/miniorange-saml": "<1.4.3", "mittwald/typo3_forum": "<1.2.1", "mobiledetect/mobiledetectlib": "<2.8.32", - "modx/revolution": "<= 2.8.3-pl|<2.8", + "modx/revolution": "<=2.8.3.0-patch", "mojo42/jirafeau": "<4.4", + "mongodb/mongodb": ">=1,<1.9.2", "monolog/monolog": ">=1.8,<1.12", - "moodle/moodle": "<4.2-rc.2|= 3.11", + "moodle/moodle": "<=4.3.3", + "mos/cimage": "<0.7.19", + "movim/moxl": ">=0.8,<=0.10", + "mpdf/mpdf": "<=7.1.7", + "munkireport/comment": "<4.1", + "munkireport/managedinstalls": "<2.6", + "munkireport/munkireport": ">=2.5.3,<5.6.3", "mustache/mustache": ">=2,<2.14.1", "namshi/jose": "<2.2", "neoan3-apps/template": "<1.1.1", - "neorazorx/facturascripts": "<2022.4", + "neorazorx/facturascripts": "<2022.04", "neos/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6", "neos/form": ">=1.2,<4.3.3|>=5,<5.0.9|>=5.1,<5.1.3", + "neos/media-browser": "<7.3.19|>=8,<8.0.16|>=8.1,<8.1.11|>=8.2,<8.2.11|>=8.3,<8.3.9", "neos/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4|>=2.3,<2.9.99|>=3,<3.0.20|>=3.1,<3.1.18|>=3.2,<3.2.14|>=3.3,<5.3.10|>=7,<7.0.9|>=7.1,<7.1.7|>=7.2,<7.2.6|>=7.3,<7.3.4|>=8,<8.0.2", "neos/swiftmailer": ">=4.1,<4.1.99|>=5.4,<5.4.5", "netgen/tagsbundle": ">=3.4,<3.4.11|>=4,<4.0.15", "nette/application": ">=2,<2.0.19|>=2.1,<2.1.13|>=2.2,<2.2.10|>=2.3,<2.3.14|>=2.4,<2.4.16|>=3,<3.0.6", "nette/nette": ">=2,<2.0.19|>=2.1,<2.1.13", - "nilsteampassnet/teampass": "<3.0.9", + "nilsteampassnet/teampass": "<3.0.10", + "nonfiction/nterchange": "<4.1.1", "notrinos/notrinos-erp": "<=0.7", "noumo/easyii": "<=0.9", - "nukeviet/nukeviet": "<4.5.2", + "nukeviet/nukeviet": "<4.5.02", "nyholm/psr7": "<1.6.1", "nystudio107/craft-seomatic": "<3.4.12", "nzo/url-encryptor-bundle": ">=4,<4.3.2|>=5,<5.0.1", "october/backend": "<1.1.2", - "october/cms": "= 1.1.1|= 1.0.471|= 1.0.469|>=1.0.319,<1.0.469", - "october/october": ">=1.0.319,<1.0.466|>=2.1,<2.1.12", + "october/cms": "<1.0.469|==1.0.469|==1.0.471|==1.1.1", + "october/october": "<=3.4.4", "october/rain": "<1.0.472|>=1.1,<1.1.2", - "october/system": "<1.0.476|>=1.1,<1.1.12|>=2,<2.2.34|>=3,<3.0.66", + "october/system": "<1.0.476|>=1.1,<1.1.12|>=2,<2.2.34|>=3,<3.5.2", + "omeka/omeka-s": "<4.0.3", "onelogin/php-saml": "<2.10.4", - "oneup/uploader-bundle": "<1.9.3|>=2,<2.1.5", + "oneup/uploader-bundle": ">=1,<1.9.3|>=2,<2.1.5", "open-web-analytics/open-web-analytics": "<1.7.4", - "opencart/opencart": "<=3.0.3.7", + "opencart/opencart": "<=3.0.3.7|>=4,<4.0.2.3-dev", "openid/php-openid": "<2.3", - "openmage/magento-lts": "<19.4.22|>=20,<20.0.19", - "orchid/platform": ">=9,<9.4.4", - "oro/commerce": ">=4.1,<5.0.6", + "openmage/magento-lts": "<20.5", + "opensource-workshop/connect-cms": "<1.7.2|>=2,<2.3.2", + "orchid/platform": ">=9,<9.4.4|>=14.0.0.0-alpha4,<14.5", + "oro/calendar-bundle": ">=4.2,<=4.2.6|>=5,<=5.0.6|>=5.1,<5.1.1", + "oro/commerce": ">=4.1,<5.0.11|>=5.1,<5.1.1", "oro/crm": ">=1.7,<1.7.4|>=3.1,<4.1.17|>=4.2,<4.2.7", - "oro/platform": ">=1.7,<1.7.4|>=3.1,<3.1.29|>=4.1,<4.1.17|>=4.2,<4.2.8", + "oro/crm-call-bundle": ">=4.2,<=4.2.5|>=5,<5.0.4|>=5.1,<5.1.1", + "oro/customer-portal": ">=4.1,<=4.1.13|>=4.2,<=4.2.10|>=5,<=5.0.11|>=5.1,<=5.1.3", + "oro/platform": ">=1.7,<1.7.4|>=3.1,<3.1.29|>=4.1,<4.1.17|>=4.2,<=4.2.10|>=5,<=5.0.12|>=5.1,<=5.1.3", + "oxid-esales/oxideshop-ce": "<4.5", "packbackbooks/lti-1-3-php-library": "<5", "padraic/humbug_get_contents": "<1.1.2", - "pagarme/pagarme-php": ">=0,<3", + "pagarme/pagarme-php": "<3", "pagekit/pagekit": "<=1.0.18", "paragonie/random_compat": "<2", "passbolt/passbolt_api": "<2.11", "paypal/merchant-sdk-php": "<3.12", "pear/archive_tar": "<1.4.14", + "pear/auth": "<1.2.4", "pear/crypt_gpg": "<1.6.7", + "pear/pear": "<=1.10.1", "pegasus/google-for-jobs": "<1.5.1|>=2,<2.1.1", "personnummer/personnummer": "<3.0.2", "phanan/koel": "<5.1.4", + "phenx/php-svg-lib": "<0.5.2", "php-mod/curl": "<2.3.2", - "phpbb/phpbb": ">=3.2,<3.2.10|>=3.3,<3.3.1", + "phpbb/phpbb": "<3.2.10|>=3.3,<3.3.1", + "phpems/phpems": ">=6,<=6.1.3", "phpfastcache/phpfastcache": "<6.1.5|>=7,<7.1.2|>=8,<8.0.7", "phpmailer/phpmailer": "<6.5", "phpmussel/phpmussel": ">=1,<1.6", "phpmyadmin/phpmyadmin": "<5.2.1", - "phpmyfaq/phpmyfaq": "<=3.1.7", + "phpmyfaq/phpmyfaq": "<3.2.5|==3.2.5", "phpoffice/phpexcel": "<1.8", "phpoffice/phpspreadsheet": "<1.16", - "phpseclib/phpseclib": "<2.0.31|>=3,<3.0.19", - "phpservermon/phpservermon": "<=3.5.2", - "phpsysinfo/phpsysinfo": "<3.2.5", - "phpunit/phpunit": ">=4.8.19,<4.8.28|>=5,<5.6.3", + "phpseclib/phpseclib": "<2.0.47|>=3,<3.0.36", + "phpservermon/phpservermon": "<3.6", + "phpsysinfo/phpsysinfo": "<3.4.3", + "phpunit/phpunit": ">=4.8.19,<4.8.28|>=5.0.10,<5.6.3", "phpwhois/phpwhois": "<=4.2.5", "phpxmlrpc/extras": "<0.6.1", "phpxmlrpc/phpxmlrpc": "<4.9.2", - "pimcore/customer-management-framework-bundle": "<3.3.10", + "pi/pi": "<=2.5", + "pimcore/admin-ui-classic-bundle": "<1.3.4", + "pimcore/customer-management-framework-bundle": "<4.0.6", "pimcore/data-hub": "<1.2.4", + "pimcore/demo": "<10.3", + "pimcore/ecommerce-framework-bundle": "<1.0.10", "pimcore/perspective-editor": "<1.5.1", - "pimcore/pimcore": "<10.5.23", - "pixelfed/pixelfed": "<=0.11.4", + "pimcore/pimcore": "<11.1.6.1-dev|>=11.2,<11.2.2", + "pixelfed/pixelfed": "<0.11.11", + "plotly/plotly.js": "<2.25.2", "pocketmine/bedrock-protocol": "<8.0.2", - "pocketmine/pocketmine-mp": "<4.20.5|>=4.21,<4.21.1|< 4.18.0-ALPHA2|>= 4.0.0-BETA5, < 4.4.2", + "pocketmine/pocketmine-mp": "<5.11.2", + "pocketmine/raklib": ">=0.14,<0.14.6|>=0.15,<0.15.1", "pressbooks/pressbooks": "<5.18", "prestashop/autoupgrade": ">=4,<4.10.1", + "prestashop/blockreassurance": "<=5.1.3", "prestashop/blockwishlist": ">=2,<2.1.1", "prestashop/contactform": ">=1.0.1,<4.3", "prestashop/gamification": "<2.3.2", - "prestashop/prestashop": "<8.0.4", + "prestashop/prestashop": "<8.1.4", "prestashop/productcomments": "<5.0.2", "prestashop/ps_emailsubscription": "<2.6.1", "prestashop/ps_facetedsearch": "<3.4.1", "prestashop/ps_linklist": "<3.1", "privatebin/privatebin": "<1.4", - "processwire/processwire": "<=3.0.200", - "propel/propel": ">=2-alpha.1,<=2-alpha.7", + "processwire/processwire": "<=3.0.210", + "propel/propel": ">=2.0.0.0-alpha1,<=2.0.0.0-alpha7", "propel/propel1": ">=1,<=1.7.1", "pterodactyl/panel": "<1.7", + "ptheofan/yii2-statemachine": ">=2.0.0.0-RC1-dev,<=2", "ptrofimov/beanstalk_console": "<1.7.14", + "pubnub/pubnub": "<6.1", "pusher/pusher-php-server": "<2.2.1", - "pwweb/laravel-core": "<=0.3.6-beta", + "pwweb/laravel-core": "<=0.3.6.0-beta", "pyrocms/pyrocms": "<=3.9.1", + "rainlab/blog-plugin": "<1.4.1", "rainlab/debugbar-plugin": "<3.1", + "rainlab/user-plugin": "<=1.4.5", "rankmath/seo-by-rank-math": "<=1.0.95", + "rap2hpoutre/laravel-log-viewer": "<0.13", "react/http": ">=0.7,<1.9", "really-simple-plugins/complianz-gdpr": "<6.4.2", - "remdex/livehelperchat": "<3.99", + "redaxo/source": "<=5.15.1", + "remdex/livehelperchat": "<4.29", + "reportico-web/reportico": "<=8.1", + "rhukster/dom-sanitizer": "<1.0.7", "rmccue/requests": ">=1.6,<1.8", - "robrichards/xmlseclibs": "<3.0.4", + "robrichards/xmlseclibs": ">=1,<3.0.4", "roots/soil": "<4.1", "rudloff/alltube": "<3.0.3", "s-cart/core": "<6.9", "s-cart/s-cart": "<6.9", "sabberworm/php-css-parser": ">=1,<1.0.1|>=2,<2.0.1|>=3,<3.0.1|>=4,<4.0.1|>=5,<5.0.9|>=5.1,<5.1.3|>=5.2,<5.2.1|>=6,<6.0.2|>=7,<7.0.4|>=8,<8.0.1|>=8.1,<8.1.1|>=8.2,<8.2.1|>=8.3,<8.3.1", - "sabre/dav": ">=1.6,<1.6.99|>=1.7,<1.7.11|>=1.8,<1.8.9", - "scheb/two-factor-bundle": ">=0,<3.26|>=4,<4.11", + "sabre/dav": ">=1.6,<1.7.11|>=1.8,<1.8.9", + "scheb/two-factor-bundle": "<3.26|>=4,<4.11", "sensiolabs/connect": "<4.2.3", "serluck/phpwhois": "<=4.2.6", - "shopware/core": "<=6.4.20", - "shopware/platform": "<=6.4.20", + "sfroemken/url_redirect": "<=1.2.1", + "sheng/yiicms": "<=1.2", + "shopware/core": "<6.5.8.8-dev|>=6.6.0.0-RC1-dev,<6.6.1", + "shopware/platform": "<6.5.8.8-dev|>=6.6.0.0-RC1-dev,<6.6.1", "shopware/production": "<=6.3.5.2", - "shopware/shopware": "<=5.7.14", - "shopware/storefront": "<=6.4.8.1", + "shopware/shopware": "<=5.7.17", + "shopware/storefront": "<=6.4.8.1|>=6.5.8,<6.5.8.7-dev", "shopxo/shopxo": "<2.2.6", "showdoc/showdoc": "<2.10.4", - "silverstripe/admin": "<1.12.7", + "silverstripe-australia/advancedreports": ">=1,<=2", + "silverstripe/admin": "<1.13.19|>=2,<2.1.8", "silverstripe/assets": ">=1,<1.11.1", "silverstripe/cms": "<4.11.3", "silverstripe/comments": ">=1.3,<1.9.99|>=2,<2.9.99|>=3,<3.1.1", "silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3", - "silverstripe/framework": "<4.12.5", - "silverstripe/graphql": "<3.5.2|>=4-alpha.1,<4-alpha.2|>=4.1.1,<4.1.2|>=4.2.2,<4.2.3|= 4.0.0-alpha1", + "silverstripe/framework": "<4.13.39|>=5,<5.1.11", + "silverstripe/graphql": ">=2,<2.0.5|>=3,<3.8.2|>=4,<4.3.7|>=5,<5.1.3", "silverstripe/hybridsessions": ">=1,<2.4.1|>=2.5,<2.5.1", + "silverstripe/recipe-cms": ">=4.5,<4.5.3", "silverstripe/registry": ">=2.1,<2.1.2|>=2.2,<2.2.1", "silverstripe/restfulserver": ">=1,<1.0.9|>=2,<2.0.4", "silverstripe/silverstripe-omnipay": "<2.5.2|>=3,<3.0.2|>=3.1,<3.1.4|>=3.2,<3.2.1", @@ -4041,38 +3943,44 @@ "silverstripe/userforms": "<3", "silverstripe/versioned-admin": ">=1,<1.11.1", "simple-updates/phpwhois": "<=1", - "simplesamlphp/saml2": "<1.10.6|>=2,<2.3.8|>=3,<3.1.4", + "simplesamlphp/saml2": "<1.10.6|>=2,<2.3.8|>=3,<3.1.4|==5.0.0.0-alpha12", "simplesamlphp/simplesamlphp": "<1.18.6", "simplesamlphp/simplesamlphp-module-infocard": "<1.0.1", "simplesamlphp/simplesamlphp-module-openid": "<1", "simplesamlphp/simplesamlphp-module-openidprovider": "<0.9", + "simplesamlphp/xml-security": "==1.6.11", "simplito/elliptic-php": "<1.0.6", "sitegeist/fluid-components": "<3.5", + "sjbr/sr-freecap": "<2.4.6|>=2.5,<2.5.3", "slim/psr7": "<1.4.1|>=1.5,<1.5.1|>=1.6,<1.6.1", "slim/slim": "<2.6", + "slub/slub-events": "<3.0.3", "smarty/smarty": "<3.1.48|>=4,<4.3.1", - "snipe/snipe-it": "<=6.0.14|>= 6.0.0-RC-1, <= 6.0.0-RC-5", + "snipe/snipe-it": "<=6.2.2", "socalnick/scn-social-auth": "<1.15.2", "socialiteproviders/steam": "<1.1", "spatie/browsershot": "<3.57.4", - "spipu/html2pdf": "<5.2.4", + "spipu/html2pdf": "<5.2.8", + "spoon/library": "<1.4.1", "spoonity/tcpdf": "<6.2.22", "squizlabs/php_codesniffer": ">=1,<2.8.1|>=3,<3.0.1", - "ssddanbrown/bookstack": "<22.2.3", - "statamic/cms": "<3.2.39|>=3.3,<3.3.2", - "stormpath/sdk": ">=0,<9.9.99", + "ssddanbrown/bookstack": "<22.02.3", + "statamic/cms": "<4.46", + "stormpath/sdk": "<9.9.99", "studio-42/elfinder": "<2.1.62", - "subrion/cms": "<=4.2.1", + "subhh/libconnect": "<7.0.8|>=8,<8.1", "sukohi/surpass": "<1", - "sulu/sulu": "= 2.4.0-RC1|<1.6.44|>=2,<2.2.18|>=2.3,<2.3.8", + "sulu/sulu": "<1.6.44|>=2,<2.4.17|>=2.5,<2.5.13", "sumocoders/framework-user-bundle": "<1.4", + "superbig/craft-audit": "<3.0.2", "swag/paypal": "<5.4.4", "swiftmailer/swiftmailer": ">=4,<5.4.5", + "swiftyedit/swiftyedit": "<1.2", "sylius/admin-bundle": ">=1,<1.0.17|>=1.1,<1.1.9|>=1.2,<1.2.2", "sylius/grid": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1", "sylius/grid-bundle": "<1.10.1", "sylius/paypal-plugin": ">=1,<1.2.4|>=1.3,<1.3.1", - "sylius/resource-bundle": "<1.3.14|>=1.4,<1.4.7|>=1.5,<1.5.2|>=1.6,<1.6.4", + "sylius/resource-bundle": ">=1,<1.3.14|>=1.4,<1.4.7|>=1.5,<1.5.2|>=1.6,<1.6.4", "sylius/sylius": "<1.9.10|>=1.10,<1.10.11|>=1.11,<1.11.2", "symbiote/silverstripe-multivaluefield": ">=3,<3.0.99", "symbiote/silverstripe-queuedjobs": ">=3,<3.0.2|>=3.1,<3.1.4|>=4,<4.0.7|>=4.1,<4.1.2|>=4.2,<4.2.4|>=4.3,<4.3.3|>=4.4,<4.4.3|>=4.5,<4.5.1|>=4.6,<4.6.4", @@ -4083,7 +3991,7 @@ "symfony/dependency-injection": ">=2,<2.0.17|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", "symfony/error-handler": ">=4.4,<4.4.4|>=5,<5.0.4", "symfony/form": ">=2.3,<2.3.35|>=2.4,<2.6.12|>=2.7,<2.7.50|>=2.8,<2.8.49|>=3,<3.4.20|>=4,<4.0.15|>=4.1,<4.1.9|>=4.2,<4.2.1", - "symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7|>=5.3.14,<=5.3.14|>=5.4.3,<=5.4.3|>=6.0.3,<=6.0.3|= 6.0.3|= 5.4.3|= 5.3.14", + "symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7|>=5.3.14,<5.3.15|>=5.4.3,<5.4.4|>=6.0.3,<6.0.4", "symfony/http-foundation": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7", "symfony/http-kernel": ">=2,<4.4.50|>=5,<5.4.20|>=6,<6.0.20|>=6.1,<6.1.12|>=6.2,<6.2.6", "symfony/intl": ">=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", @@ -4099,69 +4007,91 @@ "symfony/security-core": ">=2.4,<2.6.13|>=2.7,<2.7.9|>=2.7.30,<2.7.32|>=2.8,<3.4.49|>=4,<4.4.24|>=5,<5.2.9", "symfony/security-csrf": ">=2.4,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", "symfony/security-guard": ">=2.8,<3.4.48|>=4,<4.4.23|>=5,<5.2.8", - "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7|>=5.1,<5.2.8|>=5.3,<5.3.2", + "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7|>=5.1,<5.2.8|>=5.3,<5.3.2|>=5.4,<5.4.31|>=6,<6.3.8", "symfony/serializer": ">=2,<2.0.11|>=4.1,<4.4.35|>=5,<5.3.12", - "symfony/symfony": ">=2,<4.4.50|>=5,<5.4.20|>=6,<6.0.20|>=6.1,<6.1.12|>=6.2,<6.2.6", + "symfony/symfony": ">=2,<4.4.51|>=5,<5.4.31|>=6,<6.3.8", "symfony/translation": ">=2,<2.0.17", + "symfony/twig-bridge": ">=2,<4.4.51|>=5,<5.4.31|>=6,<6.3.8", + "symfony/ux-autocomplete": "<2.11.2", "symfony/validator": ">=2,<2.0.24|>=2.1,<2.1.12|>=2.2,<2.2.5|>=2.3,<2.3.3", "symfony/var-exporter": ">=4.2,<4.2.12|>=4.3,<4.3.8", "symfony/web-profiler-bundle": ">=2,<2.3.19|>=2.4,<2.4.9|>=2.5,<2.5.4", - "symfony/yaml": ">=2,<2.0.22|>=2.1,<2.1.7", - "t3/dce": ">=2.2,<2.6.2", + "symfony/webhook": ">=6.3,<6.3.8", + "symfony/yaml": ">=2,<2.0.22|>=2.1,<2.1.7|>=2.2.0.0-beta1,<2.2.0.0-beta2", + "symphonycms/symphony-2": "<2.6.4", + "t3/dce": "<0.11.5|>=2.2,<2.6.2", "t3g/svg-sanitizer": "<1.0.3", + "t3s/content-consent": "<1.0.3|>=2,<2.0.2", "tastyigniter/tastyigniter": "<3.3", "tcg/voyager": "<=1.4", - "tecnickcom/tcpdf": "<6.2.22", + "tecnickcom/tcpdf": "<6.7.4", "terminal42/contao-tablelookupwizard": "<3.3.5", "thelia/backoffice-default-template": ">=2.1,<2.1.2", - "thelia/thelia": ">=2.1-beta.1,<2.1.3", + "thelia/thelia": ">=2.1,<2.1.3", "theonedemon/phpwhois": "<=4.2.5", "thinkcmf/thinkcmf": "<=5.1.7", - "thorsten/phpmyfaq": "<3.2-beta", - "tinymce/tinymce": "<5.10.7|>=6,<6.3.1", + "thorsten/phpmyfaq": "<3.2.2", + "tikiwiki/tiki-manager": "<=17.1", + "timber/timber": "<=1.23|==1.24|==2", + "tinymce/tinymce": "<7", "tinymighty/wiki-seo": "<1.2.2", - "titon/framework": ">=0,<9.9.99", - "tobiasbg/tablepress": "<= 2.0-RC1", + "titon/framework": "<9.9.99", + "tobiasbg/tablepress": "<=2.0.0.0-RC1", "topthink/framework": "<6.0.14", "topthink/think": "<=6.1.1", "topthink/thinkphp": "<=3.2.3", + "torrentpier/torrentpier": "<=2.4.1", "tpwd/ke_search": "<4.0.3|>=4.1,<4.6.6|>=5,<5.0.2", - "tribalsystems/zenario": "<=9.3.57595", + "tribalsystems/zenario": "<=9.4.59197", "truckersmp/phpwhois": "<=4.3.1", "ttskch/pagination-service-provider": "<1", "twig/twig": "<1.44.7|>=2,<2.15.3|>=3,<3.4.3", - "typo3/cms": "<2.0.5|>=3,<3.0.3|>=6.2,<6.2.30|>=7,<7.6.32|>=8,<8.7.38|>=9,<9.5.29|>=10,<10.4.35|>=11,<11.5.23|>=12,<12.2", - "typo3/cms-backend": ">=7,<=7.6.50|>=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1", - "typo3/cms-core": "<8.7.51|>=9,<9.5.40|>=10,<10.4.36|>=11,<11.5.23|>=12,<12.2", + "typo3/cms": "<9.5.29|>=10,<10.4.35|>=11,<11.5.23|>=12,<12.2", + "typo3/cms-backend": "<4.1.14|>=4.2,<4.2.15|>=4.3,<4.3.7|>=4.4,<4.4.4|>=7,<=7.6.50|>=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1", + "typo3/cms-core": "<=8.7.56|>=9,<=9.5.45|>=10,<=10.4.42|>=11,<=11.5.34|>=12,<=12.4.10|==13", + "typo3/cms-extbase": "<6.2.24|>=7,<7.6.8|==8.1.1", + "typo3/cms-fluid": "<4.3.4|>=4.4,<4.4.1", "typo3/cms-form": ">=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1", + "typo3/cms-frontend": "<4.3.9|>=4.4,<4.4.5", + "typo3/cms-install": "<4.1.14|>=4.2,<4.2.16|>=4.3,<4.3.9|>=4.4,<4.4.5|>=12.2,<12.4.8", + "typo3/cms-rte-ckeditor": ">=9.5,<9.5.42|>=10,<10.4.39|>=11,<11.5.30", "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6", - "typo3/html-sanitizer": ">=1,<1.5|>=2,<2.1.1", + "typo3/html-sanitizer": ">=1,<=1.5.2|>=2,<=2.1.3", "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4|>=2.3,<2.3.99|>=3,<3.0.20|>=3.1,<3.1.18|>=3.2,<3.2.14|>=3.3,<3.3.23|>=4,<4.0.17|>=4.1,<4.1.16|>=4.2,<4.2.12|>=4.3,<4.3.3", "typo3/phar-stream-wrapper": ">=1,<2.1.1|>=3,<3.1.1", "typo3/swiftmailer": ">=4.1,<4.1.99|>=5.4,<5.4.5", "typo3fluid/fluid": ">=2,<2.0.8|>=2.1,<2.1.7|>=2.2,<2.2.4|>=2.3,<2.3.7|>=2.4,<2.4.4|>=2.5,<2.5.11|>=2.6,<2.6.10", "ua-parser/uap-php": "<3.8", - "unisharp/laravel-filemanager": "<=2.5.1", + "uasoft-indonesia/badaso": "<=2.9.7", + "unisharp/laravel-filemanager": "<2.6.4", "userfrosting/userfrosting": ">=0.3.1,<4.6.3", "usmanhalalit/pixie": "<1.0.3|>=2,<2.0.2", "uvdesk/community-skeleton": "<=1.1.1", + "uvdesk/core-framework": "<=1.1.1", "vanilla/safecurl": "<0.9.2", - "verot/class.upload.php": "<=1.0.3|>=2,<=2.0.4", + "verot/class.upload.php": "<=2.1.6", "vova07/yii2-fileapi-widget": "<0.1.9", "vrana/adminer": "<4.8.1", + "waldhacker/hcaptcha": "<2.1.2", "wallabag/tcpdf": "<6.2.22", - "wallabag/wallabag": "<2.5.4", + "wallabag/wallabag": "<2.6.7", "wanglelecc/laracms": "<=1.0.3", "web-auth/webauthn-framework": ">=3.3,<3.3.4", "webbuilders-group/silverstripe-kapost-bridge": "<0.4", "webcoast/deferred-image-processing": "<1.0.2", + "webklex/laravel-imap": "<5.3", + "webklex/php-imap": "<5.3", "webpa/webpa": "<3.1.2", + "wikibase/wikibase": "<=1.39.3", "wikimedia/parsoid": "<0.12.2", "willdurand/js-translation-bundle": "<2.1.1", - "wintercms/winter": "<1.0.475|>=1.1,<1.1.10|>=1.2,<1.2.1", + "winter/wn-backend-module": "<1.2.4", + "winter/wn-dusk-plugin": "<2.1", + "winter/wn-system-module": "<1.2.4", + "wintercms/winter": "<=1.2.3", "woocommerce/woocommerce": "<6.6", - "wp-cli/wp-cli": "<2.5", - "wp-graphql/wp-graphql": "<0.3.5", + "wp-cli/wp-cli": ">=0.12,<2.5", + "wp-graphql/wp-graphql": "<=1.14.5", "wpanel/wpanel4-cms": "<=4.3.1", "wpcloud/wp-stateless": "<3.2", "wwbn/avideo": "<=12.4", @@ -4171,8 +4101,9 @@ "yetiforce/yetiforce-crm": "<=6.4", "yidashi/yii2cmf": "<=2", "yii2mod/yii2-cms": "<1.9.2", - "yiisoft/yii": "<1.1.27", + "yiisoft/yii": "<1.1.29", "yiisoft/yii2": "<2.0.38", + "yiisoft/yii2-authclient": "<2.2.15", "yiisoft/yii2-bootstrap": "<2.0.4", "yiisoft/yii2-dev": "<2.0.43", "yiisoft/yii2-elasticsearch": "<2.0.5", @@ -4182,11 +4113,13 @@ "yikesinc/yikes-inc-easy-mailchimp-extender": "<6.8.6", "yoast-seo-for-typo3/yoast_seo": "<7.2.3", "yourls/yourls": "<=1.8.2", + "yuan1994/tpadmin": "<=1.3.12", + "zencart/zencart": "<=1.5.7.0-beta", "zendesk/zendesk_api_client_php": "<2.2.11", "zendframework/zend-cache": ">=2.4,<2.4.8|>=2.5,<2.5.3", "zendframework/zend-captcha": ">=2,<2.4.9|>=2.5,<2.5.2", "zendframework/zend-crypt": ">=2,<2.4.9|>=2.5,<2.5.2", - "zendframework/zend-db": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.10|>=2.3,<2.3.5", + "zendframework/zend-db": "<2.2.10|>=2.3,<2.3.5", "zendframework/zend-developer-tools": ">=1.2.2,<1.2.3", "zendframework/zend-diactoros": "<1.8.4", "zendframework/zend-feed": "<2.10.3", @@ -4202,13 +4135,22 @@ "zendframework/zend-xmlrpc": ">=2.1,<2.1.6|>=2.2,<2.2.6", "zendframework/zendframework": "<=3", "zendframework/zendframework1": "<1.12.20", - "zendframework/zendopenid": ">=2,<2.0.2", + "zendframework/zendopenid": "<2.0.2", + "zendframework/zendrest": "<2.0.2", + "zendframework/zendservice-amazon": "<2.0.3", + "zendframework/zendservice-api": "<1", + "zendframework/zendservice-audioscrobbler": "<2.0.2", + "zendframework/zendservice-nirvanix": "<2.0.2", + "zendframework/zendservice-slideshare": "<2.0.2", + "zendframework/zendservice-technorati": "<2.0.2", + "zendframework/zendservice-windowsazure": "<2.0.2", "zendframework/zendxml": ">=1,<1.0.1", + "zenstruck/collection": "<0.2.1", "zetacomponents/mail": "<1.8.2", "zf-commons/zfc-user": "<1.2.2", "zfcampus/zf-apigility-doctrine": ">=1,<1.0.3", "zfr/zfr-oauth2-server-module": "<0.1.2", - "zoujingli/thinkadmin": "<6.0.22" + "zoujingli/thinkadmin": "<=6.1.53" }, "type": "metapackage", "notification-url": "https://packagist.org/downloads/", @@ -4245,36 +4187,36 @@ "type": "tidelift" } ], - "time": "2023-06-14T05:04:21+00:00" + "time": "2024-04-16T20:05:01+00:00" }, { "name": "robmorgan/phinx", - "version": "0.12.13", + "version": "0.16.0", "source": { "type": "git", "url": "https://github.com/cakephp/phinx.git", - "reference": "6eb0f295e140ed2804d93396755f0ce9ada4ec07" + "reference": "e039a723e9fe33e406102ac1c3dc0a54c031152f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/phinx/zipball/6eb0f295e140ed2804d93396755f0ce9ada4ec07", - "reference": "6eb0f295e140ed2804d93396755f0ce9ada4ec07", + "url": "https://api.github.com/repos/cakephp/phinx/zipball/e039a723e9fe33e406102ac1c3dc0a54c031152f", + "reference": "e039a723e9fe33e406102ac1c3dc0a54c031152f", "shasum": "" }, "require": { - "cakephp/database": "^4.0", - "php": ">=7.2", - "psr/container": "^1.0 || ^2.0", - "symfony/config": "^3.4|^4.0|^5.0|^6.0", - "symfony/console": "^3.4|^4.0|^5.0|^6.0" + "cakephp/database": "^5.0.2", + "php-64bit": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/config": "^3.4|^4.0|^5.0|^6.0|^7.0", + "symfony/console": "^6.0|^7.0" }, "require-dev": { - "cakephp/cakephp-codesniffer": "^4.0", + "cakephp/cakephp": "^5.0.2", + "cakephp/cakephp-codesniffer": "^5.0", "ext-json": "*", "ext-pdo": "*", - "phpunit/phpunit": "^8.5|^9.3", - "sebastian/comparator": ">=1.2.3", - "symfony/yaml": "^3.4|^4.0|^5.0" + "phpunit/phpunit": "^9.5.19", + "symfony/yaml": "^3.4|^4.0|^5.0|^6.0|^7.0" }, "suggest": { "ext-json": "Install if using JSON configuration format", @@ -4329,22 +4271,22 @@ ], "support": { "issues": "https://github.com/cakephp/phinx/issues", - "source": "https://github.com/cakephp/phinx/tree/0.12.13" + "source": "https://github.com/cakephp/phinx/tree/0.16.0" }, - "time": "2022-10-03T04:57:40+00:00" + "time": "2024-01-24T05:06:44+00:00" }, { "name": "sabberworm/php-css-parser", - "version": "8.4.0", + "version": "v8.5.1", "source": { "type": "git", - "url": "https://github.com/sabberworm/PHP-CSS-Parser.git", - "reference": "e41d2140031d533348b2192a83f02d8dd8a71d30" + "url": "https://github.com/MyIntervals/PHP-CSS-Parser.git", + "reference": "4a3d572b0f8b28bb6fd016ae8bbfc445facef152" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sabberworm/PHP-CSS-Parser/zipball/e41d2140031d533348b2192a83f02d8dd8a71d30", - "reference": "e41d2140031d533348b2192a83f02d8dd8a71d30", + "url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/4a3d572b0f8b28bb6fd016ae8bbfc445facef152", + "reference": "4a3d572b0f8b28bb6fd016ae8bbfc445facef152", "shasum": "" }, "require": { @@ -4352,13 +4294,17 @@ "php": ">=5.6.20" }, "require-dev": { - "codacy/coverage": "^1.4", - "phpunit/phpunit": "^4.8.36" + "phpunit/phpunit": "^5.7.27" }, "suggest": { "ext-mbstring": "for parsing UTF-8 CSS" }, "type": "library", + "extra": { + "branch-alias": { + "dev-main": "9.0.x-dev" + } + }, "autoload": { "psr-4": { "Sabberworm\\CSS\\": "src/" @@ -4371,6 +4317,14 @@ "authors": [ { "name": "Raphael Schweikert" + }, + { + "name": "Oliver Klee", + "email": "github@oliverklee.de" + }, + { + "name": "Jake Hotson", + "email": "jake.github@qzdesign.co.uk" } ], "description": "Parser for CSS Files written in PHP", @@ -4381,45 +4335,41 @@ "stylesheet" ], "support": { - "issues": "https://github.com/sabberworm/PHP-CSS-Parser/issues", - "source": "https://github.com/sabberworm/PHP-CSS-Parser/tree/8.4.0" + "issues": "https://github.com/MyIntervals/PHP-CSS-Parser/issues", + "source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v8.5.1" }, - "time": "2021-12-11T13:40:54+00:00" + "time": "2024-02-15T16:41:13+00:00" }, { "name": "symfony/config", - "version": "v5.4.21", + "version": "v6.4.6", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "2a6b1111d038adfa15d52c0871e540f3b352d1e4" + "reference": "18ac9da3106222dde9fc9e09ec016e5de9d2658f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/2a6b1111d038adfa15d52c0871e540f3b352d1e4", - "reference": "2a6b1111d038adfa15d52c0871e540f3b352d1e4", + "url": "https://api.github.com/repos/symfony/config/zipball/18ac9da3106222dde9fc9e09ec016e5de9d2658f", + "reference": "18ac9da3106222dde9fc9e09ec016e5de9d2658f", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/filesystem": "^4.4|^5.0|^6.0", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-php80": "^1.16", - "symfony/polyfill-php81": "^1.22" + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/filesystem": "^5.4|^6.0|^7.0", + "symfony/polyfill-ctype": "~1.8" }, "conflict": { - "symfony/finder": "<4.4" + "symfony/finder": "<5.4", + "symfony/service-contracts": "<2.5" }, "require-dev": { - "symfony/event-dispatcher": "^4.4|^5.0|^6.0", - "symfony/finder": "^4.4|^5.0|^6.0", - "symfony/messenger": "^4.4|^5.0|^6.0", - "symfony/service-contracts": "^1.1|^2|^3", - "symfony/yaml": "^4.4|^5.0|^6.0" - }, - "suggest": { - "symfony/yaml": "To use the yaml reference dumper" + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/finder": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/yaml": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -4447,7 +4397,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v5.4.21" + "source": "https://github.com/symfony/config/tree/v6.4.6" }, "funding": [ { @@ -4463,56 +4413,51 @@ "type": "tidelift" } ], - "time": "2023-02-14T08:03:56+00:00" + "time": "2024-03-27T19:47:45+00:00" }, { "name": "symfony/console", - "version": "v5.4.24", + "version": "v6.4.6", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "560fc3ed7a43e6d30ea94a07d77f9a60b8ed0fb8" + "reference": "a2708a5da5c87d1d0d52937bdeac625df659e11f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/560fc3ed7a43e6d30ea94a07d77f9a60b8ed0fb8", - "reference": "560fc3ed7a43e6d30ea94a07d77f9a60b8ed0fb8", + "url": "https://api.github.com/repos/symfony/console/zipball/a2708a5da5c87d1d0d52937bdeac625df659e11f", + "reference": "a2708a5da5c87d1d0d52937bdeac625df659e11f", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php73": "^1.9", - "symfony/polyfill-php80": "^1.16", - "symfony/service-contracts": "^1.1|^2|^3", - "symfony/string": "^5.1|^6.0" + "symfony/service-contracts": "^2.5|^3", + "symfony/string": "^5.4|^6.0|^7.0" }, "conflict": { - "psr/log": ">=3", - "symfony/dependency-injection": "<4.4", - "symfony/dotenv": "<5.1", - "symfony/event-dispatcher": "<4.4", - "symfony/lock": "<4.4", - "symfony/process": "<4.4" + "symfony/dependency-injection": "<5.4", + "symfony/dotenv": "<5.4", + "symfony/event-dispatcher": "<5.4", + "symfony/lock": "<5.4", + "symfony/process": "<5.4" }, "provide": { - "psr/log-implementation": "1.0|2.0" + "psr/log-implementation": "1.0|2.0|3.0" }, "require-dev": { - "psr/log": "^1|^2", - "symfony/config": "^4.4|^5.0|^6.0", - "symfony/dependency-injection": "^4.4|^5.0|^6.0", - "symfony/event-dispatcher": "^4.4|^5.0|^6.0", - "symfony/lock": "^4.4|^5.0|^6.0", - "symfony/process": "^4.4|^5.0|^6.0", - "symfony/var-dumper": "^4.4|^5.0|^6.0" - }, - "suggest": { - "psr/log": "For using the console logger", - "symfony/event-dispatcher": "", - "symfony/lock": "", - "symfony/process": "" + "psr/log": "^1|^2|^3", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/lock": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/stopwatch": "^5.4|^6.0|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -4546,7 +4491,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.24" + "source": "https://github.com/symfony/console/tree/v6.4.6" }, "funding": [ { @@ -4562,25 +4507,24 @@ "type": "tidelift" } ], - "time": "2023-05-26T05:13:16+00:00" + "time": "2024-03-29T19:07:53+00:00" }, { "name": "symfony/css-selector", - "version": "v5.4.21", + "version": "v6.4.3", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "95f3c7468db1da8cc360b24fa2a26e7cefcb355d" + "reference": "ee0f7ed5cf298cc019431bb3b3977ebc52b86229" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/95f3c7468db1da8cc360b24fa2a26e7cefcb355d", - "reference": "95f3c7468db1da8cc360b24fa2a26e7cefcb355d", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/ee0f7ed5cf298cc019431bb3b3977ebc52b86229", + "reference": "ee0f7ed5cf298cc019431bb3b3977ebc52b86229", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/polyfill-php80": "^1.16" + "php": ">=8.1" }, "type": "library", "autoload": { @@ -4612,7 +4556,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v5.4.21" + "source": "https://github.com/symfony/css-selector/tree/v6.4.3" }, "funding": [ { @@ -4628,29 +4572,29 @@ "type": "tidelift" } ], - "time": "2023-02-14T08:03:56+00:00" + "time": "2024-01-23T14:51:35+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v2.5.2", + "version": "v3.4.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66" + "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66", - "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", + "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=8.1" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "2.5-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", @@ -4679,7 +4623,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.4.0" }, "funding": [ { @@ -4695,27 +4639,26 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2023-05-23T14:45:45+00:00" }, { "name": "symfony/filesystem", - "version": "v5.4.23", + "version": "v6.4.6", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "b2f79d86cd9e7de0fff6d03baa80eaed7a5f38b5" + "reference": "9919b5509ada52cc7f66f9a35c86a4a29955c9d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/b2f79d86cd9e7de0fff6d03baa80eaed7a5f38b5", - "reference": "b2f79d86cd9e7de0fff6d03baa80eaed7a5f38b5", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/9919b5509ada52cc7f66f9a35c86a4a29955c9d3", + "reference": "9919b5509ada52cc7f66f9a35c86a4a29955c9d3", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.1", "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.8", - "symfony/polyfill-php80": "^1.16" + "symfony/polyfill-mbstring": "~1.8" }, "type": "library", "autoload": { @@ -4743,7 +4686,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.4.23" + "source": "https://github.com/symfony/filesystem/tree/v6.4.6" }, "funding": [ { @@ -4759,39 +4702,40 @@ "type": "tidelift" } ], - "time": "2023-03-02T11:38:35+00:00" + "time": "2024-03-21T19:36:20+00:00" }, { "name": "symfony/http-foundation", - "version": "v5.4.24", + "version": "v6.4.4", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "3c59f97f6249ce552a44f01b93bfcbd786a954f5" + "reference": "ebc713bc6e6f4b53f46539fc158be85dfcd77304" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/3c59f97f6249ce552a44f01b93bfcbd786a954f5", - "reference": "3c59f97f6249ce552a44f01b93bfcbd786a954f5", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/ebc713bc6e6f4b53f46539fc158be85dfcd77304", + "reference": "ebc713bc6e6f4b53f46539fc158be85dfcd77304", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.1", - "symfony/polyfill-php80": "^1.16" + "symfony/polyfill-php83": "^1.27" }, - "require-dev": { - "predis/predis": "~1.0", - "symfony/cache": "^4.4|^5.0|^6.0", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/expression-language": "^4.4|^5.0|^6.0", - "symfony/http-kernel": "^5.4.12|^6.0.12|^6.1.4", - "symfony/mime": "^4.4|^5.0|^6.0", - "symfony/rate-limiter": "^5.2|^6.0" + "conflict": { + "symfony/cache": "<6.3" }, - "suggest": { - "symfony/mime": "To use the file extension guesser" + "require-dev": { + "doctrine/dbal": "^2.13.1|^3|^4", + "predis/predis": "^1.1|^2.0", + "symfony/cache": "^6.3|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^5.4.12|^6.0.12|^6.1.4|^7.0", + "symfony/mime": "^5.4|^6.0|^7.0", + "symfony/rate-limiter": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -4819,7 +4763,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v5.4.24" + "source": "https://github.com/symfony/http-foundation/tree/v6.4.4" }, "funding": [ { @@ -4835,43 +4779,44 @@ "type": "tidelift" } ], - "time": "2023-05-19T07:21:23+00:00" + "time": "2024-02-08T15:01:18+00:00" }, { "name": "symfony/mime", - "version": "v5.4.23", + "version": "v6.4.6", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "ae0a1032a450a3abf305ee44fc55ed423fbf16e3" + "reference": "14762b86918823cb42e3558cdcca62e58b5227fe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/ae0a1032a450a3abf305ee44fc55ed423fbf16e3", - "reference": "ae0a1032a450a3abf305ee44fc55ed423fbf16e3", + "url": "https://api.github.com/repos/symfony/mime/zipball/14762b86918823cb42e3558cdcca62e58b5227fe", + "reference": "14762b86918823cb42e3558cdcca62e58b5227fe", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-intl-idn": "^1.10", - "symfony/polyfill-mbstring": "^1.0", - "symfony/polyfill-php80": "^1.16" + "symfony/polyfill-mbstring": "^1.0" }, "conflict": { "egulias/email-validator": "~3.0.0", "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", - "symfony/mailer": "<4.4", - "symfony/serializer": "<5.4.14|>=6.0,<6.0.14|>=6.1,<6.1.6" + "symfony/mailer": "<5.4", + "symfony/serializer": "<6.3.2" }, "require-dev": { "egulias/email-validator": "^2.1.10|^3.1|^4", + "league/html-to-markdown": "^5.0", "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", - "symfony/dependency-injection": "^4.4|^5.0|^6.0", - "symfony/property-access": "^4.4|^5.1|^6.0", - "symfony/property-info": "^4.4|^5.1|^6.0", - "symfony/serializer": "^5.4.14|~6.0.14|^6.1.6" + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.4|^7.0", + "symfony/property-access": "^5.4|^6.0|^7.0", + "symfony/property-info": "^5.4|^6.0|^7.0", + "symfony/serializer": "^6.3.2|^7.0" }, "type": "library", "autoload": { @@ -4903,7 +4848,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v5.4.23" + "source": "https://github.com/symfony/mime/tree/v6.4.6" }, "funding": [ { @@ -4919,20 +4864,20 @@ "type": "tidelift" } ], - "time": "2023-04-19T09:49:13+00:00" + "time": "2024-03-21T19:36:20+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.27.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "5bbc823adecdae860bb64756d639ecfec17b050a" + "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a", - "reference": "5bbc823adecdae860bb64756d639ecfec17b050a", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4", + "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4", "shasum": "" }, "require": { @@ -4946,9 +4891,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -4985,7 +4927,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0" }, "funding": [ { @@ -5001,20 +4943,20 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.27.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "511a08c03c1960e08a883f4cffcacd219b758354" + "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/511a08c03c1960e08a883f4cffcacd219b758354", - "reference": "511a08c03c1960e08a883f4cffcacd219b758354", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/32a9da87d7b3245e09ac426c83d334ae9f06f80f", + "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f", "shasum": "" }, "require": { @@ -5025,9 +4967,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -5066,7 +5005,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.29.0" }, "funding": [ { @@ -5082,20 +5021,20 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.27.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "639084e360537a19f9ee352433b84ce831f3d2da" + "reference": "a287ed7475f85bf6f61890146edbc932c0fff919" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/639084e360537a19f9ee352433b84ce831f3d2da", - "reference": "639084e360537a19f9ee352433b84ce831f3d2da", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/a287ed7475f85bf6f61890146edbc932c0fff919", + "reference": "a287ed7475f85bf6f61890146edbc932c0fff919", "shasum": "" }, "require": { @@ -5108,9 +5047,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -5134,110 +5070,26 @@ "email": "laurent@bassin.info" }, { - "name": "Trevor Rowbotham", - "email": "trevor.rowbotham@pm.me" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "idn", - "intl", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/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/polyfill-intl-normalizer", - "version": "v1.27.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6", - "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "suggest": { - "ext-intl": "For best performance" - }, - "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\\Intl\\Normalizer\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for intl's Normalizer class and related functions", + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", "homepage": "https://symfony.com", "keywords": [ "compatibility", + "idn", "intl", - "normalizer", "polyfill", "portable", "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.29.0" }, "funding": [ { @@ -5253,36 +5105,30 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { - "name": "symfony/polyfill-mbstring", - "version": "v1.27.0", + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.29.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "bc45c394692b948b4d383a08d7753968bed9a83d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", - "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/bc45c394692b948b4d383a08d7753968bed9a83d", + "reference": "bc45c394692b948b4d383a08d7753968bed9a83d", "shasum": "" }, "require": { "php": ">=7.1" }, - "provide": { - "ext-mbstring": "*" - }, "suggest": { - "ext-mbstring": "For best performance" + "ext-intl": "For best performance" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -5293,8 +5139,11 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - } + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -5310,17 +5159,18 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for the Mbstring extension", + "description": "Symfony polyfill for intl's Normalizer class and related functions", "homepage": "https://symfony.com", "keywords": [ "compatibility", - "mbstring", + "intl", + "normalizer", "polyfill", "portable", "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.29.0" }, "funding": [ { @@ -5336,30 +5186,33 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { - "name": "symfony/polyfill-php72", - "version": "v1.27.0", + "name": "symfony/polyfill-mbstring", + "version": "v1.29.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "869329b1e9894268a8a61dabb69153029b7a8c97" + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/869329b1e9894268a8a61dabb69153029b7a8c97", - "reference": "869329b1e9894268a8a61dabb69153029b7a8c97", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec", + "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec", "shasum": "" }, "require": { "php": ">=7.1" }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -5370,7 +5223,7 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Php72\\": "" + "Symfony\\Polyfill\\Mbstring\\": "" } }, "notification-url": "https://packagist.org/downloads/", @@ -5387,16 +5240,17 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "description": "Symfony polyfill for the Mbstring extension", "homepage": "https://symfony.com", "keywords": [ "compatibility", + "mbstring", "polyfill", "portable", "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0" }, "funding": [ { @@ -5412,20 +5266,20 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { - "name": "symfony/polyfill-php73", - "version": "v1.27.0", + "name": "symfony/polyfill-php72", + "version": "v1.29.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9" + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "861391a8da9a04cbad2d232ddd9e4893220d6e25" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/9e8ecb5f92152187c4799efd3c96b78ccab18ff9", - "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/861391a8da9a04cbad2d232ddd9e4893220d6e25", + "reference": "861391a8da9a04cbad2d232ddd9e4893220d6e25", "shasum": "" }, "require": { @@ -5433,9 +5287,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -5446,11 +5297,8 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Php73\\": "" - }, - "classmap": [ - "Resources/stubs" - ] + "Symfony\\Polyfill\\Php72\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -5466,7 +5314,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", @@ -5475,7 +5323,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-php72/tree/v1.29.0" }, "funding": [ { @@ -5491,20 +5339,20 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.27.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" + "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", - "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", + "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", "shasum": "" }, "require": { @@ -5512,9 +5360,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -5558,7 +5403,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0" }, "funding": [ { @@ -5574,30 +5419,28 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { - "name": "symfony/polyfill-php81", - "version": "v1.27.0", + "name": "symfony/polyfill-php83", + "version": "v1.29.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a" + "url": "https://github.com/symfony/polyfill-php83.git", + "reference": "86fcae159633351e5fd145d1c47de6c528f8caff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/707403074c8ea6e2edaf8794b0157a0bfa52157a", - "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/86fcae159633351e5fd145d1c47de6c528f8caff", + "reference": "86fcae159633351e5fd145d1c47de6c528f8caff", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.1", + "symfony/polyfill-php80": "^1.14" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -5608,7 +5451,7 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Php81\\": "" + "Symfony\\Polyfill\\Php83\\": "" }, "classmap": [ "Resources/stubs" @@ -5628,7 +5471,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", @@ -5637,7 +5480,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-php83/tree/v1.29.0" }, "funding": [ { @@ -5653,47 +5496,40 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "symfony/routing", - "version": "v5.4.22", + "version": "v6.4.6", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "c2ac11eb34947999b7c38fb4c835a57306907e6d" + "reference": "f2591fd1f8c6e3734656b5d6b3829e8bf81f507c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/c2ac11eb34947999b7c38fb4c835a57306907e6d", - "reference": "c2ac11eb34947999b7c38fb4c835a57306907e6d", + "url": "https://api.github.com/repos/symfony/routing/zipball/f2591fd1f8c6e3734656b5d6b3829e8bf81f507c", + "reference": "f2591fd1f8c6e3734656b5d6b3829e8bf81f507c", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/polyfill-php80": "^1.16" + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3" }, "conflict": { "doctrine/annotations": "<1.12", - "symfony/config": "<5.3", - "symfony/dependency-injection": "<4.4", - "symfony/yaml": "<4.4" + "symfony/config": "<6.2", + "symfony/dependency-injection": "<5.4", + "symfony/yaml": "<5.4" }, "require-dev": { "doctrine/annotations": "^1.12|^2", "psr/log": "^1|^2|^3", - "symfony/config": "^5.3|^6.0", - "symfony/dependency-injection": "^4.4|^5.0|^6.0", - "symfony/expression-language": "^4.4|^5.0|^6.0", - "symfony/http-foundation": "^4.4|^5.0|^6.0", - "symfony/yaml": "^4.4|^5.0|^6.0" - }, - "suggest": { - "symfony/config": "For using the all-in-one router or any loader", - "symfony/expression-language": "For using expression matching", - "symfony/http-foundation": "For using a Symfony Request object", - "symfony/yaml": "For using the YAML loader" + "symfony/config": "^6.2|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^5.4|^6.0|^7.0", + "symfony/yaml": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -5727,7 +5563,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v5.4.22" + "source": "https://github.com/symfony/routing/tree/v6.4.6" }, "funding": [ { @@ -5743,37 +5579,33 @@ "type": "tidelift" } ], - "time": "2023-03-14T14:59:20+00:00" + "time": "2024-03-28T13:28:49+00:00" }, { "name": "symfony/service-contracts", - "version": "v2.5.2", + "version": "v3.4.2", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" + "reference": "11bbf19a0fb7b36345861e85c5768844c552906e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", - "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/11bbf19a0fb7b36345861e85c5768844c552906e", + "reference": "11bbf19a0fb7b36345861e85c5768844c552906e", "shasum": "" }, "require": { - "php": ">=7.2.5", - "psr/container": "^1.1", - "symfony/deprecation-contracts": "^2.1|^3" + "php": ">=8.1", + "psr/container": "^1.1|^2.0" }, "conflict": { "ext-psr": "<1.1|>=2" }, - "suggest": { - "symfony/service-implementation": "" - }, "type": "library", "extra": { "branch-alias": { - "dev-main": "2.5-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", @@ -5783,7 +5615,10 @@ "autoload": { "psr-4": { "Symfony\\Contracts\\Service\\": "" - } + }, + "exclude-from-classmap": [ + "/Test/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -5810,7 +5645,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v2.5.2" + "source": "https://github.com/symfony/service-contracts/tree/v3.4.2" }, "funding": [ { @@ -5826,38 +5661,38 @@ "type": "tidelift" } ], - "time": "2022-05-30T19:17:29+00:00" + "time": "2023-12-19T21:51:00+00:00" }, { "name": "symfony/string", - "version": "v5.4.22", + "version": "v6.4.4", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "8036a4c76c0dd29e60b6a7cafcacc50cf088ea62" + "reference": "4e465a95bdc32f49cf4c7f07f751b843bbd6dcd9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/8036a4c76c0dd29e60b6a7cafcacc50cf088ea62", - "reference": "8036a4c76c0dd29e60b6a7cafcacc50cf088ea62", + "url": "https://api.github.com/repos/symfony/string/zipball/4e465a95bdc32f49cf4c7f07f751b843bbd6dcd9", + "reference": "4e465a95bdc32f49cf4c7f07f751b843bbd6dcd9", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.1", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-intl-grapheme": "~1.0", "symfony/polyfill-intl-normalizer": "~1.0", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php80": "~1.15" + "symfony/polyfill-mbstring": "~1.0" }, "conflict": { - "symfony/translation-contracts": ">=3.0" + "symfony/translation-contracts": "<2.5" }, "require-dev": { - "symfony/error-handler": "^4.4|^5.0|^6.0", - "symfony/http-client": "^4.4|^5.0|^6.0", - "symfony/translation-contracts": "^1.1|^2", - "symfony/var-exporter": "^4.4|^5.0|^6.0" + "symfony/error-handler": "^5.4|^6.0|^7.0", + "symfony/http-client": "^5.4|^6.0|^7.0", + "symfony/intl": "^6.2|^7.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -5896,7 +5731,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.4.22" + "source": "https://github.com/symfony/string/tree/v6.4.4" }, "funding": [ { @@ -5912,42 +5747,39 @@ "type": "tidelift" } ], - "time": "2023-03-14T06:11:53+00:00" + "time": "2024-02-01T13:16:41+00:00" }, { "name": "symfony/var-dumper", - "version": "v5.4.24", + "version": "v6.4.6", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "8e12706bf9c68a2da633f23bfdc15b4dce5970b3" + "reference": "95bd2706a97fb875185b51ecaa6112ec184233d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/8e12706bf9c68a2da633f23bfdc15b4dce5970b3", - "reference": "8e12706bf9c68a2da633f23bfdc15b4dce5970b3", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/95bd2706a97fb875185b51ecaa6112ec184233d4", + "reference": "95bd2706a97fb875185b51ecaa6112ec184233d4", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php80": "^1.16" + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0" }, "conflict": { - "symfony/console": "<4.4" + "symfony/console": "<5.4" }, "require-dev": { "ext-iconv": "*", - "symfony/console": "^4.4|^5.0|^6.0", - "symfony/process": "^4.4|^5.0|^6.0", - "symfony/uid": "^5.1|^6.0", + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/error-handler": "^6.3|^7.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/uid": "^5.4|^6.0|^7.0", "twig/twig": "^2.13|^3.0.4" }, - "suggest": { - "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", - "ext-intl": "To show region name in time zone dump", - "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" - }, "bin": [ "Resources/bin/var-dump-server" ], @@ -5984,7 +5816,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v5.4.24" + "source": "https://github.com/symfony/var-dumper/tree/v6.4.6" }, "funding": [ { @@ -6000,26 +5832,27 @@ "type": "tidelift" } ], - "time": "2023-05-25T13:05:00+00:00" + "time": "2024-03-19T11:56:30+00:00" }, { "name": "vanilla/htmlawed", - "version": "v2.2.5", + "version": "v2.2.15", "source": { "type": "git", "url": "https://github.com/vanilla/htmlawed.git", - "reference": "b1fc7b3990796112387c08a132f85b7333022ec2" + "reference": "e9bbc21d22a6c13afa1cc9a4b3be9805acc10049" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vanilla/htmlawed/zipball/b1fc7b3990796112387c08a132f85b7333022ec2", - "reference": "b1fc7b3990796112387c08a132f85b7333022ec2", + "url": "https://api.github.com/repos/vanilla/htmlawed/zipball/e9bbc21d22a6c13afa1cc9a4b3be9805acc10049", + "reference": "e9bbc21d22a6c13afa1cc9a4b3be9805acc10049", "shasum": "" }, "require": { - "php": ">=5.4.0" + "php": ">=7.4.0" }, "require-dev": { + "phpunit/phpunit": "^9.0", "tburry/pquery": "~1.0.1" }, "type": "library", @@ -6041,9 +5874,9 @@ "description": "A composer wrapper for the htmLawed library to purify & filter HTML. Tested with PHPUnit and PhantomJS!", "support": { "issues": "https://github.com/vanilla/htmlawed/issues", - "source": "https://github.com/vanilla/htmlawed/tree/master" + "source": "https://github.com/vanilla/htmlawed/tree/v2.2.15" }, - "time": "2019-10-16T15:36:02+00:00" + "time": "2023-09-29T18:41:55+00:00" }, { "name": "webmozart/assert", @@ -6105,108 +5938,32 @@ } ], "packages-dev": [ - { - "name": "doctrine/annotations", - "version": "2.0.1", - "source": { - "type": "git", - "url": "https://github.com/doctrine/annotations.git", - "reference": "e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f", - "reference": "e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f", - "shasum": "" - }, - "require": { - "doctrine/lexer": "^2 || ^3", - "ext-tokenizer": "*", - "php": "^7.2 || ^8.0", - "psr/cache": "^1 || ^2 || ^3" - }, - "require-dev": { - "doctrine/cache": "^2.0", - "doctrine/coding-standard": "^10", - "phpstan/phpstan": "^1.8.0", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "symfony/cache": "^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/2.0.1" - }, - "time": "2023-02-02T22:02:53+00:00" - }, { "name": "doctrine/instantiator", - "version": "1.5.0", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b" + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/0a0fa9780f5d4e507415a065172d26a98d02047b", - "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", "shasum": "" }, "require": { - "php": "^7.1 || ^8.0" + "php": "^8.1" }, "require-dev": { - "doctrine/coding-standard": "^9 || ^11", + "doctrine/coding-standard": "^11", "ext-pdo": "*", "ext-phar": "*", - "phpbench/phpbench": "^0.16 || ^1", - "phpstan/phpstan": "^1.4", - "phpstan/phpstan-phpunit": "^1", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "vimeo/psalm": "^4.30 || ^5.4" + "phpbench/phpbench": "^1.2", + "phpstan/phpstan": "^1.9.4", + "phpstan/phpstan-phpunit": "^1.3", + "phpunit/phpunit": "^9.5.27", + "vimeo/psalm": "^5.4" }, "type": "library", "autoload": { @@ -6233,7 +5990,7 @@ ], "support": { "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/1.5.0" + "source": "https://github.com/doctrine/instantiator/tree/2.0.0" }, "funding": [ { @@ -6249,32 +6006,31 @@ "type": "tidelift" } ], - "time": "2022-12-30T00:15:36+00:00" + "time": "2022-12-30T00:23:10+00:00" }, { "name": "doctrine/lexer", - "version": "2.1.0", + "version": "3.0.1", "source": { "type": "git", "url": "https://github.com/doctrine/lexer.git", - "reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124" + "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/39ab8fcf5a51ce4b85ca97c7a7d033eb12831124", - "reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", + "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", "shasum": "" }, "require": { - "doctrine/deprecations": "^1.0", - "php": "^7.1 || ^8.0" + "php": "^8.1" }, "require-dev": { - "doctrine/coding-standard": "^9 || ^10", - "phpstan/phpstan": "^1.3", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "doctrine/coding-standard": "^12", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^10.5", "psalm/plugin-phpunit": "^0.18.3", - "vimeo/psalm": "^4.11 || ^5.0" + "vimeo/psalm": "^5.21" }, "type": "library", "autoload": { @@ -6311,7 +6067,7 @@ ], "support": { "issues": "https://github.com/doctrine/lexer/issues", - "source": "https://github.com/doctrine/lexer/tree/2.1.0" + "source": "https://github.com/doctrine/lexer/tree/3.0.1" }, "funding": [ { @@ -6327,7 +6083,7 @@ "type": "tidelift" } ], - "time": "2022-12-14T08:49:07+00:00" + "time": "2024-02-05T11:56:58+00:00" }, { "name": "elgg/sniffs", @@ -6430,47 +6186,48 @@ }, { "name": "jms/serializer", - "version": "3.25.0", + "version": "3.30.0", "source": { "type": "git", "url": "https://github.com/schmittjoh/serializer.git", - "reference": "d1384d37926a32b38731c1d9fed6dc71ad630d8b" + "reference": "bf1105358123d7c02ee6cad08ea33ab535a09d5e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/d1384d37926a32b38731c1d9fed6dc71ad630d8b", - "reference": "d1384d37926a32b38731c1d9fed6dc71ad630d8b", + "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/bf1105358123d7c02ee6cad08ea33ab535a09d5e", + "reference": "bf1105358123d7c02ee6cad08ea33ab535a09d5e", "shasum": "" }, "require": { - "doctrine/annotations": "^1.13 || ^2.0", - "doctrine/instantiator": "^1.0.3 || ^2.0", - "doctrine/lexer": "^2", + "doctrine/instantiator": "^1.3.1 || ^2.0", + "doctrine/lexer": "^2.0 || ^3.0", "jms/metadata": "^2.6", - "php": "^7.2||^8.0", - "phpstan/phpdoc-parser": "^0.4 || ^0.5 || ^1.0" + "php": "^7.4 || ^8.0", + "phpstan/phpdoc-parser": "^1.20" }, "require-dev": { - "doctrine/coding-standard": "^8.1", - "doctrine/orm": "~2.1", - "doctrine/persistence": "^1.3.3|^2.0|^3.0", - "doctrine/phpcr-odm": "^1.3|^2.0", + "doctrine/annotations": "^1.14 || ^2.0", + "doctrine/coding-standard": "^12.0", + "doctrine/orm": "^2.14 || ^3.0", + "doctrine/persistence": "^2.5.2 || ^3.0", + "doctrine/phpcr-odm": "^1.5.2 || ^2.0", "ext-pdo_sqlite": "*", - "jackalope/jackalope-doctrine-dbal": "^1.1.5", - "ocramius/proxy-manager": "^1.0|^2.0", + "jackalope/jackalope-doctrine-dbal": "^1.3", + "ocramius/proxy-manager": "^1.0 || ^2.0", "phpbench/phpbench": "^1.0", "phpstan/phpstan": "^1.0.2", - "phpunit/phpunit": "^8.5.21||^9.0||^10.0", - "psr/container": "^1.0|^2.0", - "symfony/dependency-injection": "^3.0|^4.0|^5.0|^6.0", - "symfony/expression-language": "^3.2|^4.0|^5.0|^6.0", - "symfony/filesystem": "^3.0|^4.0|^5.0|^6.0", - "symfony/form": "^3.0|^4.0|^5.0|^6.0", - "symfony/translation": "^3.0|^4.0|^5.0|^6.0", - "symfony/uid": "^5.1|^6.0", - "symfony/validator": "^3.1.9|^4.0|^5.0|^6.0", - "symfony/yaml": "^3.3|^4.0|^5.0|^6.0", - "twig/twig": "~1.34|~2.4|^3.0" + "phpunit/phpunit": "^9.0 || ^10.0", + "psr/container": "^1.0 || ^2.0", + "rector/rector": "^0.19.0", + "symfony/dependency-injection": "^5.4 || ^6.0 || ^7.0", + "symfony/expression-language": "^5.4 || ^6.0 || ^7.0", + "symfony/filesystem": "^5.4 || ^6.0 || ^7.0", + "symfony/form": "^5.4 || ^6.0 || ^7.0", + "symfony/translation": "^5.4 || ^6.0 || ^7.0", + "symfony/uid": "^5.4 || ^6.0 || ^7.0", + "symfony/validator": "^5.4 || ^6.0 || ^7.0", + "symfony/yaml": "^5.4 || ^6.0 || ^7.0", + "twig/twig": "^1.34 || ^2.4 || ^3.0" }, "suggest": { "doctrine/collections": "Required if you like to use doctrine collection types as ArrayCollection.", @@ -6514,7 +6271,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/serializer/issues", - "source": "https://github.com/schmittjoh/serializer/tree/3.25.0" + "source": "https://github.com/schmittjoh/serializer/tree/3.30.0" }, "funding": [ { @@ -6522,7 +6279,7 @@ "type": "github" } ], - "time": "2023-06-09T15:44:27+00:00" + "time": "2024-02-24T14:12:14+00:00" }, { "name": "myclabs/deep-copy", @@ -6585,25 +6342,27 @@ }, { "name": "nikic/php-parser", - "version": "v4.15.5", + "version": "v5.0.2", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e" + "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/11e2663a5bc9db5d714eedb4277ee300403b4a9e", - "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/139676794dc1e9231bf7bcd123cfc0c99182cb13", + "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13", "shasum": "" }, "require": { + "ext-ctype": "*", + "ext-json": "*", "ext-tokenizer": "*", - "php": ">=7.0" + "php": ">=7.4" }, "require-dev": { "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" }, "bin": [ "bin/php-parse" @@ -6611,7 +6370,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.9-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -6635,26 +6394,27 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.5" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.0.2" }, - "time": "2023-05-19T20:20:00+00:00" + "time": "2024-03-05T20:51:40+00:00" }, { "name": "phar-io/manifest", - "version": "2.0.3", + "version": "2.0.4", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53" + "reference": "54750ef60c58e43759730615a392c31c80e23176" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", "shasum": "" }, "require": { "ext-dom": "*", + "ext-libxml": "*", "ext-phar": "*", "ext-xmlwriter": "*", "phar-io/version": "^3.0.1", @@ -6695,9 +6455,15 @@ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", "support": { "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/2.0.3" + "source": "https://github.com/phar-io/manifest/tree/2.0.4" }, - "time": "2021-07-20T11:28:43+00:00" + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" }, { "name": "phar-io/version", @@ -6805,28 +6571,35 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.3.0", + "version": "5.4.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" + "reference": "298d2febfe79d03fe714eb871d5538da55205b1a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", - "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/298d2febfe79d03fe714eb871d5538da55205b1a", + "reference": "298d2febfe79d03fe714eb871d5538da55205b1a", "shasum": "" }, "require": { + "doctrine/deprecations": "^1.1", "ext-filter": "*", - "php": "^7.2 || ^8.0", + "php": "^7.4 || ^8.0", "phpdocumentor/reflection-common": "^2.2", - "phpdocumentor/type-resolver": "^1.3", + "phpdocumentor/type-resolver": "^1.7", + "phpstan/phpdoc-parser": "^1.7", "webmozart/assert": "^1.9.1" }, "require-dev": { - "mockery/mockery": "~1.3.2", - "psalm/phar": "^4.8" + "mockery/mockery": "~1.3.5", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-webmozart-assert": "^1.2", + "phpunit/phpunit": "^9.5", + "vimeo/psalm": "^5.13" }, "type": "library", "extra": { @@ -6850,33 +6623,33 @@ }, { "name": "Jaap van Otterdijk", - "email": "account@ijaap.nl" + "email": "opensource@ijaap.nl" } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "support": { "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.4.0" }, - "time": "2021-10-19T17:43:47+00:00" + "time": "2024-04-09T21:13:58+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "1.7.2", + "version": "1.8.2", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "b2fe4d22a5426f38e014855322200b97b5362c0d" + "reference": "153ae662783729388a584b4361f2545e4d841e3c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b2fe4d22a5426f38e014855322200b97b5362c0d", - "reference": "b2fe4d22a5426f38e014855322200b97b5362c0d", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/153ae662783729388a584b4361f2545e4d841e3c", + "reference": "153ae662783729388a584b4361f2545e4d841e3c", "shasum": "" }, "require": { "doctrine/deprecations": "^1.0", - "php": "^7.4 || ^8.0", + "php": "^7.3 || ^8.0", "phpdocumentor/reflection-common": "^2.0", "phpstan/phpdoc-parser": "^1.13" }, @@ -6914,22 +6687,22 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.2" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.8.2" }, - "time": "2023-05-30T18:13:47+00:00" + "time": "2024-02-23T11:10:43+00:00" }, { "name": "phpoption/phpoption", - "version": "1.9.1", + "version": "1.9.2", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "dd3a383e599f49777d8b628dadbb90cae435b87e" + "reference": "80735db690fe4fc5c76dfa7f9b770634285fa820" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/dd3a383e599f49777d8b628dadbb90cae435b87e", - "reference": "dd3a383e599f49777d8b628dadbb90cae435b87e", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/80735db690fe4fc5c76dfa7f9b770634285fa820", + "reference": "80735db690fe4fc5c76dfa7f9b770634285fa820", "shasum": "" }, "require": { @@ -6937,7 +6710,7 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.32 || ^9.6.3 || ^10.0.12" + "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" }, "type": "library", "extra": { @@ -6979,7 +6752,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/php-option/issues", - "source": "https://github.com/schmittjoh/php-option/tree/1.9.1" + "source": "https://github.com/schmittjoh/php-option/tree/1.9.2" }, "funding": [ { @@ -6991,20 +6764,20 @@ "type": "tidelift" } ], - "time": "2023-02-25T19:38:58+00:00" + "time": "2023-11-12T21:59:55+00:00" }, { "name": "phpstan/phpdoc-parser", - "version": "1.22.0", + "version": "1.28.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "ec58baf7b3c7f1c81b3b00617c953249fb8cf30c" + "reference": "cd06d6b1a1b3c75b0b83f97577869fd85a3cd4fb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/ec58baf7b3c7f1c81b3b00617c953249fb8cf30c", - "reference": "ec58baf7b3c7f1c81b3b00617c953249fb8cf30c", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/cd06d6b1a1b3c75b0b83f97577869fd85a3cd4fb", + "reference": "cd06d6b1a1b3c75b0b83f97577869fd85a3cd4fb", "shasum": "" }, "require": { @@ -7036,41 +6809,41 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.22.0" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.28.0" }, - "time": "2023-06-01T12:35:21+00:00" + "time": "2024-04-03T18:51:33+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.26", + "version": "10.1.14", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1" + "reference": "e3f51450ebffe8e0efdf7346ae966a656f7d5e5b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", - "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/e3f51450ebffe8e0efdf7346ae966a656f7d5e5b", + "reference": "e3f51450ebffe8e0efdf7346ae966a656f7d5e5b", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.15", - "php": ">=7.3", - "phpunit/php-file-iterator": "^3.0.3", - "phpunit/php-text-template": "^2.0.2", - "sebastian/code-unit-reverse-lookup": "^2.0.2", - "sebastian/complexity": "^2.0", - "sebastian/environment": "^5.1.2", - "sebastian/lines-of-code": "^1.0.3", - "sebastian/version": "^3.0.1", + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=8.1", + "phpunit/php-file-iterator": "^4.0", + "phpunit/php-text-template": "^3.0", + "sebastian/code-unit-reverse-lookup": "^3.0", + "sebastian/complexity": "^3.0", + "sebastian/environment": "^6.0", + "sebastian/lines-of-code": "^2.0", + "sebastian/version": "^4.0", "theseer/tokenizer": "^1.2.0" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.1" }, "suggest": { "ext-pcov": "PHP extension that provides line coverage", @@ -7079,7 +6852,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.2-dev" + "dev-main": "10.1-dev" } }, "autoload": { @@ -7107,7 +6880,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.26" + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.14" }, "funding": [ { @@ -7115,32 +6889,32 @@ "type": "github" } ], - "time": "2023-03-06T12:58:08+00:00" + "time": "2024-03-12T15:33:41+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "3.0.6", + "version": "4.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" + "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", - "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a95037b6d9e608ba092da1b23931e537cadc3c3c", + "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -7167,7 +6941,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" + "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/4.1.0" }, "funding": [ { @@ -7175,28 +6950,28 @@ "type": "github" } ], - "time": "2021-12-02T12:48:52+00:00" + "time": "2023-08-31T06:24:48+00:00" }, { "name": "phpunit/php-invoker", - "version": "3.1.1", + "version": "4.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-invoker.git", - "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" + "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", - "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7", + "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { "ext-pcntl": "*", - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "suggest": { "ext-pcntl": "*" @@ -7204,7 +6979,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -7230,7 +7005,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-invoker/issues", - "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" + "source": "https://github.com/sebastianbergmann/php-invoker/tree/4.0.0" }, "funding": [ { @@ -7238,32 +7013,32 @@ "type": "github" } ], - "time": "2020-09-28T05:58:55+00:00" + "time": "2023-02-03T06:56:09+00:00" }, { "name": "phpunit/php-text-template", - "version": "2.0.4", + "version": "3.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" + "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", - "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/0c7b06ff49e3d5072f057eb1fa59258bf287a748", + "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -7289,7 +7064,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-text-template/issues", - "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" + "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/3.0.1" }, "funding": [ { @@ -7297,32 +7073,32 @@ "type": "github" } ], - "time": "2020-10-26T05:33:50+00:00" + "time": "2023-08-31T14:07:24+00:00" }, { "name": "phpunit/php-timer", - "version": "5.0.3", + "version": "6.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" + "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", - "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/e2a2d67966e740530f4a3343fe2e030ffdc1161d", + "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -7348,7 +7124,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-timer/issues", - "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" + "source": "https://github.com/sebastianbergmann/php-timer/tree/6.0.0" }, "funding": [ { @@ -7356,24 +7132,23 @@ "type": "github" } ], - "time": "2020-10-26T13:16:10+00:00" + "time": "2023-02-03T06:57:52+00:00" }, { "name": "phpunit/phpunit", - "version": "9.6.9", + "version": "10.5.18", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "a9aceaf20a682aeacf28d582654a1670d8826778" + "reference": "835df1709ac6c968ba34bf23f3c30e5d5a266de8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a9aceaf20a682aeacf28d582654a1670d8826778", - "reference": "a9aceaf20a682aeacf28d582654a1670d8826778", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/835df1709ac6c968ba34bf23f3c30e5d5a266de8", + "reference": "835df1709ac6c968ba34bf23f3c30e5d5a266de8", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.3.1 || ^2", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", @@ -7383,27 +7158,26 @@ "myclabs/deep-copy": "^1.10.1", "phar-io/manifest": "^2.0.3", "phar-io/version": "^3.0.2", - "php": ">=7.3", - "phpunit/php-code-coverage": "^9.2.13", - "phpunit/php-file-iterator": "^3.0.5", - "phpunit/php-invoker": "^3.1.1", - "phpunit/php-text-template": "^2.0.3", - "phpunit/php-timer": "^5.0.2", - "sebastian/cli-parser": "^1.0.1", - "sebastian/code-unit": "^1.0.6", - "sebastian/comparator": "^4.0.8", - "sebastian/diff": "^4.0.3", - "sebastian/environment": "^5.1.3", - "sebastian/exporter": "^4.0.5", - "sebastian/global-state": "^5.0.1", - "sebastian/object-enumerator": "^4.0.3", - "sebastian/resource-operations": "^3.0.3", - "sebastian/type": "^3.2", - "sebastian/version": "^3.0.2" + "php": ">=8.1", + "phpunit/php-code-coverage": "^10.1.5", + "phpunit/php-file-iterator": "^4.0", + "phpunit/php-invoker": "^4.0", + "phpunit/php-text-template": "^3.0", + "phpunit/php-timer": "^6.0", + "sebastian/cli-parser": "^2.0", + "sebastian/code-unit": "^2.0", + "sebastian/comparator": "^5.0", + "sebastian/diff": "^5.0", + "sebastian/environment": "^6.0", + "sebastian/exporter": "^5.1", + "sebastian/global-state": "^6.0.1", + "sebastian/object-enumerator": "^5.0", + "sebastian/recursion-context": "^5.0", + "sebastian/type": "^4.0", + "sebastian/version": "^4.0" }, "suggest": { - "ext-soap": "To be able to generate mocks based on WSDL files", - "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + "ext-soap": "To be able to generate mocks based on WSDL files" }, "bin": [ "phpunit" @@ -7411,7 +7185,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.6-dev" + "dev-main": "10.5-dev" } }, "autoload": { @@ -7443,7 +7217,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.9" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.18" }, "funding": [ { @@ -7459,7 +7233,7 @@ "type": "tidelift" } ], - "time": "2023-06-11T06:13:56+00:00" + "time": "2024-04-14T07:05:31+00:00" }, { "name": "scrutinizer/ocular", @@ -7508,28 +7282,28 @@ }, { "name": "sebastian/cli-parser", - "version": "1.0.1", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/c34583b87e7b7a8055bf6c450c2c77ce32a24084", + "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-main": "2.0-dev" } }, "autoload": { @@ -7552,7 +7326,8 @@ "homepage": "https://github.com/sebastianbergmann/cli-parser", "support": { "issues": "https://github.com/sebastianbergmann/cli-parser/issues", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/2.0.1" }, "funding": [ { @@ -7560,32 +7335,32 @@ "type": "github" } ], - "time": "2020-09-28T06:08:49+00:00" + "time": "2024-03-02T07:12:49+00:00" }, { "name": "sebastian/code-unit", - "version": "1.0.8", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit.git", - "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" + "reference": "a81fee9eef0b7a76af11d121767abc44c104e503" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", - "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/a81fee9eef0b7a76af11d121767abc44c104e503", + "reference": "a81fee9eef0b7a76af11d121767abc44c104e503", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-main": "2.0-dev" } }, "autoload": { @@ -7608,7 +7383,7 @@ "homepage": "https://github.com/sebastianbergmann/code-unit", "support": { "issues": "https://github.com/sebastianbergmann/code-unit/issues", - "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" + "source": "https://github.com/sebastianbergmann/code-unit/tree/2.0.0" }, "funding": [ { @@ -7616,32 +7391,32 @@ "type": "github" } ], - "time": "2020-10-26T13:08:54+00:00" + "time": "2023-02-03T06:58:43+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", - "version": "2.0.3", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" + "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/5e3a687f7d8ae33fb362c5c0743794bbb2420a1d", + "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -7663,7 +7438,7 @@ "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", "support": { "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", - "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/3.0.0" }, "funding": [ { @@ -7671,34 +7446,36 @@ "type": "github" } ], - "time": "2020-09-28T05:30:19+00:00" + "time": "2023-02-03T06:59:15+00:00" }, { "name": "sebastian/comparator", - "version": "4.0.8", + "version": "5.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "fa0f136dd2334583309d32b62544682ee972b51a" + "reference": "2db5010a484d53ebf536087a70b4a5423c102372" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", - "reference": "fa0f136dd2334583309d32b62544682ee972b51a", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2db5010a484d53ebf536087a70b4a5423c102372", + "reference": "2db5010a484d53ebf536087a70b4a5423c102372", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/diff": "^4.0", - "sebastian/exporter": "^4.0" + "ext-dom": "*", + "ext-mbstring": "*", + "php": ">=8.1", + "sebastian/diff": "^5.0", + "sebastian/exporter": "^5.0" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -7737,7 +7514,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", - "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" + "security": "https://github.com/sebastianbergmann/comparator/security/policy", + "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.1" }, "funding": [ { @@ -7745,33 +7523,33 @@ "type": "github" } ], - "time": "2022-09-14T12:41:17+00:00" + "time": "2023-08-14T13:18:12+00:00" }, { "name": "sebastian/complexity", - "version": "2.0.2", + "version": "3.2.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" + "reference": "68ff824baeae169ec9f2137158ee529584553799" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68ff824baeae169ec9f2137158ee529584553799", + "reference": "68ff824baeae169ec9f2137158ee529584553799", "shasum": "" }, "require": { - "nikic/php-parser": "^4.7", - "php": ">=7.3" + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-main": "3.2-dev" } }, "autoload": { @@ -7794,7 +7572,8 @@ "homepage": "https://github.com/sebastianbergmann/complexity", "support": { "issues": "https://github.com/sebastianbergmann/complexity/issues", - "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" + "security": "https://github.com/sebastianbergmann/complexity/security/policy", + "source": "https://github.com/sebastianbergmann/complexity/tree/3.2.0" }, "funding": [ { @@ -7802,33 +7581,33 @@ "type": "github" } ], - "time": "2020-10-26T15:52:27+00:00" + "time": "2023-12-21T08:37:17+00:00" }, { "name": "sebastian/diff", - "version": "4.0.5", + "version": "5.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" + "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", - "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/c41e007b4b62af48218231d6c2275e4c9b975b2e", + "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3", - "symfony/process": "^4.2 || ^5" + "phpunit/phpunit": "^10.0", + "symfony/process": "^6.4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-main": "5.1-dev" } }, "autoload": { @@ -7860,7 +7639,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5" + "security": "https://github.com/sebastianbergmann/diff/security/policy", + "source": "https://github.com/sebastianbergmann/diff/tree/5.1.1" }, "funding": [ { @@ -7868,27 +7648,27 @@ "type": "github" } ], - "time": "2023-05-07T05:35:17+00:00" + "time": "2024-03-02T07:15:17+00:00" }, { "name": "sebastian/environment", - "version": "5.1.5", + "version": "6.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" + "reference": "8074dbcd93529b357029f5cc5058fd3e43666984" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", - "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/8074dbcd93529b357029f5cc5058fd3e43666984", + "reference": "8074dbcd93529b357029f5cc5058fd3e43666984", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "suggest": { "ext-posix": "*" @@ -7896,7 +7676,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.1-dev" + "dev-main": "6.1-dev" } }, "autoload": { @@ -7915,7 +7695,7 @@ } ], "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "http://www.github.com/sebastianbergmann/environment", + "homepage": "https://github.com/sebastianbergmann/environment", "keywords": [ "Xdebug", "environment", @@ -7923,7 +7703,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/environment/issues", - "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" + "security": "https://github.com/sebastianbergmann/environment/security/policy", + "source": "https://github.com/sebastianbergmann/environment/tree/6.1.0" }, "funding": [ { @@ -7931,34 +7712,34 @@ "type": "github" } ], - "time": "2023-02-03T06:03:51+00:00" + "time": "2024-03-23T08:47:14+00:00" }, { "name": "sebastian/exporter", - "version": "4.0.5", + "version": "5.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" + "reference": "955288482d97c19a372d3f31006ab3f37da47adf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", - "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/955288482d97c19a372d3f31006ab3f37da47adf", + "reference": "955288482d97c19a372d3f31006ab3f37da47adf", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/recursion-context": "^4.0" + "ext-mbstring": "*", + "php": ">=8.1", + "sebastian/recursion-context": "^5.0" }, "require-dev": { - "ext-mbstring": "*", - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-main": "5.1-dev" } }, "autoload": { @@ -8000,7 +7781,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" + "security": "https://github.com/sebastianbergmann/exporter/security/policy", + "source": "https://github.com/sebastianbergmann/exporter/tree/5.1.2" }, "funding": [ { @@ -8008,38 +7790,35 @@ "type": "github" } ], - "time": "2022-09-14T06:03:37+00:00" + "time": "2024-03-02T07:17:12+00:00" }, { "name": "sebastian/global-state", - "version": "5.0.5", + "version": "6.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2" + "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2", - "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/987bafff24ecc4c9ac418cab1145b96dd6e9cbd9", + "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/object-reflector": "^2.0", - "sebastian/recursion-context": "^4.0" + "php": ">=8.1", + "sebastian/object-reflector": "^3.0", + "sebastian/recursion-context": "^5.0" }, "require-dev": { "ext-dom": "*", - "phpunit/phpunit": "^9.3" - }, - "suggest": { - "ext-uopz": "*" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -8058,13 +7837,14 @@ } ], "description": "Snapshotting of global state", - "homepage": "http://www.github.com/sebastianbergmann/global-state", + "homepage": "https://www.github.com/sebastianbergmann/global-state", "keywords": [ "global state" ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5" + "security": "https://github.com/sebastianbergmann/global-state/security/policy", + "source": "https://github.com/sebastianbergmann/global-state/tree/6.0.2" }, "funding": [ { @@ -8072,33 +7852,33 @@ "type": "github" } ], - "time": "2022-02-14T08:28:10+00:00" + "time": "2024-03-02T07:19:19+00:00" }, { "name": "sebastian/lines-of-code", - "version": "1.0.3", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" + "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/856e7f6a75a84e339195d48c556f23be2ebf75d0", + "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0", "shasum": "" }, "require": { - "nikic/php-parser": "^4.6", - "php": ">=7.3" + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-main": "2.0-dev" } }, "autoload": { @@ -8121,7 +7901,8 @@ "homepage": "https://github.com/sebastianbergmann/lines-of-code", "support": { "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" + "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.2" }, "funding": [ { @@ -8129,34 +7910,34 @@ "type": "github" } ], - "time": "2020-11-28T06:42:11+00:00" + "time": "2023-12-21T08:38:20+00:00" }, { "name": "sebastian/object-enumerator", - "version": "4.0.4", + "version": "5.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" + "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", - "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/202d0e344a580d7f7d04b3fafce6933e59dae906", + "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/object-reflector": "^2.0", - "sebastian/recursion-context": "^4.0" + "php": ">=8.1", + "sebastian/object-reflector": "^3.0", + "sebastian/recursion-context": "^5.0" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -8178,7 +7959,7 @@ "homepage": "https://github.com/sebastianbergmann/object-enumerator/", "support": { "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", - "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/5.0.0" }, "funding": [ { @@ -8186,32 +7967,32 @@ "type": "github" } ], - "time": "2020-10-26T13:12:34+00:00" + "time": "2023-02-03T07:08:32+00:00" }, { "name": "sebastian/object-reflector", - "version": "2.0.4", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" + "reference": "24ed13d98130f0e7122df55d06c5c4942a577957" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", - "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/24ed13d98130f0e7122df55d06c5c4942a577957", + "reference": "24ed13d98130f0e7122df55d06c5c4942a577957", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -8233,7 +8014,7 @@ "homepage": "https://github.com/sebastianbergmann/object-reflector/", "support": { "issues": "https://github.com/sebastianbergmann/object-reflector/issues", - "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" + "source": "https://github.com/sebastianbergmann/object-reflector/tree/3.0.0" }, "funding": [ { @@ -8241,32 +8022,32 @@ "type": "github" } ], - "time": "2020-10-26T13:14:26+00:00" + "time": "2023-02-03T07:06:18+00:00" }, { "name": "sebastian/recursion-context", - "version": "4.0.5", + "version": "5.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" + "reference": "05909fb5bc7df4c52992396d0116aed689f93712" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", - "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/05909fb5bc7df4c52992396d0116aed689f93712", + "reference": "05909fb5bc7df4c52992396d0116aed689f93712", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -8296,62 +8077,7 @@ "homepage": "https://github.com/sebastianbergmann/recursion-context", "support": { "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T06:07:39+00:00" - }, - { - "name": "sebastian/resource-operations", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides a list of PHP built-in functions that operate on resources", - "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "support": { - "issues": "https://github.com/sebastianbergmann/resource-operations/issues", - "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + "source": "https://github.com/sebastianbergmann/recursion-context/tree/5.0.0" }, "funding": [ { @@ -8359,32 +8085,32 @@ "type": "github" } ], - "time": "2020-09-28T06:45:17+00:00" + "time": "2023-02-03T07:05:40+00:00" }, { "name": "sebastian/type", - "version": "3.2.1", + "version": "4.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" + "reference": "462699a16464c3944eefc02ebdd77882bd3925bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", - "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/462699a16464c3944eefc02ebdd77882bd3925bf", + "reference": "462699a16464c3944eefc02ebdd77882bd3925bf", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.5" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.2-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -8407,7 +8133,7 @@ "homepage": "https://github.com/sebastianbergmann/type", "support": { "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" + "source": "https://github.com/sebastianbergmann/type/tree/4.0.0" }, "funding": [ { @@ -8415,29 +8141,29 @@ "type": "github" } ], - "time": "2023-02-03T06:13:03+00:00" + "time": "2023-02-03T07:10:45+00:00" }, { "name": "sebastian/version", - "version": "3.0.2", + "version": "4.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/version.git", - "reference": "c6c1022351a901512170118436c764e473f6de8c" + "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", - "reference": "c6c1022351a901512170118436c764e473f6de8c", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c51fa83a5d8f43f1402e3f32a005e6262244ef17", + "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -8460,7 +8186,7 @@ "homepage": "https://github.com/sebastianbergmann/version", "support": { "issues": "https://github.com/sebastianbergmann/version/issues", - "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" + "source": "https://github.com/sebastianbergmann/version/tree/4.0.1" }, "funding": [ { @@ -8468,20 +8194,20 @@ "type": "github" } ], - "time": "2020-09-28T06:39:44+00:00" + "time": "2023-02-07T11:34:05+00:00" }, { "name": "squizlabs/php_codesniffer", - "version": "3.7.2", + "version": "3.9.1", "source": { "type": "git", - "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879" + "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", + "reference": "267a4405fff1d9c847134db3a3c92f1ab7f77909" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ed8e00df0a83aa96acf703f8c2979ff33341f879", - "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/267a4405fff1d9c847134db3a3c92f1ab7f77909", + "reference": "267a4405fff1d9c847134db3a3c92f1ab7f77909", "shasum": "" }, "require": { @@ -8491,11 +8217,11 @@ "php": ">=5.4.0" }, "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" }, "bin": [ - "bin/phpcs", - "bin/phpcbf" + "bin/phpcbf", + "bin/phpcs" ], "type": "library", "extra": { @@ -8510,40 +8236,62 @@ "authors": [ { "name": "Greg Sherwood", - "role": "lead" + "role": "Former lead" + }, + { + "name": "Juliette Reinders Folmer", + "role": "Current lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" } ], "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", + "homepage": "https://github.com/PHPCSStandards/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" + "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", + "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", + "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" }, - "time": "2023-02-22T23:07:41+00:00" + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + } + ], + "time": "2024-03-31T21:03:09+00:00" }, { "name": "symfony/process", - "version": "v5.4.24", + "version": "v6.4.4", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "e3c46cc5689c8782944274bb30702106ecbe3b64" + "reference": "710e27879e9be3395de2b98da3f52a946039f297" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/e3c46cc5689c8782944274bb30702106ecbe3b64", - "reference": "e3c46cc5689c8782944274bb30702106ecbe3b64", + "url": "https://api.github.com/repos/symfony/process/zipball/710e27879e9be3395de2b98da3f52a946039f297", + "reference": "710e27879e9be3395de2b98da3f52a946039f297", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/polyfill-php80": "^1.16" + "php": ">=8.1" }, "type": "library", "autoload": { @@ -8571,7 +8319,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.4.24" + "source": "https://github.com/symfony/process/tree/v6.4.4" }, "funding": [ { @@ -8587,20 +8335,20 @@ "type": "tidelift" } ], - "time": "2023-05-17T11:26:05+00:00" + "time": "2024-02-20T12:31:00+00:00" }, { "name": "theseer/tokenizer", - "version": "1.2.1", + "version": "1.2.3", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", - "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", "shasum": "" }, "require": { @@ -8629,7 +8377,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.1" + "source": "https://github.com/theseer/tokenizer/tree/1.2.3" }, "funding": [ { @@ -8637,7 +8385,7 @@ "type": "github" } ], - "time": "2021-07-28T10:34:58+00:00" + "time": "2024-03-03T12:36:25+00:00" } ], "aliases": [], @@ -8649,15 +8397,16 @@ "prefer-stable": true, "prefer-lowest": false, "platform": { - "php": ">=8.0", - "ext-pdo": "*", - "ext-gd": "*", + "php": ">=8.1", + "ext-intl": "*", "ext-json": "*", + "ext-gd": "*", + "ext-pdo": "*", "ext-xml": "*" }, "platform-dev": [], "platform-overrides": { - "php": "8.0" + "php": "8.1" }, - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } diff --git a/docs/admin/performance.rst b/docs/admin/performance.rst index a560ecd6153..666cae47453 100644 --- a/docs/admin/performance.rst +++ b/docs/admin/performance.rst @@ -188,8 +188,14 @@ Uncomment and populate the following sections in ``settings.php`` $CONFIG->memcache = true; $CONFIG->memcache_servers = array ( - array('server1', 11211), - array('server2', 11211) + array ( + 'host' => 'server1', + 'port' => 11211 + ), + array ( + 'host' => 'server2', + 'port' => 11211 + ) ); Optionaly if you run multiple Elgg installations but use ony one Memcache server, you may want diff --git a/docs/appendix/support.rst b/docs/appendix/support.rst index 74ff905430a..53afe2cbcd9 100644 --- a/docs/appendix/support.rst +++ b/docs/appendix/support.rst @@ -76,7 +76,9 @@ Below is a table outlining the specifics for each release (future dates are tent +----------+----------------------+--------------------+------------------------+ | 4.3 LTS | July 2022 | June 2024 | **Until 6.0** | +----------+----------------------+--------------------+------------------------+ -| 5.0 | June 2023 | | | +| 5.0 | June 2023 | October 2023 | | ++----------+----------------------+--------------------+------------------------+ +| 5.1 | October 2023 | | | +----------+----------------------+--------------------+------------------------+ | 6.0 | TBD | | | +----------+----------------------+--------------------+------------------------+ diff --git a/docs/appendix/upgrade-notes.rst b/docs/appendix/upgrade-notes.rst index 6e7907e62ab..d4354ca3f9c 100644 --- a/docs/appendix/upgrade-notes.rst +++ b/docs/appendix/upgrade-notes.rst @@ -8,6 +8,8 @@ See the administrator guides for :doc:`how to upgrade a live site /after`` is deprecated: Extend the correct ``page/elements/
`` + * ``page/elements/
/before`` is deprecated: Prepend the correct ``page/elements/
`` + * ``resources/comments/edit`` is deprecated: This resource is no longer in use + +Deprecated Routes +----------------- + + * ``edit:object:comment`` is deprecated: Editing comments uses an inline form diff --git a/docs/appendix/upgrade-notes/5.x-to-6.0.rst b/docs/appendix/upgrade-notes/5.x-to-6.0.rst new file mode 100644 index 00000000000..503e5b84ad9 --- /dev/null +++ b/docs/appendix/upgrade-notes/5.x-to-6.0.rst @@ -0,0 +1,164 @@ +From 5.x to 6.0 +=============== + +.. contents:: Contents + :local: + :depth: 1 + +Databases +--------- + +DB Requirements +~~~~~~~~~~~~~~~ + + - The minimal MySQL version is now 8.0 + - The minimal MariaDB version is now 10.6 + +Deleted state +~~~~~~~~~~~~~ + +Entities can now be marked as deleted in the database. This allows entities to be restored from the database when deletion +was done too soon. + +.. note:: + + Because of changes to ``ElggEntity::delete()`` the working of ``ElggFile::delete()`` was changed. It was possible to + symlink a file to a different location (through other ways then Elgg) and when deleting the ``ElggFile`` is was possible + to only delete the symlink and not the target file. This was changed and ``ElggFile::delete()`` will now always delete + both the symlink and the target file. + +.. seealso:: + + Check the :ref:`database ` documentation or the :doc:`/guides/restore` documentation for more information. + +ES Modules +---------- + +We no longer use RequireJS for inclusion of AMD JavaScript modules. Instead we now rely on the native use of ECMAScript modules. +All modules can be referenced under the same name as an importable module. + +Related functions changes +~~~~~~~~~~~~~~~~~~~~~~~~~ + +* ``elgg_define_js()`` this function has been removed. You might need ``elgg_register_esm()`` as a replacement. +* ``elgg_require_js()`` this function has been removed. You might need ``elgg_import_esm()`` as a replacement. +* ``elgg_unrequire_js()`` this function has been removed + +The event 'config', 'amd' has been removed. +The event 'elgg.data', 'site' has been removed. You can switch to the 'elgg.data', 'page' event. + +.. note:: + + With the switch to ECMAScript modules we can no longer add Sub-Resource Integrity checks to the imported modules. + +.. note:: + + With the switch to ECMAScript modules we temporarily dropped Javascript testing features. This will be added in the future. + +Composer +-------- + +PHP Requirements +~~~~~~~~~~~~~~~~ + +The minimal PHP version is now 8.1. Also the ``intl`` module is now required to be enabled. + +PHPUnit +~~~~~~~ + +Elgg now uses PHPUnit 10.5. You might need to update your tests. + +Annotations +----------- + +Due to a naming conflict in the default join alias between the ``annotations`` and ``metadata`` table, the default join +alias for the ``annotations`` table has been changed from ``n_table`` to ``a_table``. + +If your code uses very specific clauses (select, where, order_by, etc.) you need to update your code. If you use the +``\Elgg\Database\QueryBuilder`` for your query parts you should be ok. + +Enabled column +~~~~~~~~~~~~~~ + +The ``enabled`` column for annotations has been removed. An annotation is no longer enabled or disabled. +You can no longer perform the ``enable`` and ``disable`` API calls on annotations. Other related API functions have been removed. + +Entity Icons +------------ + +Cropping coordinates +~~~~~~~~~~~~~~~~~~~~ + +The cropping coordinates of the default icon (``icon``) are now stored in a uniform way, same as those of the other icon types. +The metadata ``x1``, ``x2``, ``y1`` and ``y2`` no longer exist. Use the new ``\ElggEntity`` function ``getIconCoordinates()``. + +Icontime +~~~~~~~~ + +The metadata ``icontime`` has been removed from the database. This was an unreliable way to check if an icon was uploaded. +This was only stored for the icon type ``icon``. + +A reliable way to check if an icon was uploaded is to use the ``\ElggEntity::hasIcon()`` function. + +Headings +-------- + +The use of headings (h1, h2, h3) have been revisited throughout the entire codebase to make sure they are used when appropriate +and that they also are used in the correct order. You can read more about the intended usage in :doc:`/design/a11y`. + +Most notable changes are the following: + +* H1 is always the page title (and no longer the logo / site name) +* Modules (info, sidebar, widgets) use the H2 heading +* H3 headings on entity / relationship / annotation summary titles have been replaced by a regular text element + +CSS and HTML structure changes +------------------------------ + +The HTML structure of pages have been changed. Entity summaries and full view entity pages have been wrapped in an ``article`` element. +Sidebar elements now use the ``aside`` html element. Modules (like widgets of info-modules) now use a ``section`` element instead of a ``div``. +Duplicate css classes on the same element like ``elgg-body`` and ``elgg-layout-body`` have been removed. + +Elgg provided some helper classes for creating a grid layout (like ``elgg-grid``, ``elgg-col``, ``elgg-row``). +These helper classes have been removed. You can do all those things with regular css like ``display: grid``. + +Some other styling changes include a new background color for the body, improved styling of breadcrumbs and a more basic owner block chip. + +Changes in functions +-------------------- + +Removed lib functions +~~~~~~~~~~~~~~~~~~~~~ + +* ``elgg_disable_annotations()`` has been removed +* ``elgg_enable_annotations()`` has been removed +* ``elgg_set_view_location()`` has been removed +* ``elgg_strrchr()`` has been removed +* ``elgg_strripos()`` has been removed +* ``elgg_unrequire_css()`` has been removed. Use ``elgg_unregister_external_file('css', $view)`` as replacement. + +Removed class functions +~~~~~~~~~~~~~~~~~~~~~~~ + +* ``\ElggAnnotation->enable()`` +* ``\ElggAnnotation->disable()`` +* ``\ElggEntity->disableAnnotations()`` +* ``\ElggEntity->enableAnnotations()`` +* ``\ElggEntity->getTags()`` use ``elgg_get_metadata()`` as an alternative. + +Lib functions function parameters +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* ``elgg_get_entity_statistics()`` now requires an ``array`` of ``$options`` to be used by ``elgg_get_entities()``. +* ``elgg_get_simplecache_url()`` has the second argument (``$subview``) removed. The full ``$view`` name needs to be provided as the first argument. + +Miscellaneous API changes +------------------------- + +* The interface ``\Elgg\EntityIcon`` has been removed. Implemented functions in ``\ElggEntity`` have been moved to ``\Elgg\Traits\Entity\Icons`` +* View names from a 'css' or 'js' view folder now always need to be referenced by their full view name (previously is was possible to omit the first folder if it was 'css' or 'js') + +Removed Config values +------------------------ + +* ``system_cache_loaded`` diff --git a/docs/conf.py b/docs/conf.py index 532cb9be836..cd16017f292 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -29,6 +29,7 @@ # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [ + 'sphinx_rtd_theme', 'sphinxcontrib.phpdomain' ] @@ -109,7 +110,7 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'default' +html_theme = 'sphinx_rtd_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the diff --git a/docs/contribute/code.rst b/docs/contribute/code.rst index 73470c635a5..3f75c01b062 100644 --- a/docs/contribute/code.rst +++ b/docs/contribute/code.rst @@ -242,70 +242,6 @@ Due to these local references, replacing services on the SP within a test often * The ``events`` service has methods ``backup()`` and ``restore()``. * The ``logger`` service has methods ``disable()`` and ``enable()``. -Jasmine Tests -------------- - -Test files must be named ``*Test.js`` and should go in either ``js/tests/`` or next -to their source files in ``views/default/**.js``. Karma will automatically pick up -on new ``*Test.js`` files and run those tests. - -Test boilerplate ----------------- - -.. code-block:: js - - define(['elgg'], function(elgg) { - describe("This new test", function() { - it("fails automatically", function() { - expect(true).toBe(false); - }); - }); - }); - -Running the tests ------------------ -Elgg uses `Karma`_ with `Jasmine`_ to run JS unit tests. - -.. _Karma: http://karma-runner.github.io/0.8/index.html -.. _Jasmine: http://pivotal.github.io/jasmine/ - -You will need to have nodejs and yarn installed. - -First install all the development dependencies: - -.. code-block:: sh - - yarn - -Run through the tests just once and then quit: - -.. code-block:: sh - - yarn test - -You can also run tests continuously during development so they run on each save: - -.. code-block:: sh - - karma start js/tests/karma.conf.js - -Debugging JS tests -^^^^^^^^^^^^^^^^^^ - -You can run the test suite inside Chrome dev tools: - -.. code-block:: sh - - yarn run chrome - -This will output a URL like ``http://localhost:9876/``. - -#. Open the URL in Chrome, and click "Debug". -#. Open Chrome dev tools and the Console tab. -#. Reload the page. - -If you alter a test you'll have to quit Karma with ``Ctrl-c`` and restart it. - Coding best practices ===================== @@ -780,20 +716,10 @@ Javascript guidelines Same formatting standards as PHP apply. -Related functions should be in a namespaced ``AMD`` module. +Related functions should be in a namespaced ``ECMAScript`` module. Function expressions should end with a semi-colon. -.. code-block:: js - - define(['elgg'], function(elgg) { - function toggles(event) { - event.preventDefault(); - $(target).slideToggle('medium'); - }; - }); - - Deprecating APIs ================ diff --git a/docs/contribute/core/move_plugin.rst b/docs/contribute/core/move_plugin.rst index 8bc96050168..2b105f81df0 100644 --- a/docs/contribute/core/move_plugin.rst +++ b/docs/contribute/core/move_plugin.rst @@ -69,9 +69,6 @@ Make sure the ``composer.json`` of the plugin contains all the relevant informat "source": "https://github.com/elgg/", "issues": "https://github.com/elgg//issues" }, - "require": { - "composer/installers": ">=1.0.8" - }, "conflict": { "elgg/elgg": "< " } diff --git a/docs/contribute/core/releases.rst b/docs/contribute/core/releases.rst index 39e03429dc8..7f634622eea 100644 --- a/docs/contribute/core/releases.rst +++ b/docs/contribute/core/releases.rst @@ -110,13 +110,7 @@ Merge latest commits up from lowest supported branch. Visit ``https://github.com/Elgg/Elgg/compare/...`` and submit the PR if there is anything that needs to be merged up. -Install the prerequisites: - -.. code-block:: sh - - yarn install elgg-conventional-changelog - -.. note:: +.. note:: On Windows you need to run these command in a console with admin privileges diff --git a/docs/design/a11y.rst b/docs/design/a11y.rst new file mode 100644 index 00000000000..e862f155eb3 --- /dev/null +++ b/docs/design/a11y.rst @@ -0,0 +1,53 @@ +Accessibility +############# + +This document describes various design choices to improve accessibility of an Elgg site. + +.. toctree:: + :maxdepth: 2 + +Forms +===== + +Input fields should always have an associated label. When using ``elgg_view_field($options)`` to draw fields on a form you will need to +pass ``$options['#label'] = elgg_echo('my_field:label')`` to have a correct label with your field. + +If you have a form that will perform a search when submitted it is recommended to add ``'role' => 'search'`` to your form attributes. +You can provide this in ``$form_vars`` when using ``elgg_view_form()``. + +Images +====== + +When using ``elgg_view('output/img', $options)`` it is recommended to provide an ``alt`` description of the image. +Elgg will report notices in the error log to let developers know when an ``alt`` attribute is missing. + +Headings +======== + +Headings should be used to give structure to a page. +There should always be a ``h1`` on the page and there should also be no gaps (so no ``h3`` without a ``h2``). + +Elgg uses ``h1`` for the page title (like 'All blogs', the title of a blog or the name of a group on the group profile page). +The ``h2`` heading is used by modules on a page, like an 'info' module, a widget or a module in the sidebar. + +User generated content with markup, for example a description of a blog, should not allow ``h1`` to be used, +but should start with ``h2`` as the first level heading. The configuration of the CKEditor plugin already handles this. + +Sections +======== + +A webpage in Elgg is typically sectioned into the following sections: + +* ``header`` for the topbar contents like the site logo, site navigation and search +* ``main`` the main content like the blog page or an overview of members +* ``footer`` typically found at the bottom of the page containing some links or other site related information + +Menus +===== + +All our menus should be keyboard accessible. This is especially important with menus with multiple levels or submenus. +If you rely on the default menu functionality of Elgg by using the function ``elgg_view_menu()`` Elgg will take care of this. + +When using ``elgg_view_menu()`` the menu items will be wrapped inside a ``nav`` html tag. To allow screenreaders to know what menu is being listed, +the ``aria-label`` attribute is added to the ``nav`` element to describe the menu. By default Elgg uses the ``name`` of the menu, but it is +possible to provide a translation. You need to register this translation with the following key: ``menu:name_of_the_menu:header``. diff --git a/docs/design/amd.rst b/docs/design/amd.rst deleted file mode 100644 index 37e2b605416..00000000000 --- a/docs/design/amd.rst +++ /dev/null @@ -1,58 +0,0 @@ -AMD -### - -.. toctree:: - :maxdepth: 2 - -Overview -======== - -If you want to use JavaScript in Elgg: we use a `AMD (Asynchronous Module -Definition) `_ compatible system. - -This discusses the benefits of using AMD in Elgg. - -Why AMD? -======== - -We have been working hard to make Elgg's JavaScript more maintainable and useful. -We made some strides in 1.8 with the introduction of the "``elgg``" JavaScript object and library, but -have quickly realized the approach we were taking was not scalable. - -The size of `JS on the web is growing -`_ -quickly, and JS in Elgg is growing too. We want Elgg to be able to offer a solution that makes JS -development as productive and maintainable as possible going forward. - -The `reasons to choose AMD `_ are plenteous and -well-documented. Let's highlight just a few of the most relevant reasons as they relate to Elgg -specifically. - -1. Simplified dependency management ------------------------------------ -AMD modules load asynchronously and execute as soon as their dependencies are available, so this -eliminates the need to specify "priority" and "location" when registering JS libs in Elgg. Also, you -don't need to worry about explicitly loading a module's dependencies in PHP. The AMD loader (RequireJS in this -case) takes care of all that hassle for you. It's also possible have -`text dependencies `_ with the RequireJS text plugin, -so client-side templating should be a breeze. - -2. AMD works in all browsers. Today. ------------------------------------- -Elgg developers are already writing lots of JavaScript. We know you want to write more. We cannot -accept waiting 5-10 years for a native JS modules solution to be available in all browsers before -we can organize our JavaScript in a maintainable way. - -3. You do not need a build step to develop in AMD. --------------------------------------------------- -We like the edit-refresh cycle of web development. We wanted to make sure everyone developing in -Elgg could continue experiencing that joy. Synchronous module formats like Closure or CommonJS just -weren't an option for us. But even though AMD doesn't require a build step, *it is still very -build-friendly*. Because of the ``define()`` wrapper, it's possible to concatenate multiple modules -into a single file and ship them all at once in a production environment. [#]_ - -AMD is a battle-tested and well thought out module loading system for the web today. We're very -thankful for the work that has gone into it, and are excited to offer it as the standard solution -for JavaScript development in Elgg starting with Elgg 1.9. - -.. [#] This is not currently supported by Elgg core, but we'll be looking into it since reducing round-trips is critical for a good first-view experience, especially on mobile devices. diff --git a/docs/design/database.rst b/docs/design/database.rst index e6fa63a2098..ddce850ad41 100644 --- a/docs/design/database.rst +++ b/docs/design/database.rst @@ -44,7 +44,7 @@ The main differences between metadata and annotations: These differences might have implications for performance and your business logic, so consider carefully, how you would like to attach data to your entities. -In certain cases, it may be benefitial to avoid using metadata and annotations and create new +In certain cases, it may be beneficial to avoid using metadata and annotations and create new entities instead and attaching them via ``container_guid`` or a relationship. Datamodel @@ -63,18 +63,24 @@ Entities ``ElggEntity`` is the base class for the Elgg data model and supports a common set of properties and methods. -- A numeric Globally Unique IDentifier (See `GUIDs`_). -- Access permissions. (When a plugin requests data, it never gets to - touch data that the current user doesn't have permission to see.) -- An arbitrary subtype (more below). -- An owner. -- The site that the entity belongs to. -- A container, used to associate content with a group or a user. +- A numeric Globally Unique IDentifier (See `GUIDs`_) +- Access permissions. (When a plugin requests data, it never gets to + touch data that the current user doesn't have permission to see) +- An arbitrary subtype (more below) +- An owner +- A container, used to associate content with a group or a user +- UNIX timestamps for certain actions: + - When was the entity created + - When was the entity last updated + - When did the the entity perform it's last action, or was acted upon + - When was the entity deleted +- A deleted state (deleted entities aren't shown in normal circumstances) +- A disabled state (disabled entities aren't shown in normal circumstances) Types ----- -*Actual* entities will be instances of four different subclasses, each having a distinct **type** +**Actual** entities will be instances of four different subclasses, each having a distinct **type** property and their own additional properties and methods. ======= ============== =================================================================== @@ -101,7 +107,7 @@ E.g. the blog plugin creates objects with subtype ``"blog"``. By default, users, groups and sites have the subtypes of ``user``, ``group`` and ``site`` respectively. Plugins can use custom entity classes that extend the base type class. To do so, they need to register their class at -runtime (e.g. in the ``'init','system'`` handler), using ``elgg_set_entity_class()``. +runtime (e.g. in the ``'init', 'system'`` handler), using ``elgg_set_entity_class()``. For example, the blog plugin could use ``elgg_set_entity_class('object', 'blog', \ElggBlog::class)``. Plugins can use ``elgg-plugin.php`` to define entity class via shortcut ``entities`` parameter. @@ -109,8 +115,11 @@ Plugins can use ``elgg-plugin.php`` to define entity class via shortcut ``entiti Subtype Gotchas --------------- -- Before an entity's ``save()`` method is called, the subtype must be set by writing a string to the ``subtype`` property. -- *Subtype cannot be changed after saving.* +Before an entity's ``save()`` method is called, the subtype must be set by writing a string to the ``subtype`` property. + +.. warning:: + + Subtype cannot be changed after saving. GUIDs ----- @@ -121,13 +130,41 @@ when the entity is first saved and can never be changed. Some Elgg API functions work with GUIDs instead of ``ElggEntity`` objects. +.. _database-deleted: + +Deleted state +------------- + +As of Elgg 6.0 entities also have a deleted state. When a given entity type/subtype supports it before it's removed from +the database it can get the deleted state. This way a user can restore the entity if the delete action was done too hastily. +For example the user removes a blog post, but this shouldn't have been done. Now the user has the option to restore the +blog in it's original state without having to rewrite it. + +In the database this is managed by the ``deleted`` column in the ``entities`` table which can have a value of ``yes`` or +``no`` (default) and by the ``time_deleted`` column which holds a UNIX timestamp when the entity was deleted. + +A site administrator can set a retention period for deleted items. Once the retention period is passed the entity will be +permanently removed from the database. + +Deleted items will not show in normal use cases. In the example of the blog post, the blog will not show up in the blog +listing and if anyone has saved a link to the blog post the page will return a ``404 - Not Found`` error. + +There is a special page in the user settings section where all the deleted entities of the user can be viewed. Here the +user has the option to restore the entity or permanently delete it before the retention period has passed. + +This special page is also available to group owners for deleted entities in their group. + +.. seealso:: + + For more information check out the :doc:`/guides/restore` documentation + ElggObject ========== The ``ElggObject`` entity type represents arbitrary content within an -Elgg install; things like blog posts, uploaded files, etc. +Elgg installation things like blog posts, uploaded files, etc. -Beyond the standard ElggEntity properties, ElggObjects also support: +Beyond the standard ``ElggEntity`` properties, ``ElggObject`` also supports: - ``title`` The title of the object (HTML escaped text) - ``description`` A description of the object (HTML) @@ -137,19 +174,17 @@ Most other data about the object is generally stored via metadata. ElggUser ======== -The ``ElggUser`` entity type represents users within an Elgg install. +The ``ElggUser`` entity type represents users within an Elgg installation. These will be set to disabled until their accounts have been activated (unless they were created from within the admin panel). -Beyond the standard ElggEntity properties, ElggUsers also support: +Beyond the standard ``ElggEntity`` properties, ``ElggUser`` also supports: - ``name`` The user's plain text name. e.g. "Hugh Jackman" - ``username`` Their login name. E.g. "hjackman" - ``password`` A hashed version of their password - ``email`` Their email address - ``language`` Their default language code. -- ``code`` Their session code (moved to a separate table in 1.9). -- ``last_action`` The UNIX timestamp of the last time they loaded a page - ``prev_last_action`` The previous value of ``last_action`` - ``last_login`` The UNIX timestamp of their last log in - ``prev_last_login`` the previous value of ``last_login`` @@ -159,7 +194,7 @@ ElggSite The ``ElggSite`` entity type represents your Elgg installation (via your site URL). -Beyond the standard ElggEntity properties, ElggSites also support: +Beyond the standard ``ElggEntity`` properties, ``ElggSite`` also supports: - ``name`` The site name - ``description`` A description of the site @@ -171,7 +206,7 @@ ElggGroup The ``ElggGroup`` entity type represents an association of Elgg users. Users can join, leave, and post content to groups. -Beyond the standard ElggEntity properties, ElggGroups also support: +Beyond the standard ``ElggEntity`` properties, ``ElggGroup`` also supports: - ``name`` The group's name (HTML escaped text) - ``description`` A description of the group (HTML) @@ -183,12 +218,14 @@ The Groups plugin Not to be confused with the entity type ``ElggGroup``, Elgg comes with a plugin called "Groups" that provides a default UI/UX for site users -to interact with groups. Each group is given a discussion forum and a -profile page linking users to content within the group. +to interact with groups. Each group is given a profile page linking +users to content within the group. You can alter the user experience via the traditional means of extending plugins or completely replace the Groups plugin with your own. +Several of the Elgg core plugins offer support for group content like blogs, bookmarks, discussions, files and pages. + Writing a group-aware plugin ---------------------------- @@ -250,15 +287,17 @@ Containers In order to easily search content by group or by user, content is generally set to be "contained" by either the user who posted it, or the group to which the user posted. This means the new object's ``container_guid`` property -will be set to the GUID of the current ElggUser or the target ElggGroup. +will be set to the GUID of the current ``ElggUser`` or the target ``ElggGroup``. E.g., three blog posts may be owned by different authors, but all be contained by the group they were posted to. -Note: This is not always true. Comment entities are contained by the object -commented upon, and in some 3rd party plugins the container may be used -to model a parent-child relationship between entities (e.g. a "folder" -object containing a file object). +.. note:: + + This is not always true. Comment entities are contained by the object + commented upon, and in some 3rd party plugins the container may be used + to model a parent-child relationship between entities (e.g. a "folder" + object containing a file object). Annotations =========== @@ -272,13 +311,10 @@ Annotations are stored as instances of the ``ElggAnnotation`` class. Each annotation has: - An internal annotation type (like *comment*) -- A value (which can be a string or integer) +- A value (which can be a string, a boolean or an integer) - An access permission distinct from the entity it's attached to - An owner -Like metadata, values are stored as strings unless the value given is a PHP integer (``is_int($value)`` is true), -or unless the ``$vartype`` is manually specified as ``integer``. - Adding an annotation -------------------- @@ -342,7 +378,7 @@ following function will provide the full listing, form and actions: Metadata ======== -Metadata in Elgg allows you to store extra data on an ``entity`` beyond +Metadata in Elgg allows you to store extra data on an ``ElggEntity`` beyond the built-in fields that entity supports. For example, ``ElggObjects`` only support the basic entity fields plus title and description, but you might want to include tags or an ISBN number. Similarly, you might want @@ -356,6 +392,7 @@ reference). What you need to know is: - You can potentially have multiple items of each type of metadata attached to a single entity - Like annotations, values are stored as strings, booleans or integers +- The metadata name is case sensitive The simple case --------------- @@ -389,8 +426,8 @@ This is suitable for most purposes. Be careful to note which attributes are metadata and which are built in to the entity type that you are working with. You do not need to save an entity after adding or updating metadata. You do need to save an entity if you have changed one of its -built in attributes. As an example, if you changed the access id of an -ElggObject, you need to save it or the change isn't pushed to the +built in attributes. As an example, if you changed the ``access_id`` of an +``ElggObject``, you need to save it or the change isn't pushed to the database. Reading metadata @@ -403,12 +440,12 @@ To retrieve metadata, treat it as a property of the entity: $tags_value = $object->tags; Note that this will return the absolute value of the metadata. To get -metadata as an ElggMetadata object, you will need to use the methods +metadata as an ``ElggMetadata`` object, you will need to use the methods described in the *finer control* section below. If you stored multiple values in this piece of metadata (as in the "tags" example above), you will get an array of all those values back. -If you stored only one value, you will get a string or integer back. +If you stored only one value, you will get a string, boolean or integer back. Storing an array with only one value will return a string back to you. E.g. @@ -427,8 +464,7 @@ To always get an array back, simply cast to an array; Reading metadata as objects --------------------------- -``elgg_get_metadata`` is the best function for retrieving metadata as ElggMetadata -objects: +``elgg_get_metadata`` is the best function for retrieving metadata as ``ElggMetadata`` objects: E.g., to retrieve a user's DOB @@ -448,6 +484,11 @@ Or to get all metadata objects: 'limit' => false, ]); +.. note:: + + When retrieving metadata by name the names are matched case-insensitive. + Keep your code clean and do not mix uppercase and lowercase metadata names. + Common mistakes --------------- @@ -521,7 +562,7 @@ the subject (the archer) to the target. **A relationship does not imply reciprocity**. **A** follows **B** does not imply that **B** follows **A**. -**Relationships_ do not have access control.** They're never +**Relationships do not have access control.** They're never hidden from view and can be edited with code at any privilege level, with the caveat that *the entities* in a relationship may be invisible due to access control! @@ -663,8 +704,8 @@ The character set of the database should be ``utf8mb4``, this will provide full InnoDB ------ -As of Elgg 3.0 the database uses the InnoDB engine. In order for a correct installation or migration some settings may need to be adjusted -in the database settings. +As of Elgg 3.0 the database uses the InnoDB engine. In order for a correct installation or migration some settings may +need to be adjusted in the database settings. - ``innodb_large_prefix`` should be ``on`` - ``innodb_file_format`` should be ``Barracuda`` @@ -681,7 +722,7 @@ Table: entities This is the main `Entities`_ table containing Elgg users, sites, objects and groups. When you first install Elgg this is automatically -populated with your first site. +populated with your first site, your first user and a set of bundled plugins. It contains the following fields: @@ -693,9 +734,14 @@ It contains the following fields: - **access\_id** Access controls on this entity - **time\_created** Unix timestamp of when the entity is created - **time\_updated** Unix timestamp of when the entity was updated +- **last\_action** Unix timestamp of when the user last performed an action or when within the entity as container something happened - **enabled** If this is 'yes' an entity is accessible, if 'no' the entity has been disabled (Elgg treats it as if it were deleted without actually removing it from the database) +- **deleted** If this is 'yes' an entity is marked as deleted, + if 'no' (default) the entity is visible within the regular site. + Deleted entities can be viewed in the trash +- **time\_deleted** Unix timestamp of when the entity was deleted Table: metadata ~~~~~~~~~~~~~~~ @@ -706,9 +752,8 @@ This table contains `Metadata`_, extra information attached to an entity. - **entity\_guid** The entity this is attached to - **name** The name string - **value** The value string -- **value\_type** The value class, either text or an integer +- **value\_type** The value class, either text, bool or an integer - **time\_created** Unix timestamp of when the metadata is created -- **enabled** If this is 'yes' an item is accessible, if 'no' the item has been disabled Table: annotations ~~~~~~~~~~~~~~~~~~ @@ -719,11 +764,10 @@ This table contains `Annotations`_, this is distinct from `Metadata`_. - **entity\_guid** The entity this is attached to - **name** The name string - **value** The value string -- **value\_type** The value class, either text or an integer +- **value\_type** The value class, either text, bool or an integer - **owner\_guid** The owner GUID of the owner who set this annotation - **access\_id** An Access controls on this annotation - **time\_created** Unix timestamp of when the annotation is created. -- **enabled** If this is 'yes' an item is accessible, if 'no' the item has been disabled Table: relationships ~~~~~~~~~~~~~~~~~~~~ @@ -733,6 +777,7 @@ This table defines `Relationships`_, these link one entity with another. - **guid\_one** The GUID of the subject entity. - **relationship** The type of the relationship. - **guid\_two** The GUID of the target entity. +- **time\_created** Unix timestamp of when the relationship is created. Secundairy tables ----------------- @@ -743,6 +788,6 @@ Table: access_collections This table defines Access Collections, which grant users access to `Entities`_ or `Annotations`_. - **id** A unique IDentifier -- ***name** The name of the access collection +- **name** The name of the access collection - **owner_guid** The GUID of the owning entity (eg. a user or a group) - **subtype** the subtype of the access collection (eg. `friends` or `group_acl`) diff --git a/docs/design/events.rst b/docs/design/events.rst index 2db63459dd6..f51ef70b5b2 100644 --- a/docs/design/events.rst +++ b/docs/design/events.rst @@ -48,7 +48,7 @@ something happens. Handlers can cancel the event by returning ``false``. When ``false`` is returned by a handler, following handlers will not be called. After Events, with names ending in ":after", are triggered after -something happened. Handlers *cannot* cancel these events; all handlers will always be called. +something happened. Handlers **cannot** cancel these events; all handlers will always be called. Where before and after events are available, developers are encouraged to transition to them, though older events will be supported for @@ -201,6 +201,8 @@ Parameters: - **$params** Arbitrary data passed from the trigger to the handlers. - **$value** The initial value of the event. +.. _event-sequence: + Trigger an Elgg Event sequence ------------------------------ @@ -211,6 +213,9 @@ the ``:before`` event, then the actual event and finally the ``:after`` event. elgg()->events->triggerSequence($event, $type, $object, $callable); + // or if you wish to have a result sequence + $result = elgg->events->triggerResultsSequence($name, $type, $params, $value, $callable); + When called with for example ``'cache:clear', 'system'`` the following three events are triggered - ``'cache:clear:before', 'system'`` @@ -224,6 +229,14 @@ Parameters: - **$object** The object (e.g. an instance of ``ElggUser`` or ``ElggGroup``) - **$callable** Callable to run on successful event, before event:after +.. note:: + + As of Elgg 6.0 the ``:after`` event will no longer be triggered if the result of the callable is ``false``. This was + done in order to prevent the system from thinking something was done which wasn't successful. For example the + ``'delete', 'user'`` event sequence. If the callback (which handles the actual removal from the database) wasn't + successful the ``:after`` event implied that the user was deleted. Now this is only triggered when the user is actually + removed from the database. + Unregister Event Handlers ------------------------- diff --git a/docs/design/i18n.rst b/docs/design/i18n.rst deleted file mode 100644 index 26d887fbb63..00000000000 --- a/docs/design/i18n.rst +++ /dev/null @@ -1,7 +0,0 @@ -Internationalization -#################### - -Elgg 1.0+ departs from previous versions in that it uses a custom text array rather than gettext. -This improves system performance and reliability of the translation system. - -TODO: more plz \ No newline at end of file diff --git a/docs/design/index.rst b/docs/design/index.rst index b31a6c03d12..a9ee3ad3f33 100644 --- a/docs/design/index.rst +++ b/docs/design/index.rst @@ -7,10 +7,9 @@ and why it's built the way it is. .. toctree:: :maxdepth: 1 + a11y actions database events - i18n - amd security loggable diff --git a/docs/guides/actions.rst b/docs/guides/actions.rst index ca70db72dcf..0c135c610c9 100644 --- a/docs/guides/actions.rst +++ b/docs/guides/actions.rst @@ -378,6 +378,8 @@ Elgg offers some helper input types * ``input/captcha`` - placeholder view for plugins to extend * ``input/friendspicker`` - renders an Elgg friend autocomplete * ``input/userpicker`` - renders an Elgg user autocomplete +* ``input/grouppicker`` - renders an Elgg group autocomplete +* ``input/objectpicker`` - renders an Elgg object autocomplete * ``input/location`` renders an Elgg location input Files and images @@ -471,7 +473,7 @@ The basic flow of using sticky forms is: * ``sticky_enabled``: a ``bool`` to enable automatic sticky form support * ``sticky_form_name``: an optional ``string`` to set where the sticky form values are saved. This defaults to the ``$action_name`` and should only be changed if the ``$action_name`` is different from the actual action -* ``sticky_ignored_fields: an ``array`` with the names fo the form fields that should be saved. For example password fields +* ``sticky_ignored_fields``: an ``array`` with the names fo the form fields that should be saved. For example password fields Example: User registration -------------------------- diff --git a/docs/guides/ajax.rst b/docs/guides/ajax.rst index 352ebbdfc4f..b163b1ad9ba 100644 --- a/docs/guides/ajax.rst +++ b/docs/guides/ajax.rst @@ -1,7 +1,7 @@ Ajax #### -The ``elgg/Ajax`` AMD module (introduced in Elgg 2.1) provides a set of methods for communicating with the server in a concise and uniform way, which allows plugins to collaborate on the request data, the server response, and the returned client-side data. +The ``elgg/Ajax`` module (introduced in Elgg 2.1) provides a set of methods for communicating with the server in a concise and uniform way, which allows plugins to collaborate on the request data, the server response, and the returned client-side data. .. contents:: Contents :local: @@ -32,7 +32,7 @@ More notes: * If a non-empty ``options.data`` is given, the default method is always ``POST``. * For client caching, set ``options.method`` to ``"GET"`` and ``options.data.elgg_response_ttl`` to the max-age you want in seconds. * To save system messages for the next page load, set ``options.data.elgg_fetch_messages = 0``. You may want to do this if you intent to redirect the user based on the response. -* To stop client-side API from requiring AMD modules required server-side with ``elgg_require_js()``, set ``options.data.elgg_fetch_deps = 0``. +* To stop client-side API from requiring modules required server-side with ``elgg_import_esm()``, set ``options.data.elgg_fetch_deps = 0``. * All methods accept a query string in the first argument. This is passed on to the fetch URL, but does not appear in the hook types. Performing actions @@ -350,12 +350,12 @@ The first and third case are the most common cases in the system. Use the ``done // handle error condition if needed }); -Requiring AMD modules ---------------------- +Requiring ES modules +-------------------- -Each response from an Ajax service will contain a list of AMD modules required server side with `elgg_require_js()`. +Each response from an Ajax service will contain a list of ES modules required server side with `elgg_import_esm()`. When response data is unwrapped, these modules will be loaded asynchronously - plugins should not expect these -modules to be loaded in their `$.done()` and `$.then()` handlers and must use `require()` for any modules they depend on. -Additionally AMD modules should not expect the DOM to have been altered by an Ajax request when they are loaded - +modules to be loaded in their `$.done()` and `$.then()` handlers and must use `import` for any modules they depend on. +Additionally modules should not expect the DOM to have been altered by an Ajax request when they are loaded - DOM events should be delegated and manipulations on DOM elements should be delayed until all Ajax requests have been resolved. diff --git a/docs/guides/errors.rst b/docs/guides/errors.rst index 179b15a0164..6ee4aceed15 100644 --- a/docs/guides/errors.rst +++ b/docs/guides/errors.rst @@ -18,6 +18,6 @@ You can add custom handlers (see Monolog_ documentation for a full list of handl 'admin@example.com', 'Critical error', 'no-reply@mysite.com', - \Monolog\Logger::CRITICAL + \Monolog\Level::Critical ) ); \ No newline at end of file diff --git a/docs/guides/events-list.rst b/docs/guides/events-list.rst index 83c587a9902..40c8ee88020 100644 --- a/docs/guides/events-list.rst +++ b/docs/guides/events-list.rst @@ -10,7 +10,7 @@ For more information on how events work visit :doc:`/design/events`. .. note:: Some events are marked with |sequence| this means those events also have a ``:before`` and ``:after`` event - Also see :ref:`Event sequence ` + Also see :ref:`Event sequence ` Some events are marked with |results| this means those events allow altering the output of an event @@ -41,6 +41,12 @@ System events **cron, ** |results| Triggered by cron for each period. + The ``$params`` array will contain: + + * ``time`` - the timestamp of when the cron command was started + * ``dt`` - the ``\DateTime`` object of when the cron command was started + * ``logger`` - instance of ``\Elgg\Logger\Cron`` to log any information to the cron log + **cron:intervals, system** |results| Allow the configuration of custom cron intervals @@ -51,10 +57,7 @@ System events Filter the output for the diagnostics report download. **elgg.data, page** |results| - Filters uncached, page-specific configuration data to pass to the client. :ref:`More info ` - -**elgg.data, site** |results| - Filters cached configuration data to pass to the client. :ref:`More info ` + Filters uncached, page-specific configuration data to pass to the client. :doc:`More info ` **format, friendly:title** |results| Formats the "friendly" title for strings. This is used for generating URLs. @@ -233,7 +236,7 @@ System events Triggered after a system upgrade has finished. All upgrade scripts have run, but the caches are not cleared. -**upgrade:execute, system** |sequence| +**upgrade:execute, system** |sequence| |results| Triggered when executing an ``ElggUpgrade``. The ``$object`` of the event is the ``ElggUpgrade``. User events @@ -256,11 +259,8 @@ User events **invalidate:after, user** Triggered when user's account validation has been revoked. -**login:after, user** - Triggered after the user logs in. - -**login:before, user** - Triggered during login. Returning false prevents the user from logging +**login, user** |sequence| + Triggered when a user is being logged in. **login:forward, user** |results| Filters the URL to which the user will be forwarded after login. @@ -371,14 +371,8 @@ Entity events **create:before, ** Triggered for user, group, object, and site entities before creation. Return false to prevent creating the entity. -**delete, ** - Triggered before entity deletion. - -**delete:after, ** - Triggered after entity deletion. - -**delete:before, ** - Triggered before entity deletion. Return false to prevent deletion. +**delete, ** |sequence| + Triggered when an entity is permanently removed from the database. Also see :doc:`/guides/restore` **disable, ** Triggered before the entity is disabled. Return false to prevent disabling. @@ -394,7 +388,10 @@ Entity events **likes:count, ** |results| Return the number of likes for ``$params['entity']``. - + +**trash, ** |sequence| + Triggered when an entity is marked as deleted in the database. Also see :doc:`/guides/restore` + **update, ** Triggered before an update for the user, group, object, and site entities. Return false to prevent update. The entity method ``getOriginalAttributes()`` can be used to identify which attributes have changed since @@ -431,12 +428,6 @@ Annotation events **delete, annotation** Called before annotation is deleted. Return false to prevent deletion. - -**disable, annotations** - Called when disabling annotations. Return false to prevent disabling. - -**enable, annotation** - Called when enabling annotations. Return false to prevent enabling. **update, annotation** Called after the annotation has been updated. Return false to *delete the annotation.* @@ -862,7 +853,7 @@ Ajax ==== **ajax_response, \*** |results| - When the ``elgg/Ajax`` AMD module is used, this event gives access to the response object + When the ``elgg/Ajax`` module is used, this event gives access to the response object (``\Elgg\Services\AjaxResponse``) so it can be altered/extended. The event type depends on the method call: @@ -1078,9 +1069,6 @@ Other **classes, icon** |results| Can be used to filter CSS classes applied to icon glyphs. By default, Elgg uses FontAwesome. Plugins can use this event to switch to a different font family and remap icon classes. - -**config, amd** |results| - Filter the AMD config for the requirejs library. **entity:icon:sizes, ** |results| Triggered by ``elgg_get_icon_sizes()`` and sets entity type/subtype specific icon sizes. @@ -1145,14 +1133,15 @@ Other * * @param \Elgg\Event $event 'entity:icon:url', 'user' * - * @return string + * @return string|null */ - function gravatar_icon_handler(\Elgg\Event $event) { + function gravatar_icon_handler(\Elgg\Event $event): ?string { $entity = $event->getEntityParam(); - + $size = $event->getParam('size'); + // Allow users to upload avatars - if ($entity->icontime) { - return $url; + if ($entity->hasIcon($size)) { + return null; } // Generate gravatar hash for user email @@ -1169,7 +1158,7 @@ Other } // Produce URL used to retrieve icon - return "http://www.gravatar.com/avatar/$hash?s=$size"; + return "https://www.gravatar.com/avatar/{$hash}?s={$size}"; } **entity::url, ** |results| diff --git a/docs/guides/i18n.rst b/docs/guides/i18n.rst index c067419fa1f..b8f2c5b714d 100644 --- a/docs/guides/i18n.rst +++ b/docs/guides/i18n.rst @@ -93,12 +93,10 @@ Javascript API This function is like ``elgg_echo`` in PHP. -Client-side translations are loaded asynchronously. Ensure translations are available by requiring the "elgg" AMD module: +Client-side translations are loaded asynchronously. Ensure translations are available by requiring the "elgg/i18n" module: .. code-block:: js - define(['elgg/i18n'], function(i18n) { - alert(i18n.echo('my_key')); - }); - -Translations are also available after the ``init, system`` JavaScript event. + import i18n from 'elgg/i18n'; + + alert(i18n.echo('my_key')); diff --git a/docs/guides/javascript.rst b/docs/guides/javascript.rst index 14a5e03b1e4..63ca155bc3a 100644 --- a/docs/guides/javascript.rst +++ b/docs/guides/javascript.rst @@ -5,14 +5,12 @@ JavaScript :local: :depth: 2 -AMD -=== +JavaScript Modules +================== -Developers should use the `AMD (Asynchronous Module -Definition) `_ standard for writing JavaScript code in Elgg. +Developers should use the browser native `ECMAScript modules `_ for writing JavaScript code in Elgg. -Here we'll describe making and executing AMD modules. The RequireJS documentation for -`defining modules `_ may also be of use. +Here we'll describe making and importing these modules in Elgg. Executing a module in the current page -------------------------------------- @@ -22,54 +20,26 @@ Telling Elgg to load an existing module in the current page is easy: .. code-block:: php getValue(); - - // this will be cached client-side $value['myplugin']['api'] = elgg_get_site_url() . 'myplugin-api'; $value['myplugin']['key'] = 'none'; - return $value; - } - - function myplugin_config_page(\Elgg\Event $event) { $user = elgg_get_logged_in_user_entity(); - if (!$user) { - return; + if ($user) { + $value['myplugin']['key'] = $user->myplugin_api_key; } - $value = $event->getValue(); - - $value['myplugin']['key'] = $user->myplugin_api_key; - return $value; } - elgg_register_event_handler('elgg.data', 'site', 'myplugin_config_site'); elgg_register_event_handler('elgg.data', 'page', 'myplugin_config_page'); .. code-block:: js @@ -123,43 +81,6 @@ Let's pass some data to a module: // ... }); -.. note:: - - In ``elgg.data``, page data overrides site data. Also note ``json_encode()`` is used to copy - data client-side, so the data must be JSON-encodable. - -Making a config module -^^^^^^^^^^^^^^^^^^^^^^ - -You can use a PHP-based module to pass values from the server. To make the module ``myplugin/settings``, -create the view file ``views/default/myplugin/settings.js.php`` (note the double extension -``.js.php``). - -.. code-block:: php - - elgg_get_site_url() . 'myplugin-api', - 'key' => null, - ]; - ?> - define(); - -You must also manually register the view as an external resource: - -.. code-block:: php - - ['jquery'], - 'exports' => 'jQuery.fn.ajaxForm', - ]); - -When this is requested client-side: - -#. The jQuery module is loaded, as it's marked as a dependency. -#. ``https://elgg.example.org/cache/125235034/views/default/jquery.form.js`` is loaded and executed. -#. The value of ``window.jQuery.fn.ajaxForm`` is returned by the module. - -.. warning:: Calls to ``elgg_define_js()`` must be in an ``init, system`` event handler. - -Some things to note -^^^^^^^^^^^^^^^^^^^ - -#. Return the value of the module instead of adding to a global variable. -#. Static (.js,.css,etc.) files are automatically minified and cached by Elgg's simplecache system. -#. The configuration is also cached in simplecache, and should not rely on user-specific values - like ``elgg_get_current_language()``. - Modules provided with Elgg ========================== @@ -405,7 +294,7 @@ attribute and defining target module with a ``href`` (or ``data-href``) attribut ]); // Button with custom positioning of the popup - elgg_require_js('elgg/popup'); + elgg_import_esm('elgg/popup'); echo elgg_format_element('button', [ 'class' => 'elgg-button elgg-button-submit elgg-popup', 'text' => 'Show popup', @@ -480,8 +369,8 @@ Plugins that load a widget layout via Ajax should initialize via this module: .. code-block:: js - require(['elgg/widgets'], function (widgets) { - widgets.init(); + import('elgg/widgets').then((widgets) => { + widgets.default.init(); }); Module ``elgg/lightbox`` @@ -533,12 +422,12 @@ To support gallery sets (via ``rel`` attribute), you need to bind colorbox direc .. code-block:: js - require(['elgg/lightbox'], function(lightbox) { + import('elgg/lightbox').then((lightbox) => { var options = { photo: true, width: 500 }; - lightbox.bind('a[rel="my-gallery"]', options, false); // 3rd attribute ensures binding is done without proxies + lightbox.default.bind('a[rel="my-gallery"]', options, false); // 3rd attribute ensures binding is done without proxies }); You can also resize the lightbox programmatically if needed: @@ -570,19 +459,19 @@ Note that WYSIWYG will be automatically attached to all instances of ``.elgg-inp .. code-block:: js - require(['elgg/ckeditor'], function (elggCKEditor) { - elggCKEditor.bind('#my-text-area'); + import('elgg/ckeditor').then((elggCKEditor) => { + elggCKEditor.default.bind('#my-text-area'); // Toggle CKEditor - elggCKEditor.toggle('#my-text-area'); + elggCKEditor.default.toggle('#my-text-area'); // Focus on CKEditor input - elggCKEditor.focus('#my-text-area'); + elggCKEditor.default.focus('#my-text-area'); // or $('#my-text-area').trigger('focus'); // Reset CKEditor input - elggCKEditor.reset('#my-text-area'); + elggCKEditor.default.reset('#my-text-area'); // or $('#my-text-area').trigger('reset'); @@ -597,17 +486,15 @@ Inline tabs component fires an ``open`` event whenever a tabs is open and, in ca .. code-block:: js // Add custom animation to tab content - require(['jquery'], function($) { - $(document).on('open', '.theme-sandbox-tab-callback', function() { - $(this).find('a').text('Clicked!'); - $(this).data('target').hide().show('slide', { - duration: 2000, - direction: 'right', - complete: function() { - alert('Thank you for clicking. We hope you enjoyed the show!'); - $(this).css('display', ''); // .show() adds display property - } - }); + $(document).on('open', '.theme-sandbox-tab-callback', function() { + $(this).find('a').text('Clicked!'); + $(this).data('target').hide().show('slide', { + duration: 2000, + direction: 'right', + complete: function() { + alert('Thank you for clicking. We hope you enjoyed the show!'); + $(this).css('display', ''); // .show() adds display property + } }); }); diff --git a/docs/guides/menus.rst b/docs/guides/menus.rst index 95084c95fda..772a94585e6 100644 --- a/docs/guides/menus.rst +++ b/docs/guides/menus.rst @@ -44,7 +44,7 @@ Admin menu You can also register ``page`` menu items to the admin backend menu. When registering for the admin menu you can set the context of the menu items to ``admin`` so the menu items only show in the ``admin`` context. There are 3 default sections to add your menu items to. - - ``administer`` for daily tasks, usermanagement and other actionable tasks + - ``administer`` for daily tasks, user management and other actionable tasks - ``configure`` for settings, configuration and utilities that configure stuff - ``information`` for statistics, overview of information or status @@ -52,6 +52,25 @@ the menu items to ``admin`` so the menu items only show in the ``admin`` context Advanced usage ============== +Headers +------- + +For accessibility reasons each menu will get an ``aria-label`` which defaults to the menu name, but can be translated by making sure +the language key ``menu::header`` is available. + +It's also possible to show menu section headers by setting ``show_section_headers`` to ``true`` in ``elgg_view_menu()`` + +.. code-block:: php + + echo elgg_view_menu('my_menu', [ + 'show_section_headers' => true, + ]); + +The headers have a magic language key available ``menu::header:
`` in order to be able to translate the headers. + +Events +------ + You can get more control over menus by using :doc:`events ` and the public methods provided by the ``ElggMenuItem`` class. @@ -280,7 +299,7 @@ JavaScript ========== It is common that menu items rely on JavaScript. You can bind client-side events -to menu items by placing your JavaScript into AMD module and defining the +to menu items by placing your JavaScript into a module and defining the requirement during the registration. .. code-block:: php @@ -296,12 +315,10 @@ requirement during the registration. .. code-block:: js - // in navigation/menu/item/hide_on_click.js - define(function(require) { - var $ = require('jquery'); + // in navigation/menu/item/hide_on_click.mjs + import 'jquery'; - $(document).on('click', '.hide-on-click', function(e) { - e.preventDefault(); - $(this).hide(); - }); + $(document).on('click', '.hide-on-click', function(e) { + e.preventDefault(); + $(this).hide(); }); diff --git a/docs/guides/plugins.rst b/docs/guides/plugins.rst index 478d8ddcd64..72f351ce4a9 100644 --- a/docs/guides/plugins.rst +++ b/docs/guides/plugins.rst @@ -169,9 +169,6 @@ Besides magic constants like ``__DIR__``, its return value should not change. Th ], 'view_extensions' => [ - 'elgg.js' => [ - 'bookmarks.js' => [], - ], 'page/components/list' => [ 'list/extension' => [ 'priority' => 600, @@ -294,13 +291,12 @@ Important parts in the ``composer.json`` file are: - ``name``: the name of your plugin, keep this inline with the name of your plugin folder to ensure correct installation - ``type``: this will tell Composer where to install your plugin, ALWAYS keep this as ``elgg-plugin`` -- ``require``: the ``composer/installers`` requirement is to make sure Composer knows where to install your plugin -As a suggestion, include a ``conflict`` rule with any Elgg version below your mininal required version, this will help prevent the accidental -installation of your plugin on an incompatible Elgg version. +As a suggestion, include a ``conflict`` rule with any Elgg version below your minimal required version, this will help +prevent the accidental installation of your plugin on an incompatible Elgg version. -After adding a ``composer.json`` file to your plugin project, you need to register your project on `Packagist`_ in order for other people to be able to -install your plugin. +After adding a ``composer.json`` file to your plugin project, you need to register your project on `Packagist`_ in +order for other people to be able to install your plugin. Tests ===== diff --git a/docs/guides/plugins/dependencies.rst b/docs/guides/plugins/dependencies.rst index e2df107c382..fa60044b165 100644 --- a/docs/guides/plugins/dependencies.rst +++ b/docs/guides/plugins/dependencies.rst @@ -24,7 +24,7 @@ Add a section in your ``composer.json`` as described in de `Composer JSON refere { "require": { - "php": ">8.0", + "php": ">8.1", "ext-json": "*" } } diff --git a/docs/guides/restore.rst b/docs/guides/restore.rst new file mode 100644 index 00000000000..8181b028eca --- /dev/null +++ b/docs/guides/restore.rst @@ -0,0 +1,171 @@ +Restore capability +################## + +.. contents:: Contents + :local: + :depth: 2 + +As of Elgg 6.0 it's possible to set the ``restorable`` :doc:`capability ` on an ``ElggEntity``. +Enabling this capability will mark an entity as deleted in the database when the ``ElggEntity::delete()`` function is called. +The entity will then no longer show up in listings or work when viewing it directly. + +Site setting +------------ + +A site administrator has the option to enable/disable all restore features. By default this feature is disabled. This +means that even if an entity has the capability ``restorable`` it will always be permanently removed from the database. + +Registration +------------ + +Just like any other entity capability you can enable the ``restorable`` capability in the ``elgg-plugin.php`` + +.. code-block:: php + + 'entities' => [ + [ + 'type' => 'object', + 'subtype' => 'my_custom_subtype', + 'capabilities' => [ + 'restorable' => true, + ], + ], + ] + +Entity menu +----------- + +By default a menu item is added to the entity menu which allows a user to delete the entity when the user has the rights +to do so. + +If an entity has the ``restorable`` capability this menu item will be replaced with a menu item which will mark the entity +as deleted. + +.. note:: + + When the site administrator hasn't enabled the feature no menu items will be replaced. + +.. note:: + + There are 2 generic actions to help developers in case they need to add a delete link somewhere. + + - ``entity/delete``: this will permanently delete the entity from the database, requires a ``guid`` to be submitted to the action + - ``entity/trash``: this will mark the entity as deleted in the database, requires a ``guid`` to be submitted to the action + +View deleted items +------------------ + +Once an entity has been marked as deleted it'll no longer show up in the normal functionality of your Elgg website. + +In order for a user to see the entities that have been deleted there is a link in the user settings to a list of all +deleted items that are owned by the given user. + +Group owners also have the ability to see the deleted content from their group. This is accessible from the group profile +page. The list will show all deleted content contained by their group. + +.. note:: + + The list will only show the deleted entities with the ``restorable`` capability. For example when a blog has been + deleted which also has comments only the blog will show up in the deleted list of the owner (and in the deleted + list of the group if the blog was posted in a group). + + The comments will not show up in any list of deleted items. + +Custom views +============ + +When a developer needs to have a custom view of a deleted item a view ``trash//`` can be made +which will get provided the deleted entity in ``$vars['entity']``. As a fallback ``trash//default`` will be +tried and ultimately ``trash/entity/default`` which is provided by Elgg core. + +Different sub-elements can be found in the views ``trash/elements/*``. + +.. note:: + + When making a custom view for an entity make sure it doesn't include links to the deleted entity as that link will + not work. Also keep in mind other links to entities that could have been deleted. + +Restore a deleted item +---------------------- + +From the deleted list the user (or group owner) has the ability to restore the deleted item to it's original state. If +the entity was contained in a group which was removed, the user has the option to restore the entity to a different container. + +Events +------ + +When an entity is being marked as deleted there is an :ref:`event sequence` ``'trash', ''`` +with which a developer can program additional action or logic. + +ElggEntity functions +-------------------- + +There are 3 functions in an ``ElggEntity`` related to the deletion of that entity: + +- ``public function delete(bool $recursive = true, bool $persistent = null): bool`` +- ``protected function persistentDelete(bool $recursive = true): bool`` +- ``protected function trash(bool $recursive = true): bool`` +- ``public function isDeleted(): bool`` + +Function: delete +================ + +This is the only public function to delete an entity. The ``$recursive`` parameter will determine whether or not other entities +which have this entity as it's owner or container will also be deleted (default ``true``). + +The ``$persistent`` parameter can force a persistent removal from the database or it being marked as deleted. The default +value is ``null`` which means the ``restorable`` capability will be checked. + +.. warning:: + + It's not recommended that a developer overrules this function as the developer will have to handle part of the logic + of determining the correct value of the ``$persistent`` parameter. + +Function: persistentDelete +========================== + +This function is called when the ``$persistent`` parameter is ``true`` in the ``delete()`` function. This function must +handle cases where the entity is permanently removed from the database. An example of when a developer would overrule this +function is an ``ElggFile`` where the physical file on disk needs to be removed when the entity is removed from the database, +but the physical file shouldn't be removed from the disk when the entity is only marked as deleted in the database. + +This will trigger the ``'delete', ''`` event sequence. + +Function: trash +=============== + +This function is called when the ``$persistent`` parameter is ``false`` in the ``delete()`` function. This function must +handle cases where the entity is marked as deleted in the database. + +This will trigger the ``'trash', ''`` event sequence. + +Function: isDeleted +=================== + +To check if an entity is marked as deleted. + +Show deleted items +------------------ + +When a developer needs to be sure to include deleted entities when fetching/listing entities the code needs to be wrapped +in an ``elgg_call()`` with the flag ``ELGG_SHOW_DELETED_ENTITIES``. + +The same applies when the developer needs to be sure to exclude all deleted items set the flag ``ELGG_HIDE_DELETED_ENTITIES``. + +Cleanup of deleted entities +--------------------------- + +In order to cleanup the database of the deleted entities a :doc:`cron job` runs every hour. It'll cleanup +all the deleted entities that have been removed when a retention period has passed. A site administrator can set this +retention period (default: 30 days). + +In order to not put too much stress on the system the cron job will only run for a maximum of 5 minutes per hour. Entities +that couldn't be removed in that period will be removed in the next period. The oldest deleted entity (by when the entity +was deleted) will be removed first. + +More information +---------------- + +.. seealso:: + + Check out the :doc:`/guides/capabilities` documentation \ No newline at end of file diff --git a/docs/guides/search.rst b/docs/guides/search.rst index 3623859d7ce..e666bd41724 100644 --- a/docs/guides/search.rst +++ b/docs/guides/search.rst @@ -183,7 +183,7 @@ Elgg core only supports entity search. You can implement custom searches, e.g. u Autocomplete and livesearch endpoint ------------------------------------ -Core provides a JSON endpoint for searching users and groups. These endpoints are used by ``input/autocomplete`` and ``input/userpicker`` views. +Core provides a JSON endpoint for searching users and groups. These endpoints are used by ``input/autocomplete`` and ``input/entitypicker`` views. .. code-block:: php diff --git a/docs/guides/views/foot-vs-footer.rst b/docs/guides/views/foot-vs-footer.rst index ace5d3a044c..2522da6facb 100644 --- a/docs/guides/views/foot-vs-footer.rst +++ b/docs/guides/views/foot-vs-footer.rst @@ -13,4 +13,5 @@ Page/elements/foot vs footer Its content is visible to end users and usually where you would put a sitemap or other secondary global navigation, copyright info, powered by elgg, etc. -``page/elements/foot`` is inserted just before the ending ```` tag and is mostly meant as a place to insert scripts that don't already work with ``elgg_require_js('amd/module');``. In other words, you should never override this view and probably don't need to extend it either. Just use the ``elgg_*_js`` functions instead +``page/elements/foot`` is inserted just before the ending ```` tag and is mostly meant as a place to insert scripts that don't already work with ``elgg_import_esm('my/module');``. +In other words, you should never override this view and probably don't need to extend it either. Just use the ``elgg_*_esm`` functions instead diff --git a/docs/guides/web-services/hmac.rst b/docs/guides/web-services/hmac.rst index cdfdc866356..8b373401e1a 100644 --- a/docs/guides/web-services/hmac.rst +++ b/docs/guides/web-services/hmac.rst @@ -28,7 +28,7 @@ If you are sending POST data you must also send: - **X-Elgg-posthash** - The hash of the POST data - **X-Elgg-posthash-algo** - The algorithm used to produce the POST data hash -- **Content-type** - The content type of the data you are sending (if in doubt use ``application/octet-stream``) +- **Content-type** - The content type of the data you are sending (this can be ``application/x-www-form-urlencoded`` or ``multipart/form-data``) - **Content-Length** - The length in bytes of your POST data Elgg provides a sample API client that implements this HMAC signature: ``\Elgg\WebServices\ElggApiClient``. It serves as a good @@ -41,13 +41,23 @@ Supported hashing algorithms - ``sha1``: fast however less secure - ``md5``: weak and will be removed in the future -Post hash calculation +POST hash calculation --------------------- -The post hash needs to be calculated over all the post data using one of the supported hashing algorithms. -The result of the hashing needs to be reported in the ``X-Elgg-posthash`` header and the used hashing algorithm must be +When sending the POST data as ``Content-Type: application/x-www-form-urlencoded;`` the post hash needs to be calculated +over all the post data using one of the supported hashing algorithms. + +When sending the POST data as ``Content-Type: multipart/form-data;`` the post hash needs to be calculated +over an empty string. + +The result of the hashing needs to be reported in the ``X-Elgg-posthash`` header and the used hashing algorithm must be reported in the ``X-Elgg-posthash-algo`` header. +.. warning:: + + Since the POST hash isn't calculated when using ``Content-Type: multipart/form-data;`` only use this when calling + APIs that need an file input. + HMAC hash calculation --------------------- @@ -60,7 +70,7 @@ of the supported hashing algorithms: 4. the url query string (for example ``method=test.test&foo=bar``) 5. when the request is a POST add the ``posthash`` as reported in the ``X-Elgg-posthash`` header -The resulting string needs to be base64 encoded and then url encoded and be repoted in the ``X-Elgg-hmac`` header. +The resulting string needs to be base64 encoded and then url encoded and be reported in the ``X-Elgg-hmac`` header. The used hashing algorithm needs to be reported in the ``X-Elgg-hmac-algo``. Hashing cache diff --git a/docs/guides/web-services/result.rst b/docs/guides/web-services/result.rst index f48279497e7..6100096cada 100644 --- a/docs/guides/web-services/result.rst +++ b/docs/guides/web-services/result.rst @@ -19,7 +19,7 @@ A successful API result looks like this: Depending on the API call ``result`` can contain any type of content (string, number, array, object, etc.). -An example of a numberic result (for example a user count): +An example of a numeric result (for example a user count): .. code-block:: json @@ -72,5 +72,5 @@ on the error message to know what went wrong. .. note:: ``result`` and ``message`` can contain messages in different languages. This is depending on the user language when using - user authenticated API calls or the site langauge for other API calls. Keep in mind that the language can change, eighter by the user + user authenticated API calls or the site language for other API calls. Keep in mind that the language can change, eighter by the user or by a site administrator for the site language. diff --git a/docs/index.rst b/docs/index.rst index 045470511df..bb95900f4d6 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -14,7 +14,7 @@ Features * **Cacheable system of static assets** that allows themes and plugins to serve images, stylesheets, fonts and scripts bypassing the engine * **User authentication** is powered by pluggable auth modules, which allow applications to implement custom authentication protocols * **Security** is ensured by built-in anti CSRF validation, strict XSS filters, HMAC signatures, latest cryptographic approaches to password hashing - * **Client-side API** powered by asynchronous JavaScript modules via RequireJS and a build-in Ajax service for easy communication with the server + * **Client-side API** powered by asynchronous ES modules and a built-in Ajax service for easy communication with the server * **Flexible entity system** that allows applications to prototype new types of content and user interactions * **Opinionated data model** with a consolidated API layer that allows the developers to easily interface with the database * **Access control system** that allows applications to build granular content access policies, as well as create private networks and intranets @@ -30,7 +30,7 @@ Under the hood: * Elgg is a modular OOP framework that is driven by DI services * NGINX or Apache compatible * Symfony2 HTTP Foundation handles requests and responses - * RequireJS handles AMD + * modular javascript with ECMAScript modules * Laminas Mail handles outgoing email * htmLawed XSS filters * DBAL diff --git a/docs/info/composer.json b/docs/info/composer.json index ac3f1a030c5..d25d3511bbd 100644 --- a/docs/info/composer.json +++ b/docs/info/composer.json @@ -8,9 +8,6 @@ "source": "URL to your code repository", "issues": "URL to your issue tracker" }, - "require": { - "composer/installers": "^1.0.8" - }, "conflict": { "elgg/elgg": "<3.0" } diff --git a/docs/intro/development.rst b/docs/intro/development.rst index 054e789283f..b17d9473b14 100644 --- a/docs/intro/development.rst +++ b/docs/intro/development.rst @@ -9,7 +9,7 @@ See the :doc:`/guides/index` for tutorials or the :doc:`/design/index` for in-de Database and Persistence ======================== -Elgg uses MySQL 5.7 or higher for data persistence, and maps database values into Entities (a +Elgg uses MySQL for data persistence, and maps database values into Entities (a representation of an atomic unit of information) and Extenders (additional information and descriptions about Entities). Elgg supports additional information such as relationships between Entities, activity streams, and various types of settings. @@ -42,10 +42,7 @@ view. JavaScript ========== -Elgg uses an AMD-compatible JavaScript system provided by RequireJs. Bundled with Elgg are jQuery, jQuery UI, -jQuery Form, and jQuery UI Autocomplete. - -Plugins can load their own JS libs. +Elgg uses native ES modules. Plugins can register their own modules or load their own JS libs. Internationalization ==================== @@ -61,7 +58,7 @@ Elgg uses two caches to improve performance: a system cache and SimpleCache. =================== The use of 3rd party libraries in Elgg is managed by using `Composer`_ dependencies. Examples of 3rd party libraries are -jQuery, RequireJs or Laminas mail. +jQuery, CSS Crush or Laminas mail. To get a list of all the Elgg dependencies check out the `Packagist`_ page for Elgg. diff --git a/docs/intro/elgg-cli.rst b/docs/intro/elgg-cli.rst index 3e4a4a045c2..390dc881233 100644 --- a/docs/intro/elgg-cli.rst +++ b/docs/intro/elgg-cli.rst @@ -42,7 +42,7 @@ Available commands vendor/bin/elgg-cli install [--no-plugins] [-c|--config CONFIG] # Seed the database with fake entities - # limit: (int) number of items to seed + # limit: (int) number of items to seed (will be asked interactively for each seeder unless the -n/--no-interaction is used or only one type is seeded) # type: (string) only seed given entity type # create_since: (string) a compatible PHP date/time string to set the lower bound entity time created (eg, '-5 months') # create_until: (string) a compatible PHP date/time string to set the upper bound entity time created (eg, 'yesterday') diff --git a/docs/intro/install.rst b/docs/intro/install.rst index 834d2d2d403..68f086a3df8 100644 --- a/docs/intro/install.rst +++ b/docs/intro/install.rst @@ -10,15 +10,15 @@ Get your own instance of Elgg running in no time. Requirements ============ -- MySQL 5.7+ or MariaDB 10.3+ -- PHP 8.0+ with the following extensions: +- MySQL 8.0+ or MariaDB 10.6+ +- PHP 8.1+ with the following extensions: - GD (for graphics processing) - - PDO (for database connection) + - INTL (for internationalization) - JSON (for AJAX responses, etc.) + - PDO (for database connection) - XML (for xml resource and web services, etc.) - `Multibyte String support`_ (for i18n) - - (optional) intl (for i18n) - Proper configuration and ability to send email through an MTA - Web server with support for URL rewriting diff --git a/docs/locale/fr/LC_MESSAGES/admin.mo b/docs/locale/fr/LC_MESSAGES/admin.mo index e6530546e6b..c25fd6180c8 100644 Binary files a/docs/locale/fr/LC_MESSAGES/admin.mo and b/docs/locale/fr/LC_MESSAGES/admin.mo differ diff --git a/docs/locale/fr/LC_MESSAGES/admin.po b/docs/locale/fr/LC_MESSAGES/admin.po index cf808a61b23..24a5e17fc25 100644 --- a/docs/locale/fr/LC_MESSAGES/admin.po +++ b/docs/locale/fr/LC_MESSAGES/admin.po @@ -12,7 +12,7 @@ msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-31 15:46+0200\n" +"POT-Creation-Date: 2023-12-15 13:56+0100\n" "PO-Revision-Date: 2023-04-05 07:42+0000\n" "Last-Translator: Florian DANIEL aka Facyla , 2023\n" "Language-Team: French (https://app.transifex.com/elgg/teams/11337/fr/)\n" @@ -364,7 +364,7 @@ msgstr "une autre structure de répertoire avec pour contenu :" #: ../../admin/backup-restore.rst:127 msgid "``/home/userx/public_html``" -msgstr "\"/home/userx/public_html\"" +msgstr "``/home/userx/public_html``" #: ../../admin/backup-restore.rst:128 msgid "``/home/userx/elggdata``" @@ -2327,7 +2327,7 @@ msgstr "" "Dé-commentez et renseignez les sections suivantes dans le fichier " "``settings.php``" -#: ../../admin/performance.rst:195 +#: ../../admin/performance.rst:201 msgid "" "Optionaly if you run multiple Elgg installations but use ony one Memcache " "server, you may want to add a namespace prefix. In order to do this, " @@ -2337,21 +2337,21 @@ msgstr "" "n'utilisez qu'un seul serveur Memcache, vous pouvez vouloir ajouter un " "préfixe d'espace de nom. Afin de faire cela, dé-commentez la ligne suivante" -#: ../../admin/performance.rst:203 +#: ../../admin/performance.rst:209 msgid "Squid" msgstr "Squid" -#: ../../admin/performance.rst:205 +#: ../../admin/performance.rst:211 msgid "We have had good results by using `Squid`_ to cache images for us." msgstr "" "Nous avons obtenu de bons résultats en utilisant `Squid`_ pour mettre en " "cache les images." -#: ../../admin/performance.rst:211 +#: ../../admin/performance.rst:217 msgid "Bytecode caching" msgstr "Mise en cache du code exécutable - \"bytecode\"" -#: ../../admin/performance.rst:213 +#: ../../admin/performance.rst:219 msgid "" "There are numerous PHP code caches available on the market. These speed up " "your site by caching the compiled byte code from your script meaning that " @@ -2362,11 +2362,11 @@ msgstr "" "script, ce qui signifie que votre serveur n'a pas à compiler le code PHP à " "chaque fois qu'il est exécuté." -#: ../../admin/performance.rst:219 +#: ../../admin/performance.rst:225 msgid "Direct file serving" msgstr "Servir directement les fichiers" -#: ../../admin/performance.rst:221 +#: ../../admin/performance.rst:227 msgid "" "If your server can be configured to support the X-Sendfile or X-Accel " "headers, you can configure it to be used in ``settings.php``. This allows " @@ -2378,11 +2378,11 @@ msgstr "" "Ceci permet à votre serveur web de diffuser directement les fichiers au " "client au lieu d'utiliser la fonction PHP ``readfile()``." -#: ../../admin/performance.rst:226 +#: ../../admin/performance.rst:232 msgid "Composer Autoloader Optimization" msgstr "Optimisation de l'Autoloader de Composer" -#: ../../admin/performance.rst:228 +#: ../../admin/performance.rst:234 msgid "" "The Composer autoloader is responsible for loading classes provided by " "dependencies of Elgg. The way the autoloader works is it searches for a " @@ -2395,7 +2395,7 @@ msgstr "" "installées. Bien qu’il s’agisse principalement d’un processus rapide, il " "peut être optimisé." -#: ../../admin/performance.rst:231 +#: ../../admin/performance.rst:237 msgid "" "You can optimize the autoloader 2 different ways. The first is in the " "commandline, the other is in the ``composer.json`` of your project." @@ -2404,7 +2404,7 @@ msgstr "" "via la ligne de commande, l’autre est d'utiliser le fichier " "``composer.json`` de votre projet." -#: ../../admin/performance.rst:233 +#: ../../admin/performance.rst:239 msgid "" "If you want to optimize the autoloader using the commandline use the ``-o`` " "flag. The disadvantage is you have to add the ``-o`` flag every time you run" @@ -2414,7 +2414,7 @@ msgstr "" "commande, utilisez le drapeau ``-o``. L’inconvénient est que vous devez " "ajouter le drapeau ``-o`` à chaque fois que vous exécutez Composer." -#: ../../admin/performance.rst:244 +#: ../../admin/performance.rst:250 msgid "" "The second option is to add the optimization to your ``composer.json`` file," " that way you never forget it." @@ -2422,7 +2422,7 @@ msgstr "" "La deuxième option consiste à ajouter l’optimisation à votre fichier " "``composer.json``, de cette façon vous ne l’oubliez jamais." -#: ../../admin/performance.rst:257 +#: ../../admin/performance.rst:263 msgid "" "Check out the `Autoloader Optimization`__ page for more information about " "how to optimize the Composer autoloader." @@ -2431,7 +2431,7 @@ msgstr "" "Optimization`__ pour plus d’informations sur l’optimisation du chargeur " "automatique Composer." -#: ../../admin/performance.rst:263 +#: ../../admin/performance.rst:269 msgid "" "As of Elgg 3.0 all the `downloads`__ of Elgg from the website have the " "optimized autoloader." @@ -2439,11 +2439,11 @@ msgstr "" "À partir de Elgg 3.0 tous les `téléchargements`__ de Elgg à partir du site " "disposent du chargeur automatique optimisé." -#: ../../admin/performance.rst:268 +#: ../../admin/performance.rst:274 msgid "Hosting" msgstr "Hébergement" -#: ../../admin/performance.rst:270 +#: ../../admin/performance.rst:276 msgid "" "Don't expect to run a site catering for millions of users on a cheap shared " "host. You will need to have your own host hardware and access over the " @@ -2454,11 +2454,11 @@ msgstr "" "d'hébergement et d'avoir la main sur la configuration, ainsi que de beaucoup" " de bande passante et de mémoire disponibles." -#: ../../admin/performance.rst:275 +#: ../../admin/performance.rst:281 msgid "Memory, CPU and bandwidth" msgstr "Mémoire, CPU et bande passante" -#: ../../admin/performance.rst:277 +#: ../../admin/performance.rst:283 msgid "" "Due to the nature of caching, all caching solutions will require memory. It " "is a fairly cheap return to throw memory and CPU at the problem." @@ -2467,7 +2467,7 @@ msgstr "" "auront besoin de mémoire. C'est un investissement plutôt économique " "d'augmenter la mémoire et le CPU." -#: ../../admin/performance.rst:280 +#: ../../admin/performance.rst:286 msgid "" "On advanced hardware it is likely that bandwidth is going to be your " "bottleneck before the server itself. Ensure that your host can support the " @@ -2478,11 +2478,11 @@ msgstr "" "Assurez-vous que votre hébergement peut supporter le trafic que vous " "attendez." -#: ../../admin/performance.rst:284 +#: ../../admin/performance.rst:290 msgid "Configuration" msgstr "Configuration" -#: ../../admin/performance.rst:286 +#: ../../admin/performance.rst:292 msgid "" "Lastly, take a look at your configuration as there are a few gotchas that " "can catch people." @@ -2490,7 +2490,7 @@ msgstr "" "Enfin, jetez un coup d’œil à votre configuration car il y a quelques points " "d'attention qui peuvent surprendre les gens." -#: ../../admin/performance.rst:288 +#: ../../admin/performance.rst:294 msgid "" "For example, out of the box, Apache can handle quite a high load. However, " "most distros of Linux come with mysql configured for small sites. This can " @@ -2502,11 +2502,11 @@ msgstr "" "de petits sites. Ceci peut peut donner lieu à des processus Apache bloqués " "qui attendent de pouvoir parler à un processus MySQL très surchargé." -#: ../../admin/performance.rst:293 +#: ../../admin/performance.rst:299 msgid "Check for poorly-behaved plugins" msgstr "Vérifiez les plugins ayant un mauvais comportement" -#: ../../admin/performance.rst:295 +#: ../../admin/performance.rst:301 msgid "" "Plugins can be programmed in a very naive way and this can cause your whole " "site to feel slow." @@ -2514,7 +2514,7 @@ msgstr "" "Des plugins peuvent être développés d'une manière très naïve et ceci peut " "ralentir l'ensemble du site." -#: ../../admin/performance.rst:297 +#: ../../admin/performance.rst:303 msgid "" "Try disabling some plugins to see if that noticeably improves performance. " "Once you've found a likely offender, go to the original plugin author and " @@ -2525,11 +2525,11 @@ msgstr "" "potentiel, rendez-vous sur la page de l'auteur du plugin et signalez vos " "résultats." -#: ../../admin/performance.rst:301 +#: ../../admin/performance.rst:307 msgid "Use client-rendered HTML" msgstr "Utilisez du HTML rendu côté client" -#: ../../admin/performance.rst:303 +#: ../../admin/performance.rst:309 msgid "" "We've found that at a certain point, much of the time spent on the server is" " simply building the HTML of the page with Elgg's views system." @@ -2538,7 +2538,7 @@ msgstr "" "sur le serveur est simplement le temps de construction du HTML de la page " "avec le système de vues de Elgg." -#: ../../admin/performance.rst:306 +#: ../../admin/performance.rst:312 msgid "" "It's very difficult to cache the output of templates since they can " "generally take arbitrary inputs. Instead of trying to cache the HTML output " @@ -2556,7 +2556,7 @@ msgstr "" "faire le travail de générer le résultat en appliquant des données JSON à ces" " modèles." -#: ../../admin/performance.rst:311 +#: ../../admin/performance.rst:317 msgid "" "This can be very effective, but has the downside of being significant extra " "development cost. The Elgg team is looking to integrate this strategy into " diff --git a/docs/locale/fr/LC_MESSAGES/appendix.mo b/docs/locale/fr/LC_MESSAGES/appendix.mo index 1e44f831efb..a30fc4f3c4a 100644 Binary files a/docs/locale/fr/LC_MESSAGES/appendix.mo and b/docs/locale/fr/LC_MESSAGES/appendix.mo differ diff --git a/docs/locale/fr/LC_MESSAGES/appendix.po b/docs/locale/fr/LC_MESSAGES/appendix.po index 3cba9e1775b..277bf2c8b8d 100644 --- a/docs/locale/fr/LC_MESSAGES/appendix.po +++ b/docs/locale/fr/LC_MESSAGES/appendix.po @@ -12,7 +12,7 @@ msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-31 15:46+0200\n" +"POT-Creation-Date: 2023-12-15 13:56+0100\n" "PO-Revision-Date: 2023-04-05 07:42+0000\n" "Last-Translator: Florian DANIEL aka Facyla , 2023\n" "Language-Team: French (https://app.transifex.com/elgg/teams/11337/fr/)\n" @@ -49,6 +49,7 @@ msgstr "Ci-dessous quelques questions fréquemment posées à propos de Elgg." #: ../../appendix/upgrade-notes/4.1-to-4.2.rst:6 #: ../../appendix/upgrade-notes/4.2-to-4.3.rst:6 #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:6 +#: ../../appendix/upgrade-notes/5.0-to-5.1.rst:6 msgid "Contents" msgstr "Contenu" @@ -1397,6 +1398,12 @@ msgid "" "with the htmLawed filtering code as a plugin. Developers can drop in any " "additional or replacement filtering code as a plugin." msgstr "" +"Le filtrage est effectué via la fonction ``elgg_sanitize_input()``. Cette " +"fonction récupère une chaîne et renvoie une chaîne filtrée. Elle déclenche " +"un :doc:`event ` *sanitize*, *input*. Par défaut, Elgg est " +"livré avec la bibliothèque de filtrage htmLawed sous forme de plugin. Les " +"développeurs peuvent ajouter n’importe quel code de filtrage supplémentaire " +"ou de remplacement via un plugin." #: ../../appendix/faqs/security.rst:23 ../../appendix/faqs/security.rst:23 msgid "" @@ -2184,6 +2191,8 @@ msgid "" "All event callbacks should never be called directly but only be called by " "triggering the event." msgstr "" +"Tous les rappels d'événement ne doivent jamais être appelés directement mais" +" uniquement en déclenchant l'événement." #: ../../appendix/releases.rst:99 msgid "" @@ -2233,29 +2242,42 @@ msgid "``upgrade``" msgstr "``upgrade``" #: ../../appendix/releases.rst:116 +msgid "Test suite" +msgstr "Suite de tests" + +#: ../../appendix/releases.rst:118 +msgid "" +"The Elgg PHPUnit test suite files are not considered part of the public API " +"and can be changed / removed at any time." +msgstr "" +"Les fichiers de la suite de tests Elgg PHPUnit ne sont pas considérés comme " +"faisant partie de l'API publique et peuvent être modifiés/supprimés à tout " +"moment." + +#: ../../appendix/releases.rst:121 msgid "Views" msgstr "Vues" -#: ../../appendix/releases.rst:118 +#: ../../appendix/releases.rst:123 msgid "View names are API." msgstr "Les noms de vue sont des APIs." -#: ../../appendix/releases.rst:119 +#: ../../appendix/releases.rst:124 msgid "View arguments ($vars array) are API." msgstr "Les arguments de la vue (tableau $vars) sont des API." -#: ../../appendix/releases.rst:120 +#: ../../appendix/releases.rst:125 msgid "Removing views or renaming views follows API deprecation policies." msgstr "" "La suppression de vues ou le changement de nom de vues suit les stratégies " "de dépréciation de l’API." -#: ../../appendix/releases.rst:121 +#: ../../appendix/releases.rst:126 msgid "Adding new views requires a minor version change." msgstr "" "L’ajout de nouvelles vues nécessite une modification mineure de la version." -#: ../../appendix/releases.rst:122 +#: ../../appendix/releases.rst:127 msgid "View output is not API and can be changed between patch releases." msgstr "" "La sortie des vues n’est pas une API et peut être modifiée entre deux " @@ -2657,16 +2679,16 @@ msgid "January 2020" msgstr "Janvier 2020" #: ../../appendix/support.rst:69 -msgid "3.3 LTS" -msgstr "3.3 LTS" +msgid "3.3" +msgstr "3.3" #: ../../appendix/support.rst:69 msgid "September 2022" msgstr "Septembre 2022" -#: ../../appendix/support.rst:69 -msgid "**Until 5.0**" -msgstr "**Jusqu'à la 5.0**" +#: ../../appendix/support.rst:69 ../../appendix/support.rst:79 +msgid "June 2023" +msgstr "Juin 2023" #: ../../appendix/support.rst:71 msgid "4.0" @@ -2693,14 +2715,34 @@ msgid "July 2022" msgstr "Juillet 2022" #: ../../appendix/support.rst:77 -msgid "4.3" -msgstr "4.3" +msgid "4.3 LTS" +msgstr "4.3 LTS" + +#: ../../appendix/support.rst:77 +msgid "June 2024" +msgstr "Juin 2024" + +#: ../../appendix/support.rst:77 +msgid "**Until 6.0**" +msgstr "**Jusqu'à la 6.0**" #: ../../appendix/support.rst:79 msgid "5.0" msgstr "5.0" -#: ../../appendix/support.rst:79 +#: ../../appendix/support.rst:79 ../../appendix/support.rst:81 +msgid "October 2023" +msgstr "Octobre 2023" + +#: ../../appendix/support.rst:81 +msgid "5.1" +msgstr "5.1" + +#: ../../appendix/support.rst:83 +msgid "6.0" +msgstr "6.0" + +#: ../../appendix/support.rst:83 msgid "TBD" msgstr "A FAIRE" @@ -5219,6 +5261,7 @@ msgstr "" #: ../../appendix/upgrade-notes/2.1-to-2.2.rst:19 #: ../../appendix/upgrade-notes/2.2-to-2.3.rst:38 +#: ../../appendix/upgrade-notes/5.0-to-5.1.rst:15 msgid "Deprecated Views" msgstr "Vues obsolètes" @@ -8072,6 +8115,9 @@ msgid "" "` documentation for detailed information about " "new search capabilities." msgstr "" +"Voir la documentation :doc:`Search Service ` et :ref:`Search" +" hooks ` pour des informations détaillées sur les" +" nouvelles fonctionnalités de recherche." #: ../../appendix/upgrade-notes/2.x-to-3.0.rst:536 msgid "Form and field related changes" @@ -10455,6 +10501,7 @@ msgstr "" "possible." #: ../../appendix/upgrade-notes/3.0-to-3.1.rst:76 +#: ../../appendix/upgrade-notes/5.0-to-5.1.rst:22 msgid "Deprecated Routes" msgstr "Routes obsolètes" @@ -10629,6 +10676,15 @@ msgid "" " See :ref:`the plugin hook reference for 'access:collections:write:subtypes'" " ` for more details." msgstr "" +"Pour résoudre un problème où les collections d'accès appartenant à " +"l'utilisateur telles que `Friends` ou `Friend Collections` s'affichaient " +"toujours dans la liste déroulante d'accès lors de la création de contenu, " +"même si les plugins associés sont désactivés, nous avons dû modifier une " +"certaine logique interne. Si vous souhaitez qu'un sous-type de collection " +"d'accès soit disponible dans l'accès en écriture, vous devez maintenant " +"enregistrer le sous-type avec un hook de plugin. Voir :ref:`la référence du " +"hook du plugin pour 'access:collections:write:subtypes' ` pour plus de détails." #: ../../appendix/upgrade-notes/3.1-to-3.2.rst:18 msgid "River items enabled state" @@ -16069,10 +16125,15 @@ msgid "" "Most notable are The Wire (which now also has mention support) and the " "removal of the Embed plugin." msgstr "" +"L'éditeur a été mis à jour vers la version 5. Cela apporte quelques " +"nouvelles fonctionnalités (comme les mentions et les images dans le contenu)" +" mais impacte également les plugins existants. Les plus notables sont The " +"Wire (qui a désormais également mentionné le support) et la suppression du " +"plugin Embed." #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:14 msgid "The related 'longtext' menu is no longer available." -msgstr "" +msgstr "Le menu 'longtext' associé n'est plus disponible." #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:22 msgid "The minimal PHP version is now 8.0." @@ -16087,6 +16148,8 @@ msgid "" "The faker library is no longer maintained by fzaninotto so we switched to a " "fork which is maintained by FakerPHP." msgstr "" +"La bibliothèque faker n'est plus maintenue par fzaninotto, nous sommes donc " +"passés à un fork qui est maintenu par FakerPHP." #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:30 msgid "Events and Hooks" @@ -16100,6 +16163,12 @@ msgid "" "hook callbacks that expect a type hinted `Elgg\\Hook` argument you will need" " to update this to `Elgg\\Event`." msgstr "" +"Ces deux concepts similaires ont été fusionnés et nous ne ferons désormais " +"référence qu'à des événements. Les « crochets » du service public n'existent" +" plus. Tous les hooks peuvent maintenant être enregistrés dans la section « " +"événements » de votre plugin. Si vous utilisez des rappels de hook qui " +"attendent un argument `Elgg\\Hook` d'indication de type, vous devrez le " +"mettre à jour vers `Elgg\\Event`." #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:37 msgid "Create event" @@ -16111,6 +16180,9 @@ msgid "" " prevent the creation of the entity. Use ``create:before`` if you wish to " "prevent the creation." msgstr "" +"Les événements ``create``, ```` ne peuvent plus être" +" utilisés pour empêcher la création de l'entité. Utilisez ``create:before`` " +"si vous souhaitez empêcher la création." #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:43 msgid "Private Settings" @@ -16122,10 +16194,13 @@ msgid "" "private settings have been copied to metadata. All related functions have " "been removed." msgstr "" +"Le concept de paramètres privés a été supprimé du système. Tous les " +"paramètres privés ont été copiés dans les métadonnées. Toutes les fonctions " +"associées ont été supprimées." #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:48 msgid "Breadcrumbs integrated into menu system" -msgstr "" +msgstr "Fil d'Ariane intégré au système de menu" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:50 msgid "" @@ -16134,6 +16209,10 @@ msgid "" "Breadcrumb related events have been removed in favor of the regular menu " "events." msgstr "" +"Les fonctions d'assistance pour le menu du fil d'Ariane ont été modifiées " +"pour utiliser ``elgg_register_menu_item()`` pour ajouter des éléments au " +"menu du fil d'Ariane. Les événements liés au fil d'Ariane ont été supprimés " +"au profit des événements de menu standards." #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:54 msgid "Upgrades" @@ -16147,6 +16226,12 @@ msgid "" "``ElggUpgrade`` entity from the ``Batch`` that runs a part of the upgrade. " "You can access the upgrade by calling ``$this->getUpgrade()``." msgstr "" +"Les mises à niveau asynchrones ou système ne sont plus des classes qui " +"implémentent des interfaces, mais étendent des classes abstraites. Mettez à " +"jour vos mises à niveau pour étendre les classes appropriées. La raison de " +"ce changement est de pouvoir accéder à l'entité ``ElggUpgrade`` à partir du " +"``Batch`` qui exécute une partie de la mise à niveau. Vous pouvez accéder à " +"la mise à niveau en appelant ``$this->getUpgrade()``." #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:61 msgid "Session" @@ -16158,6 +16243,10 @@ msgid "" "might need to update your code. Various functions of this class have been " "moved to the ``elgg()->session_manager`` service." msgstr "" +"Si vous utilisez le service de session directement (ou via " +"``elgg_get_session()``), vous devrez peut-être mettre à jour votre code. " +"Diverses fonctions de cette classe ont été déplacées vers le service " +"``elgg()->session_manager``." #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:66 msgid "Gatekeepers" @@ -16168,6 +16257,9 @@ msgid "" "The ``PageOwnerCanEditGatekeeper`` middleware now requires a pageowner to be" " set. This gatekeeper now also requires a logged in user at all times." msgstr "" +"Le middleware ``PageOwnerCanEditGatekeeper`` requiert désormais de définir " +"un propriétaire de page. Ce contrôleur d'accès requiert désormais également " +"un utilisateur connecté à tout moment." #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:71 msgid "Files plugin" @@ -16180,6 +16272,11 @@ msgid "" "only available for image file types. Icon sizes have been changed to use the" " default icon sizes." msgstr "" +"Les fichiers téléchargés à l'aide du plugin de fichiers \"file\" ne sont " +"plus stockés avec le propriétaire mais avec l'entité du fichier. Les icônes " +"de fichiers ont également été modifiées. Les images d'icônes ne sont " +"disponibles que pour les types de fichiers image. La taille des icônes a été" +" modifiée pour utiliser les tailles d'icône par défaut." #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:77 msgid "Embed plugin" @@ -16199,10 +16296,14 @@ msgid "" "javascript hooks than you need to update your code to use the ``elgg/hook`` " "module. The concept of 'instant hooks' is no longer present in the system." msgstr "" +"Les fonctions de hook javascript ont été déplacées vers un module AMD. Si " +"vous avez utilisé des hooks javascript, vous devez mettre à jour votre code " +"pour utiliser le module ``elgg/hook``. Le concept de 'hooks instantanés' " +"n'est plus présent dans le système." #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:90 msgid "The ``'init', 'system'`` event is no longer triggered in javascript." -msgstr "" +msgstr "L'événement ``'init', 'system'`` n'est plus déclenché en javascript." #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:95 msgid "``elgg.is_in_object_array``" @@ -16225,6 +16326,8 @@ msgid "" "``elgg.register_hook_handler`` use the ``register`` function provide by the " "``elgg\\hooks`` module" msgstr "" +"``elgg.register_hook_handler`` utilise la fonction ``register`` fournie par " +"le module ``elgg\\hooks``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:100 msgid "``elgg.register_instant_hook``" @@ -16236,9 +16339,11 @@ msgstr "``elgg.set_triggered_hook``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:102 msgid "" -"``elgg.trigger_hook`` use the ``trigger`` function provide by the " +"``elgg.trigger_hook`` use the ``trigger`` function provided by the " "``elgg\\hooks`` module" msgstr "" +"``elgg.trigger_hook`` utilisez la fonction ``trigger`` fournie par le module" +" ``elgg\\hooks``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:105 msgid "Exceptions" @@ -16252,6 +16357,12 @@ msgid "" "``\\Elgg\\Exceptions\\InvalidArgumentException`` has been checked. In some " "cases the exception was replaced by a more appropriate exception." msgstr "" +"L'utilisation des exceptions dans Elgg a été revisitée. " +"``\\Elgg\\Exceptions\\InvalidParameterException`` a été supprimé et remplacé" +" par l'exception correcte. L'utilisation de " +"``\\Elgg\\Exceptions\\InvalidArgumentException`` a également été vérifiée. " +"Dans certains cas, l'exception a été remplacée par une exception plus " +"appropriée." #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:115 msgid "ElggRiverItem" @@ -16264,16 +16375,24 @@ msgid "" "saved to the database this distinction has been removed. When setting an " "unsupported attribute an ``\\Elgg\\Exceptions\\RuntimeException`` is thrown." msgstr "" +"Il n'est désormais plus permis de définir des données arbitraires pendant " +"l'exécution sur un ``ElggRiverItem``. Étant donné que les données n'étaient " +"disponibles que pendant l'exécution et n'étaient pas enregistrées dans la " +"base de données, cette distinction a été supprimée. Lors de la définition " +"d'un attribut non pris en charge, une " +"``\\Elgg\\Exceptions\\RuntimeException`` est levée." #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:131 msgid "Metadata options in getter functions" -msgstr "" +msgstr "Options des métadonnées dans les fonctions de récupération (\"getter\")" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:133 msgid "" "Previously there was a magic that would turn the ``metadata_value`` string " "into an array if it contained an ``,``." msgstr "" +"Auparavant, il existait une magie qui transformait la chaîne " +"``metadata_value`` en tableau si elle contenait un ``,``." #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:135 msgid "" @@ -16281,6 +16400,9 @@ msgid "" "Because of this magic it was impossible to query for a metadata value that " "contained an ``,``." msgstr "" +"Cette magie a été supprimée. Vous devez maintenant fournir le tableau vous-" +"même. En raison de cette magie, il était impossible de rechercher une valeur" +" de métadonnées contenant un ``,``." #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:160 msgid "Changes in functions" @@ -16294,10 +16416,16 @@ msgid "" "definition. Some function might have their arguments changed or the return " "type has been changed." msgstr "" +"Les fonctions suivantes ont maintenant leurs arguments et/ou valeurs de " +"retour typées, ce qui peut provoquer des erreurs ``TypeError``. De plus, " +"certaines fonctions de classe ont leur type de valeur de retour indiqué et " +"vous devez mettre à jour la définition de votre fonction. Certaines " +"fonctions peuvent avoir leurs arguments modifiés, ou le type de retour a été" +" modifié." #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:167 msgid "Lib functions return types" -msgstr "" +msgstr "Types de retour des fonctions des bibliothèques" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:169 msgid "" @@ -16312,6 +16440,8 @@ msgid "" "``elgg_create_river_item()`` now returns ``null`` on failure or an " "``ElggRiverItem``" msgstr "" +"``elgg_create_river_item()`` renvoie désormaisun ``ElggRiverItem``, ou " +"``null`` en cas d'échec" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:171 msgid "``elgg_delete_metadata()`` no longer returns ``null``" @@ -16346,6 +16476,8 @@ msgid "" "``elgg_get_annotation_from_id()`` now returns ``null`` if no annotation is " "found instead of a ``bool``" msgstr "" +"``elgg_get_annotation_from_id()`` renvoie désormais ``null`` au lieu d'un " +"``bool`` si aucune annotation n'est trouvée" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:177 msgid "``elgg_get_download_url()`` now returns ``null`` if there is an error" @@ -16357,6 +16489,8 @@ msgid "" "``elgg_get_entity_as_row()`` now returns ``null`` if no entity is found " "instead of a ``bool``" msgstr "" +"``elgg_get_entity_as_row()`` renvoie désormais ``null`` au lieu d'un " +"``bool`` si aucune entité n'est trouvée" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:179 msgid "``elgg_get_entity_dates()`` no longer returns a ``bool``" @@ -16375,36 +16509,48 @@ msgid "" "``elgg_get_metadata_from_id()`` now returns ``null`` if no metadata could be" " found" msgstr "" +"``elgg_get_metadata_from_id()`` renvoie désormais ``null`` si aucune " +"métadonnée n'a pu être trouvée" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:183 msgid "" "``elgg_get_page_owner_entity()`` now returns ``null`` if page owner could " "not be found" msgstr "" +"``elgg_get_page_owner_entity()`` renvoie désormais ``null`` si le " +"propriétaire de la page n'a pas pu être trouvé" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:184 msgid "" "``elgg_get_river_item_from_id()`` now returns ``null`` if no river item " "could be found" msgstr "" +"``elgg_get_river_item_from_id()`` renvoie désormais ``null`` si aucun " +"élément de rivière n'a pu être trouvé" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:185 msgid "" "``elgg_get_system_cache()`` now returns an instance of " "``\\Elgg\\Cache\\BaseCache`` instead of an ``\\ElggCache``" msgstr "" +"``elgg_get_system_cache()`` renvoie désormais une instance de " +"``\\Elgg\\Cache\\BaseCache`` au lieu de ``\\ElggCache``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:186 msgid "" -"``elgg_get_uploaded_file()`` now returns ``null`` no file could be found or " -"the file was invalid" +"``elgg_get_uploaded_file()`` now returns ``null`` if no file could be found " +"or the file was invalid" msgstr "" +"``elgg_get_uploaded_file()`` renvoie désormais ``null`` si aucun fichier n'a" +" pu être trouvé ou si le fichier n'était pas valide" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:187 msgid "" "``elgg_normalize_site_url()`` now returns ``null`` when the url is not a " "site url" msgstr "" +"``elgg_normalize_site_url()`` renvoie désormais ``null`` lorsque l'URL n'est" +" pas une URL de site" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:188 msgid "``elgg_register_action()`` no longer returns a ``bool``" @@ -16412,39 +16558,40 @@ msgstr "``elgg_register_action()`` ne renvoie plus un ``bool``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:189 msgid "``elgg_register_menu_item()`` no longer has a return value" -msgstr "" +msgstr "``elgg_register_menu_item()`` n'a plus de valeur de retour" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:190 msgid "``elgg_register_widget_type()`` no longer has a return value" -msgstr "" +msgstr "``elgg_register_widget_type()`` n'a plus de valeur de retour" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:191 msgid "``elgg_set_form_footer()`` no longer has a return value" -msgstr "" +msgstr "``elgg_set_form_footer()`` n'a plus de valeur de retour" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:192 msgid "``elgg_trigger_after_event()`` no longer has a return value" -msgstr "" +msgstr "``elgg_trigger_after_event()`` n'a plus de valeur de retour" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:193 msgid "``elgg_unregister_action()`` no longer has a return value" -msgstr "" +msgstr "``elgg_unregister_action()`` n'a plus de valeur de retour" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:194 msgid "``elgg_unregister_event_handler()`` no longer has a return value" -msgstr "" +msgstr "``elgg_unregister_event_handler()`` n'a plus de valeur de retour" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:195 msgid "``elgg_unregister_notification_event()`` no longer has a return value" -msgstr "" +msgstr "``elgg_unregister_notification_event()`` n'a plus de valeur de retour" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:196 msgid "``elgg_unregister_notification_method()`` no longer has a return value" msgstr "" +"``elgg_unregister_notification_method()`` n'a plus de valeur de retour" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:197 msgid "``elgg_unregister_widget_type()`` no longer has a return value" -msgstr "" +msgstr "``elgg_unregister_widget_type()`` n'a plus de valeur de retour" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:198 msgid "``elgg_view_annotation()`` no longer returns a ``bool``" @@ -16467,12 +16614,16 @@ msgid "" "``get_entity()`` now returns ``null`` if no entity is found instead of a " "``bool``" msgstr "" +"``get_entity()`` renvoie désormais ``null`` au lieu d'un ``bool`` si aucune " +"entité n'est trouvée" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:203 msgid "" "``get_user()`` now returns ``null`` if no user is found instead of a " "``bool``" msgstr "" +"``get_user()`` renvoie désormais ``null`` au lieu d'un ``bool`` si aucun " +"utilisateur n'est trouvé" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:204 msgid "``elgg_ws_expose_function()`` no longer returns a ``bool``" @@ -16480,78 +16631,100 @@ msgstr "``elgg_ws_expose_function()`` ne renvoie plus un ``bool``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:207 msgid "Lib functions function parameters" -msgstr "" +msgstr "Paramètres de fonction des fonctions des bibliothèques" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:209 msgid "" "``blog_prepare_form_vars()`` now requires a ``ElggBlog`` for ``$blog`` and a" " ``ElggAnnotation`` for ``$revision``" msgstr "" +"``blog_prepare_form_vars()`` requiert désormais un ``ElggBlog`` pour " +"``$blog`` et un ``ElggAnnotation`` pour ``$revision``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:210 msgid "" "``bookmarks_prepare_form_vars()`` now requires a ``ElggBookmark`` for " "``$bookmark``" msgstr "" +"``bookmarks_prepare_form_vars()`` requiert désormais un ``ElggBookmark`` " +"pour ``$bookmark``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:211 msgid "" "``discussion_prepare_form_vars()`` now requires a ``ElggDiscussion`` for " "``$topic``" msgstr "" +"``discussion_prepare_form_vars()`` requiert désormais un ``ElggDiscussion`` " +"pour ``$topic``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:212 msgid "" "``elgg_add_action_tokens_to_url()`` now requires a ``string`` for ``$url`` " "and a ``bool`` for ``$html_encode``" msgstr "" +"``elgg_add_action_tokens_to_url()`` requiert désormais un ``string`` pour " +"``$url`` et un ``bool`` pour ``$html_encode``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:213 msgid "" "``elgg_can_edit_widget_layout()`` now requires a ``string`` for ``$context``" " and ``int`` for ``$user_guid``" msgstr "" +"``elgg_can_edit_widget_layout()`` requiert désormais un ``string`` pour " +"``$context`` et un ``int`` pour ``$user_guid``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:214 msgid "" "``elgg_clear_event_handlers()`` now requires a ``string`` for ``$event`` and" " ``$type``" msgstr "" +"``elgg_clear_event_handlers()`` requiert désormais un ``string`` pour " +"``$event`` et ``$type``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:215 msgid "" "``elgg_clear_sticky_form()`` now requires a ``string`` for ``$context``" msgstr "" +"``elgg_clear_sticky_form()`` requiert désormais un ``string`` pour " +"``$context``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:216 msgid "" "``elgg_create_widget()`` now requires an ``int`` for ``$owner_guid`` and " "``$access_id`` and a ``string`` for ``$handler`` and ``$context``" msgstr "" +"``elgg_create_widget()`` requiert désormais un ``int`` pour ``$owner_guid`` " +"et ``$access_id`` et un ``string`` pour ``$handler`` et ``$context``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:217 msgid "" "``elgg_define_js()`` now requires a ``string`` for ``$name`` and an " "``array`` for ``$config``" msgstr "" +"``elgg_define_js()`` requiert désormais un ``string`` pour ``$name`` et un " +"``array`` pour ``$config``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:218 msgid "``elgg_delete_system_cache()`` now requires a ``string`` for ``$type``" msgstr "" +"``elgg_delete_system_cache()`` requiert désormais un ``string`` pour " +"``$type``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:219 msgid "" "``elgg_echo()`` now requires a ``string`` for ``$message_key`` and a " "``string`` for ``$language``" msgstr "" +"``elgg_echo()`` requiert désormais un ``string`` pour ``$message_key`` et un" +" ``string`` pour ``$language``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:220 msgid "``elgg_enqueue_notification_event()`` no longer requires a ``$type``" -msgstr "" +msgstr "``elgg_enqueue_notification_event()`` n'a plus besoin d'un ``$type``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:221 msgid "``elgg_entity_exists()`` now requires a ``int`` for ``$guid``" -msgstr "" +msgstr "``elgg_entity_exists()`` requiert désormais un ``int`` pour ``$guid``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:222 msgid "" @@ -16559,314 +16732,421 @@ msgid "" "``string`` for ``$type`` and a ``string`` for ``$subtype`` and a ``bool`` " "for ``$validate_can_edit``" msgstr "" +"``elgg_entity_gatekeeper()`` requiert désormais un ``int`` pour ``$guid``, " +"un ``string`` pour ``$type``, un ``string`` pour ``$subtype`` et un ``bool``" +" pour ``$validate_can_edit``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:223 msgid "" "``elgg_error_response()`` now requires a ``string`` or ``array`` for " "``$message`` and a ``string`` for ``$forward_url``" msgstr "" +"``elgg_error_response()`` requiert désormais un ``string`` ou un ``array`` " +"pour ``$message`` et un ``string`` pour ``$forward_url``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:224 msgid "" "``elgg_extend_view()`` now requires a ``string`` for ``$view`` and " "``$view_extension``" msgstr "" +"``elgg_extend_view()`` requiert désormais un ``string`` pour ``$view`` et " +"``$view_extension``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:225 msgid "``elgg_extract()`` now requires a ``bool`` for ``$strict``" -msgstr "" +msgstr "``elgg_extract()`` requiert désormais un ``bool`` pour ``$strict``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:226 msgid "" "``elgg_format_bytes()`` now requires an ``int`` for ``$size`` and " "``$precision``" msgstr "" +"``elgg_format_bytes()`` requiert désormais un ``int`` pour ``$size`` et " +"``$precision``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:227 msgid "" "``elgg_format_element()`` now requires a ``string`` for ``$tag_name`` and a " "``string`` for ``$text``" msgstr "" +"``elgg_format_element()`` requiert désormais un ``string`` pour " +"``$tag_name`` et un ``string`` pour ``$text``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:228 msgid "``elgg_format_html()`` now requires a ``string`` for ``$html``" msgstr "" +"``elgg_format_html()`` requiert désormais un ``string`` pour ``$html``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:229 msgid "" "``elgg_generate_action_url()`` now requires a ``string`` for ``$action`` and" " a boolean for ``$add_csrf_tokens``" msgstr "" +"``elgg_generate_action_url()`` requiert désormais un ``string`` pour " +"``$action`` et un booléen pour ``$add_csrf_tokens``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:230 msgid "" "``elgg_generate_entity_url()`` now requires a ``string`` for ``$resource`` " "and ``$subresource``" msgstr "" +"``elgg_generate_entity_url()`` requiert désormais un ``string`` pour " +"``$resource`` et ``$subresource``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:231 msgid "``elgg_generate_url()`` now requires a ``string`` for ``$name``" msgstr "" +"``elgg_generate_url()`` requiert désormais un ``string`` pour ``$name``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:232 msgid "``elgg_get_config()`` now requires a ``string`` for ``$name``" -msgstr "" +msgstr "``elgg_get_config()`` requiert désormais un ``string`` pour ``$name``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:233 msgid "" "``elgg_get_download_url()`` now requires a ``bool`` for ``$use_cookie`` and " "a ``string`` for ``$expires``" msgstr "" +"``elgg_get_download_url()`` requiert désormais un ``bool`` pour " +"``$use_cookie`` et un ``string`` pour ``$expires``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:234 msgid "``elgg_get_embed_url()`` now requires a ``string`` for ``$size``" msgstr "" +"``elgg_get_embed_url()`` requiert désormais un ``string`` pour ``$size``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:235 msgid "" "``elgg_get_entity_class()`` now requires a ``string`` for ``$type`` and a " "``string`` for ``$subtype``" msgstr "" +"``elgg_get_entity_class()`` requiert désormais un ``string`` pour ``$type`` " +"et un ``string`` pour ``$subtype``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:236 msgid "" "``elgg_get_excerpt()`` now requires a ``string`` for ``$text`` and an " "``int`` for ``$num_chars``" msgstr "" +"``elgg_get_excerpt()`` requiert désormais un ``string`` pour ``$text`` et un" +" ``int`` pour ``$num_chars``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:237 msgid "" "``elgg_get_friendly_upload_error()`` now requires an ``int`` for " "``$error_code``" msgstr "" +"``elgg_get_friendly_upload_error()`` requiert désormais un ``int`` pour " +"``$error_code``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:238 msgid "" "``elgg_get_friendly_time()`` now requires an ``int`` for ``$time`` and " "``$current_time``" msgstr "" +"``elgg_get_friendly_time()`` requiert désormais un ``int`` pour ``$time`` et" +" ``$current_time``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:239 msgid "``elgg_get_friendly_title()`` now requires a ``string`` for ``$title``" msgstr "" +"``elgg_get_friendly_title()`` requiert désormais un ``string`` pour " +"``$title``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:240 msgid "" "``elgg_get_icon_sizes()`` now requires a ``string`` for ``$entity_type`` and" " ``$entity_subtype``" msgstr "" +"``elgg_get_icon_sizes()`` requiert désormais un ``string`` pour " +"``$entity_type`` et ``$entity_subtype``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:241 msgid "" "``elgg_get_ini_setting_in_bytes()`` now requires a ``string`` for " "``$setting``" msgstr "" +"``elgg_get_ini_setting_in_bytes()`` requiert désormais un ``string`` pour " +"``$setting``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:242 msgid "" "``elgg_get_inline_url()`` now requires a ``bool`` for ``$use_cookie`` and a " "``string`` for ``$expires``" msgstr "" +"``elgg_get_inline_url()`` requiert désormais un ``bool`` pour " +"``$use_cookie`` et un ``string`` pour ``$expires``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:243 msgid "``elgg_get_login_url()`` now requires a ``string`` for ``$fragment``" msgstr "" +"``elgg_get_login_url()`` requiert désormais un ``string`` pour ``$fragment``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:244 msgid "``elgg_get_metadata_from_id()`` now requires an ``int`` for ``$id``" msgstr "" +"``elgg_get_metadata_from_id()`` requiert désormais un ``int`` pour ``$id``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:245 msgid "" "``elgg_get_registration_url()`` now requires a ``string`` for ``$fragment``" msgstr "" +"``elgg_get_registration_url()`` requiert désormais un ``string`` pour " +"``$fragment``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:246 msgid "" "``elgg_get_request_data()`` now requires a ``bool`` for ``$filter_result``" msgstr "" +"``elgg_get_request_data()`` requiert désormais un ``bool`` pour " +"``$filter_result``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:247 msgid "" "``elgg_get_simplecache_url()`` now requires a ``string`` for ``$view`` and " "``$sub_view``" msgstr "" +"``elgg_get_simplecache_url()`` requiert désormais un ``string`` pour " +"``$view`` et ``$sub_view``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:248 msgid "" "``elgg_get_sticky_value()`` now requires a ``string`` for ``$form_name`` and" " a string for ``$variable`` and a ``bool`` for ``$filter_result``" msgstr "" +"``elgg_get_sticky_value()`` requiert désormais un ``string`` pour " +"``$form_name`` et une chaine de caractères pour ``$variable`` et un a " +"``bool`` pour ``$filter_result``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:249 msgid "" "``elgg_get_sticky_values()`` now requires a ``string`` for ``$form_name`` " "and a ``bool`` for ``$filter_result``" msgstr "" +"``elgg_get_sticky_values()`` requiert désormais un ``string`` pour " +"``$form_name`` et un ``bool`` pour ``$filter_result``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:250 msgid "" "``elgg_get_title_input()`` now requires a ``string`` for ``$variable`` and a" " string for ``$default``" msgstr "" +"``elgg_get_title_input()`` requiert désormais un ``string`` pour " +"``$variable`` et une chaîne de caractères pour ``$default``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:251 msgid "" "``elgg_get_uploaded_file()`` now requires a ``string`` for ``$input_name`` " "and a ``bool`` for ``$check_for_validity``" msgstr "" +"``elgg_get_uploaded_file()`` requiert désormais un ``string`` pour " +"``$input_name`` et un ``bool`` pour ``$check_for_validity``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:252 msgid "" "``elgg_get_uploaded_files()`` now requires a ``string`` for ``$input_name``" msgstr "" +"``elgg_get_uploaded_files()`` requiert désormais un ``string`` pour " +"``$input_name``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:253 msgid "``elgg_get_view_extensions()`` now requires a ``string`` for ``$view``" msgstr "" +"``elgg_get_view_extensions()`` requiert désormais un ``string`` pour " +"``$view``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:254 msgid "" "``elgg_get_widget_types()`` now requires a ``string`` or ``array`` for " "``$context``" msgstr "" +"``elgg_get_widget_types()`` requiert désormais un ``string`` ou un ``array``" +" pour ``$context``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:255 msgid "" "``elgg_get_widgets()`` now requires a ``int`` for ``$owner_guid`` and " "``string`` for ``$context``" msgstr "" +"``elgg_get_widgets()`` requiert désormais un ``int`` pour ``$owner_guid`` et" +" un ``string`` pour ``$context``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:256 msgid "" "``elgg_group_tool_gatekeeper()`` now requires a ``string`` for " "``$tool_name`` and an ``int`` for ``$group_guid``" msgstr "" +"``elgg_group_tool_gatekeeper()`` requiert désormais un ``string`` pour " +"``$tool_name`` et un ``int`` pour ``$group_guid``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:257 msgid "``elgg_html_decode()`` now requires a ``string`` for ``$string``" msgstr "" +"``elgg_html_decode()`` requiert désormais un ``string`` pour ``$string``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:258 msgid "" "``elgg_http_add_url_query_elements()`` now requires a ``string`` for " "``$url``" msgstr "" +"``elgg_http_add_url_query_elements()`` requiert désormais un ``string`` pour" +" ``$url``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:259 msgid "``elgg_http_build_url()`` now requires a ``bool`` for ``$html_encode``" msgstr "" +"``elgg_http_build_url()`` requiert désormais un ``bool`` pour " +"``$html_encode``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:260 msgid "" "``elgg_http_get_signed_url()`` now requires a ``string`` for ``$url`` and " "``$expires``" msgstr "" +"``elgg_http_get_signed_url()`` requiert désormais un ``string`` pour " +"``$url`` et ``$expires``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:261 msgid "" "``elgg_http_remove_url_query_element()`` now requires a ``string`` for " "``$url`` and a ``string`` for ``$element``" msgstr "" +"``elgg_http_remove_url_query_element()`` requiert désormais un ``string`` " +"pour ``$url`` et un ``string`` pour ``$element``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:262 msgid "" "``elgg_http_url_is_identical()`` now requires a ``string`` for ``$url1`` and" " ``$url2`` and an ``array`` for ``$ignore_params``" msgstr "" +"``elgg_http_url_is_identical()`` requiert désormais un ``string`` pour " +"``$url1`` et ``$url2`` et un ``array`` pour ``$ignore_params``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:263 msgid "" "``elgg_http_validate_signed_url()`` now requires a ``string`` for ``$url``" msgstr "" +"``elgg_http_validate_signed_url()`` requiert désormais un ``string`` pour " +"``$url``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:264 msgid "``elgg_in_context()`` now requires a ``string`` for ``$context``" msgstr "" +"``elgg_in_context()`` requiert désormais un ``string`` pour ``$context``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:265 msgid "``elgg_is_sticky_form()`` now requires a ``string`` for ``$form_name``" msgstr "" +"``elgg_is_sticky_form()`` requiert désormais un ``string`` pour " +"``$form_name``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:266 msgid "" "``elgg_is_widget_type()`` now requires a ``string`` for ``$handler`` and " "``$context``" msgstr "" +"``elgg_is_widget_type()`` requiert désormais un ``string`` pour ``$handler``" +" et ``$context``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:267 msgid "" "``elgg_language_key_exists()`` now requires a ``string`` for ``$key`` and a " "``string`` for ``$language``" msgstr "" +"``elgg_language_key_exists()`` requiert désormais un ``string`` pour " +"``$key`` et un ``string`` pour ``$language``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:268 msgid "" "``elgg_list_entities()`` now requires a ``callable`` for ``$getter`` and a " "``callable`` for ``$viewer``" msgstr "" +"``elgg_list_entities()`` requiert désormais un ``callable`` pour ``$getter``" +" et un ``callable`` pour ``$viewer``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:269 msgid "" "``elgg_list_entities_from_relationship_count()`` now requires an ``array`` " "for ``$options``" msgstr "" +"``elgg_list_entities_from_relationship_count()`` requiert désormais un " +"``array`` pour ``$options``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:270 msgid "" "``elgg_list_relationships()`` now requires an ``array`` for ``$options``" msgstr "" +"``elgg_list_relationships()`` requiert désormais un ``array`` pour " +"``$options``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:271 msgid "``elgg_load_system_cache()`` now requires a ``string`` for ``$type``" msgstr "" +"``elgg_load_system_cache()`` requiert désormais un ``string`` pour ``$type``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:272 msgid "" "``elgg_make_sticky_form()`` now requires a ``string`` for ``$form_name``" msgstr "" +"``elgg_make_sticky_form()`` requiert désormais un ``string`` pour " +"``$form_name``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:273 msgid "" "``elgg_normalize_site_url()`` now requires a ``string`` for ``$unsafe_url``" msgstr "" +"``elgg_normalize_site_url()`` requiert désormais un ``string`` pour " +"``$unsafe_url``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:274 msgid "``elgg_normalize_url()`` now requires a ``string`` for ``$url``" msgstr "" +"``elgg_normalize_url()`` requiert désormais un ``string`` pour ``$url``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:275 msgid "" "``elgg_ok_response()`` now requires a ``string`` or ``array`` for " "``$message`` and a ``string`` for ``$forward_url``" msgstr "" +"``elgg_ok_response()`` requiert désormais un ``string`` ou un ``array`` pour" +" ``$message`` et un ``string`` pour ``$forward_url``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:276 msgid "``elgg_parse_emails()`` now requires a ``string`` for ``$text``" msgstr "" +"``elgg_parse_emails()`` requiert désormais un ``string`` pour ``$text``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:277 msgid "``elgg_push_context()`` now requires a ``string`` for ``$context``" msgstr "" +"``elgg_push_context()`` requiert désormais un ``string`` pour ``$context``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:278 msgid "" "``elgg_redirect_response()`` now requires a ``string`` for ``$forward_url``" msgstr "" +"``elgg_redirect_response()`` requiert désormais un ``string`` pour " +"``$forward_url``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:279 msgid "``elgg_register_action()`` now requires a ``string`` for ``$filename``" msgstr "" +"``elgg_register_action()`` requiert désormais un ``string`` pour " +"``$filename``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:280 msgid "``elgg_register_ajax_view()`` now requires a ``string`` for ``$view``" msgstr "" +"``elgg_register_ajax_view()`` requiert désormais un ``string`` pour " +"``$view``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:281 msgid "" "``elgg_register_error_message()`` now requires a ``string|array`` for " "``$message``" msgstr "" +"``elgg_register_error_message()`` requiert désormais un ``string|array`` " +"pour ``$message``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:282 msgid "" @@ -16874,40 +17154,54 @@ msgid "" "and ``$type`` and an ``int`` for ``$priority`` and a ``callable|string`` for" " ``$callable``" msgstr "" +"``elgg_register_event_handler()`` requiert désormais un ``string`` pour " +"``$event`` et ``$type`` et un ``int`` pour ``$priority`` et un " +"``callable|string`` pour ``$callable``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:283 msgid "" "``elgg_register_menu_item()`` now requires a ``string`` for ``$menu_name`` " "and a ``array|\\ElggMenuItem`` for ``$menu_item``" msgstr "" +"``elgg_register_menu_item()`` requiert désormais un ``string`` pour " +"``$menu_name`` et un ``array|\\ElggMenuItem`` pour ``$menu_item``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:284 msgid "" "``elgg_register_notification_event()`` now requires a ``string`` for " "``$object_type`` and ``$object_subtype``" msgstr "" +"``elgg_register_notification_event()`` requiert désormais un ``string`` pour" +" ``$object_type`` et ``$object_subtype``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:285 msgid "" "``elgg_register_notification_method()`` now requires a ``string`` for " "``$name``" msgstr "" +"``elgg_register_notification_method()`` requiert désormais un ``string`` " +"pour ``$name``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:286 msgid "``elgg_register_route()`` now requires a ``string`` for ``$name``" msgstr "" +"``elgg_register_route()`` requiert désormais un ``string`` pour ``$name``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:287 msgid "" "``elgg_register_simplecache_view()`` now requires a ``string`` for " "``$view_name``" msgstr "" +"``elgg_register_simplecache_view()`` requiert désormais un ``string`` pour " +"``$view_name``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:288 msgid "" "``elgg_register_success_message()`` now requires a ``string|array`` for " "``$message``" msgstr "" +"``elgg_register_success_message()`` requiert désormais un ``string|array`` " +"pour ``$message``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:289 msgid "" @@ -16915,156 +17209,204 @@ msgid "" "removed and requires a ``string`` for ``$name``, ``$entity_type`` and " "``$entity_subtype``" msgstr "" +"Le premier argument (``$handler``) de ``elgg_register_title_button()`` a été" +" supprimé et requiert un ``string`` pour ``$name``, ``$entity_type`` et " +"``$entity_subtype``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:290 msgid "" "``elgg_register_viewtype_fallback()`` now requires a ``string`` for " "``$viewtype``" msgstr "" +"``elgg_register_viewtype_fallback()`` requiert désormais un ``string`` pour " +"``$viewtype``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:291 msgid "" "``elgg_register_widget_type()`` now only supports an ``array`` suitable for " "``\\Elgg\\WidgetDefinition::factory()`` for ``$options``" msgstr "" +"``elgg_register_widget_type()`` ne supporte plus pour ``$options`` qu'un " +"``array`` adapté pour ``\\Elgg\\WidgetDefinition::factory()`` " #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:292 msgid "``elgg_remove_config()`` now requires a ``string`` for ``$name``" msgstr "" +"``elgg_remove_config()`` requiert désormais un ``string`` pour ``$name``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:293 msgid "``elgg_require_js()`` now requires a ``string`` for ``$name``" -msgstr "" +msgstr "``elgg_require_js()`` requiert désormais un ``string`` pour ``$name``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:294 msgid "``elgg_save_config()`` now requires a ``string`` for ``$name``" msgstr "" +"``elgg_save_config()`` requiert désormais un ``string`` pour ``$name``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:295 msgid "" "``elgg_save_resized_image()`` now requires a ``string`` for ``$source`` and " "a ``string`` for ``$destination``" msgstr "" +"``elgg_save_resized_image()`` requiert désormais un ``string`` pour " +"``$source`` et un ``string`` pour ``$destination``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:296 msgid "``elgg_save_system_cache()`` now requires a ``string`` for ``$type``" msgstr "" +"``elgg_save_system_cache()`` requiert désormais un ``string`` pour ``$type``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:297 msgid "``elgg_set_config()`` now requires a ``string`` for ``$name``" -msgstr "" +msgstr "``elgg_set_config()`` requiert désormais un ``string`` pour ``$name``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:298 msgid "``elgg_set_context()`` now requires a ``string`` for ``$context``" msgstr "" +"``elgg_set_context()`` requiert désormais un ``string`` pour ``$context``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:299 msgid "" "``elgg_set_entity_class()`` now requires a ``string`` for ``$type`` and a " "``string`` for ``$subtype`` and a ``string`` for ``$class``" msgstr "" +"``elgg_set_entity_class()`` requiert désormais un ``string`` pour ``$type`` " +"et un ``string`` pour ``$subtype`` et un ``string`` pour ``$class``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:300 msgid "``elgg_set_form_footer()`` now requires a ``string`` for ``$footer``" msgstr "" +"``elgg_set_form_footer()`` requiert désormais un ``string`` pour ``$footer``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:301 msgid "" "``elgg_set_http_header()`` now requires a ``string`` for ``$header`` and a " "``bool`` for ``$replace``" msgstr "" +"``elgg_set_http_header()`` requiert désormais un ``string`` pour ``$header``" +" et un ``bool`` pour ``$replace``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:302 msgid "``elgg_set_page_owner_guid()`` now requires a ``int`` for ``$guid``" msgstr "" +"``elgg_set_page_owner_guid()`` requiert désormais un ``int`` pour ``$guid``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:303 msgid "" "``elgg_set_view_location()`` now requires a ``string`` for ``$view``, " "``$location`` and ``$viewtype``" msgstr "" +"``elgg_set_view_location()`` requiert désormais un ``string`` pour " +"``$view``, ``$location`` et ``$viewtype``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:304 msgid "``elgg_set_viewtype()`` now requires a ``string`` for ``$viewtype``" msgstr "" +"``elgg_set_viewtype()`` requiert désormais un ``string`` pour ``$viewtype``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:305 msgid "" "``elgg_strip_tags()`` now requires a ``string`` for ``$string`` and " "``$allowable_tags``" msgstr "" +"``elgg_strip_tags()`` requiert désormais un ``string`` pour ``$string`` et " +"``$allowable_tags``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:306 msgid "" "``elgg_trigger_after_event()`` now requires a ``string`` for ``$event`` and " "``$type``" msgstr "" +"``elgg_trigger_after_event()`` requiert désormais un ``string`` pour " +"``$event`` et ``$type``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:307 msgid "" "``elgg_trigger_before_event()`` now requires a ``string`` for ``$event`` and" " ``$type``" msgstr "" +"``elgg_trigger_before_event()`` requiert désormais un ``string`` pour " +"``$event`` et ``$type``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:308 msgid "" "``elgg_trigger_deprecated_event()`` now requires a ``string`` for " "``$event``, ``$type``, ``$message`` and ``$version``" msgstr "" +"``elgg_trigger_deprecated_event()`` requiert désormais un ``string`` pour " +"``$event``, ``$type``, ``$message`` et ``$version``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:309 msgid "" "``elgg_trigger_event()`` now requires a ``string`` for ``$event`` and " "``$type``" msgstr "" +"``elgg_trigger_event()`` requiert désormais un ``string`` pour ``$event`` et" +" ``$type``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:310 msgid "" "``elgg_unregister_ajax_view()`` now requires a ``string`` for ``$view``" msgstr "" +"``elgg_unregister_ajax_view()`` requiert désormais un ``string`` pour " +"``$view``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:311 msgid "" "``elgg_register_event_handler()`` now requires a ``string`` for ``$event`` " "and ``$type`` and a ``callable|string`` for ``$callable``" msgstr "" +"``elgg_register_event_handler()`` requiert désormais un ``string`` pour " +"``$event`` et ``$type`` et un ``callable|string`` pour ``$callable``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:312 msgid "" "``elgg_unregister_menu_item()`` now requires a ``string`` for ``$menu_name``" " and ``$item_name``" msgstr "" +"``elgg_unregister_menu_item()`` requiert désormais un ``string`` pour " +"``$menu_name`` et ``$item_name``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:313 msgid "" "``elgg_unregister_notification_event()`` now requires a ``string`` for " "``$object_type`` and ``$object_subtype``" msgstr "" +"``elgg_unregister_notification_event()`` requiert désormais un ``string`` " +"pour ``$object_type`` et ``$object_subtype``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:314 msgid "" "``elgg_unregister_notification_method()`` now requires a ``string`` for " "``$name``" msgstr "" +"``elgg_unregister_notification_method()`` requiert désormais un ``string`` " +"pour ``$name``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:315 msgid "``elgg_unregister_route()`` now requires a ``string`` for ``$name``" msgstr "" +"``elgg_unregister_route()`` requiert désormais un ``string`` pour ``$name``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:316 msgid "" "``elgg_unregister_widget_type()`` now requires a ``string`` for ``$handler``" msgstr "" +"``elgg_unregister_widget_type()`` requiert désormais un ``string`` pour " +"``$handler``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:317 msgid "``elgg_unrequire_js()`` now requires a ``string`` for ``$name``" msgstr "" +"``elgg_unrequire_js()`` requiert désormais un ``string`` pour ``$name``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:318 msgid "" "``elgg_validate_invite_code()`` now requires a ``string`` for ``$username`` " "and ``$code``" msgstr "" +"``elgg_validate_invite_code()`` requiert désormais un ``string`` pour " +"``$username`` et ``$code``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:319 msgid "" @@ -17072,77 +17414,104 @@ msgid "" "``$username``, ``$name`` and ``$email``, a ``bool`` for ``$multiple`` and a " "``string|array`` for ``$password``" msgstr "" +"``elgg_validate_registration_data()`` requiert désormais un ``string`` pour " +"``$username``, ``$name`` et ``$email``, un ``bool`` pour ``$multiple`` et un" +" ``string|array`` pour ``$password``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:320 msgid "" "``elgg_view()`` now requires a ``string`` for ``$view`` and ``$viewtype`` " "and a ``bool`` for ``$recurse``" msgstr "" +"``elgg_view()`` requiert désormais un ``string`` pour ``$view`` et " +"``$viewtype`` et un ``bool`` pour ``$recurse``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:321 msgid "" "``elgg_view_annotation_list()`` now requires an ``array`` for " "``$annotations``" msgstr "" +"``elgg_view_annotation_list()`` requiert désormais un ``array`` pour " +"``$annotations``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:322 msgid "" "``elgg_view_deprecated()`` now requires a ``string`` for ``$view``, " "``$message`` and ``$version``" msgstr "" +"``elgg_view_deprecated()`` requiert désormais un ``string`` pour ``$view``, " +"``$message`` et ``$version``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:323 msgid "" "``elgg_view_comments()`` now requires an ``ElggEntity`` for ``$entity`` and " "a ``bool`` for ``$add_comment``" msgstr "" +"``elgg_view_comments()`` requiert désormais un ``ElggEntity`` pour " +"``$entity`` et un ``bool`` pour ``$add_comment``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:324 msgid "" "``elgg_view_entity_icon()`` now requires a ``string`` for ``$size`` and an " "``array`` for ``$vars``" msgstr "" +"``elgg_view_entity_icon()`` requiert désormais un ``string`` pour ``$size`` " +"et un ``array`` pour ``$vars``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:325 msgid "" "``elgg_view_entity_list()`` now requires an ``array`` for ``$entities``" msgstr "" +"``elgg_view_entity_list()`` requiert désormais un ``array`` pour " +"``$entities``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:326 msgid "" "``elgg_view_exists()`` now requires a ``string`` for ``$view`` and " "``$viewtype`` and an ``array`` for ``$vars``" msgstr "" +"``elgg_view_exists()`` requiert désormais un ``string`` pour ``$view`` et " +"``$viewtype`` et un ``array`` pour ``$vars``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:327 msgid "" "``elgg_view_form()`` now requires a ``string`` for ``$action`` and an " "``array`` for ``$form_vars`` and ``$body_vars``" msgstr "" +"``elgg_view_form()`` requiert désormais un ``string`` pour ``$action`` et un" +" ``array`` pour ``$form_vars`` et ``$body_vars``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:328 msgid "" "``elgg_view_icon()`` now requires a ``string`` for ``$name`` and an " "``array`` for ``$vars``" msgstr "" +"``elgg_view_icon()`` requiert désormais un ``string`` pour ``$name`` et un " +"``array`` pour ``$vars``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:329 msgid "" "``elgg_view_image_block()`` now requires a ``string`` for ``$type``, " "``$title`` and ``$body``" msgstr "" +"``elgg_view_image_block()`` requiert désormais un ``string`` pour ``$type``," +" ``$title`` et ``$body``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:330 msgid "" "``elgg_view_layout()`` now requires a ``string`` for ``$layout_name`` and an" " ``array`` for ``$vars``" msgstr "" +"``elgg_view_layout()`` requiert désormais un ``string`` pour " +"``$layout_name`` et un ``array`` pour ``$vars``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:331 msgid "" "``elgg_view_message()`` now requires a ``string`` for ``$type`` and " "``$body``" msgstr "" +"``elgg_view_message()`` requiert désormais un ``string`` pour ``$type`` et " +"``$body``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:332 msgid "" @@ -17150,109 +17519,143 @@ msgid "" "``$page_shell``, an ``array`` for ``$vars`` and a ``string|array`` for " "``$body``" msgstr "" +"``elgg_view_page()`` requiert désormais un ``string`` pour ``$title`` et " +"``$page_shell``, un ``array`` pour ``$vars`` et un ``string|array`` pour " +"``$body``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:333 msgid "" "``elgg_view_relationship_list()`` now requires an ``array`` for " "``$relationships``" msgstr "" +"``elgg_view_relationship_list()`` requiert désormais un ``array`` pour " +"``$relationships``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:334 msgid "" "``elgg_view_river_item()`` now requires an ``ElggRiverItem`` for ``$item``" msgstr "" +"``elgg_view_river_item()`` requiert désormais un ``ElggRiverItem`` pour " +"``$item``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:335 msgid "``elgg_view_resource()`` now requires a ``string`` for ``$name``" msgstr "" +"``elgg_view_resource()`` requiert désormais un ``string`` pour ``$name``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:336 msgid "``elgg_view_title()`` now requires a ``string`` for ``$title``" msgstr "" +"``elgg_view_title()`` requiert désormais un ``string`` pour ``$title``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:337 msgid "" "``embed_get_list_options()`` now requires an ``array`` for ``$options``" msgstr "" +"``embed_get_list_options()`` requiert désormais un ``array`` pour " +"``$options``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:338 msgid "" "``embed_list_items()`` now requires an ``array`` for ``$entities`` and " "``$vars``" msgstr "" +"``embed_list_items()`` requiert désormais un ``array`` pour ``$entities`` et" +" ``$vars``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:339 msgid "" "``file_prepare_form_vars()`` now requires an ``ElggFile`` for ``$file``" msgstr "" +"``file_prepare_form_vars()`` requiert désormais un ``ElggFile`` pour " +"``$file``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:340 msgid "``get_entity()`` now requires a ``int`` for ``$guid``" -msgstr "" +msgstr "``get_entity()`` requiert désormais un ``int`` pour ``$guid``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:341 msgid "" "``get_input()`` now requires a ``string`` for ``$variable`` and a ``bool`` " "for ``$filter_result``" msgstr "" +"``get_input()`` requiert désormais un ``string`` pour ``$variable`` et un " +"``bool`` pour ``$filter_result``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:342 msgid "``get_user()`` now requires a ``int`` for ``$guid``" -msgstr "" +msgstr "``get_user()`` requiert désormais un ``int`` pour ``$guid``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:343 msgid "" "``groups_get_group_join_menu_item()`` now requires an ``ElggUser`` for " "``$user``" msgstr "" +"``groups_get_group_join_menu_item()`` requiert désormais un ``ElggUser`` " +"pour ``$user``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:344 msgid "" "``groups_get_group_leave_menu_item()`` now requires an ``ElggUser`` for " "``$user``" msgstr "" +"``groups_get_group_leave_menu_item()`` requiert désormais un ``ElggUser`` " +"pour ``$user``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:345 msgid "" "``groups_get_invited_groups()`` now requires an ``int`` for ``$user_guid``, " "a ``bool`` for ``$return_guids`` and an ``array`` for ``$options``" msgstr "" +"``groups_get_invited_groups()`` requiert désormais un ``int`` pour " +"``$user_guid``, un ``bool`` pour ``$return_guids`` et un ``array`` pour " +"``$options``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:346 msgid "" "``notify_user()`` now requires an ``int|array`` for ``$to`` and a ``int`` " "for ``$from`` and a ``string`` for ``$subject`` and ``$message``" msgstr "" +"``notify_user()`` requiert désormais un ``int|array`` pour ``$to`` et un " +"``int`` pour ``$from`` et un ``string`` pour ``$subject`` et ``$message``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:347 msgid "" "``pages_get_navigation_tree()`` now requires a ``ElggEntity`` for " "``$container``" msgstr "" +"``pages_get_navigation_tree()`` requiert désormais un ``ElggEntity`` pour " +"``$container``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:348 msgid "" "``pages_prepare_form_vars()`` now requires a ``ElggPage`` for ``$page``, an " "``int`` for ``$parent_guid`` and a ``ElggAnnotation`` for ``$revision``" msgstr "" +"``pages_prepare_form_vars()`` requiert désormais un ``ElggPage`` pour " +"``$page``, un ``int`` pour ``$parent_guid`` et un ``ElggAnnotation`` pour " +"``$revision``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:349 msgid "" "``pages_prepare_parent_breadcrumbs()`` now requires a ``ElggPage`` for " "``$page``" msgstr "" +"``pages_prepare_parent_breadcrumbs()`` requiert désormais un ``ElggPage`` " +"pour ``$page``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:350 msgid "``set_input()`` now requires a ``string`` for ``$variable``" -msgstr "" +msgstr "``set_input()`` requiert désormais un ``string`` pour ``$variable``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:351 msgid "``thewire_filter()`` now requires a ``string`` for ``$text``" -msgstr "" +msgstr "``thewire_filter()`` requiert désormais un ``string`` pour ``$text``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:352 msgid "``thewire_get_hashtags()`` now requires a ``string`` for ``$text``" msgstr "" +"``thewire_get_hashtags()`` requiert désormais un ``string`` pour ``$text``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:353 msgid "" @@ -17260,12 +17663,17 @@ msgid "" "``$method`` and an ``int`` for ``$userid`` and ``$access_id`` and " "``$parent_guid``" msgstr "" +"``thewire_save_post()`` requiert désormais un ``string`` pour ``$text`` et " +"``$method`` et un ``int`` pour ``$userid``, ``$access_id`` et " +"``$parent_guid``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:354 msgid "" "``uservalidationbyemail_request_validation()`` now requires an ``int`` for " "``$user_guid``" msgstr "" +"``uservalidationbyemail_request_validation()`` requiert désormais un ``int``" +" pour ``$user_guid``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:355 msgid "" @@ -17274,28 +17682,38 @@ msgid "" "a ``bool`` for ``$require_api_auth`` and ``$require_user_auth`` and " "``$assoc``" msgstr "" +"``elgg_ws_expose_function()`` requiert désormais un ``string`` pour " +"``$method``, ``$description`` et ``$call_method``, un ``array`` pour " +"``$parameters`` et un ``bool`` pour ``$require_api_auth``, " +"``$require_user_auth`` et ``$assoc``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:356 msgid "" "``elgg_ws_register_service_handler()`` now requires a ``string`` for " "``$handler``" msgstr "" +"``elgg_ws_register_service_handler()`` requiert désormais un ``string`` pour" +" ``$handler``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:357 msgid "" "``elgg_ws_unexpose_function()`` now requires a ``string`` for ``$method`` " "and a ``string`` for ``$http_request_method``" msgstr "" +"``elgg_ws_unexpose_function()`` requiert désormais un ``string`` pour " +"``$method`` et un ``string`` pour ``$http_request_method``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:358 msgid "" "``elgg_ws_unregister_service_handler()`` now requires a ``string`` for " "``$handler``" msgstr "" +"``elgg_ws_unregister_service_handler()`` requiert désormais un ``string`` " +"pour ``$handler``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:361 msgid "Class function return types" -msgstr "" +msgstr "Types de retour des fonctions de classes" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:363 msgid "``\\ElggEntity::deleteMetadata()`` no longer returns ``null``" @@ -17343,462 +17761,641 @@ msgid "" "``\\ElggAccessCollection::getObjectFromID()`` now requires a ``int`` for " "``$id``" msgstr "" +"``\\ElggAccessCollection::getObjectFromID()`` requiert désormais un ``int`` " +"pour ``$id``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:375 msgid "" "``\\ElggAnnotation::getObjectFromID()`` now requires a ``int`` for ``$id``" msgstr "" +"``\\ElggAnnotation::getObjectFromID()`` requiert désormais un ``int`` pour " +"``$id``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:376 msgid "" "``\\ElggEntity::addRelationship()`` now requires an ``int`` for " "``$guid_two`` and a ``string`` for ``$relationship``" msgstr "" +"``\\ElggEntity::addRelationship()`` requiert désormais un ``int`` pour " +"``$guid_two`` et un ``string`` pour ``$relationship``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:377 msgid "``\\ElggEntity::cache()`` now requires a ``bool`` for ``$persist``" msgstr "" +"``\\ElggEntity::cache()`` requiert désormais un ``bool`` pour ``$persist``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:378 msgid "" "``\\ElggEntity::canAnnotate()`` now requires an ``int`` for ``$user_guid`` " "and a ``string`` for ``$annotation_name``" msgstr "" +"``\\ElggEntity::canAnnotate()`` requiert désormais un ``int`` pour " +"``$user_guid`` et un ``string`` pour ``$annotation_name``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:379 msgid "" "``\\ElggEntity::canComment()`` now requires an ``int`` for ``$user_guid``" msgstr "" +"``\\ElggEntity::canComment()`` requiert désormais un ``int`` pour " +"``$user_guid``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:380 msgid "``\\ElggEntity::canDelete()`` now requires an ``int`` for ``$user_guid``" msgstr "" +"``\\ElggEntity::canDelete()`` requiert désormais un ``int`` pour " +"``$user_guid``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:381 msgid "``\\ElggEntity::canEdit()`` now requires an ``int`` for ``$user_guid``" msgstr "" +"``\\ElggEntity::canEdit()`` requiert désormais un ``int`` pour " +"``$user_guid``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:382 msgid "" "``\\ElggEntity::canWriteToContainer()`` now requires an ``int`` for " "``$user_guid`` and a ``string`` for ``$type`` and ``$subtype``" msgstr "" +"``\\ElggEntity::canWriteToContainer()`` requiert désormais un ``int`` pour " +"``$user_guid`` et un ``string`` pour ``$type`` et ``$subtype``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:383 msgid "" "``\\ElggEntity::countAnnotations()`` now requires a ``string`` for ``$name``" msgstr "" +"``\\ElggEntity::countAnnotations()`` requiert désormais un ``string`` pour " +"``$name``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:384 msgid "" "``\\ElggEntity::countEntitiesFromRelationship()`` now requires a ``string`` " "for ``$relationship`` and a ``bool`` for ``$inverse_relationship``" msgstr "" +"``\\ElggEntity::countEntitiesFromRelationship()`` requiert désormais un " +"``string`` pour ``$relationship`` et un ``bool`` pour " +"``$inverse_relationship``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:385 msgid "``\\ElggEntity::delete()`` now requires a ``bool`` for ``$recursive``" msgstr "" +"``\\ElggEntity::delete()`` requiert désormais un ``bool`` pour " +"``$recursive``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:386 msgid "" "``\\ElggEntity::deleteAnnotations()`` now requires a ``string`` for " "``$name``" msgstr "" +"``\\ElggEntity::deleteAnnotations()`` requiert désormais un ``string`` pour " +"``$name``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:387 msgid "``\\ElggEntity::deleteIcon()`` now requires a ``string`` for ``$type``" msgstr "" +"``\\ElggEntity::deleteIcon()`` requiert désormais un ``string`` pour " +"``$type``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:388 msgid "" "``\\ElggEntity::deleteMetadata()`` now requires a ``string`` for ``$name``" msgstr "" +"``\\ElggEntity::deleteMetadata()`` requiert désormais un ``string`` pour " +"``$name``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:389 msgid "" "``\\ElggEntity::deleteOwnedAnnotations()`` now requires a ``string`` for " "``$name``" msgstr "" +"``\\ElggEntity::deleteOwnedAnnotations()`` requiert désormais un ``string`` " +"pour ``$name``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:390 msgid "" "``\\ElggEntity::disable()`` now requires a ``string`` for ``$reason`` and a " "``bool`` for ``$recursive``" msgstr "" +"``\\ElggEntity::disable()`` requiert désormais un ``string`` pour " +"``$reason`` et un ``bool`` pour ``$recursive``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:391 msgid "" "``\\ElggEntity::disableAnnotations()`` now requires a ``string`` for " "``$name``" msgstr "" +"``\\ElggEntity::disableAnnotations()`` requiert désormais un ``string`` pour" +" ``$name``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:392 msgid "``\\ElggEntity::enable()`` now requires a ``bool`` for ``$recursive``" msgstr "" +"``\\ElggEntity::enable()`` requiert désormais un ``bool`` pour " +"``$recursive``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:393 msgid "" "``\\ElggEntity::enableAnnotations()`` now requires a ``string`` for " "``$name``" msgstr "" +"``\\ElggEntity::enableAnnotations()`` requiert désormais un ``string`` pour " +"``$name``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:394 msgid "" "``\\ElggEntity::getAnnotationsAvg()`` now requires a ``string`` for " "``$name``" msgstr "" +"``\\ElggEntity::getAnnotationsAvg()`` requiert désormais un ``string`` pour " +"``$name``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:395 msgid "" "``\\ElggEntity::getAnnotationsMax()`` now requires a ``string`` for " "``$name``" msgstr "" +"``\\ElggEntity::getAnnotationsMax()`` requiert désormais un ``string`` pour " +"``$name``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:396 msgid "" "``\\ElggEntity::getAnnotationsSum()`` now requires a ``string`` for " "``$name``" msgstr "" +"``\\ElggEntity::getAnnotationsSum()`` requiert désormais un ``string`` pour " +"``$name``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:397 msgid "" "``\\ElggEntity::getIcon()`` now requires a ``string`` for ``$size`` and " "``$type``" msgstr "" +"``\\ElggEntity::getIcon()`` requiert désormais un ``string`` pour ``$size`` " +"et ``$type``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:398 msgid "" "``\\ElggEntity::getIconLastChange()`` now requires a ``string`` for " "``$size`` and ``$type``" msgstr "" +"``\\ElggEntity::getIconLastChange()`` requiert désormais un ``string`` pour " +"``$size`` et ``$type``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:399 msgid "" "``\\ElggEntity::getIconURL()`` now requires a ``string`` or ``array`` for " "``$params``" msgstr "" +"``\\ElggEntity::getIconURL()`` requiert désormais un ``string`` ou un " +"``array`` pour ``$params``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:400 msgid "``\\ElggEntity::getObjectFromID()`` now requires an ``int`` for ``$id``" msgstr "" +"``\\ElggEntity::getObjectFromID()`` requiert désormais un ``int`` pour " +"``$id``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:401 msgid "" "``\\ElggEntity::getOwnedAccessCollections()`` now requires an ``array`` for " "``$options``" msgstr "" +"``\\ElggEntity::getOwnedAccessCollections()`` requiert désormais un " +"``array`` pour ``$options``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:402 msgid "" "``\\ElggEntity::getOwnedAccessCollection()`` now requires a ``string`` for " "``$subtype``" msgstr "" +"``\\ElggEntity::getOwnedAccessCollection()`` requiert désormais un " +"``string`` pour ``$subtype``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:403 msgid "``\\ElggEntity::getMetadata()`` now requires a ``string`` for ``$name``" msgstr "" +"``\\ElggEntity::getMetadata()`` requiert désormais un ``string`` pour " +"``$name``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:404 msgid "" "``\\ElggEntity::getVolatileData()`` now requires a ``string`` for ``$name``" msgstr "" +"``\\ElggEntity::getVolatileData()`` requiert désormais un ``string`` pour " +"``$name``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:405 msgid "" "``\\ElggEntity::hasIcon()`` now requires a ``string`` for ``$size`` and " "``$type``" msgstr "" +"``\\ElggEntity::hasIcon()`` requiert désormais un ``string`` pour ``$size`` " +"et ``$type``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:406 msgid "" "``\\ElggEntity::removeAllRelationships()`` no longer allows ``null`` to be " "passed to ``$relationship``" msgstr "" +"``\\ElggEntity::removeAllRelationships()`` ne permet plus de transmettre " +"``null`` à ``$relationship``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:407 msgid "" "``\\ElggEntity::removeRelationship()`` now requires an ``int`` for " "``$guid_two`` and a ``string`` for ``$relationship``" msgstr "" +"``\\ElggEntity::removeRelationship()`` requiert désormais un ``int`` pour " +"``$guid_two`` et un ``string`` pour ``$relationship``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:408 msgid "" "``\\ElggEntity::saveIconFromElggFile()`` now requires a ``string`` for " "``$type``" msgstr "" +"``\\ElggEntity::saveIconFromElggFile()`` requiert désormais un ``string`` " +"pour ``$type``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:409 msgid "" "``\\ElggEntity::saveIconFromLocalFile()`` now requires a ``string`` for " "``$input_name`` and ``$type``" msgstr "" +"``\\ElggEntity::saveIconFromLocalFile()`` requiert désormais un ``string`` " +"pour ``$input_name`` et ``$type``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:410 msgid "" "``\\ElggEntity::saveIconFromUploadedFile()`` now requires a ``string`` for " "``$input_name`` and ``$type``" msgstr "" +"``\\ElggEntity::saveIconFromUploadedFile()`` requiert désormais un " +"``string`` pour ``$input_name`` et ``$type``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:411 msgid "" "``\\ElggEntity::setContainerGUID()`` now requires an ``int`` for " "``$container_guid``" msgstr "" +"``\\ElggEntity::setContainerGUID()`` requiert désormais un ``int`` pour " +"``$container_guid``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:412 msgid "" "``\\ElggEntity::setDisplayName()`` now requires a ``string`` for " "``$display_name``" msgstr "" +"``\\ElggEntity::setDisplayName()`` requiert désormais un ``string`` pour " +"``$display_name``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:413 msgid "" "``\\ElggEntity::setMetadata()`` now requires a ``string`` for ``$name`` and " "``$value_type`` and a ``bool`` for ``$multiple``" msgstr "" +"``\\ElggEntity::setMetadata()`` requiert désormais un ``string`` pour " +"``$name`` et ``$value_type`` et un ``bool`` pour ``$multiple``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:414 msgid "" "``\\ElggEntity::setTempMetadata()`` now requires a ``string`` for ``$name`` " "and a ``bool`` for ``$multiple``" msgstr "" +"``\\ElggEntity::setTempMetadata()`` requiert désormais un ``string`` pour " +"``$name`` et un ``bool`` pour ``$multiple``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:415 msgid "" "``\\ElggEntity::setVolatileData()`` now requires a ``string`` for ``$name``" msgstr "" +"``\\ElggEntity::setVolatileData()`` requiert désormais un ``string`` pour " +"``$name``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:416 msgid "" "``\\ElggEntity::updateLastAction()`` now requires an ``int`` for ``$posted``" msgstr "" +"``\\ElggEntity::updateLastAction()`` requiert désormais un ``int`` pour " +"``$posted``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:417 msgid "``\\ElggMetadata::getObjectFromID()`` now requires a ``int`` for ``$id``" msgstr "" +"``\\ElggMetadata::getObjectFromID()`` requiert désormais un ``int`` pour " +"``$id``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:418 msgid "" "``\\ElggRelationship::getObjectFromID()`` now requires a ``int`` for ``$id``" msgstr "" +"``\\ElggRelationship::getObjectFromID()`` requiert désormais un ``int`` pour" +" ``$id``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:419 msgid "" "``\\ElggFile::getDownloadURL()`` now requires a ``bool`` for ``$use_cookie``" " and a ``string`` for ``$expires``" msgstr "" +"``\\ElggFile::getDownloadURL()`` requiert désormais un ``bool`` pour " +"``$use_cookie`` et un ``string`` pour ``$expires``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:420 msgid "" "``\\ElggFile::getInlineURL()`` now requires a ``bool`` for ``$use_cookie`` " "and a ``string`` for ``$expires``" msgstr "" +"``\\ElggFile::getInlineURL()`` requiert désormais un ``bool`` pour " +"``$use_cookie`` et un ``string`` pour ``$expires``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:421 msgid "``\\ElggGroup::isToolEnabled()`` now requires a ``string`` for ``$name``" msgstr "" +"``\\ElggGroup::isToolEnabled()`` requiert désormais un ``string`` pour " +"``$name``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:422 msgid "``\\ElggMenuItem::factory()`` now requires an ``array`` for ``$options``" msgstr "" +"``\\ElggMenuItem::factory()`` requiert désormais un ``array`` pour " +"``$options``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:423 msgid "" "``\\ElggTempFile::getDownloadURL()`` now requires a ``bool`` for " "``$use_cookie`` and a ``string`` for ``$expires``" msgstr "" +"``\\ElggTempFile::getDownloadURL()`` requiert désormais un ``bool`` pour " +"``$use_cookie`` et un ``string`` pour ``$expires``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:424 msgid "" "``\\ElggTempFile::getInlineURL()`` now requires a ``bool`` for " "``$use_cookie`` and a ``string`` for ``$expires``" msgstr "" +"``\\ElggTempFile::getInlineURL()`` requiert désormais un ``bool`` pour " +"``$use_cookie`` et un ``string`` pour ``$expires``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:425 msgid "" "``\\Elgg\\WebServices\\Di\\ApiRegistrationService::registerApiMethod()`` now" " requires a ``\\Elgg\\WebServices\\ApiMethod`` as the only parameter" msgstr "" +"``\\Elgg\\WebServices\\Di\\ApiRegistrationService::registerApiMethod()`` " +"requiert désormais un ``\\Elgg\\WebServices\\ApiMethod`` comme unique " +"paramètre" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:428 msgid "Moved classes" -msgstr "" +msgstr "Classes déplacées" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:430 msgid "``\\ElggAutoP`` has been moved to ``\\Elgg\\Views\\AutoParagraph``" -msgstr "" +msgstr "``\\ElggAutoP`` a été déplacé vers ``\\Elgg\\Views\\AutoParagraph``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:431 msgid "``\\ElggCache`` has been moved to ``\\Elgg\\Cache\\BaseCache``" -msgstr "" +msgstr "``\\ElggCache`` a été déplacé vers ``\\Elgg\\Cache\\BaseCache``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:432 msgid "" "``\\ElggDiskFilestore`` has been moved to " "``\\Elgg\\Filesystem\\Filestore\\DiskFilestore``" msgstr "" +"``\\ElggDiskFilestore`` a été déplacé vers " +"``\\Elgg\\Filesystem\\Filestore\\DiskFilestore``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:433 msgid "``\\ElggFilestore`` has been moved to ``\\Elgg\\Filesystem\\Filestore``" -msgstr "" +msgstr "``\\ElggFilestore`` a été déplacé vers ``\\Elgg\\Filesystem\\Filestore``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:434 msgid "``\\ElggRewriteTester`` has been moved to ``\\Elgg\\Router\\RewriteTester``" -msgstr "" +msgstr "``\\ElggRewriteTester`` a été déplacé vers ``\\Elgg\\Router\\RewriteTester``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:435 msgid "" "``\\ElggTempDiskFilestore`` has been moved to " "``\\Elgg\\Filesystem\\Filestore\\TempDiskFilestore``" msgstr "" +"``\\ElggTempDiskFilestore`` a été déplacé vers " +"``\\Elgg\\Filesystem\\Filestore\\TempDiskFilestore``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:436 msgid "" "``\\Elgg\\Database\\SiteSecret`` has been moved to " "``\\Elgg\\Security\\SiteSecret``" msgstr "" +"``\\Elgg\\Database\\SiteSecret`` a été déplacé vers " +"``\\Elgg\\Security\\SiteSecret``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:441 msgid "``elgg_clear_plugin_hook_handlers`` use ``elgg_clear_event_handlers``" msgstr "" +"``elgg_clear_plugin_hook_handlers`` utilisez ``elgg_clear_event_handlers``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:442 msgid "" "``elgg_register_plugin_hook_handler`` use ``elgg_register_event_handler``" msgstr "" +"``elgg_register_plugin_hook_handler`` utilisez " +"``elgg_register_event_handler``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:443 -msgid "``elgg_trigger_plugin_hook`` use ``elgg_trigger_event_result``" -msgstr "" +msgid "``elgg_trigger_plugin_hook`` use ``elgg_trigger_event_results``" +msgstr "``elgg_trigger_plugin_hook`` utilisez ``elgg_trigger_event_results``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:444 msgid "" "``elgg_unregister_plugin_hook_handler`` use " "``elgg_unregister_event_handler``" msgstr "" +"``elgg_unregister_plugin_hook_handler`` utilisez " +"``elgg_unregister_event_handler``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:445 #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:466 msgid "``get_user_by_email`` use ``elgg_get_user_by_email``" -msgstr "" +msgstr "``get_user_by_email`` utilisez ``elgg_get_user_by_email``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:446 #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:467 msgid "``get_user_by_username`` use ``elgg_get_user_by_username``" -msgstr "" +msgstr "``get_user_by_username`` utilisez ``elgg_get_user_by_username``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:451 msgid "``Elgg\\WebServices\\ApiKeyForm``" -msgstr "" +msgstr "``Elgg\\WebServices\\ApiKeyForm``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:452 msgid "" "``Loggable`` this interface has been merged into the ``ElggData`` class" msgstr "" +"``Loggable`` cette interface a été fusionnée dans la classe ``ElggData``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:457 msgid "``blog_prepare_form_vars``" -msgstr "" +msgstr "``blog_prepare_form_vars``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:458 msgid "``bookmarks_prepare_form_vars``" -msgstr "" +msgstr "``bookmarks_prepare_form_vars``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:459 msgid "``discussion_prepare_form_vars``" -msgstr "" +msgstr "``discussion_prepare_form_vars``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:460 msgid "``elgg_get_breadcrumbs``" -msgstr "" +msgstr "``elgg_get_breadcrumbs``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:461 msgid "``elgg_pop_breadcrumb``" -msgstr "" +msgstr "``elgg_pop_breadcrumb``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:462 msgid "" "``elgg_set_email_transport`` use ``_elgg_services()->set('mailer', ...)``" msgstr "" +"``elgg_set_email_transport`` utilisez ``_elgg_services()->set('mailer', " +"...)``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:463 msgid "``elgg_trigger_deprecated_plugin_hook``" -msgstr "" +msgstr "``elgg_trigger_deprecated_plugin_hook``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:464 msgid "" "``elgg_ws_expose_function`` use ``elgg-plugin.php`` or ``'register', " "'api_methods'`` event" msgstr "" +"``elgg_ws_expose_function`` utilisez ``elgg-plugin.php`` ou l'événement " +"``'register', 'api_methods'``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:465 msgid "``file_prepare_form_vars``" -msgstr "" +msgstr "``file_prepare_form_vars``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:468 msgid "``groups_prepare_form_vars``" -msgstr "" +msgstr "``groups_prepare_form_vars``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:469 msgid "``messages_prepare_form_vars``" -msgstr "" +msgstr "``messages_prepare_form_vars``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:470 msgid "``pages_prepare_form_vars``" -msgstr "" +msgstr "``pages_prepare_form_vars``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:471 msgid "``thewire_latest_guid``" -msgstr "" +msgstr "``thewire_latest_guid``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:474 msgid "Removed class functions" -msgstr "" +msgstr "Fonctions de classe supprimées" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:476 msgid "``\\ElggWidget::saveSettings()``" -msgstr "" +msgstr "``\\ElggWidget::saveSettings()``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:479 msgid "Removed events" -msgstr "" +msgstr "Événements supprimés" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:481 msgid "" "``access:collections:addcollection, collection`` use the ``create, " "access_collection`` sequence" msgstr "" +"``access:collections:addcollection, collection`` utilisez la séquence " +"``create, access_collection``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:482 msgid "" "``access:collections:deletecollection, collection`` use the ``delete, " "access_collection`` sequence" msgstr "" +"``access:collections:deletecollection, collection`` utilisez la séquence " +"``delete, access_collection``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:483 msgid "``prepare, breadcrumbs`` use ``register, menu:breadcrumbs``" -msgstr "" +msgstr "``prepare, breadcrumbs`` utilisez ``register, menu:breadcrumbs``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:484 msgid "``widget_settings, ``" -msgstr "" +msgstr "``widget_settings, ``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:489 msgid "``\\Elgg\\Exceptions\\InvalidParameterException``" -msgstr "" +msgstr "``\\Elgg\\Exceptions\\InvalidParameterException``" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:492 msgid "Constants" -msgstr "" +msgstr "Constantes" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:494 msgid "" "The misspelled ``REFERER`` constant has been removed. Use ``REFERRER`` " "instead." msgstr "" +"La constante ``REFERER`` mal orthographiée a été supprimée. Utilisez plutôt " +"``REFERRER``." #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:495 msgid "" "The ``REFERRER`` constant has been changed to a string with the value " "``__elgg_referrer``" msgstr "" +"La constante ``REFERRER`` a été remplacée par une chaîne de caractères avec " +"la valeur ``__elgg_referrer``" + +#: ../../appendix/upgrade-notes/5.0-to-5.1.rst:2 +msgid "From 5.0 to 5.1" +msgstr "De 5.0 à 5.1" + +#: ../../appendix/upgrade-notes/5.0-to-5.1.rst:9 +msgid "Changes in the DOM structure" +msgstr "Changements dans la structure DOM" + +#: ../../appendix/upgrade-notes/5.0-to-5.1.rst:11 +msgid "" +"In order to improve accessibility the HTML DOM structure has been changed " +"slightly. Some sections of the page have been changed from a ``div`` to " +"``header``, ``main`` or ``footer``. The classes or place in the DOM has not " +"been changed." +msgstr "" +"Afin d'améliorer l'accessibilité, la structure DOM HTML a été légèrement " +"modifiée. Certaines sections de la page ont été modifiées de ``div`` à " +"``header``, ``main`` ou ``footer``. Les classes ou la position dans le DOM " +"n'ont pas été modifiées." + +#: ../../appendix/upgrade-notes/5.0-to-5.1.rst:17 +msgid "" +"``page/elements/
/after`` is deprecated: Extend the correct " +"``page/elements/
``" +msgstr "" +"``page/elements/
/after`` est obsolète : étendez le bon " +"``page/elements/
``" + +#: ../../appendix/upgrade-notes/5.0-to-5.1.rst:18 +msgid "" +"``page/elements/
/before`` is deprecated: Prepend the correct " +"``page/elements/
``" +msgstr "" +"``page/elements/
/before`` est obsolète : ajoutez le bon préfixe " +"``page/elements/
``" + +#: ../../appendix/upgrade-notes/5.0-to-5.1.rst:19 +msgid "" +"``resources/comments/edit`` is deprecated: This resource is no longer in use" +msgstr "" +"``resources/comments/edit`` est obsolète : cette ressource n'est plus " +"utilisée" + +#: ../../appendix/upgrade-notes/5.0-to-5.1.rst:24 +msgid "" +"``edit:object:comment`` is deprecated: Editing comments uses an inline form" +msgstr "" +"``edit:object:comment`` est obsolète : la modification des commentaires " +"utilise un formulaire en ligne" diff --git a/docs/locale/fr/LC_MESSAGES/contribute.mo b/docs/locale/fr/LC_MESSAGES/contribute.mo index 43dbd5295fd..26dda6928d2 100644 Binary files a/docs/locale/fr/LC_MESSAGES/contribute.mo and b/docs/locale/fr/LC_MESSAGES/contribute.mo differ diff --git a/docs/locale/fr/LC_MESSAGES/contribute.po b/docs/locale/fr/LC_MESSAGES/contribute.po index 5f0a00a69ce..342b76028f0 100644 --- a/docs/locale/fr/LC_MESSAGES/contribute.po +++ b/docs/locale/fr/LC_MESSAGES/contribute.po @@ -12,7 +12,7 @@ msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-31 15:46+0200\n" +"POT-Creation-Date: 2023-12-15 13:56+0100\n" "PO-Revision-Date: 2023-04-05 07:42+0000\n" "Last-Translator: Florian DANIEL aka Facyla , 2023\n" "Language-Team: French (https://app.transifex.com/elgg/teams/11337/fr/)\n" @@ -1085,7 +1085,7 @@ msgstr "" "La compatibilité avec `PSR-1`__ est encouragée, mais pas strictement " "requise." -#: ../../contribute/code.rst:479 ../../contribute/core/move_plugin.rst:124 +#: ../../contribute/code.rst:479 ../../contribute/core/move_plugin.rst:121 msgid "Documentation" msgstr "Documentation" @@ -1487,7 +1487,7 @@ msgstr "" "Assurez-vous que le ``composer.json`` du plugin contient bien toutes les " "informations pertinentes. Voici un exemple :" -#: ../../contribute/core/move_plugin.rst:80 +#: ../../contribute/core/move_plugin.rst:77 msgid "" "The ``conflict`` rule is there to help prevent the installation of this " "plugin in an unsupported Elgg version." @@ -1495,7 +1495,7 @@ msgstr "" "La règle ``conflict`` est ici pour aider à éviter l'installation de ce " "plugin dans une version de Elgg non supportée." -#: ../../contribute/core/move_plugin.rst:82 +#: ../../contribute/core/move_plugin.rst:79 msgid "" "Add the repository to `Packagist`_, for the existing repositories this was " "already done. Make sure `Packagist`_ is updated correctly with all the " @@ -1505,11 +1505,11 @@ msgstr "" "fait. Assurez-vous que `Packagist`_ est mis à jour correctement avec tous " "les commits." -#: ../../contribute/core/move_plugin.rst:86 +#: ../../contribute/core/move_plugin.rst:83 msgid "Tag a release" msgstr "Taguer une release" -#: ../../contribute/core/move_plugin.rst:88 +#: ../../contribute/core/move_plugin.rst:85 msgid "" "In order for Composer to be able to cache the plugin for faster " "installation, a release has to be made on the repository. Probably the first" @@ -1523,12 +1523,12 @@ msgstr "" "mentionnée dans ``elgg-plugin.php`` ou ``composer.json``. Après cela le " "développement peut commencer, en suivant le schéma de version `Semver`_." -#: ../../contribute/core/move_plugin.rst:93 -#: ../../contribute/core/move_plugin.rst:109 ../../contribute/i18n.rst:2 +#: ../../contribute/core/move_plugin.rst:90 +#: ../../contribute/core/move_plugin.rst:106 ../../contribute/i18n.rst:2 msgid "Translations" msgstr "Traductions" -#: ../../contribute/core/move_plugin.rst:95 +#: ../../contribute/core/move_plugin.rst:92 msgid "" "If the translations for the plugin need to be managed by `Transifex`_, add " "the plugin to `Transifex`_." @@ -1536,11 +1536,11 @@ msgstr "" "Si les traductions pour le plugin doivent être gérées par `Transifex`_, " "ajoutez le plugin à `Transifex`_." -#: ../../contribute/core/move_plugin.rst:98 +#: ../../contribute/core/move_plugin.rst:95 msgid "Elgg core cleanup" msgstr "Nettoyage du noyau de Elgg" -#: ../../contribute/core/move_plugin.rst:100 +#: ../../contribute/core/move_plugin.rst:97 msgid "" "Now that the plugin has been moved to it's own repository, it's time to make" " a Pull Request on Elgg core to remove the original code." @@ -1549,15 +1549,15 @@ msgstr "" "de faire une Pull Request sur le noyau de Elgg pour supprimer le code " "originel." -#: ../../contribute/core/move_plugin.rst:103 +#: ../../contribute/core/move_plugin.rst:100 msgid "Remove the plugin" msgstr "Supprimez le plugin" -#: ../../contribute/core/move_plugin.rst:105 +#: ../../contribute/core/move_plugin.rst:102 msgid "Delete the ``mod`` folder for the plugin" msgstr "Supprimez le plugin du dossier ``mod``" -#: ../../contribute/core/move_plugin.rst:106 +#: ../../contribute/core/move_plugin.rst:103 msgid "" "Search for the plugin name in core to find any references which also need to" " be removed (eg. old docs, special tests, etc.)" @@ -1566,7 +1566,7 @@ msgstr "" "aurait également besoin d'être retirée (par ex. anciennes documentations, " "tests spéciaux, etc.)" -#: ../../contribute/core/move_plugin.rst:111 +#: ../../contribute/core/move_plugin.rst:108 msgid "" "Since the plugin no longer is part of Elgg core, make sure the configuration" " of `Transifex`_ no longer contains the plugin." @@ -1574,11 +1574,11 @@ msgstr "" "Dans la mesure où le plugin ne fait plus partie du noyau de Elgg, assurez-" "vous que la configuration de `Transifex`_ ne contient plus le plugin." -#: ../../contribute/core/move_plugin.rst:114 +#: ../../contribute/core/move_plugin.rst:111 msgid "Bundled" msgstr "Plugins inclus" -#: ../../contribute/core/move_plugin.rst:116 +#: ../../contribute/core/move_plugin.rst:113 msgid "" "If the plugin still comes bundled with the release of a new Elgg version, " "make sure to add the plugin to the ``composer.json``." @@ -1587,11 +1587,11 @@ msgstr "" "nouvelle version de Elgg, assurez-vous d'ajouter le plugin dans " "``composer.json``." -#: ../../contribute/core/move_plugin.rst:119 +#: ../../contribute/core/move_plugin.rst:116 msgid "Composer" msgstr "Composer" -#: ../../contribute/core/move_plugin.rst:121 +#: ../../contribute/core/move_plugin.rst:118 msgid "" "Check the core composer dependencies if requirements that were specific for " "the removed plugin can also be removed in the core dependencies." @@ -1600,7 +1600,7 @@ msgstr "" "qui étaient spécifiques pour le plugin retiré peuvent également être " "retirées des dépendances du noyau." -#: ../../contribute/core/move_plugin.rst:126 +#: ../../contribute/core/move_plugin.rst:123 msgid "" "Add a mention in the :doc:`/appendix/upgrade-notes` documentation that the " "plugin was removed from Elgg core." @@ -1765,12 +1765,11 @@ msgid "Make a PR with translation updates" msgstr "Faites un PR avec les mises à jour des traductions" #: ../../contribute/core/releases.rst:75 -#: ../../contribute/core/releases.rst:113 msgid "Install the prerequisites:" msgstr "Installez les pré-requis :" #: ../../contribute/core/releases.rst:85 -#: ../../contribute/core/releases.rst:121 +#: ../../contribute/core/releases.rst:115 msgid "" "On Windows you need to run these command in a console with admin privileges" msgstr "" @@ -1824,16 +1823,16 @@ msgstr "" "Visitez ``https://github.com/Elgg/Elgg/compare/...`` et soumettez " "le PR si quoi que ce soit a besoin d'être fusionné plus haut." -#: ../../contribute/core/releases.rst:123 +#: ../../contribute/core/releases.rst:117 msgid "Run the ``release.php`` script. For example, to release 1.12.5:" msgstr "" "Exécutez le script ``release.php``. Par exemple, pour publier 1.12.5 :" -#: ../../contribute/core/releases.rst:130 +#: ../../contribute/core/releases.rst:124 msgid "This creates a ``release-1.12.5`` branch in your local repo." msgstr "Ceci crée une branche ``release-1.12.5`` dans votre repo local." -#: ../../contribute/core/releases.rst:132 +#: ../../contribute/core/releases.rst:126 msgid "" "Next, submit a pull request via GitHub for automated testing and approval by" " another developer:" @@ -1841,27 +1840,27 @@ msgstr "" "Ensuite, soumettez une demande de fusion -PR- via GitHub pour les tests " "automatisés et l’approbation par un autre développeur :" -#: ../../contribute/core/releases.rst:139 +#: ../../contribute/core/releases.rst:133 msgid "Tag the release" msgstr "Taguez la release" -#: ../../contribute/core/releases.rst:141 +#: ../../contribute/core/releases.rst:135 msgid "Once approved and merged, create a release on GitHub:" msgstr "Une fois approuvée et fusionnée, créez une version sur GitHub :" -#: ../../contribute/core/releases.rst:143 +#: ../../contribute/core/releases.rst:137 msgid "Goto releases" msgstr "Allez sur les releases" -#: ../../contribute/core/releases.rst:144 +#: ../../contribute/core/releases.rst:138 msgid "Click 'Draft a new release'" msgstr "Cliquez sur 'Draft a new release'" -#: ../../contribute/core/releases.rst:145 +#: ../../contribute/core/releases.rst:139 msgid "Enter the version" msgstr "Saisissez la version" -#: ../../contribute/core/releases.rst:146 +#: ../../contribute/core/releases.rst:140 msgid "" "Select the correct branch (eg 1.12 for a 1.12.x release, 2.3 for a 2.3.x " "release, etc)" @@ -1869,17 +1868,17 @@ msgstr "" "Sélectionnez la bonne branche (par ex. 1.12 pour une release 1.12.x, 2.3 " "pour une release 2.3.x, etc.)" -#: ../../contribute/core/releases.rst:147 +#: ../../contribute/core/releases.rst:141 msgid "Set the release title as 'Elgg {version}'" msgstr "Définissez le titre de la release comme 'Elgg {version}'" -#: ../../contribute/core/releases.rst:148 +#: ../../contribute/core/releases.rst:142 msgid "Paste the CHANGELOG.md part related to this release in the description" msgstr "" "Collez la partie de CHANGELOG.md relative à cette release dans la " "description" -#: ../../contribute/core/releases.rst:152 +#: ../../contribute/core/releases.rst:146 msgid "" "GitHub is setup to listen to the creation of a new release to automaticly " "make the ZIP release of Elgg. After the release was created wait a few " @@ -1889,29 +1888,29 @@ msgstr "" " créer automatiquement la version ZIP de Elgg. Une fois la version créée, " "attendez quelques minutes et le ZIP devrait être ajouté à la version." -#: ../../contribute/core/releases.rst:155 +#: ../../contribute/core/releases.rst:149 msgid "Some final administration" msgstr "Un peu d'administration pour terminer" -#: ../../contribute/core/releases.rst:157 +#: ../../contribute/core/releases.rst:151 msgid "Mark GitHub release milestones as completed" msgstr "Marquez les jalons de release Github comme terminés" -#: ../../contribute/core/releases.rst:158 +#: ../../contribute/core/releases.rst:152 msgid "Move unresolved tickets in released milestones to later milestones" msgstr "" "Déplacez les tickets non résolus des jalons publiés vers des jalons " "ultérieurs" -#: ../../contribute/core/releases.rst:161 +#: ../../contribute/core/releases.rst:155 msgid "Additional actions for the first new minor / major" msgstr "Actions supplémentaires pour la première nouvelle mineure / majeure" -#: ../../contribute/core/releases.rst:163 +#: ../../contribute/core/releases.rst:157 msgid "Make a new branch on GitHub (for example 3.3)" msgstr "Créez une nouvelle branche sur GitHub (par exemple 3.3)" -#: ../../contribute/core/releases.rst:164 +#: ../../contribute/core/releases.rst:158 msgid "" "Set the new branch as the default branch (optional, but suggested for stable" " releases)" @@ -1919,17 +1918,17 @@ msgstr "" "Définissez la nouvelle branche comme branche par défaut (facultatif, mais " "suggéré pour les versions stables)" -#: ../../contribute/core/releases.rst:165 +#: ../../contribute/core/releases.rst:159 msgid "Configure `Read The Docs`_ to build the new branch (not the new tag)" msgstr "" "Configurez `Read The Docs`_ pour créer la nouvelle branche (pas le nouveau " "tag)" -#: ../../contribute/core/releases.rst:166 +#: ../../contribute/core/releases.rst:160 msgid "Configure `Scrutinizer`_ to build the new branch" msgstr "Configurez `Scrutinizer`_ pour créer la nouvelle branche" -#: ../../contribute/core/releases.rst:167 +#: ../../contribute/core/releases.rst:161 msgid "" "Check the Elgg starter project for potential requirement / config changes in" " the ``composer.json``" @@ -1937,7 +1936,7 @@ msgstr "" "Vérifiez le projet de démarrage Elgg pour les pré-requis potentiels / " "modifications de configuration dans le ``composer.json``" -#: ../../contribute/core/releases.rst:168 +#: ../../contribute/core/releases.rst:162 msgid "" "Add the new minor / major version to the ``Elgg/community_plugins`` " "repository so developers can upload plugins for the new release" @@ -1946,7 +1945,7 @@ msgstr "" "``Elgg/community_plugins`` afin que les développeurs puissent télécharger " "des plugins pour la nouvelle version" -#: ../../contribute/core/releases.rst:169 +#: ../../contribute/core/releases.rst:163 msgid "" "Update the build configuration for the `Elgg reference`_ (on the Elgg.org " "webserver)" @@ -1954,93 +1953,93 @@ msgstr "" "Mettez à jour la configuration de build pour `Elgg reference`_ (sur le " "serveur web Elgg.org)" -#: ../../contribute/core/releases.rst:179 +#: ../../contribute/core/releases.rst:173 msgid "Additional action for the first new major" msgstr "Action supplémentaire pour la première nouvelle majeure" -#: ../../contribute/core/releases.rst:181 +#: ../../contribute/core/releases.rst:175 msgid "On GitHub add a branch protection rule (for example ``4.*``)" msgstr "" "Sur GitHub ajoutez une règle de protection de branche (par exemple ``4.*``)" -#: ../../contribute/core/releases.rst:182 +#: ../../contribute/core/releases.rst:176 msgid "" "Configure Scrutinizer to track the new major branches (for example ``4.*``)" msgstr "" "Configurez Scrutinizer pour suivre les nouvelles branches principales (par " "exemple ``4.*``)" -#: ../../contribute/core/releases.rst:185 +#: ../../contribute/core/releases.rst:179 msgid "Update the website" msgstr "Mettez à jour le site web" -#: ../../contribute/core/releases.rst:188 +#: ../../contribute/core/releases.rst:182 msgid "Update elgg.org download page" msgstr "Mettez à jour la page de téléchargement de elgg.org" -#: ../../contribute/core/releases.rst:190 +#: ../../contribute/core/releases.rst:184 msgid "Clone https://github.com/Elgg/community" msgstr "Clonez https://github.com/Elgg/community" -#: ../../contribute/core/releases.rst:191 +#: ../../contribute/core/releases.rst:185 msgid "Add the new version to ``classes/Elgg/Releases.php``" msgstr "Ajoutez la nouvelle version dans ``classes/Elgg/Releases.php``" -#: ../../contribute/core/releases.rst:192 -#: ../../contribute/core/releases.rst:212 +#: ../../contribute/core/releases.rst:186 +#: ../../contribute/core/releases.rst:206 msgid "Commit and push the changes" msgstr "Commitez et poussez les modifications" -#: ../../contribute/core/releases.rst:193 +#: ../../contribute/core/releases.rst:187 msgid "Download the ZIP release from GitHub" msgstr "Téléchargez la version ZIP depuis GitHub" -#: ../../contribute/core/releases.rst:194 +#: ../../contribute/core/releases.rst:188 msgid "Upload the ZIP to the elgg.org webserver" msgstr "Chargez le ZIP sur le serveur web elgg.org" -#: ../../contribute/core/releases.rst:202 +#: ../../contribute/core/releases.rst:196 msgid "Update elgg.org" msgstr "Mettez à jour elgg.org" -#: ../../contribute/core/releases.rst:204 +#: ../../contribute/core/releases.rst:198 msgid "Clone https://github.com/Elgg/www.elgg.org" msgstr "Clonez https://github.com/Elgg/www.elgg.org" -#: ../../contribute/core/releases.rst:205 +#: ../../contribute/core/releases.rst:199 msgid "(optional) Change the required Elgg version in ``composer.json``" msgstr "" "(facultatif) Modifiez la version de Elgg requise dans ``composer.json``" -#: ../../contribute/core/releases.rst:206 +#: ../../contribute/core/releases.rst:200 msgid "Update vendors" msgstr "Mettez à jours les vendors" -#: ../../contribute/core/releases.rst:213 +#: ../../contribute/core/releases.rst:207 msgid "Pull to live site" msgstr "Faites un pull vers le site en activité" -#: ../../contribute/core/releases.rst:222 +#: ../../contribute/core/releases.rst:216 msgid "Go to community admin panel" msgstr "Allez sur la panneau admin de la communauté" -#: ../../contribute/core/releases.rst:223 +#: ../../contribute/core/releases.rst:217 msgid "Flush APC cache" msgstr "Videz le cache APC" -#: ../../contribute/core/releases.rst:224 +#: ../../contribute/core/releases.rst:218 msgid "Run upgrade" msgstr "Exécutez la mise à niveau" -#: ../../contribute/core/releases.rst:227 +#: ../../contribute/core/releases.rst:221 msgid "Make the announcement" msgstr "Faites l'annonce" -#: ../../contribute/core/releases.rst:229 +#: ../../contribute/core/releases.rst:223 msgid "This should be the very last thing you do." msgstr "Ceci devrait être la toute dernière chose à faire." -#: ../../contribute/core/releases.rst:231 +#: ../../contribute/core/releases.rst:225 msgid "" "Open ``https://github.com/Elgg/Elgg/blob//CHANGELOG.md`` and copy the " "contents for that version" @@ -2048,13 +2047,13 @@ msgstr "" "Ouvrez ``https://github.com/Elgg/Elgg/blob//CHANGELOG.md`` et copiez le" " contenu pour cette version" -#: ../../contribute/core/releases.rst:232 +#: ../../contribute/core/releases.rst:226 msgid "Sign in at https://elgg.org/blog and compose a new blog with a summary" msgstr "" "Connectez-vous sur https://elgg.org/blog et rédigez un nouvel article de " "blog avec un sommaire" -#: ../../contribute/core/releases.rst:233 +#: ../../contribute/core/releases.rst:227 msgid "" "Copy in the CHANGELOG contents, clear formatting, and manually remove the " "SVG anchors" @@ -2062,7 +2061,7 @@ msgstr "" "Copiez le contenu dans le CHANGELOG, supprimez le formattage, et supprimez " "manuellement les balises SVG" -#: ../../contribute/core/releases.rst:234 +#: ../../contribute/core/releases.rst:228 msgid "" "Add tags ``release`` and ``elgg2.x`` where x is whatever branch is being " "released" @@ -2070,7 +2069,7 @@ msgstr "" "Ajoutez les tags ``release`` et ``elgg2.x`` où x est le nom de la branche en" " train d'être publiée" -#: ../../contribute/core/releases.rst:235 +#: ../../contribute/core/releases.rst:229 msgid "Tweet from the elgg `Twitter account`_" msgstr "Tweetez depuis le `compte Twitter account`_ de Elgg" diff --git a/docs/locale/fr/LC_MESSAGES/design.mo b/docs/locale/fr/LC_MESSAGES/design.mo index 21373da973b..4b48d145d09 100644 Binary files a/docs/locale/fr/LC_MESSAGES/design.mo and b/docs/locale/fr/LC_MESSAGES/design.mo differ diff --git a/docs/locale/fr/LC_MESSAGES/design.po b/docs/locale/fr/LC_MESSAGES/design.po index c74ee8f9cd7..d81b97fb0e4 100644 --- a/docs/locale/fr/LC_MESSAGES/design.po +++ b/docs/locale/fr/LC_MESSAGES/design.po @@ -5,15 +5,16 @@ # # Translators: # Jerôme Bakker, 2023 +# Florian DANIEL aka Facyla , 2023 # #, fuzzy msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-31 15:46+0200\n" +"POT-Creation-Date: 2023-12-15 13:56+0100\n" "PO-Revision-Date: 2023-04-05 07:42+0000\n" -"Last-Translator: Jerôme Bakker, 2023\n" +"Last-Translator: Florian DANIEL aka Facyla , 2023\n" "Language-Team: French (https://app.transifex.com/elgg/teams/11337/fr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -444,7 +445,7 @@ msgstr "Représente" #: ../../design/database.rst:83 msgid "object" -msgstr "objet" +msgstr "object" #: ../../design/database.rst:83 msgid "``ElggObject``" @@ -458,7 +459,7 @@ msgstr "" #: ../../design/database.rst:84 msgid "group" -msgstr "groupe" +msgstr "group" #: ../../design/database.rst:84 msgid "``ElggGroup``" @@ -470,7 +471,7 @@ msgstr "Un groupe organisé d'utilisateurs avec sa propre page de profil" #: ../../design/database.rst:85 msgid "user" -msgstr "utilisateur" +msgstr "user" #: ../../design/database.rst:85 msgid "``ElggUser``" @@ -1538,6 +1539,13 @@ msgid "" "reference for permissions\\_check ` for more" " details." msgstr "" +"Vous pouvez remplacer ce comportement en utilisant un :doc:`event " +"` appelé ``permissions_check``, qui transmet l'entité en " +"question à toute fonction ayant annoncé qu'elle souhaite être référencée. " +"Renvoyer ``true`` autorisera l'accès en écriture ; renvoyer ``false`` le " +"bloquera. Voir :ref:`le guide de référence des événement pour la " +"vérification des permissions ` pour plus de " +"détails." #: ../../design/database.rst:657 msgid "Schema" @@ -1798,7 +1806,7 @@ msgstr "" #: ../../design/events.rst:2 msgid "Events" -msgstr "" +msgstr "Événements" #: ../../design/events.rst:11 msgid "" @@ -1814,6 +1822,9 @@ msgid "" "`_ such as functions " "and methods) and registering them to handle the events." msgstr "" +"Les plugins modifient le système en créant des gestionnaires (`callables " +"`_ tels que des " +"fonctions et des méthodes) et en les enregistrant pour gérer les événements." #: ../../design/events.rst:16 msgid "" @@ -1852,12 +1863,16 @@ msgid "" "These events are mostly used to notify the rest of the system that something" " has happened." msgstr "" +"Ces événements sont principalement utilisés pour informer le reste du " +"système que quelque chose s'est produit." #: ../../design/events.rst:32 msgid "" "There are also events that are used to influence output, configuration or " "behaviour of the system." msgstr "" +"Certains événements sont également utilisés pour modifier la sortie, la " +"configuration ou le comportement du système." #: ../../design/events.rst:34 msgid "" @@ -1865,6 +1880,9 @@ msgid "" "name, annotation, group) describing the type of object passed to the " "handlers." msgstr "" +"Chaque événement Elgg a un nom et un type (système, utilisateur, objet, nom " +"de relation, annotation, groupe) décrivant le type d'objet passé aux " +"gestionnaires." #: ../../design/events.rst:40 msgid "Before and After Events" @@ -1888,6 +1906,10 @@ msgid "" "When ``false`` is returned by a handler, following handlers will not be " "called." msgstr "" +"Les événements Précédents ont des noms se terminant par \":before\" et sont " +"déclenchés avant que quelque chose ne se produise. Les gestionnaires peuvent" +" annuler l'événement en renvoyant ``false``. Lorsque ``false`` est renvoyé " +"par un gestionnaire, les gestionnaires suivants ne seront pas appelés." #: ../../design/events.rst:50 msgid "" @@ -1895,6 +1917,10 @@ msgid "" " happened. Handlers *cannot* cancel these events; all handlers will always " "be called." msgstr "" +"Les événements Suivants, dont les noms se terminent par \":after\", sont " +"déclenchés après que quelque chose s'est produit. Les gestionnaires *ne " +"peuvent pas* annuler ces événements ; tous les gestionnaires seront toujours" +" appelés." #: ../../design/events.rst:53 msgid "" @@ -1950,6 +1976,8 @@ msgid "" "**$type** The event type (e.g. \"user\" or \"object\") or 'all' for all " "types on which the event is fired." msgstr "" +"**$type** Le type d'événement (par exemple \"user\" ou \"object\") ou 'all' " +"pour tous les types sur lesquels l'événement est déclenché." #: ../../design/events.rst:93 msgid "**$handler** The callback of the handler function." @@ -1988,6 +2016,9 @@ msgid "" "register the class name and it will be instantiated (with no arguments) for " "the lifetime of the event." msgstr "" +"Vous pouvez utiliser une classe avec une méthode ``__invoke()`` comme " +"gestionnaire. Enregistrez simplement le nom de la classe et il sera " +"instancié (sans argument) pour toute la durée de vie de l'événement." #: ../../design/events.rst:135 msgid "Trigger an Elgg Event" @@ -2033,7 +2064,7 @@ msgstr "" #: ../../design/events.rst:177 msgid "Trigger an Event with results" -msgstr "" +msgstr "Déclencher un Événement avec des résultats" #: ../../design/events.rst:179 msgid "" @@ -2041,6 +2072,10 @@ msgid "" "or alter a value. For example, to decide whether a user has permission to " "edit an entity or to add additional configuration options to a plugin." msgstr "" +"Les Événements avec résultats permettent aux plugins de déterminer ou de " +"modifier une valeur de manière collaborative. Par exemple, pour décider si " +"un utilisateur est autorisé à modifier une entité ou à ajouter des options " +"de configuration supplémentaires à un plugin." #: ../../design/events.rst:183 msgid "" @@ -2049,18 +2084,24 @@ msgid "" "After the last handler has completed, the final value is returned by the " "trigger." msgstr "" +"Un événement a une valeur transmise à la fonction de déclenchement, et " +"chaque gestionnaire a la possibilité de modifier cette valeur avant qu'elle " +"ne soit transmise au gestionnaire suivant. Une fois le dernier gestionnaire " +"terminé, la valeur finale est renvoyée par le déclencheur." #: ../../design/events.rst:188 msgid "You can trigger a custom event using ``elgg_trigger_event_results``:" msgstr "" +"Vous pouvez déclencher un événement personnalisé en utilisant " +"``elgg_trigger_event_results`` :" #: ../../design/events.rst:199 msgid "**$name** The name of the event." -msgstr "" +msgstr "**$name** Le nom de l'événement." #: ../../design/events.rst:200 msgid "**$type** The type of the event or 'all' for all types." -msgstr "" +msgstr "**$type** Le type d'événement ou \"all\" pour tous les types." #: ../../design/events.rst:201 msgid "**$params** Arbitrary data passed from the trigger to the handlers." @@ -2070,7 +2111,7 @@ msgstr "" #: ../../design/events.rst:202 msgid "**$value** The initial value of the event." -msgstr "" +msgstr "**$value** La valeur initiale de l'événement." #: ../../design/events.rst:205 msgid "Trigger an Elgg Event sequence" @@ -2115,7 +2156,7 @@ msgstr "" #: ../../design/events.rst:228 msgid "Unregister Event Handlers" -msgstr "" +msgstr "Dés-inscrire des Gestionnaires d'événement" #: ../../design/events.rst:230 msgid "" @@ -2124,6 +2165,10 @@ msgid "" "are in the same order as the registration functions, except there's no " "priority parameter." msgstr "" +"Les fonctions ``elgg_unregister_event_handler`` peuvent être utilisées pour " +"supprimer les gestionnaires déjà enregistrés par un autre plugin ou le coeur" +" de Elgg. Les paramètres sont dans le même ordre que les fonctions " +"d'enregistrement, sauf qu'il n'y a pas de paramètre de priorité." #: ../../design/events.rst:240 msgid "" @@ -2352,6 +2397,11 @@ msgid "" "config/settings.php``. Additional criteria can be added by a plugin by " "registering for the ``registeruser:validate:password`` event." msgstr "" +"La seule restriction que Elgg impose sur un mot de passe est qu'il doit " +"contenir au moins 6 caractères par défaut, même si cela puisse être modifié " +"dans ``/elgg-config/settings.php``. Des critères supplémentaires peuvent " +"être ajoutés par un plugin en s'enregistrant auprès de l'événement " +"``registeruser:validate:password``." #: ../../design/security.rst:25 msgid "Password hashing" @@ -2557,6 +2607,9 @@ msgid "" "function takes in a string and returns a filtered string. It triggers a " "``sanitize, input`` event." msgstr "" +"Le filtrage est effectué via la fonction ``elgg_sanitize_input()``. Cette " +"fonction récupère une chaîne et renvoie une chaîne filtrée. Il déclenche un " +"événement ``sanitize, input``." #: ../../design/security.rst:96 msgid "" diff --git a/docs/locale/fr/LC_MESSAGES/guides.mo b/docs/locale/fr/LC_MESSAGES/guides.mo index a5368afe3c3..d76af5780bb 100644 Binary files a/docs/locale/fr/LC_MESSAGES/guides.mo and b/docs/locale/fr/LC_MESSAGES/guides.mo differ diff --git a/docs/locale/fr/LC_MESSAGES/guides.po b/docs/locale/fr/LC_MESSAGES/guides.po index 69a4c7a4685..7c63751d995 100644 --- a/docs/locale/fr/LC_MESSAGES/guides.po +++ b/docs/locale/fr/LC_MESSAGES/guides.po @@ -5,15 +5,16 @@ # # Translators: # Jerôme Bakker, 2023 +# Florian DANIEL aka Facyla , 2024 # #, fuzzy msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-31 15:46+0200\n" +"POT-Creation-Date: 2023-12-15 13:56+0100\n" "PO-Revision-Date: 2023-04-05 07:42+0000\n" -"Last-Translator: Jerôme Bakker, 2023\n" +"Last-Translator: Florian DANIEL aka Facyla , 2024\n" "Language-Team: French (https://app.transifex.com/elgg/teams/11337/fr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -563,7 +564,7 @@ msgstr "Personnaliser des actions" #: ../../guides/actions.rst:158 msgid "Before executing any action, Elgg triggers an event:" -msgstr "" +msgstr "Avant d'exécuter chaque action, Elgg déclenche un événement :" #: ../../guides/actions.rst:164 msgid "" @@ -571,6 +572,8 @@ msgid "" " then the action will not be executed. Don't return anything if your " "validation passes." msgstr "" +"Où ``$action`` est l'action appelée. Si l'événement renvoie ``false`` alors " +"l'action ne sera pas exécutée. Ne renvoyez rien si votre validation réussit." #: ../../guides/actions.rst:168 msgid "Example: Captcha" @@ -849,19 +852,31 @@ msgstr "" "autocomplétion" #: ../../guides/actions.rst:381 +msgid "``input/grouppicker`` - renders an Elgg group autocomplete" +msgstr "" +"``input/grouppicker`` - affiche un sélecteur de groupe Elgg par " +"autocomplétion" + +#: ../../guides/actions.rst:382 +msgid "``input/objectpicker`` - renders an Elgg object autocomplete" +msgstr "" +"``input/objectpicker`` - affiche un sélecteur d'objet Elgg par " +"autocomplétion" + +#: ../../guides/actions.rst:383 msgid "``input/location`` renders an Elgg location input" msgstr "``input/location`` affiche une entrée de type adresse" -#: ../../guides/actions.rst:384 +#: ../../guides/actions.rst:386 msgid "Files and images" msgstr "Fichiers et images" -#: ../../guides/actions.rst:386 +#: ../../guides/actions.rst:388 msgid "Use the ``input/file`` view in your form’s content view." msgstr "" "Utilisez la vue ``input/file`` dans la vue du contenu de votre formulaire." -#: ../../guides/actions.rst:393 +#: ../../guides/actions.rst:395 msgid "" "If you wish to upload an icon for entity you can use the helper view " "``entity/edit/icon``. This view shows a file input for uploading a new icon " @@ -873,11 +888,11 @@ msgstr "" " téléchargement d’une nouvelle icône pour l’entité, une miniature de l’icône" " actuelle et l’option de supprimer l’icône actuelle." -#: ../../guides/actions.rst:397 +#: ../../guides/actions.rst:399 msgid "The view supports some variables to control the output" msgstr "La vue prend en charge quelques variables pour contrôler la sortie" -#: ../../guides/actions.rst:399 +#: ../../guides/actions.rst:401 msgid "" "``entity`` - the entity to add/remove the icon for. If provided based on " "this entity the thumbnail and remove option wil be shown" @@ -886,7 +901,7 @@ msgstr "" "est fournie, la miniature et l’option de suppression s’affichent en fonction" " de cette entité" -#: ../../guides/actions.rst:400 +#: ../../guides/actions.rst:402 msgid "" "``entity_type`` - the entity type for which the icon will be uploaded. " "Plugins could find this useful, maybe to validate icon sizes" @@ -895,7 +910,7 @@ msgstr "" " plugins pourraient trouver cela utile, peut-être pour valider les " "dimensions d’icônes" -#: ../../guides/actions.rst:401 +#: ../../guides/actions.rst:403 msgid "" "``entity_subtype`` - the entity subtype for which the icon will be uploaded." " Plugins could find this useful, maybe to validate icon sizes" @@ -904,15 +919,15 @@ msgstr "" "téléchargée. Des plugins pourraient trouver cela utile, peut-être pour " "valider les dimensions d’icônes" -#: ../../guides/actions.rst:402 +#: ../../guides/actions.rst:404 msgid "``icon_type`` - the type of the icon (default: icon)" msgstr "``icon_type`` - le type de l’icône (par défaut : icon)" -#: ../../guides/actions.rst:403 +#: ../../guides/actions.rst:405 msgid "``name`` - name of the input/file (default: icon)" msgstr "``name`` - le nom du champ input/file (par défaut : icon)" -#: ../../guides/actions.rst:404 +#: ../../guides/actions.rst:406 msgid "" "``remove_name`` - name of the remove icon toggle (default: $vars['name'] . " "'_remove')" @@ -920,36 +935,38 @@ msgstr "" "``remove_name`` - nom de la bascule de suppression de l'icône (par défaut : " "$vars['name'] . '_remove')" -#: ../../guides/actions.rst:405 +#: ../../guides/actions.rst:407 msgid "``required`` - is icon upload required (default: false)" msgstr "" "``required`` - est-ce que le téléchargement d'une icône est requis (par " "défaut : false)" -#: ../../guides/actions.rst:406 +#: ../../guides/actions.rst:408 msgid "``cropper_enabled`` - is icon cropping allowed (default: true)" msgstr "" +"``cropper_enabled`` - le recadrage des icônes est-il autorisé (par défaut : " +"true)" -#: ../../guides/actions.rst:407 +#: ../../guides/actions.rst:409 msgid "``show_remove`` - show the remove icon option (default: true)" msgstr "" "``show_remove`` - affiche l’option pour supprimer l’icône (par défaut : " "true)" -#: ../../guides/actions.rst:408 +#: ../../guides/actions.rst:410 msgid "" "``show_thumb`` - show the thumb of the entity if available (default: true)" msgstr "" "``show_thumb`` - afficher la miniature de l’entité si elle est disponible " "(par défaut : true)" -#: ../../guides/actions.rst:409 +#: ../../guides/actions.rst:411 msgid "``thumb_size`` - the icon size to use as the thumb (default: medium)" msgstr "" "``thumb_size`` - la taille de l’icône à utiliser pour la miniature (par " "défaut : medium)" -#: ../../guides/actions.rst:411 +#: ../../guides/actions.rst:413 msgid "" "If using the helper view you can use the following code in you action to " "save the icon to the entity or remove the current icon." @@ -957,12 +974,12 @@ msgstr "" "Si vous utilisez la vue, vous pouvez utiliser le code suivant dans votre " "action pour enregistrer l’icône dans l’entité ou supprimer l’icône actuelle." -#: ../../guides/actions.rst:421 +#: ../../guides/actions.rst:423 msgid "Set the enctype of the form to ``multipart/form-data``:" msgstr "" "Définissez le type d'encodage du formulaire sur ``multipart/form-data`` :" -#: ../../guides/actions.rst:431 +#: ../../guides/actions.rst:433 msgid "" "The ``enctype`` of all forms that use the method ``POST`` defaults to " "``multipart/form-data``." @@ -970,7 +987,7 @@ msgstr "" "Le type d'encodage ``enctype`` de tous les formulaires qui utilisent la " "méthode ``POST`` est par défaut ``multipart/form-data``." -#: ../../guides/actions.rst:433 +#: ../../guides/actions.rst:435 msgid "" "In your action file, use ``elgg_get_uploaded_file('your-input-name')`` to " "access the uploaded file:" @@ -978,11 +995,11 @@ msgstr "" "Dans votre fichier d’action, utilisez ``elgg_get_uploaded_file('nom-de-" "votre-input')`` pour accéder au fichier téléchargé :" -#: ../../guides/actions.rst:440 +#: ../../guides/actions.rst:442 msgid "Sticky forms" msgstr "Formulaires persistants" -#: ../../guides/actions.rst:442 +#: ../../guides/actions.rst:444 msgid "" "Sticky forms are forms that retain user input if saving fails. They are " "\"sticky\" because the user's data \"sticks\" in the form after submitting, " @@ -999,17 +1016,17 @@ msgstr "" "fonctions d’assistance afin que vous puissiez rendre n’importe quel " "formulaire persistant." -#: ../../guides/actions.rst:447 ../../guides/helpers.rst:2 +#: ../../guides/actions.rst:449 ../../guides/helpers.rst:2 msgid "Helper functions" msgstr "Fonctions d'assistance" -#: ../../guides/actions.rst:449 +#: ../../guides/actions.rst:451 msgid "Sticky forms are implemented in Elgg by the following functions:" msgstr "" "Les formulaires persistants sont implémentés dans Elgg par les fonctions " "suivantes :" -#: ../../guides/actions.rst:451 +#: ../../guides/actions.rst:453 msgid "" "``elgg_make_sticky_form($name)`` - Tells the engine to make all input on a " "form sticky." @@ -1017,7 +1034,7 @@ msgstr "" "``elgg_make_sticky_form($name)`` - Indique au moteur de persister les " "valeurs de toutes les entrées d'un formulaire." -#: ../../guides/actions.rst:452 +#: ../../guides/actions.rst:454 msgid "" "``elgg_clear_sticky_form($name)`` - Tells the engine to discard all sticky " "input on a form." @@ -1025,14 +1042,14 @@ msgstr "" "``elgg_clear_sticky_form($name)`` - Indique au moteur de supprimer toutes " "les valeurs d'un formulaire." -#: ../../guides/actions.rst:453 +#: ../../guides/actions.rst:455 msgid "" "``elgg_is_sticky_form($name)`` - Checks if ``$name`` is a valid sticky form." msgstr "" "``elgg_is_sticky_form($name)`` - Vérifie si ``$name`` est un formulaire " "persistant valide." -#: ../../guides/actions.rst:454 +#: ../../guides/actions.rst:456 msgid "" "``elgg_get_sticky_values($name)`` - Returns all sticky values saved for " "``$name`` by ``elgg_make_sticky_form($name)``." @@ -1040,16 +1057,16 @@ msgstr "" "``elgg_get_sticky_values($name)`` - Renvoie toutes les valeurs persistantes " "enregistrées pour ``$name`` par ``elgg_make_sticky_form($name)``." -#: ../../guides/actions.rst:457 ../../guides/ajax.rst:11 +#: ../../guides/actions.rst:459 ../../guides/ajax.rst:11 #: ../../guides/i18n.rst:15 ../../guides/plugins/dependencies.rst:11 msgid "Overview" msgstr "Aperçu" -#: ../../guides/actions.rst:459 +#: ../../guides/actions.rst:461 msgid "The basic flow of using sticky forms is:" msgstr "Le déroulement de l’utilisation des formulaires persistants est :" -#: ../../guides/actions.rst:461 +#: ../../guides/actions.rst:463 msgid "" "Call ``elgg_make_sticky_form($name)`` at the top of actions for forms you " "want to be sticky." @@ -1057,7 +1074,7 @@ msgstr "" "Appelez ``elgg_make_sticky_form($name)`` au début des actions des " "formulaires que vous voulez rendre persistants." -#: ../../guides/actions.rst:462 +#: ../../guides/actions.rst:464 msgid "" "Use ``elgg_is_sticky_form($name)`` and ``elgg_get_sticky_values($name)`` to " "get sticky values when rendering a form view." @@ -1066,7 +1083,7 @@ msgstr "" " pour obtenir des valeurs persistantes lors du rendu d’une vue de " "formulaire." -#: ../../guides/actions.rst:463 +#: ../../guides/actions.rst:465 msgid "" "Call ``elgg_clear_sticky_form($name)`` after the action has completed " "successfully or after data has been loaded by " @@ -1076,42 +1093,58 @@ msgstr "" "succès ou après que les données ont été chargées par " "``elgg_get_sticky_values($name)``." -#: ../../guides/actions.rst:467 +#: ../../guides/actions.rst:469 msgid "" "As of Elgg 5.0 forms rendered with ``elgg_view_form()`` can set the " "``$form_vars['sticky_enabled'] = true`` flag to automatically get sticky " "form support. The submitted values to the action will automatically be " "filled in the ``$body_vars`` when an error occured in the action." msgstr "" +"Depuis Elgg 5.0, les formulaires rendus avec ``elgg_view_form()`` peuvent " +"définir l'indicateur ``$form_vars['sticky_enabled'] = true`` pour obtenir " +"automatiquement la prise en charge des formulaires persistants. Les valeurs " +"soumises à l'action seront automatiquement renseignées dans ``$body_vars`` " +"lorsqu'une erreur survient dans l'action." -#: ../../guides/actions.rst:470 +#: ../../guides/actions.rst:472 msgid "" "``elgg_view_form()`` supports the following ``$form_vars`` to help with " "sticky form support:" msgstr "" +"``elgg_view_form()`` prend en charge les ``$form_vars`` suivants pour " +"faciliter la prise en charge des formulaires persistants :" -#: ../../guides/actions.rst:472 +#: ../../guides/actions.rst:474 msgid "``sticky_enabled``: a ``bool`` to enable automatic sticky form support" msgstr "" +"``sticky_enabled`` : un ``bool`` pour activer la prise en charge automatique" +" de formulaire persistant" -#: ../../guides/actions.rst:473 +#: ../../guides/actions.rst:475 msgid "" "``sticky_form_name``: an optional ``string`` to set where the sticky form " "values are saved. This defaults to the ``$action_name`` and should only be " "changed if the ``$action_name`` is different from the actual action" msgstr "" +"``sticky_form_name`` : une ``string`` facultative pour définir l'endroit où " +"les valeurs du formulaire collant sont enregistrées. La valeur par défaut " +"est ``$action_name`` et ne doit être modifiée que si ``$action_name`` est " +"différent de l'action réelle" -#: ../../guides/actions.rst:474 +#: ../../guides/actions.rst:476 msgid "" "``sticky_ignored_fields: an ``array`` with the names fo the form fields that" " should be saved. For example password fields" msgstr "" +"``sticky_ignored_fields`` : un ``array`` avec les noms des champs du " +"formulaire qui doivent être enregistrés. Par exemple les champs de mot de " +"passe" -#: ../../guides/actions.rst:477 +#: ../../guides/actions.rst:479 msgid "Example: User registration" msgstr "Exemple : Inscription d'un utilisateur" -#: ../../guides/actions.rst:479 +#: ../../guides/actions.rst:481 msgid "" "Simple sticky forms require little logic to determine the input values for " "the form. This logic is placed at the top of the form body view itself." @@ -1120,7 +1153,7 @@ msgstr "" "déterminer les valeurs d’entrée du formulaire. Cette logique est placée en " "haut de la vue du corps de formulaire." -#: ../../guides/actions.rst:482 +#: ../../guides/actions.rst:484 msgid "" "The registration form view first sets default values for inputs, then checks" " if there are sticky values. If so, it loads the sticky values before " @@ -1131,7 +1164,7 @@ msgstr "" "c’est le cas, il charge les valeurs persistantes avant de supprimer le " "formulaire persistant :" -#: ../../guides/actions.rst:498 +#: ../../guides/actions.rst:500 msgid "" "The registration action sets creates the sticky form and clears it once the " "action is completed:" @@ -1139,7 +1172,7 @@ msgstr "" "Les ensembles d’action d’inscription créent le formulaire persistant et " "l’effacent une fois l’action terminée :" -#: ../../guides/actions.rst:516 +#: ../../guides/actions.rst:518 msgid "" "The function ``elgg_make_sticky_form()`` supports an optional second " "argument ``$ignored_field_names``. This needs to be an ``array`` of the " @@ -1151,11 +1184,11 @@ msgstr "" "champs que vous ne souhaitez pas rendre persistants. Ceci est utile pour les" " champs qui contiennent des données sensibles, comme les mots de passe." -#: ../../guides/actions.rst:520 +#: ../../guides/actions.rst:522 msgid "Example: Bookmarks" msgstr "Exemple : Signets - Bookmarks" -#: ../../guides/actions.rst:522 +#: ../../guides/actions.rst:524 msgid "" "The bundled plugin Bookmarks' save form and action is an example of a " "complex sticky form." @@ -1163,7 +1196,7 @@ msgstr "" "Le formulaire et l’action d’enregistrement du plugin \"Bookmarks\" inclus " "est un exemple de formulaire persistant complexe." -#: ../../guides/actions.rst:524 +#: ../../guides/actions.rst:526 msgid "" "The form view for the save bookmark action uses ``elgg_extract()`` to pull " "values from the ``$vars`` array:" @@ -1171,45 +1204,54 @@ msgstr "" "La vue du formulaire pour l’action d'enregistrement d'un signet utilise " "``elgg_extract()`` pour extraire des valeurs du tableau ``$vars`` :" -#: ../../guides/actions.rst:538 +#: ../../guides/actions.rst:540 msgid "" "The page handler scripts enables sticky form support by passing the correct " "values to ``elgg_view_form()``:" msgstr "" +"Les scripts du gestionnaire de page activent le support des formulaires " +"persistants en passant les valeurs correctes à ``elgg_view_form()`` :" -#: ../../guides/actions.rst:545 +#: ../../guides/actions.rst:547 msgid "" "Similarly, ``mod/bookmarks/pages/edit.php`` uses the same sticky support, " "but passes the entity that is being edited:" msgstr "" +"De même, ``mod/bookmarks/pages/edit.php`` utilise le même support " +"persistant, mais transmet l'entité qui est en cours d'édition :" -#: ../../guides/actions.rst:556 +#: ../../guides/actions.rst:558 msgid "" "The plugin has an event listener on the ``'form:prepare:fields', " "'bookmarks/save'`` event and the handler does 2 things:" msgstr "" +"Le plugin a un écouteur d'événement sur l'événement ``'form:prepare:fields'," +" 'bookmarks/save'`` et le gestionnaire fait 2 choses :" -#: ../../guides/actions.rst:558 +#: ../../guides/actions.rst:560 msgid "Defines the input names and default values for form inputs." msgstr "" "Définit les noms et les valeurs par défaut pour les champs de formulaire." -#: ../../guides/actions.rst:559 +#: ../../guides/actions.rst:561 msgid "Extracts the values from a bookmark object if it's passed." msgstr "Extrait les valeurs d’un objet bookmark s’il est passé." -#: ../../guides/actions.rst:606 +#: ../../guides/actions.rst:608 msgid "" "The save action doesn't need to do anything with sticky form support as this" " is all handled by the system." msgstr "" +"L'action de sauvegarde n'a pas besoin de faire quoi que ce soit avec la " +"prise en charge des formulaires persistants car tout est géré par le " +"système." -#: ../../guides/actions.rst:609 ../../guides/ajax.rst:2 -#: ../../guides/events-list.rst:862 +#: ../../guides/actions.rst:611 ../../guides/ajax.rst:2 +#: ../../guides/events-list.rst:868 msgid "Ajax" msgstr "Ajax" -#: ../../guides/actions.rst:611 +#: ../../guides/actions.rst:613 msgid "" "See the :doc:`Ajax guide` for instructions on calling actions " "from JavaScript." @@ -1217,11 +1259,11 @@ msgstr "" "Voir le :doc:`guide Ajax` pour savoir comment appeler les " "actions depuis JavaScript." -#: ../../guides/actions.rst:614 ../../guides/web-services.rst:27 +#: ../../guides/actions.rst:616 ../../guides/web-services.rst:27 msgid "Security" msgstr "Sécurité" -#: ../../guides/actions.rst:616 +#: ../../guides/actions.rst:618 msgid "" "For enhanced security, all actions require an CSRF token. Calls to action " "URLs that do not include security tokens will be ignored and a warning will " @@ -1231,30 +1273,30 @@ msgstr "" "Les appels aux URLs d’action qui n’incluent pas les jetons de sécurité " "seront ignorés et un avertissement sera généré." -#: ../../guides/actions.rst:619 +#: ../../guides/actions.rst:621 msgid "A few views and functions automatically generate security tokens:" msgstr "" "Quelques vues et fonctions génèrent automatiquement des jetons de sécurité :" -#: ../../guides/actions.rst:628 +#: ../../guides/actions.rst:630 msgid "In rare cases, you may need to generate tokens manually:" msgstr "" "Dans de rares cas, vous devrez peut-être générer des jetons manuellement :" -#: ../../guides/actions.rst:635 +#: ../../guides/actions.rst:637 msgid "You can also access the tokens from javascript:" msgstr "Vous pouvez aussi accéder aux jetons depuis JavaScript :" -#: ../../guides/actions.rst:642 +#: ../../guides/actions.rst:644 msgid "These are refreshed periodically so should always be up-to-date." msgstr "" "Ces jetonsci sont rafraîchis périodiquement aussi ils devraient être à jour." -#: ../../guides/actions.rst:645 +#: ../../guides/actions.rst:647 msgid "Security Tokens" msgstr "Jetons de sécurité" -#: ../../guides/actions.rst:647 +#: ../../guides/actions.rst:649 msgid "" "On occasion we need to pass data through an untrusted party or generate an " "\"unguessable token\" based on some data. The industry-standard `HMAC " @@ -1272,7 +1314,7 @@ msgstr "" "fortes comme SHA-2 ne devraient *pas* être utilisés sans HMAC pour ces " "tâches." -#: ../../guides/actions.rst:652 +#: ../../guides/actions.rst:654 msgid "" "Elgg provides ``elgg_build_hmac()`` to generate and validate HMAC message " "authentication codes that are unguessable without the site's private key." @@ -1281,7 +1323,7 @@ msgstr "" "d’authentification des messages HMAC qui ne puissent pas être devinés sans " "la clé privée du site." -#: ../../guides/actions.rst:676 +#: ../../guides/actions.rst:678 msgid "" "Note: If you use a non-string as HMAC data, you must use types consistently." " Consider the following:" @@ -1289,11 +1331,11 @@ msgstr "" "Remarque : si vous utilisez une non-chaîne comme données HMAC, vous devez " "utiliser les types de manière cohérente. Considérez ce qui suit :" -#: ../../guides/actions.rst:689 +#: ../../guides/actions.rst:691 msgid "Signed URLs" msgstr "URLs signées" -#: ../../guides/actions.rst:691 +#: ../../guides/actions.rst:693 msgid "" "Signed URLs offer a limited level of security for situations where action " "tokens are not suitable, for example when sending a confirmation link via " @@ -1307,7 +1349,7 @@ msgstr "" " a été générée par votre installation Elgg (en utilisant le secret du site) " "et que les éléments de l'URL de requête n’ont pas été trafiqués." -#: ../../guides/actions.rst:695 +#: ../../guides/actions.rst:697 msgid "" "URLs a signed with an unguessable SHA-256 HMAC key. See `Security Tokens`_ " "for more details." @@ -1315,7 +1357,7 @@ msgstr "" "URLs signées avec une clef SHA-256 HMAC impossible à deviner. Pour plus de " "détails, consultez `Jetons de Sécurité`_ ." -#: ../../guides/actions.rst:709 +#: ../../guides/actions.rst:711 msgid "" "Signed URLs do not offer CSRF protection and should not be used instead of " "action tokens." @@ -1373,7 +1415,7 @@ msgstr "" #: ../../guides/ajax.rst:19 msgid "The response object is filtered by the event ``ajax_response``." -msgstr "" +msgstr "L'objet de réponse est filtré par l'événement ``ajax_response``." #: ../../guides/ajax.rst:20 msgid "The response object is used to create the HTTP response." @@ -1703,6 +1745,13 @@ msgid "" " normally passed as a second parameter to ``elgg_view_form()``), use the " "server-side event ``view_vars, input/form``." msgstr "" +"Seules les données de la requête sont transmises à la vue du formulaire " +"demandé (c'est-à-dire en tant que troisième paramètre accepté par " +"``elgg_view_form()``). Si vous devez transmettre des attributs ou des " +"paramètres de l'élément de formulaire rendus par la vue ``input/form`` " +"(c'est-à-dire normalement passés comme deuxième paramètre à " +"``elgg_view_form()``), utilisez l'événement côté serveur ``view_vars , " +"input/form``." #: ../../guides/ajax.rst:235 msgid "Submitting forms" @@ -1777,6 +1826,8 @@ msgid "" "The server-side ``ajax_response`` event can be used to append or filter " "response data (or metadata)." msgstr "" +"L'événement ``ajax_response`` côté serveur peut être utilisé pour ajouter ou" +" filtrer les données de réponse (ou métadonnées)." #: ../../guides/ajax.rst:288 msgid "" @@ -1791,6 +1842,8 @@ msgid "" "To capture the metadata send back to the client, we use the client-side " "``ajax_response_data`` hook:" msgstr "" +"Pour capturer les métadonnées renvoyées au client, nous utilisons le hook " +"``ajax_response_data`` côté client :" #: ../../guides/ajax.rst:330 msgid "" @@ -2282,6 +2335,9 @@ msgid "" "events will be triggered so you can register for these events from your own " "code." msgstr "" +"Si vous configurez correctement cron comme décrit dans :doc:`/admin/cron`, " +"des événements spéciaux seront déclenchés afin que vous puissiez vous " +"inscrire à ces événements à partir de votre propre code." #: ../../guides/cron.rst:7 msgid "The example below registers a function for the daily cron." @@ -2295,6 +2351,12 @@ msgid "" "provided in the event contain the original starting time of the cron, so you" " can always use that information." msgstr "" +"Si le timing est important dans votre événement cron, sachez que les " +"fonctions sont exécutées par ordre d'enregistrement. Cela pourrait signifier" +" que votre fonction pourrait démarrer (beaucoup) plus tard que prévu. " +"Cependant, les paramètres fournis dans l'événement contiennent l'heure de " +"début d'origine du cron, vous pouvez donc toujours utiliser cette " +"information." #: ../../guides/cron.rst:28 msgid "Custom intervals" @@ -2323,7 +2385,7 @@ msgstr "" #: ../../guides/cron.rst:53 msgid ":doc:`/design/events` has more information about events" -msgstr "" +msgstr ":doc:`/design/events` donne plus d'informations sur les événements" #: ../../guides/cron.rst:54 msgid "" @@ -2546,6 +2608,10 @@ msgid "" "Using specific parameters passed to ``$options`` array, you can retrieve " "entities by their attributes, metadata, annotations and relationships." msgstr "" +"Vous pouvez récupérer des entités par leurs propriétés en utilisant " +"``elgg_get_entities``. En utilisant des paramètres spécifiques passés au " +"tableau ``$options``, vous pouvez récupérer des entités par leurs attributs," +" métadonnées, annotations et relations." #: ../../guides/database.rst:123 ../../guides/views.rst:433 msgid "Displaying entities" @@ -2636,6 +2702,10 @@ msgid "" "entity type and subtype. The function triggers the ``entity:icon:sizes`` " ":ref:`event `." msgstr "" +"Utilisez ``elgg_get_icon_sizes()`` pour obtenir toutes les tailles d'icône " +"possibles pour un type et un subtype d'entité spécifiques. La fonction " +"déclenche l'événement ``entity:icon:sizes`` :ref:`event `." #: ../../guides/database.rst:178 msgid "To check if an icon is set, use ``$object->hasIcon($size)``." @@ -2651,6 +2721,12 @@ msgid "" "additional context for the event to determine the icon to serve. The method " "triggers the ``entity:icon:url`` :ref:`event `." msgstr "" +"Vous pouvez récupérer l'URL de l'icône générée avec la méthode " +"``ElggEntity::getIconURL($params)``. Cette méthode accepte un argument " +"``$params`` comme tableau qui spécifie la taille, le type et fournit un " +"contexte supplémentaire pour l'événement afin de déterminer l'icône à " +"servir. La méthode déclenche l'événement ``entity:icon:url`` :ref:`event " +"`." #: ../../guides/database.rst:185 msgid "" @@ -2708,6 +2784,9 @@ msgid "" "uploaded icon is found, the view system will scan the views (in this " "specific order):" msgstr "" +"Vous n'êtes pas obligé de renvoyer une icône de secours du gestionnaire " +"d'événements. Si aucune icône téléchargée n'est trouvée, le système de " +"visualisation analysera les vues (dans cet ordre spécifique) :" #: ../../guides/database.rst:204 msgid "views/$viewtype/$icon_type/$entity_type/$entity_subtype.svg" @@ -2776,6 +2855,10 @@ msgid "" "to add custom sizes use ``entity::url`` :ref:`event " "` to configure them." msgstr "" +"Les types d'icônes personnalisées (par ex. les photos de couverture) n'ont " +"qu'un préréglage pour la taille `master`, pour ajouter des tailles " +"personnalisées, utilisez l':ref:`événement ` " +"``entity::url`` pour les configurer." #: ../../guides/database.rst:240 msgid "" @@ -2784,6 +2867,10 @@ msgid "" "location, use the ``entity::file`` :ref:`event `." msgstr "" +"Par défaut, les icônes seront stockées dans " +"``/icons//.jpg`` par rapport au répertoire de l'entité sur " +"le répertoire de fichiers. Pour fournir un autre emplacement, utilisez " +"l':ref:`événement ` ``entity::file``." #: ../../guides/database.rst:244 msgid "Adding, reading and deleting annotations" @@ -3418,12 +3505,17 @@ msgid "" "``:before`` and ``:after`` event Also see :ref:`Event sequence " "`" msgstr "" +"Certains événements sont marqués avec |sequence| cela signifie que ces " +"événements ont également un événement ``:before`` et ``:after`` Voir aussi " +":ref:`Séquence d'événements `" #: ../../guides/events-list.rst:15 msgid "" "Some events are marked with |results| this means those events allow altering" " the output of an event" msgstr "" +"Certains événements sont marqués avec |results| cela signifie que ces " +"événements permettent de modifier la sortie d'un événement" #: ../../guides/events-list.rst:18 msgid "System events" @@ -3439,7 +3531,7 @@ msgstr "Renvoyez false pour empêcher l’activation du plugin." #: ../../guides/events-list.rst:25 msgid "**cache:clear, system** |sequence|" -msgstr "" +msgstr "**cache:clear, system** |sequence|" #: ../../guides/events-list.rst:24 msgid "" @@ -3453,7 +3545,7 @@ msgstr "" #: ../../guides/events-list.rst:29 msgid "**cache:generate, ** |results|" -msgstr "" +msgstr "**cache:generate, ** |results|" #: ../../guides/events-list.rst:28 msgid "" @@ -3467,7 +3559,7 @@ msgstr "" #: ../../guides/events-list.rst:32 msgid "**cache:invalidate, system** |sequence|" -msgstr "" +msgstr "**cache:invalidate, system** |sequence|" #: ../../guides/events-list.rst:32 msgid "Invalidate internal and external caches." @@ -3475,7 +3567,7 @@ msgstr "Invalide les caches internes et externes." #: ../../guides/events-list.rst:35 msgid "**cache:purge, system** |sequence|" -msgstr "" +msgstr "**cache:purge, system** |sequence|" #: ../../guides/events-list.rst:35 msgid "" @@ -3487,7 +3579,7 @@ msgstr "" #: ../../guides/events-list.rst:39 msgid "**commands, cli** |results|" -msgstr "" +msgstr "**commands, cli** |results|" #: ../../guides/events-list.rst:38 msgid "" @@ -3500,43 +3592,69 @@ msgstr "" "de classes de commande. Les commandes doivent étendre " "``\\Elgg\\Cli\\Command`` pour être exécutables." -#: ../../guides/events-list.rst:42 +#: ../../guides/events-list.rst:48 msgid "**cron, ** |results|" -msgstr "" +msgstr "**cron, ** |results|" #: ../../guides/events-list.rst:42 msgid "Triggered by cron for each period." msgstr "Déclenché par le cron pour chaque période." -#: ../../guides/events-list.rst:45 -msgid "**cron:intervals, system** |results|" +#: ../../guides/events-list.rst:44 ../../guides/events-list.rst:110 +#: ../../guides/events-list.rst:135 ../../guides/events-list.rst:256 +#: ../../guides/events-list.rst:297 ../../guides/events-list.rst:330 +#: ../../guides/events-list.rst:473 ../../guides/events-list.rst:480 +#: ../../guides/events-list.rst:560 ../../guides/events-list.rst:574 +#: ../../guides/events-list.rst:593 +msgid "The ``$params`` array will contain:" +msgstr "Le tableau ``$params`` va contenir :" + +#: ../../guides/events-list.rst:46 +msgid "``time`` - the timestamp of when the cron command was started" +msgstr "``time`` - l'horodatage du lancement de la commande cron" + +#: ../../guides/events-list.rst:47 +msgid "``dt`` - the ``\\DateTime`` object of when the cron command was started" +msgstr "" +"``dt`` - l'objet ``\\DateTime`` du moment où la commande cron a été lancée" + +#: ../../guides/events-list.rst:48 +msgid "" +"``logger`` - instance of ``\\Elgg\\Logger\\Cron`` to log any information to " +"the cron log" msgstr "" +"``logger`` - instance de ``\\Elgg\\Logger\\Cron`` pour enregistrer toute " +"information dans le journal cron" -#: ../../guides/events-list.rst:45 +#: ../../guides/events-list.rst:51 +msgid "**cron:intervals, system** |results|" +msgstr "**cron:intervals, system** |results|" + +#: ../../guides/events-list.rst:51 msgid "Allow the configuration of custom cron intervals" msgstr "Permet la configuration d’intervalles de cron personnalisés" -#: ../../guides/events-list.rst:48 +#: ../../guides/events-list.rst:54 msgid "**deactivate, plugin**" msgstr "**deactivate, plugin**" -#: ../../guides/events-list.rst:48 +#: ../../guides/events-list.rst:54 msgid "Return false to prevent deactivation of the plugin." msgstr "Renvoyez false pour éviter la désactivation du plugin." -#: ../../guides/events-list.rst:51 +#: ../../guides/events-list.rst:57 msgid "**diagnostics:report, system** |results|" -msgstr "" +msgstr "**diagnostics:report, system** |results|" -#: ../../guides/events-list.rst:51 +#: ../../guides/events-list.rst:57 msgid "Filter the output for the diagnostics report download." msgstr "Filtre la sortie pour le téléchargement du rapport de diagnostic." -#: ../../guides/events-list.rst:54 +#: ../../guides/events-list.rst:60 msgid "**elgg.data, page** |results|" -msgstr "" +msgstr "**elgg.data, page** |results|" -#: ../../guides/events-list.rst:54 +#: ../../guides/events-list.rst:60 msgid "" "Filters uncached, page-specific configuration data to pass to the client. " ":ref:`More info `" @@ -3545,11 +3663,11 @@ msgstr "" "page à transmettre au client. :ref:`Plus d’informations " "`" -#: ../../guides/events-list.rst:57 +#: ../../guides/events-list.rst:63 msgid "**elgg.data, site** |results|" -msgstr "" +msgstr "**elgg.data, site** |results|" -#: ../../guides/events-list.rst:57 +#: ../../guides/events-list.rst:63 msgid "" "Filters cached configuration data to pass to the client. :ref:`More info " "`" @@ -3557,11 +3675,11 @@ msgstr "" "Filtre les données de configuration mises en cache pour les transmettre au " "client. :ref:`Plus d’informations `" -#: ../../guides/events-list.rst:60 +#: ../../guides/events-list.rst:66 msgid "**format, friendly:title** |results|" -msgstr "" +msgstr "**format, friendly:title** |results|" -#: ../../guides/events-list.rst:60 +#: ../../guides/events-list.rst:66 msgid "" "Formats the \"friendly\" title for strings. This is used for generating " "URLs." @@ -3569,19 +3687,19 @@ msgstr "" "Formate un titre \"sympathique\" pour les chaînes de caractères. Ceci est " "utilisé pour générer des URLs." -#: ../../guides/events-list.rst:63 +#: ../../guides/events-list.rst:69 msgid "**format, friendly:time** |results|" -msgstr "" +msgstr "**format, friendly:time** |results|" -#: ../../guides/events-list.rst:63 +#: ../../guides/events-list.rst:69 msgid "Formats the \"friendly\" time for the timestamp ``$params['time']``." msgstr "Formate une date \"sympathique\" pour le timestamp ``$params['time']``." -#: ../../guides/events-list.rst:67 +#: ../../guides/events-list.rst:73 msgid "**format, strip_tags** |results|" -msgstr "" +msgstr "**format, strip_tags** |results|" -#: ../../guides/events-list.rst:66 +#: ../../guides/events-list.rst:72 msgid "" "Filters a string to remove tags. The original string is passed as " "``$params['original_string']`` and an optional set of allowed tags is passed" @@ -3591,38 +3709,38 @@ msgstr "" " par ``$params['original_string']`` et un ensemble facultatif de balises " "autorisées est passé par ``$params['allowed_tags']``." -#: ../../guides/events-list.rst:70 +#: ../../guides/events-list.rst:76 msgid "**gc, system** |results|" -msgstr "" +msgstr "**gc, system** |results|" -#: ../../guides/events-list.rst:70 +#: ../../guides/events-list.rst:76 msgid "Allows plugins to run garbage collection for ``$params['period']``." msgstr "" "Autorise les plugins à exécuter la collecte des déchets - \"garbage " "collection\" - pour ``$params['period']``." -#: ../../guides/events-list.rst:73 +#: ../../guides/events-list.rst:79 msgid "**generate, password** |results|" -msgstr "" +msgstr "**generate, password** |results|" -#: ../../guides/events-list.rst:73 +#: ../../guides/events-list.rst:79 msgid "Allows plugins to generate new random cleartext passwords." msgstr "" "Permet aux plugins de générer de nouveaux mots de passe textuels aléatoires." -#: ../../guides/events-list.rst:76 +#: ../../guides/events-list.rst:82 msgid "**init:cookie, **" msgstr "**init:cookie, **" -#: ../../guides/events-list.rst:76 +#: ../../guides/events-list.rst:82 msgid "Return false to override setting a cookie." msgstr "Renvoyez false pour remplacer la définition d’un cookie." -#: ../../guides/events-list.rst:79 +#: ../../guides/events-list.rst:85 msgid "**init, system** |sequence|" -msgstr "" +msgstr "**init, system** |sequence|" -#: ../../guides/events-list.rst:79 +#: ../../guides/events-list.rst:85 msgid "" "Plugins tend to use this event for initialization (extending views, " "registering callbacks, etc.)" @@ -3630,11 +3748,11 @@ msgstr "" "Les plugins ont tendance à utiliser cet événement pour l’initialisation " "(extension des vues, enregistrement des rappels, etc.)" -#: ../../guides/events-list.rst:82 +#: ../../guides/events-list.rst:88 msgid "**languages, translations** |results|" -msgstr "" +msgstr "**languages, translations** |results|" -#: ../../guides/events-list.rst:82 +#: ../../guides/events-list.rst:88 msgid "" "Allows plugins to add/remove languages from the configurable languages in " "the system." @@ -3642,11 +3760,11 @@ msgstr "" "Permet aux plugins d'ajouter/supprimer des langues des langues configurables" " du système." -#: ../../guides/events-list.rst:86 +#: ../../guides/events-list.rst:92 msgid "**log, systemlog**" msgstr "**log, systemlog**" -#: ../../guides/events-list.rst:85 +#: ../../guides/events-list.rst:91 msgid "" "Called for all triggered events by ``system_log`` plugin. Used internally by" " ``Elgg\\SystemLog\\Logger::log()`` to populate the ``system_log`` table." @@ -3655,42 +3773,49 @@ msgstr "" "Utilisé en interne par ``Elgg\\SystemLog\\Logger::log()`` pour remplir la " "table ``system_log``." -#: ../../guides/events-list.rst:91 +#: ../../guides/events-list.rst:97 msgid "**login_url, site** |results|" -msgstr "" +msgstr "**login_url, site** |results|" -#: ../../guides/events-list.rst:89 +#: ../../guides/events-list.rst:95 msgid "" "Filters site's login URL. ``$params`` array contains an array of query " "elements added to the login URL by the invoking script. The event must " "return an absolute URL of the login page." msgstr "" +"Filtre l'URL de connexion du site. Le tableau ``$params`` contient un " +"tableau d'éléments de requête ajoutés à l'URL de connexion par le script " +"appelant. L'événement doit renvoyer une URL absolue de la page de connexion." -#: ../../guides/events-list.rst:96 +#: ../../guides/events-list.rst:102 msgid "**output:before, page** |results|" -msgstr "" +msgstr "**output:before, page** |results|" -#: ../../guides/events-list.rst:94 +#: ../../guides/events-list.rst:100 msgid "" "In ``elgg_view_page()``, this filters ``$vars`` before it's passed to the " "page shell view (``page/``). To stop sending the X-Frame-Options" " header, unregister the handler " "``Elgg\\Page\\SetXFrameOptionsHeaderHandler::class`` from this event." msgstr "" +"Dans ``elgg_view_page()``, ceci filtre ``$vars`` avant qu'il soit transmis à" +" la vue de la coquille de la page (``page/``). Pour arrêter " +"d'envoyer l'entête X-Frame-Options, désenregistrez le gestionnaire " +"``Elgg\\Page\\SetXFrameOptionsHeaderHandler::class`` de cet événement." -#: ../../guides/events-list.rst:99 +#: ../../guides/events-list.rst:105 msgid "**output, page** |results|" -msgstr "" +msgstr "**output, page** |results|" -#: ../../guides/events-list.rst:99 +#: ../../guides/events-list.rst:105 msgid "In ``elgg_view_page()``, this filters the output return value." msgstr "Dans ``elgg_view_page()``, ceci filtre la valeur de retour renvoyée." -#: ../../guides/events-list.rst:108 +#: ../../guides/events-list.rst:114 msgid "**parameters, menu:** |results|" -msgstr "" +msgstr "**parameters, menu:** |results|" -#: ../../guides/events-list.rst:102 +#: ../../guides/events-list.rst:108 msgid "" "Triggered by ``elgg_view_menu()``. Used to change menu variables (like sort " "order) before rendering." @@ -3698,31 +3823,23 @@ msgstr "" "Déclenché par ``elgg_view_menu()``. Utilisé pour modifier les variables de " "menu (comme l’ordre de tri) avant le rendu." -#: ../../guides/events-list.rst:104 ../../guides/events-list.rst:129 -#: ../../guides/events-list.rst:250 ../../guides/events-list.rst:291 -#: ../../guides/events-list.rst:324 ../../guides/events-list.rst:467 -#: ../../guides/events-list.rst:474 ../../guides/events-list.rst:554 -#: ../../guides/events-list.rst:568 ../../guides/events-list.rst:587 -msgid "The ``$params`` array will contain:" -msgstr "Le tableau ``$params`` va contenir :" - -#: ../../guides/events-list.rst:106 +#: ../../guides/events-list.rst:112 msgid "``name`` - name of the menu" msgstr "``name`` - nom du menu" -#: ../../guides/events-list.rst:107 +#: ../../guides/events-list.rst:113 msgid "``sort_by`` - preferring sorting parameter" msgstr "``sort_by`` - paramètre de tri préféré" -#: ../../guides/events-list.rst:108 +#: ../../guides/events-list.rst:114 msgid "other parameters passed to ``elgg_view_menu()``" msgstr "d'autres paramètres passés à ``elgg_view_menu()``" -#: ../../guides/events-list.rst:111 +#: ../../guides/events-list.rst:117 msgid "**plugins_load, system** |sequence|" -msgstr "" +msgstr "**plugins_load, system** |sequence|" -#: ../../guides/events-list.rst:111 +#: ../../guides/events-list.rst:117 msgid "" "Triggered before the plugins are loaded. Rarely used. init, system is used " "instead. Can be used to load additional libraries." @@ -3731,11 +3848,11 @@ msgstr "" "system est utilisé à la place. Peut être utilisé pour charger des " "bibliothèques supplémentaires." -#: ../../guides/events-list.rst:114 +#: ../../guides/events-list.rst:120 msgid "**plugins_boot, system** |sequence|" -msgstr "" +msgstr "**plugins_boot, system** |sequence|" -#: ../../guides/events-list.rst:114 +#: ../../guides/events-list.rst:120 msgid "" "Triggered just after the plugins are loaded. Rarely used. init, system is " "used instead." @@ -3743,48 +3860,53 @@ msgstr "" "Déclenché juste après le chargement des plugins. Rarement utilisé. init, " "system est utilisé à la place." -#: ../../guides/events-list.rst:122 +#: ../../guides/events-list.rst:128 msgid "**prepare, html** |results|" -msgstr "" +msgstr "**prepare, html** |results|" -#: ../../guides/events-list.rst:117 +#: ../../guides/events-list.rst:123 msgid "" "Triggered by ``elgg_format_html()`` and used to prepare untrusted HTML." msgstr "" "Déclenché par ``elgg_format_html()`` et utilisé pour préparer du HTML non " "sûr." -#: ../../guides/events-list.rst:119 +#: ../../guides/events-list.rst:125 msgid "The ``$return`` value is an array:" msgstr "La valeur ``$return`` est un tableau :" -#: ../../guides/events-list.rst:121 +#: ../../guides/events-list.rst:127 msgid "``html`` - HTML string being prepared" msgstr "``html`` - La chaîne de caractères HTML en train d'être préparée" -#: ../../guides/events-list.rst:122 +#: ../../guides/events-list.rst:128 msgid "``options`` - Preparation options" msgstr "``options`` - Options de préparation" -#: ../../guides/events-list.rst:134 +#: ../../guides/events-list.rst:140 msgid "**prepare, menu:** |results|" -msgstr "" +msgstr "**prepare, menu:** |results|" -#: ../../guides/events-list.rst:125 +#: ../../guides/events-list.rst:131 msgid "" "Filters the array of menu sections before they're displayed. Each section is" " a string key mapping to an area of menu items. This is a good event to " "sort, add, remove, and modify menu items. Triggered by ``elgg_view_menu()`` " "and ``elgg()->menus->prepareMenu()``." msgstr "" +"Filtre le tableau des sections de menu avant leur affichage. Chaque section " +"est une touche de chaîne mappée à une zone d'éléments de menu. Il s'agit " +"d'un bon événement pour trier, ajouter, supprimer et modifier des éléments " +"de menu. Déclenché par ``elgg_view_menu()`` et " +"``elgg()->menus->prepareMenu()``." -#: ../../guides/events-list.rst:131 +#: ../../guides/events-list.rst:137 msgid "``selected_item`` - ``ElggMenuItem`` selected in the menu, if any" msgstr "" "``selected_item`` - ``ElggMenuItem`` sélectionné dans le menu, le cas " "échéant" -#: ../../guides/events-list.rst:133 +#: ../../guides/events-list.rst:139 msgid "" "The return value is an instance of ``\\Elgg\\Menu\\PreparedMenu``. The " "prepared menu is a collection of ``\\Elgg\\Menu\\MenuSection``, which in " @@ -3794,17 +3916,19 @@ msgstr "" "menu préparé est une collection d’objets ``\\Elgg\\Menu\\MenuSection``, qui " "sont à leur tour des collections d’objets ``\\ElggMenuItem``." -#: ../../guides/events-list.rst:142 +#: ../../guides/events-list.rst:148 msgid "**prepare, menu:::** |results|" -msgstr "" +msgstr "**prepare, menu:::** |results|" -#: ../../guides/events-list.rst:137 +#: ../../guides/events-list.rst:143 msgid "" "More granular version of the menu event triggered before the **prepare, " "menu:** event." msgstr "" +"Version plus granulaire de l'événement de menu déclenché avant l'événement " +"**prepare, menu:**." -#: ../../guides/events-list.rst:139 ../../guides/events-list.rst:168 +#: ../../guides/events-list.rst:145 ../../guides/events-list.rst:174 msgid "" "Only applied if menu params contain - params['entity'] with an " "``\\ElggEntity`` (```` is ``\\ElggEntity::type`` and ```` is " @@ -3824,11 +3948,11 @@ msgstr "" "``\\ElggRelationship::getType()`` et ```` est " "``\\ElggRelationship::getSubtype( )``)" -#: ../../guides/events-list.rst:146 +#: ../../guides/events-list.rst:152 msgid "**ready, system** |sequence|" -msgstr "" +msgstr "**ready, system** |sequence|" -#: ../../guides/events-list.rst:145 +#: ../../guides/events-list.rst:151 msgid "" "Triggered after the ``init, system`` event. All plugins are fully loaded and" " the engine is ready to serve pages." @@ -3836,11 +3960,11 @@ msgstr "" "Déclenché après l’événement ``init, system``. Tous les plugins sont " "entièrement chargés et le moteur est prêt à servir les pages." -#: ../../guides/events-list.rst:150 +#: ../../guides/events-list.rst:156 msgid "**regenerate_site_secret:before, system**" msgstr "**regenerate_site_secret:before, system**" -#: ../../guides/events-list.rst:149 +#: ../../guides/events-list.rst:155 msgid "" "Return false to cancel regenerating the site secret. You should also provide" " a message to the user." @@ -3848,19 +3972,19 @@ msgstr "" "Renvoyez false pour annuler la régénération du secret du site. Vous devez " "également fournir un message à l’utilisateur." -#: ../../guides/events-list.rst:153 +#: ../../guides/events-list.rst:159 msgid "**regenerate_site_secret:after, system**" msgstr "**regenerate_site_secret:after, system**" -#: ../../guides/events-list.rst:153 +#: ../../guides/events-list.rst:159 msgid "Triggered after the site secret has been regenerated." msgstr "Déclenché après que le secret du site a été régénéré." -#: ../../guides/events-list.rst:163 +#: ../../guides/events-list.rst:169 msgid "**register, menu:** |results|" -msgstr "" +msgstr "**register, menu:** |results|" -#: ../../guides/events-list.rst:156 +#: ../../guides/events-list.rst:162 msgid "" "Filters the initial list of menu items pulled from configuration, before the" " menu has been split into sections. Triggered by ``elgg_view_menu()`` and " @@ -3870,13 +3994,15 @@ msgstr "" "avant que le menu n’ait été divisé en sections. Déclenché par " "``elgg_view_menu()`` et ``elgg()->menus->getMenu()``." -#: ../../guides/events-list.rst:159 +#: ../../guides/events-list.rst:165 msgid "" "The ``$params`` array will contain parameters returned by ``parameters, " "menu:`` event." msgstr "" +"Le tableau ``$params`` contiendra les paramètres renvoyés par l'événement " +"``parameters, menu:``." -#: ../../guides/events-list.rst:161 +#: ../../guides/events-list.rst:167 msgid "" "The return value is an instance of ``\\Elgg\\Menu\\MenuItems`` containing " "``\\ElggMenuItem`` objects." @@ -3884,34 +4010,43 @@ msgstr "" "La valeur de retour est une instance de ``\\Elgg\\Menu\\MenuItems`` " "contenant des objets ``\\ElggMenuItem``." -#: ../../guides/events-list.rst:163 +#: ../../guides/events-list.rst:169 msgid "" "Event handlers can add/remove items to the collection using the collection " "API, as well as array access operations." msgstr "" +"Les gestionnaires d'événements peuvent ajouter/supprimer des éléments à la " +"collection à l'aide de l'API collection, ainsi que des opérations d'accès au" +" tableau." -#: ../../guides/events-list.rst:171 +#: ../../guides/events-list.rst:177 msgid "**register, menu:::** |results|" -msgstr "" +msgstr "**register, menu:::** |results|" -#: ../../guides/events-list.rst:166 +#: ../../guides/events-list.rst:172 msgid "" "More granular version of the menu event triggered before the **register, " "menu:** event." msgstr "" +"Version plus granulaire de l'événement de menu déclenché avant l'événement " +"**prepare, menu:**." -#: ../../guides/events-list.rst:191 +#: ../../guides/events-list.rst:197 msgid "**register, menu:filter:** |results|" -msgstr "" +msgstr "**register, menu:filter:** |results|" -#: ../../guides/events-list.rst:174 +#: ../../guides/events-list.rst:180 msgid "" "Allows plugins to modify layout filter tabs on layouts that specify " "```` parameter. Parameters and return values are same as in " "``register, menu:`` event." msgstr "" +"Permet aux plugins de modifier les onglets de filtre de mise en page sur les" +" mises en page qui spécifient le paramètre ````. Les paramètres " +"et les valeurs de retour sont les mêmes que dans l'événement ``register, " +"menu:``" -#: ../../guides/events-list.rst:177 +#: ../../guides/events-list.rst:183 msgid "" "If ``filter_id`` is ``filter`` (the default) then the ``all``, ``mine`` and " "``friends`` tabs will be generated base on some provided information or be " @@ -3921,19 +4056,19 @@ msgstr "" "``all``, ``mine`` et ``friends`` seront générés sur la base d'informations " "fournies, ou seront testés pour des routes similaires à la route actuelle." -#: ../../guides/events-list.rst:180 +#: ../../guides/events-list.rst:186 msgid "params['all_link'] will be used for the ``all`` tab" msgstr "params['all_link'] sera utilisé pour l'onglet ``all``" -#: ../../guides/events-list.rst:181 +#: ../../guides/events-list.rst:187 msgid "params['mine_link'] will be used for the ``mine`` tab" msgstr "params['mine_link'] sera utilisé pour l'onglet ``mine``" -#: ../../guides/events-list.rst:182 +#: ../../guides/events-list.rst:188 msgid "params['friends_link'] will be used for the ``friend`` tab" msgstr "params['friends_link'] sera utilisé pour l'onglet ``friend``" -#: ../../guides/events-list.rst:184 +#: ../../guides/events-list.rst:190 msgid "" "If the above are not provided than a route will be tried based on " "``params['entity_type']`` and ``params['entity_subtype']``. If not provided " @@ -3958,16 +4093,16 @@ msgstr "" "L'onglet `` friend`` sera basé sur la route " "``collection:::friends``" -#: ../../guides/events-list.rst:191 +#: ../../guides/events-list.rst:197 msgid "If the routes aren't registered the tabs will not appear." msgstr "" "Si les routes ne sont pas enregistrés, les onglets n'apparaîtront pas." -#: ../../guides/events-list.rst:196 +#: ../../guides/events-list.rst:202 msgid "**registration_url, site** |results|" -msgstr "" +msgstr "**registration_url, site** |results|" -#: ../../guides/events-list.rst:194 +#: ../../guides/events-list.rst:200 msgid "" "Filters site's registration URL. Can be used by plugins to attach invitation" " codes, referrer codes etc. to the registration URL. ``$params`` array " @@ -3975,20 +4110,25 @@ msgid "" "invoking script. The event must return an absolute URL to the registration " "page." msgstr "" +"Filtre l'URL d'inscription du site. Peut être utilisé par les plugins pour " +"attacher des codes d'invitation, des codes de référence, etc. à l'URL " +"d'inscription. Le tableau ``$params`` contient un tableau d'éléments de " +"requête ajoutés à l'URL d'enregistrement par le script appelant. L'événement" +" doit renvoyer une URL absolue vers la page d'inscription." -#: ../../guides/events-list.rst:199 +#: ../../guides/events-list.rst:205 msgid "**reload:after, translations**" msgstr "**reload:after, translations**" -#: ../../guides/events-list.rst:199 +#: ../../guides/events-list.rst:205 msgid "Triggered after the translations are (re)loaded." msgstr "Déclenché après que les traductions ont été (re)chargées." -#: ../../guides/events-list.rst:202 +#: ../../guides/events-list.rst:208 msgid "**sanitize, input** |results|" -msgstr "" +msgstr "**sanitize, input** |results|" -#: ../../guides/events-list.rst:202 +#: ../../guides/events-list.rst:208 msgid "" "Filter GET and POST input. This is used by ``get_input()`` to sanitize user " "input." @@ -3996,11 +4136,11 @@ msgstr "" "Filtre l'entrée GET et POST. Ceci est utilisé par ``get_input()`` pour " "assainir les entrées utilisateur." -#: ../../guides/events-list.rst:206 +#: ../../guides/events-list.rst:212 msgid "**seeds, database** |results|" -msgstr "" +msgstr "**seeds, database** |results|" -#: ../../guides/events-list.rst:205 +#: ../../guides/events-list.rst:211 msgid "" "Allows plugins to register their own database seeds. Seeds populate the " "database with fake entities for testing purposes. Seeds must extend " @@ -4013,11 +4153,11 @@ msgstr "" "``\\Elgg\\Database\\Seeds\\Seed`` pour qu’elle soit exécutable via ``elgg-" "cli database:seed``." -#: ../../guides/events-list.rst:210 +#: ../../guides/events-list.rst:216 msgid "**send:before, http_response**" msgstr "**send:before, http_response**" -#: ../../guides/events-list.rst:209 +#: ../../guides/events-list.rst:215 msgid "" "Triggered before an HTTP response is sent. Handlers will receive an instance" " of `\\Symfony\\Component\\HttpFoundation\\Response` that is to be sent to " @@ -4029,11 +4169,11 @@ msgstr "" "doit être envoyée au demandeur. Les gestionnaires peuvent mettre fin à " "l’événement et empêcher l’envoi de la réponse en renvoyant `false`." -#: ../../guides/events-list.rst:214 +#: ../../guides/events-list.rst:220 msgid "**send:after, http_response**" msgstr "**send:after, http_response**" -#: ../../guides/events-list.rst:213 +#: ../../guides/events-list.rst:219 msgid "" "Triggered after an HTTP response is sent. Handlers will receive an instance " "of `\\Symfony\\Component\\HttpFoundation\\Response` that was sent to the " @@ -4043,11 +4183,11 @@ msgstr "" "instance de la réponse `\\Symfony\\Component\\HttpFoundation\\Response` qui " "a été envoyée au demandeur." -#: ../../guides/events-list.rst:218 +#: ../../guides/events-list.rst:224 msgid "**shutdown, system**" msgstr "**shutdown, system**" -#: ../../guides/events-list.rst:217 +#: ../../guides/events-list.rst:223 msgid "" "Triggered after the page has been sent to the user. Expensive operations " "could be done here and not make the user wait." @@ -4055,7 +4195,7 @@ msgstr "" "Déclenché après l’envoi de la page à l’utilisateur. Des opérations coûteuses" " pourraient être faites ici sans que cela fasse attendre l’utilisateur." -#: ../../guides/events-list.rst:220 +#: ../../guides/events-list.rst:226 msgid "" "Depending upon your server configuration the PHP output might not be shown " "until after the process is completed. This means that any long-running " @@ -4065,7 +4205,7 @@ msgstr "" "affichée avant la fin du processus. Cela signifie que tous les processus " "longs retarderont toujours le chargement de la page." -#: ../../guides/events-list.rst:224 +#: ../../guides/events-list.rst:230 msgid "" "This event is prefered above using ``register_shutdown_function`` as you may" " not have access to all the Elgg services (eg. database) in the shutdown " @@ -4076,7 +4216,7 @@ msgstr "" "base de données) dans la fonction d’arrêt, alors que vous l'aurez dans " "l’événement." -#: ../../guides/events-list.rst:227 +#: ../../guides/events-list.rst:233 msgid "" "The Elgg session is already closed before this event. Manipulating session " "is not possible." @@ -4084,22 +4224,22 @@ msgstr "" "La session Elgg est déjà terminée avant cet événement. La manipulation de la" " session n’est plus possible." -#: ../../guides/events-list.rst:230 +#: ../../guides/events-list.rst:236 msgid "**simplecache:generate, ** |results|" -msgstr "" +msgstr "**simplecache:generate, ** |results|" -#: ../../guides/events-list.rst:230 +#: ../../guides/events-list.rst:236 msgid "" "Filters the view output for a ``/cache`` URL when simplecache is enabled." msgstr "" "Filtre la sortie de la vue pour une URL ``/cache`` quand simplecache est " "activé." -#: ../../guides/events-list.rst:234 +#: ../../guides/events-list.rst:240 msgid "**upgrade, system**" msgstr "**upgrade, system**" -#: ../../guides/events-list.rst:233 +#: ../../guides/events-list.rst:239 msgid "" "Triggered after a system upgrade has finished. All upgrade scripts have run," " but the caches are not cleared." @@ -4107,11 +4247,11 @@ msgstr "" "Déclenché une fois la mise à niveau du système terminée. Tous les scripts de" " mise à niveau sont exécutés, mais les caches ne sont pas effacés." -#: ../../guides/events-list.rst:237 +#: ../../guides/events-list.rst:243 msgid "**upgrade:execute, system** |sequence|" -msgstr "" +msgstr "**upgrade:execute, system** |sequence|" -#: ../../guides/events-list.rst:237 +#: ../../guides/events-list.rst:243 msgid "" "Triggered when executing an ``ElggUpgrade``. The ``$object`` of the event is" " the ``ElggUpgrade``." @@ -4119,104 +4259,109 @@ msgstr "" "Déclenché lors de l’exécution d’un ``ElggUpgrade``. L'objet ``$object`` de " "l’événement est le ``ElggUpgrade``." -#: ../../guides/events-list.rst:240 +#: ../../guides/events-list.rst:246 msgid "User events" msgstr "Événements utilisateur" -#: ../../guides/events-list.rst:243 +#: ../../guides/events-list.rst:249 msgid "**ban, user**" msgstr "**ban, user**" -#: ../../guides/events-list.rst:243 +#: ../../guides/events-list.rst:249 msgid "Triggered before a user is banned. Return false to prevent." msgstr "" "Déclenché avant qu'un utilisateur ne soit banni. Retournez false pour " "l'éviter." -#: ../../guides/events-list.rst:254 +#: ../../guides/events-list.rst:260 msgid "**change:email, user** |results|" -msgstr "" +msgstr "**change:email, user** |results|" -#: ../../guides/events-list.rst:246 +#: ../../guides/events-list.rst:252 msgid "" "Triggered before the user email is changed. Allows plugins to implement " "additional logic required to change email, e.g. additional email validation." " The event handler must return false to prevent the email from being changed" " right away." msgstr "" +"Déclenché avant la modification de l'adresse email de l'utilisateur. Permet " +"aux plugins d'implémenter une logique supplémentaire requise pour modifier " +"l'email, par ex. validation supplémentaire par email. Le gestionnaire " +"d'événements doit renvoyer false pour empêcher que l'e-mail soit modifié " +"immédiatement." -#: ../../guides/events-list.rst:252 ../../guides/events-list.rst:326 +#: ../../guides/events-list.rst:258 ../../guides/events-list.rst:332 msgid "``user`` - ``\\ElggUser``, whose settings are being saved" msgstr "``user`` - ``\\ElggUser``, dont les paramètres ont été sauvegardés" -#: ../../guides/events-list.rst:253 +#: ../../guides/events-list.rst:259 msgid "``email`` - Email address that passes sanity checks" msgstr "``email`` - Adresse e-mail qui passe les vérifications sanitaires" -#: ../../guides/events-list.rst:254 ../../guides/events-list.rst:327 +#: ../../guides/events-list.rst:260 ../../guides/events-list.rst:333 msgid "``request`` - ``\\Elgg\\Request`` to the action controller" msgstr "``request`` - ``\\Elgg\\Request`` vers le contrôleur de l'action" -#: ../../guides/events-list.rst:257 +#: ../../guides/events-list.rst:263 msgid "**invalidate:after, user**" msgstr "**invalidate:after, user**" -#: ../../guides/events-list.rst:257 +#: ../../guides/events-list.rst:263 msgid "Triggered when user's account validation has been revoked." msgstr "" "Déclenché lorsque la validation du compte de l’utilisateur a été révoquée." -#: ../../guides/events-list.rst:260 +#: ../../guides/events-list.rst:266 msgid "**login:after, user**" msgstr "**login:after, user**" -#: ../../guides/events-list.rst:260 +#: ../../guides/events-list.rst:266 msgid "Triggered after the user logs in." msgstr "Déclenché après que l'utilisateur se soit identifié." -#: ../../guides/events-list.rst:263 +#: ../../guides/events-list.rst:269 msgid "**login:before, user**" msgstr "**login:before, user**" -#: ../../guides/events-list.rst:263 +#: ../../guides/events-list.rst:269 msgid "Triggered during login. Returning false prevents the user from logging" msgstr "" "Déclenché lors de la connexion. Renvoyer false empêche l’utilisateur de se " "connecter" -#: ../../guides/events-list.rst:266 +#: ../../guides/events-list.rst:272 msgid "**login:forward, user** |results|" -msgstr "" +msgstr "**login:forward, user** |results|" -#: ../../guides/events-list.rst:266 +#: ../../guides/events-list.rst:272 msgid "Filters the URL to which the user will be forwarded after login." msgstr "" "Filtre l’URL vers laquelle l’utilisateur sera redirigé après la connexion." -#: ../../guides/events-list.rst:269 +#: ../../guides/events-list.rst:275 msgid "**login:first, user**" msgstr "**login:first, user**" -#: ../../guides/events-list.rst:269 +#: ../../guides/events-list.rst:275 msgid "" "Triggered after a successful login. Only if there is no previous login." msgstr "" "Déclenché après une connexion réussie. Uniquement s'il n'y a pas de " "connexion précédente." -#: ../../guides/events-list.rst:272 +#: ../../guides/events-list.rst:278 msgid "**logout:after, user**" msgstr "**logout:after, user**" -#: ../../guides/events-list.rst:272 +#: ../../guides/events-list.rst:278 msgid "Triggered after the user logouts." msgstr "Déclenché après que l'utilisateur se soit déconnecté." -#: ../../guides/events-list.rst:275 +#: ../../guides/events-list.rst:281 msgid "**logout:before, user**" msgstr "**logout:before, user**" -#: ../../guides/events-list.rst:275 +#: ../../guides/events-list.rst:281 msgid "" "Triggered during logout. Returning false should prevent the user from " "logging out." @@ -4224,38 +4369,38 @@ msgstr "" "Déclenché pendant la déconnexion. Renvoyer false empêche l’utilisateur de se" " déconnecter." -#: ../../guides/events-list.rst:278 +#: ../../guides/events-list.rst:284 msgid "**make_admin, user**" msgstr "**make_admin, user**" -#: ../../guides/events-list.rst:278 +#: ../../guides/events-list.rst:284 msgid "" "Triggered before a user is promoted to an admin. Return false to prevent." msgstr "" "Déclenché avant qu’un utilisateur ne soit promu administrateur. Retournez " "false pour l'éviter." -#: ../../guides/events-list.rst:281 +#: ../../guides/events-list.rst:287 msgid "**profileiconupdate, user**" msgstr "**profileiconupdate, user**" -#: ../../guides/events-list.rst:281 +#: ../../guides/events-list.rst:287 msgid "User has changed profile icon" msgstr "L'utilisateur a modifié son icône de profil" -#: ../../guides/events-list.rst:284 +#: ../../guides/events-list.rst:290 msgid "**profileupdate, user**" msgstr "**profileupdate, user**" -#: ../../guides/events-list.rst:284 +#: ../../guides/events-list.rst:290 msgid "User has changed profile" msgstr "L'utilisateur a modifié son profil" -#: ../../guides/events-list.rst:294 +#: ../../guides/events-list.rst:300 msgid "**register, user** |results|" -msgstr "" +msgstr "**register, user** |results|" -#: ../../guides/events-list.rst:287 +#: ../../guides/events-list.rst:293 msgid "" "Triggered by the ``register`` action after the user registers. Return " "``false`` to delete the user. Note the function ``register_user`` does *not*" @@ -4263,12 +4408,18 @@ msgid "" "``\\Elgg\\Exceptions\\Configuration\\RegistrationException`` with an error " "message to be displayed to the user." msgstr "" +"Déclenché par l'action ``register`` après l'enregistrement de l'utilisateur." +" Renvoyez ``false`` pour supprimer l'utilisateur. Notez que la fonction " +"``register_user`` ne déclenche *pas* cet événement. Les gestionnaires " +"d'événements peuvent lancer " +"``\\Elgg\\Exceptions\\Configuration\\RegistrationException`` avec un message" +" d'erreur à afficher à l'utilisateur." -#: ../../guides/events-list.rst:293 +#: ../../guides/events-list.rst:299 msgid "``user`` - Newly registered user entity" msgstr "``user`` - L'entité utilisateur nouvellement enregistrée" -#: ../../guides/events-list.rst:294 +#: ../../guides/events-list.rst:300 msgid "" "All parameters sent with the request to the action (incl. ``password``, " "``friend_guid``, ``invitecode`` etc)" @@ -4276,68 +4427,80 @@ msgstr "" "Tous les paramètres envoyés avec la requête à l’action (comprend " "``password``, ``friend_guid``, ``invitecode``, etc.)" -#: ../../guides/events-list.rst:298 +#: ../../guides/events-list.rst:304 msgid "**registeruser:validate:email, all** |results|" -msgstr "" +msgstr "**registeruser:validate:email, all** |results|" -#: ../../guides/events-list.rst:297 +#: ../../guides/events-list.rst:303 msgid "" "Return boolean for if the string in ``$params['email']`` is valid for an " "email address. Event handler can throw " "``\\Elgg\\Exceptions\\Configuration\\RegistrationException`` with an error " "message to be shown to the user." msgstr "" +"Renvoie un booléen si la chaîne dans ``$params['email']`` est une adresse " +"email valide. Le gestionnaire d'événements peut lancer " +"``\\Elgg\\Exceptions\\Configuration\\RegistrationException`` avec un message" +" d'erreur à afficher à l'utilisateur." -#: ../../guides/events-list.rst:302 +#: ../../guides/events-list.rst:308 msgid "**registeruser:validate:password, all** |results|" -msgstr "" +msgstr "**registeruser:validate:password, all** |results|" -#: ../../guides/events-list.rst:301 +#: ../../guides/events-list.rst:307 msgid "" "Return boolean for if the string in ``$params['password']`` is valid for a " "password. Event handler can throw " "``\\Elgg\\Exceptions\\Configuration\\RegistrationException`` with an error " "message to be shown to the user." msgstr "" +"Renvoie un booléen si la chaîne dans ``$params['password']`` est un mot de " +"passe valide. Le gestionnaire d'événements peut lancer une " +"``\\Elgg\\Exceptions\\Configuration\\RegistrationException`` avec un message" +" d'erreur à afficher à l'utilisateur. " -#: ../../guides/events-list.rst:306 +#: ../../guides/events-list.rst:312 msgid "**registeruser:validate:username, all** |results|" -msgstr "" +msgstr "**registeruser:validate:username, all** |results|" -#: ../../guides/events-list.rst:305 +#: ../../guides/events-list.rst:311 msgid "" "Return boolean for if the string in ``$params['username']`` is valid for a " "username. Event handler can throw " "``\\Elgg\\Exceptions\\Configuration\\RegistrationException`` with an error " "message to be shown to the user." msgstr "" +"Renvoie un booléen si la chaîne dans ``$params['username']`` est un nom " +"d'utilisateur valide. Le gestionnaire d'événements peut lancer une " +"``\\Elgg\\Exceptions\\Configuration\\RegistrationException`` avec un message" +" d'erreur à afficher à l'utilisateur." -#: ../../guides/events-list.rst:309 +#: ../../guides/events-list.rst:315 msgid "**remove_admin, user**" msgstr "**remove_admin, user**" -#: ../../guides/events-list.rst:309 +#: ../../guides/events-list.rst:315 msgid "" "Triggered before a user is demoted from an admin. Return false to prevent." msgstr "" "Déclenché avant que le rôle d'administrateur ne soit retiré à un " "utilisateur. Retournez false pour l'éviter." -#: ../../guides/events-list.rst:312 +#: ../../guides/events-list.rst:318 msgid "**unban, user**" msgstr "**unban, user**" -#: ../../guides/events-list.rst:312 +#: ../../guides/events-list.rst:318 msgid "Triggered before a user is unbanned. Return false to prevent." msgstr "" "Déclenché avant qu’un utilisateur ne soit réintégré. Retournez false pour " "l'éviter." -#: ../../guides/events-list.rst:317 +#: ../../guides/events-list.rst:323 msgid "**username:character_blacklist, user** |results|" -msgstr "" +msgstr "**username:character_blacklist, user** |results|" -#: ../../guides/events-list.rst:315 +#: ../../guides/events-list.rst:321 msgid "" "Filters the string of blacklisted characters used to validate username " "during registration. The return value should be a string consisting of the " @@ -4349,11 +4512,11 @@ msgstr "" "chaîne composée des caractères refusés. La chaîne par défaut se trouve dans " "``$params['blacklist']``." -#: ../../guides/events-list.rst:327 +#: ../../guides/events-list.rst:333 msgid "**usersettings:save, user** |results|" -msgstr "" +msgstr "**usersettings:save, user** |results|" -#: ../../guides/events-list.rst:320 +#: ../../guides/events-list.rst:326 msgid "" "Triggered in the aggregate action to save user settings. The event handler " "must return ``false`` to prevent sticky forms from being cleared (i.e. to " @@ -4361,12 +4524,19 @@ msgid "" "from your event handler, as you will override other events' output, instead " "return ``null`` to indicate successful operation." msgstr "" +"Déclenché dans l'action globale pour enregistrer les paramètres utilisateur." +" Le gestionnaire d'événements doit retourner ``false`` pour empêcher que les" +" formulaires persistants ne soient effacés (c'est-à-dire pour indiquer que " +"certaines valeurs n'ont pas été enregistrées). Ne renvoyez pas ``true`` " +"depuis votre gestionnaire d'événements, car vous écraseriez la sortie des " +"autres événements, mais renvoyez plutôt ``null`` pour indiquer une opération" +" réussie." -#: ../../guides/events-list.rst:332 +#: ../../guides/events-list.rst:338 msgid "**validate, user**" msgstr "**validate, user**" -#: ../../guides/events-list.rst:330 +#: ../../guides/events-list.rst:336 msgid "" "When a user registers, the user's account is disabled. This event is " "triggered to allow a plugin to determine how the user should be validated " @@ -4377,23 +4547,23 @@ msgstr "" " l’utilisateur doit être validé (par exemple, par le biais d’un e-mail avec " "un lien de validation)." -#: ../../guides/events-list.rst:335 +#: ../../guides/events-list.rst:341 msgid "**validate:after, user**" msgstr "**validate:after, user**" -#: ../../guides/events-list.rst:335 +#: ../../guides/events-list.rst:341 msgid "Triggered when user's account has been validated." msgstr "Déclenché lorsque le compte utilisateur a été validé." -#: ../../guides/events-list.rst:338 +#: ../../guides/events-list.rst:344 msgid "Relationship events" msgstr "Événements des relations" -#: ../../guides/events-list.rst:342 +#: ../../guides/events-list.rst:348 msgid "**create, relationship**" msgstr "**create, relationship**" -#: ../../guides/events-list.rst:341 +#: ../../guides/events-list.rst:347 msgid "" "Triggered after a relationship has been created. Returning false deletes the" " relationship that was just created." @@ -4401,11 +4571,11 @@ msgstr "" "Déclenché après la création d’une relation. Renvoyez false pour supprimer la" " relation qui vient d’être créée." -#: ../../guides/events-list.rst:346 +#: ../../guides/events-list.rst:352 msgid "**delete, relationship**" msgstr "**delete, relationship**" -#: ../../guides/events-list.rst:345 +#: ../../guides/events-list.rst:351 msgid "" "Triggered before a relationship is deleted. Return false to prevent it from " "being deleted." @@ -4413,11 +4583,11 @@ msgstr "" "Déclenché avant la suppression d’une relation. Renvoyez false pour éviter " "qu’elle soit supprimée." -#: ../../guides/events-list.rst:349 +#: ../../guides/events-list.rst:355 msgid "**join, group**" msgstr "**join, group**" -#: ../../guides/events-list.rst:349 +#: ../../guides/events-list.rst:355 msgid "" "Triggered after the user ``$params['user']`` has joined the group " "``$params['group']``." @@ -4425,11 +4595,11 @@ msgstr "" "Déclenché après que l’utilisateur ``$params['user']`` a rejoint le groupe " "``$params['group']``." -#: ../../guides/events-list.rst:352 +#: ../../guides/events-list.rst:358 msgid "**leave, group**" msgstr "**leave, group**" -#: ../../guides/events-list.rst:352 +#: ../../guides/events-list.rst:358 msgid "" "Triggered before the user ``$params['user']`` has left the group " "``$params['group']``." @@ -4437,15 +4607,15 @@ msgstr "" "Déclenché avant que l’utilisateur ``$params['user']`` n'ait quitté le groupe" " ``$params['group']``." -#: ../../guides/events-list.rst:355 +#: ../../guides/events-list.rst:361 msgid "Entity events" msgstr "Événements des entités" -#: ../../guides/events-list.rst:359 +#: ../../guides/events-list.rst:365 msgid "**comments, ** |results|" -msgstr "" +msgstr "**comments, ** |results|" -#: ../../guides/events-list.rst:358 +#: ../../guides/events-list.rst:364 msgid "" "Triggered in ``elgg_view_comments()``. If returning content, this overrides " "the ``page/elements/comments`` view." @@ -4453,117 +4623,124 @@ msgstr "" "Déclenché dans ``elgg_view_comments()``. S'il renvoie du contenu, celui-ci " "remplace la vue ``page/elements/comments``." -#: ../../guides/events-list.rst:362 +#: ../../guides/events-list.rst:368 msgid "**comments:count, ** |results|" -msgstr "" +msgstr "**comments:count, ** |results|" -#: ../../guides/events-list.rst:362 +#: ../../guides/events-list.rst:368 msgid "Return the number of comments on ``$params['entity']``." msgstr "Renvoie le nombre de commentaires sur ``$params['entity']``." -#: ../../guides/events-list.rst:366 +#: ../../guides/events-list.rst:372 msgid "**create, **" msgstr "**create, **" -#: ../../guides/events-list.rst:365 +#: ../../guides/events-list.rst:371 msgid "" "Triggered for user, group, object, and site entities after creation. " "Triggered just before the ``create:after`` event, mostly for BC reasons. The" " use of the ``create:after`` event is preferred." msgstr "" +"Déclenché pour les entités user, group, object et site après leur création. " +"Déclenché juste avant l'événement ``create:after``, principalement pour des " +"raisons de rétrocompatibilité. L'utilisation de l'événement ``create:after``" +" est préférable." -#: ../../guides/events-list.rst:369 +#: ../../guides/events-list.rst:375 msgid "**create:after, **" -msgstr "" +msgstr "**create:after, **" -#: ../../guides/events-list.rst:369 +#: ../../guides/events-list.rst:375 msgid "Triggered for user, group, object, and site entities after creation." msgstr "" +"Déclenché pour les entités user, group, object et site après la création." -#: ../../guides/events-list.rst:372 +#: ../../guides/events-list.rst:378 msgid "**create:before, **" -msgstr "" +msgstr "**create:before, **" -#: ../../guides/events-list.rst:372 +#: ../../guides/events-list.rst:378 msgid "" "Triggered for user, group, object, and site entities before creation. Return" " false to prevent creating the entity." msgstr "" +"Déclenché pour les entités user, group, object et site avant la création. " +"Renvoyez false pour empêcher la création de l’entité." -#: ../../guides/events-list.rst:375 +#: ../../guides/events-list.rst:381 msgid "**delete, **" msgstr "**delete, **" -#: ../../guides/events-list.rst:375 +#: ../../guides/events-list.rst:381 msgid "Triggered before entity deletion." msgstr "Déclenché avant la suppression d'une entité." -#: ../../guides/events-list.rst:378 +#: ../../guides/events-list.rst:384 msgid "**delete:after, **" msgstr "**delete:after, **" -#: ../../guides/events-list.rst:378 +#: ../../guides/events-list.rst:384 msgid "Triggered after entity deletion." msgstr "Déclenché après la suppression d'une entité." -#: ../../guides/events-list.rst:381 +#: ../../guides/events-list.rst:387 msgid "**delete:before, **" msgstr "**delete:before, **" -#: ../../guides/events-list.rst:381 +#: ../../guides/events-list.rst:387 msgid "Triggered before entity deletion. Return false to prevent deletion." msgstr "" "Déclenché avant la suppression d'une entité. Retournez false pour éviter la " "suppression." -#: ../../guides/events-list.rst:384 +#: ../../guides/events-list.rst:390 msgid "**disable, **" msgstr "**disable, **" -#: ../../guides/events-list.rst:384 +#: ../../guides/events-list.rst:390 msgid "" "Triggered before the entity is disabled. Return false to prevent disabling." msgstr "" "Déclenché avant qu'une entité soit désactivée. Retournez false pour éviter " "la désactivation." -#: ../../guides/events-list.rst:387 +#: ../../guides/events-list.rst:393 msgid "**disable:after, **" msgstr "**disable:after, **" -#: ../../guides/events-list.rst:387 +#: ../../guides/events-list.rst:393 msgid "Triggered after the entity is disabled." msgstr "Déclenché après qu'une entité a été désactivée." -#: ../../guides/events-list.rst:390 +#: ../../guides/events-list.rst:396 msgid "**enable, **" msgstr "**enable, **" -#: ../../guides/events-list.rst:390 +#: ../../guides/events-list.rst:396 msgid "Return false to prevent enabling." msgstr "Retournez false pour éviter l'activation." -#: ../../guides/events-list.rst:393 +#: ../../guides/events-list.rst:399 msgid "**enable:after, **" msgstr "**enable:after, **" -#: ../../guides/events-list.rst:393 +#: ../../guides/events-list.rst:399 msgid "Triggered after the entity is enabled." msgstr "Déclenché après qu'une entité a été activée." -#: ../../guides/events-list.rst:396 +#: ../../guides/events-list.rst:402 msgid "**likes:count, ** |results|" -msgstr "" +msgstr "**likes:count, ** |results|" -#: ../../guides/events-list.rst:396 +#: ../../guides/events-list.rst:402 msgid "Return the number of likes for ``$params['entity']``." msgstr "Renvoie le nombre de mentions J’aime pour ``$params['entity']``." -#: ../../guides/events-list.rst:401 +#: ../../guides/events-list.rst:407 msgid "**update, **" msgstr "**update, **" -#: ../../guides/events-list.rst:399 +#: ../../guides/events-list.rst:405 msgid "" "Triggered before an update for the user, group, object, and site entities. " "Return false to prevent update. The entity method " @@ -4575,11 +4752,11 @@ msgstr "" "``getOriginalAttributes()`` peut être utilisée pour identifier les attributs" " qui ont changé depuis la dernière fois que l’entité a été enregistrée." -#: ../../guides/events-list.rst:406 +#: ../../guides/events-list.rst:412 msgid "**update:after, **" msgstr "**update:after, **" -#: ../../guides/events-list.rst:404 +#: ../../guides/events-list.rst:410 msgid "" "Triggered after an update for the user, group, object, and site entities. " "The entity method ``getOriginalAttributes()`` can be used to identify which " @@ -4590,15 +4767,15 @@ msgstr "" "pour identifier les attributs qui ont changé depuis la dernière fois que " "l’entité a été enregistrée." -#: ../../guides/events-list.rst:409 +#: ../../guides/events-list.rst:415 msgid "Metadata events" msgstr "Événements des métadonnées" -#: ../../guides/events-list.rst:413 +#: ../../guides/events-list.rst:419 msgid "**create, metadata**" msgstr "**create, metadata**" -#: ../../guides/events-list.rst:412 +#: ../../guides/events-list.rst:418 msgid "" "Called after the metadata has been created. Return false to delete the " "metadata that was just created." @@ -4606,21 +4783,21 @@ msgstr "" "Appelé après qu'une métadonnée a été créée. Retournez false pour supprimer " "la métadonnée qui vient d'être créée." -#: ../../guides/events-list.rst:416 +#: ../../guides/events-list.rst:422 msgid "**delete, metadata**" msgstr "**delete, metadata**" -#: ../../guides/events-list.rst:416 +#: ../../guides/events-list.rst:422 msgid "Called before metadata is deleted. Return false to prevent deletion." msgstr "" "Appelé avant que métadonnée soit supprimée. Retournez false pour éviter la " "suppression." -#: ../../guides/events-list.rst:419 +#: ../../guides/events-list.rst:425 msgid "**update, metadata**" msgstr "**update, metadata**" -#: ../../guides/events-list.rst:419 +#: ../../guides/events-list.rst:425 msgid "" "Called after the metadata has been updated. Return false to *delete the " "metadata.*" @@ -4628,15 +4805,15 @@ msgstr "" "Appelé après qu'une métadonnée a été modifiée. Retournez false pour " "*supprimer la métadonnée.*" -#: ../../guides/events-list.rst:422 +#: ../../guides/events-list.rst:428 msgid "Annotation events" msgstr "Événements des annotations" -#: ../../guides/events-list.rst:426 +#: ../../guides/events-list.rst:432 msgid "**annotate, **" msgstr "**annotate, **" -#: ../../guides/events-list.rst:425 +#: ../../guides/events-list.rst:431 msgid "" "Called before the annotation has been created. Return false to prevent " "annotation of this entity." @@ -4644,11 +4821,11 @@ msgstr "" "Appelé avant que l'annotation soit créée. Retournez false pour éviter " "l'annotation de cette entité." -#: ../../guides/events-list.rst:430 +#: ../../guides/events-list.rst:436 msgid "**create, annotation**" msgstr "**create, annotation**" -#: ../../guides/events-list.rst:429 +#: ../../guides/events-list.rst:435 msgid "" "Called after the annotation has been created. Return false to delete the " "annotation." @@ -4656,41 +4833,41 @@ msgstr "" "Appelé après que l'annotation a été créée. Retournez false pour supprimer " "l'annotation." -#: ../../guides/events-list.rst:433 +#: ../../guides/events-list.rst:439 msgid "**delete, annotation**" msgstr "**delete, annotation**" -#: ../../guides/events-list.rst:433 +#: ../../guides/events-list.rst:439 msgid "Called before annotation is deleted. Return false to prevent deletion." msgstr "" "Appelé avant que l'annotation soit supprimée. Retournez false pour éviter la" " suppression." -#: ../../guides/events-list.rst:436 +#: ../../guides/events-list.rst:442 msgid "**disable, annotations**" msgstr "**disable, annotations**" -#: ../../guides/events-list.rst:436 +#: ../../guides/events-list.rst:442 msgid "Called when disabling annotations. Return false to prevent disabling." msgstr "" "Appelé lors de la désactivation d'annotations. Retournez false pour éviter " "la désactivation." -#: ../../guides/events-list.rst:439 +#: ../../guides/events-list.rst:445 msgid "**enable, annotation**" msgstr "**enable, annotation**" -#: ../../guides/events-list.rst:439 +#: ../../guides/events-list.rst:445 msgid "Called when enabling annotations. Return false to prevent enabling." msgstr "" "Appelé lors de l'activation d'annotations. Retournez false pour éviter " "l'activation." -#: ../../guides/events-list.rst:442 +#: ../../guides/events-list.rst:448 msgid "**update, annotation**" msgstr "**update, annotation**" -#: ../../guides/events-list.rst:442 +#: ../../guides/events-list.rst:448 msgid "" "Called after the annotation has been updated. Return false to *delete the " "annotation.*" @@ -4698,23 +4875,23 @@ msgstr "" "Appelé après qu'une annotation a été modifiée. Retournez false pour " "*supprimer l'annotation.*" -#: ../../guides/events-list.rst:445 +#: ../../guides/events-list.rst:451 msgid "River events" msgstr "Événements de la rivière" -#: ../../guides/events-list.rst:448 +#: ../../guides/events-list.rst:454 msgid "**create:after, river**" msgstr "**create:after, river**" -#: ../../guides/events-list.rst:448 +#: ../../guides/events-list.rst:454 msgid "Called after a river item is created." msgstr "Appelé après qu'un élément de la rivière a été créé." -#: ../../guides/events-list.rst:451 +#: ../../guides/events-list.rst:457 msgid "**create:before, river**" msgstr "**create:before, river**" -#: ../../guides/events-list.rst:451 +#: ../../guides/events-list.rst:457 msgid "" "Called before the river item is saved to the database. Return ``false`` to " "prevent the item from being created." @@ -4722,19 +4899,19 @@ msgstr "" "Appelé avant que l'élément river ne soit enregistré dans la base de données." " Renvoie ``false`` pour empêcher la création de l'élément." -#: ../../guides/events-list.rst:454 +#: ../../guides/events-list.rst:460 msgid "**delete:after, river**" msgstr "**delete:after, river**" -#: ../../guides/events-list.rst:454 +#: ../../guides/events-list.rst:460 msgid "Triggered after a river item was deleted." msgstr "Déclenché après qu'un élément de la rivière a été supprimé." -#: ../../guides/events-list.rst:457 +#: ../../guides/events-list.rst:463 msgid "**delete:before, river**" msgstr "**delete:before, river**" -#: ../../guides/events-list.rst:457 +#: ../../guides/events-list.rst:463 msgid "" "Triggered before a river item is deleted. Returning false cancels the " "deletion." @@ -4742,27 +4919,27 @@ msgstr "" "Déclenché avant qu'un élément de la rivière soit supprimé. Renvoyer false " "annule la suppression." -#: ../../guides/events-list.rst:462 +#: ../../guides/events-list.rst:468 msgid "Access events" -msgstr "" +msgstr "Événements des accès" -#: ../../guides/events-list.rst:469 +#: ../../guides/events-list.rst:475 msgid "**access_collection:url, access_collection** |results|" -msgstr "" +msgstr "**access_collection:url, access_collection** |results|" -#: ../../guides/events-list.rst:465 +#: ../../guides/events-list.rst:471 msgid "Can be used to filter the URL of the access collection." msgstr "Peut être utilisé pour filtrer l’URL de la collection d’accès." -#: ../../guides/events-list.rst:469 ../../guides/events-list.rst:476 +#: ../../guides/events-list.rst:475 ../../guides/events-list.rst:482 msgid "``access_collection`` - `ElggAccessCollection`" msgstr "``access_collection`` - `ElggAccessCollection`" -#: ../../guides/events-list.rst:476 +#: ../../guides/events-list.rst:482 msgid "**access_collection:name, access_collection** |results|" -msgstr "" +msgstr "**access_collection:name, access_collection** |results|" -#: ../../guides/events-list.rst:472 +#: ../../guides/events-list.rst:478 msgid "" "Can be used to filter the display name (readable access level) of the access" " collection." @@ -4770,29 +4947,32 @@ msgstr "" "Peut être utilisé pour filtrer le nom affiché (niveau d’accès lisible) de la" " collection d’accès." -#: ../../guides/events-list.rst:483 +#: ../../guides/events-list.rst:489 msgid "**access:collections:read, user** |results|" -msgstr "" +msgstr "**access:collections:read, user** |results|" -#: ../../guides/events-list.rst:479 +#: ../../guides/events-list.rst:485 msgid "" "Filters an array of access IDs that the user ``$params['user_id']`` can see." msgstr "" "Filtre le tableau des IDs d’accès que l’utilisateur ``$params['user_id']`` " "peut voir." -#: ../../guides/events-list.rst:482 ../../guides/events-list.rst:494 +#: ../../guides/events-list.rst:488 ../../guides/events-list.rst:500 msgid "" "The handler needs to either not use parts of the API that use the access " "system (triggering the event again) or to ignore the second call. Otherwise," " an infinite loop will be created." msgstr "" +"Le gestionnaire doit soit ne pas utiliser les parties de l'API qui utilisent" +" le système d'accès (déclenchant à nouveau l'événement), soit ignorer le " +"deuxième appel. Sinon, une boucle infinie sera créée." -#: ../../guides/events-list.rst:495 +#: ../../guides/events-list.rst:501 msgid "**access:collections:write, user** |results|" -msgstr "" +msgstr "**access:collections:write, user** |results|" -#: ../../guides/events-list.rst:486 +#: ../../guides/events-list.rst:492 msgid "" "Filters an array of access IDs that the user ``$params['user_id']`` can " "write to. In ``elgg_get_write_access_array()``, this event filters the " @@ -4802,12 +4982,20 @@ msgid "" "\"entity_subtype\" (string), \"container_guid\" (int) are provided. An empty" " entity value generally means the form is to create a new object." msgstr "" +"Filtre un tableau d'IDs d'accès sur lesquels l'utilisateur " +"``$params['user_id']`` peut écrire. Dans ``elgg_get_write_access_array()``, " +"cet événement filtre la valeur de retour, afin qu'il puisse être utilisé " +"pour modifier les options disponibles dans la vue ``input/access``. Pour les" +" plugins principaux, la valeur \"input_params\" a les clés \"entity\" " +"(ElggEntity|false), \"entity_type\" (string), \"entity_subtype\" (string), " +"\"container_guid\" (int) fournies. Une valeur d'entité vide signifie " +"généralement que le formulaire doit créer un nouvel objet. " -#: ../../guides/events-list.rst:499 +#: ../../guides/events-list.rst:505 msgid "**access:collections:write:subtypes, user** |results|" -msgstr "" +msgstr "**access:collections:write:subtypes, user** |results|" -#: ../../guides/events-list.rst:498 +#: ../../guides/events-list.rst:504 msgid "" "Returns an array of access collection subtypes to be used when retrieving " "access collections owned by a user as part of the " @@ -4817,11 +5005,11 @@ msgstr "" " récupération des collections d’accès appartenant à un utilisateur, dans le " "cadre de la fonction ``elgg_get_write_access_array()``." -#: ../../guides/events-list.rst:503 +#: ../../guides/events-list.rst:509 msgid "**access:collections:add_user, collection** |results|" -msgstr "" +msgstr "**access:collections:add_user, collection** |results|" -#: ../../guides/events-list.rst:502 +#: ../../guides/events-list.rst:508 msgid "" "Triggered before adding user ``$params['user_id']`` to collection " "``$params['collection_id']``. Return false to prevent adding." @@ -4830,11 +5018,11 @@ msgstr "" "collection ``$params['collection_id']``. Retournez false pour éviter " "l’ajout." -#: ../../guides/events-list.rst:507 +#: ../../guides/events-list.rst:513 msgid "**access:collections:remove_user, collection** |results|" -msgstr "" +msgstr "**access:collections:remove_user, collection** |results|" -#: ../../guides/events-list.rst:506 +#: ../../guides/events-list.rst:512 msgid "" "Triggered before removing user ``$params['user_id']`` to collection " "``$params['collection_id']``. Return false to prevent removal." @@ -4843,66 +5031,70 @@ msgstr "" "collection ``$params['collection_id']``. Renvoyez false pour éviter la " "suppression." -#: ../../guides/events-list.rst:510 +#: ../../guides/events-list.rst:516 msgid "**create, access_collection** |sequence|" -msgstr "" +msgstr "**create, access_collection** |sequence|" -#: ../../guides/events-list.rst:510 +#: ../../guides/events-list.rst:516 msgid "Triggered during the creation of an ``ElggAccessCollection``." -msgstr "" +msgstr "Déclenché durant la création d'une ``ElggAccessCollection``." -#: ../../guides/events-list.rst:513 +#: ../../guides/events-list.rst:519 msgid "**delete, access_collection** |sequence|" -msgstr "" +msgstr "**delete, access_collection** |sequence|" -#: ../../guides/events-list.rst:513 +#: ../../guides/events-list.rst:519 msgid "Triggered during the deletion of an ``ElggAccessCollection``." -msgstr "" +msgstr "Déclenché durant la suppression d'une ``ElggAccessCollection``." -#: ../../guides/events-list.rst:534 +#: ../../guides/events-list.rst:540 msgid "**get_sql, access** |results|" -msgstr "" +msgstr "**get_sql, access** |results|" -#: ../../guides/events-list.rst:516 +#: ../../guides/events-list.rst:522 msgid "" "Filters SQL clauses restricting/allowing access to entities and annotations." msgstr "" "Filtre les clauses SQL limitant/autorisant l’accès aux entités et aux " "annotations." -#: ../../guides/events-list.rst:519 +#: ../../guides/events-list.rst:525 msgid "" "**The event is triggered regardless if the access is ignored**. The handlers" " may need to check if access is ignored and return early, if appended " "clauses should only apply to access controlled contexts." msgstr "" +"**L'événement est déclenché même si l'accès est ignoré**. Les gestionnaires " +"devront peut-être vérifier si l'accès est ignoré et retourner une réponse " +"plus tôt, si les clauses ajoutées ne doivent s'appliquer qu'à des contextes " +"à accès contrôlé." -#: ../../guides/events-list.rst:523 +#: ../../guides/events-list.rst:529 msgid "``$return`` value is a nested array of ``ands`` and ``ors``." msgstr "" "La valeur ``$return`` est un tableau imbriqué de ``ands`` et de ``ors``." -#: ../../guides/events-list.rst:525 +#: ../../guides/events-list.rst:531 msgid "``$params`` includes:" msgstr "``$params`` comprend :" -#: ../../guides/events-list.rst:527 +#: ../../guides/events-list.rst:533 msgid "``table_alias`` - alias of the main table used in select clause" msgstr "" "``table_alias`` - alias de la table principale utilisée dans la clause de " "sélection" -#: ../../guides/events-list.rst:528 +#: ../../guides/events-list.rst:534 msgid "``ignore_access`` - whether ignored access is enabled" msgstr "``ignore_access`` - selon que les accès sont ignorés ou activés" -#: ../../guides/events-list.rst:529 +#: ../../guides/events-list.rst:535 msgid "``use_enabled_clause`` - whether disabled entities are shown/hidden" msgstr "" "``use_enabled_clause`` - selon que les entités désactivées sont " "affichées/cachées" -#: ../../guides/events-list.rst:530 +#: ../../guides/events-list.rst:536 msgid "" "``access_column`` - column in the main table containing the access " "collection ID value" @@ -4910,7 +5102,7 @@ msgstr "" "``access_column`` - colonne de la table principale contenant l'ID de la " "collection d’accès" -#: ../../guides/events-list.rst:531 +#: ../../guides/events-list.rst:537 msgid "" "``owner_guid_column`` - column in the main table referencing the GUID of the" " owner" @@ -4918,7 +5110,7 @@ msgstr "" "``owner_guid_column`` - colonne de la table principale faisant référence au " "GUID du propriétaire" -#: ../../guides/events-list.rst:532 +#: ../../guides/events-list.rst:538 msgid "" "``guid_column`` - column in the main table referencing the GUID of the " "entity" @@ -4926,7 +5118,7 @@ msgstr "" "``guid_column`` - colonne de la table principale faisant référence au GUID " "de l’entité" -#: ../../guides/events-list.rst:533 +#: ../../guides/events-list.rst:539 msgid "" "``enabled_column`` - column in the main table referencing the enabled status" " of the entity" @@ -4934,27 +5126,27 @@ msgstr "" "``enabled_column`` - colonne de la table principale faisant référence à " "l’état activé de l’entité" -#: ../../guides/events-list.rst:534 +#: ../../guides/events-list.rst:540 msgid "``query_builder`` - an instance of the ``QueryBuilder``" msgstr "``query_builder`` - une instance de ``QueryBuilder``" -#: ../../guides/events-list.rst:537 +#: ../../guides/events-list.rst:543 msgid "**update, access_collection** |sequence|" -msgstr "" +msgstr "**update, access_collection** |sequence|" -#: ../../guides/events-list.rst:537 +#: ../../guides/events-list.rst:543 msgid "Triggered during the update of an ``ElggAccessCollection``." -msgstr "" +msgstr "Déclenché durant la mise à jour d'une ``ElggAccessCollection``." -#: ../../guides/events-list.rst:542 +#: ../../guides/events-list.rst:548 msgid "Permission events" -msgstr "" +msgstr "Événements des permissions" -#: ../../guides/events-list.rst:558 +#: ../../guides/events-list.rst:564 msgid "**container_logic_check, ** |results|" -msgstr "" +msgstr "**container_logic_check, ** |results|" -#: ../../guides/events-list.rst:545 +#: ../../guides/events-list.rst:551 msgid "" "Triggered by ``ElggEntity:canWriteToContainer()`` before triggering " "``permissions_check`` and ``container_permissions_check`` events. Unlike " @@ -4963,8 +5155,16 @@ msgid "" "only be contained by discussions. This event can also be used to apply " "status logic, e.g. do disallow new replies for closed discussions." msgstr "" +"Déclenché par ``ElggEntity:canWriteToContainer()`` avant de déclencher les " +"événements ``permissions_check`` et ``container_permissions_check``. " +"Contrairement aux événements des permissions, la vérification logique peut " +"être utilisée pour empêcher certains types d'entités d'être contenus par " +"d'autres types d'entités, par ex. les réponses aux discussions ne doivent " +"être contenues que par les discussions. Cet événement peut également être " +"utilisé pour appliquer une logique d'état, par ex. pour interdire les " +"nouvelles réponses pour les discussions fermées." -#: ../../guides/events-list.rst:550 +#: ../../guides/events-list.rst:556 msgid "" "The handler should return ``false`` to prevent an entity from containing " "another entity. The default value passed to the event is ``null``, so the " @@ -4973,28 +5173,36 @@ msgid "" "``container_permissions_check`` and ``permissions_check`` events will not be" " triggered." msgstr "" +"Le gestionnaire devrait renvoyer ``false`` pour empêcher une entité de " +"contenir une autre entité. La valeur par défaut transmise à l'événement est " +"``null``, donc le gestionnaire peut vérifier si un autre événement a modifié" +" la valeur en vérifiant si la valeur de retour est définie. Si cet événement" +" renvoie ``false``, les événements ``container_permissions_check`` et " +"``permissions_check`` ne seront pas déclenchés." -#: ../../guides/events-list.rst:556 ../../guides/events-list.rst:570 +#: ../../guides/events-list.rst:562 ../../guides/events-list.rst:576 msgid "``container`` - An entity that will be used as a container" msgstr "``container`` - Une entité qui sera utilisée comme conteneur" -#: ../../guides/events-list.rst:557 ../../guides/events-list.rst:571 +#: ../../guides/events-list.rst:563 ../../guides/events-list.rst:577 msgid "``user`` - User who will own the entity to be written to container" msgstr "" "``user`` - L'utilisateur qui sera propriétaire de l’entité à écrire dans le " "conteneur" -#: ../../guides/events-list.rst:558 ../../guides/events-list.rst:572 +#: ../../guides/events-list.rst:564 ../../guides/events-list.rst:578 msgid "" "``subtype`` - Subtype of the entity to be written to container (entity type " "is assumed from event type)" msgstr "" +"``subtype`` - Subtype de l'entité à écrire dans le conteneur (le type " +"d'entité est déduit à partir du type d'événement)" -#: ../../guides/events-list.rst:572 +#: ../../guides/events-list.rst:578 msgid "**container_permissions_check, ** |results|" -msgstr "" +msgstr "**container_permissions_check, ** |results|" -#: ../../guides/events-list.rst:561 +#: ../../guides/events-list.rst:567 msgid "" "Return boolean for if the user ``$params['user']`` can use the entity " "``$params['container']`` as a container for an entity of ```` " @@ -5004,19 +5212,23 @@ msgstr "" "utiliser l’entité ``$params['container']`` comme conteneur pour une entité " "```` et le sous-type ``$params['subtype']``." -#: ../../guides/events-list.rst:564 +#: ../../guides/events-list.rst:570 msgid "" "In the rare case where an entity is created with neither the " "``container_guid`` nor the ``owner_guid`` matching the logged in user, this " "event is called *twice*, and in the first call ``$params['container']`` will" " be the *owner*, not the entity's real container." msgstr "" +"Dans les rares cas où une entité est créée sans le ``container_guid`` ni le " +"``owner_guid`` correspondant à l'utilisateur connecté, cet événement est " +"appelé *deux fois*, et lors du premier appel ``$params['container ']`` sera " +"le *propriétaire*, et pas le véritable conteneur de l'entité." -#: ../../guides/events-list.rst:575 +#: ../../guides/events-list.rst:581 msgid "**permissions_check, ** |results|" -msgstr "" +msgstr "**permissions_check, ** |results|" -#: ../../guides/events-list.rst:575 +#: ../../guides/events-list.rst:581 msgid "" "Return boolean for if the user ``$params['user']`` can edit the entity " "``$params['entity']``." @@ -5024,11 +5236,11 @@ msgstr "" "Renvoie un booléen pour indiquer si l’utilisateur ``$params['user']`` peut " "modifier l’entité ``$params['entity']``." -#: ../../guides/events-list.rst:578 +#: ../../guides/events-list.rst:584 msgid "**permissions_check:delete, ** |results|" -msgstr "" +msgstr "**permissions_check:delete, ** |results|" -#: ../../guides/events-list.rst:578 +#: ../../guides/events-list.rst:584 msgid "" "Return boolean for if the user ``$params['user']`` can delete the entity " "``$params['entity']``. Defaults to ``$entity->canEdit()``." @@ -5037,11 +5249,11 @@ msgstr "" "supprimer l’entité ``$params['entity']``. Vaut par défaut " "``$entity->canEdit()``." -#: ../../guides/events-list.rst:582 +#: ../../guides/events-list.rst:588 msgid "**permissions_check:delete, river** |results|" -msgstr "" +msgstr "**permissions_check:delete, river** |results|" -#: ../../guides/events-list.rst:581 +#: ../../guides/events-list.rst:587 msgid "" "Return boolean for if the user ``$params['user']`` can delete the river item" " ``$params['item']``. Defaults to ``true`` for admins and ``false`` for " @@ -5051,11 +5263,11 @@ msgstr "" "supprimer l’élément de la rivière ``$params['item']``. Par défaut à ``true``" " pour les administrateurs et ``false`` pour les autres utilisateurs." -#: ../../guides/events-list.rst:590 +#: ../../guides/events-list.rst:596 msgid "**permissions_check:download, file** |results|" -msgstr "" +msgstr "**permissions_check:download, file** |results|" -#: ../../guides/events-list.rst:585 +#: ../../guides/events-list.rst:591 msgid "" "Return boolean for if the user ``$params['user']`` can download the file in " "``$params['entity']``." @@ -5063,19 +5275,19 @@ msgstr "" "Renvoie un booléen pour indiquer si l’utilisateur ``$params['user']`` peut " "télécharger le fichier dans ``$params['entity']``." -#: ../../guides/events-list.rst:589 +#: ../../guides/events-list.rst:595 msgid "``entity`` - Instance of ``ElggFile``" msgstr "``entity`` - Instance de ``ElggFile``" -#: ../../guides/events-list.rst:590 +#: ../../guides/events-list.rst:596 msgid "``user`` - User who will download the file" msgstr "``user`` - Utilisateur qui va télécharger le fichier" -#: ../../guides/events-list.rst:594 +#: ../../guides/events-list.rst:600 msgid "**permissions_check, widget_layout** |results|" -msgstr "" +msgstr "**permissions_check, widget_layout** |results|" -#: ../../guides/events-list.rst:593 +#: ../../guides/events-list.rst:599 msgid "" "Return boolean for if ``$params['user']`` can edit the widgets in the " "context passed as ``$params['context']`` and with a page owner of " @@ -5085,11 +5297,11 @@ msgstr "" "widgets dans le contexte passé par ``$params['context']`` et avec le " "propriétaire de page ``$params['page_owner']``." -#: ../../guides/events-list.rst:597 +#: ../../guides/events-list.rst:603 msgid "**permissions_check:comment, ** |results|" -msgstr "" +msgstr "**permissions_check:comment, ** |results|" -#: ../../guides/events-list.rst:597 +#: ../../guides/events-list.rst:603 msgid "" "Return boolean for if the user ``$params['user']`` can comment on the entity" " ``$params['entity']``." @@ -5097,12 +5309,13 @@ msgstr "" "Renvoie un booléen pour indiquer si l’utilisateur ``$params['user']`` peut " "commenter l’entité ``$params['entity']``." -#: ../../guides/events-list.rst:603 +#: ../../guides/events-list.rst:609 msgid "" "**permissions_check:annotate:, ** |results|" msgstr "" +"**permissions_check:annotate:, ** |results|" -#: ../../guides/events-list.rst:600 +#: ../../guides/events-list.rst:606 msgid "" "Return boolean for if the user ``$params['user']`` can create an annotation " "```` on the entity ``$params['entity']``. If logged in, the" @@ -5113,17 +5326,20 @@ msgstr "" "``$params['entity']``. Si l'utilisateur est connecté, la valeur par défaut " "est true." -#: ../../guides/events-list.rst:603 +#: ../../guides/events-list.rst:609 msgid "" "This is called before the more general ``permissions_check:annotate`` event," " and its return value is that event's initial value." msgstr "" +"Ceci est appelé avant l'événement plus général " +"``permissions_check:annotate``, et sa valeur de retour est la valeur " +"initiale de cet événement." -#: ../../guides/events-list.rst:607 +#: ../../guides/events-list.rst:613 msgid "**permissions_check:annotate, ** |results|" -msgstr "" +msgstr "**permissions_check:annotate, ** |results|" -#: ../../guides/events-list.rst:606 +#: ../../guides/events-list.rst:612 msgid "" "Return boolean for if the user ``$params['user']`` can create an annotation " "``$params['annotation_name']`` on the entity ``$params['entity']``. if " @@ -5134,11 +5350,11 @@ msgstr "" "``$params['entity']``. Si l'utilisateur est connecté, la valeur par défaut " "est true." -#: ../../guides/events-list.rst:610 +#: ../../guides/events-list.rst:616 msgid "**api_key, use** |results|" -msgstr "" +msgstr "**api_key, use** |results|" -#: ../../guides/events-list.rst:610 +#: ../../guides/events-list.rst:616 msgid "" "Triggered in the class ``\\Elgg\\WebServices\\PAM\\API\\APIKey``. Returning " "false prevents the key from being authenticated." @@ -5146,11 +5362,11 @@ msgstr "" "Déclenché dans la classe ``\\Elgg\\WebServices\\PAM\\API\\APIKey``. Renvoyer" " false empêche l'authentification de la clef." -#: ../../guides/events-list.rst:622 +#: ../../guides/events-list.rst:628 msgid "**gatekeeper, :** |results|" -msgstr "" +msgstr "**gatekeeper, :** |results|" -#: ../../guides/events-list.rst:613 +#: ../../guides/events-list.rst:619 msgid "" "Filters the result of ``elgg_entity_gatekeeper()`` to prevent or allow " "access to an entity that user would otherwise have or not have access to. A " @@ -5161,34 +5377,42 @@ msgid "" " access and including disabled entities, so you have to be careful to not " "bypass the access system." msgstr "" - -#: ../../guides/events-list.rst:619 ../../guides/events-list.rst:640 -#: ../../guides/events-list.rst:654 ../../guides/events-list.rst:674 -#: ../../guides/events-list.rst:729 ../../guides/events-list.rst:737 -#: ../../guides/events-list.rst:790 ../../guides/events-list.rst:800 -#: ../../guides/events-list.rst:823 ../../guides/events-list.rst:842 +"Filtre le résultat de ``elgg_entity_gatekeeper()`` pour bloquer ou autoriser" +" l'accès à une entité à laquelle l'utilisateur aurait ou n'aurait pas accès " +"autrement. Un gestionnaire peut renvoyer ``false`` ou une instance de " +"``\\Elgg\\Exceptions\\HttpException`` pour empêcher l'accès à une entité. Un" +" gestionnaire peut retourner ``true`` pour remplacer le résultat" +" du gatekeeper. **Important** l'entité reçue par cet événement est récupérée" +" en ignorant les accès, et en incluant les entités désactivées, vous devez " +"donc faire attention à ne pas contourner le système d'accès." + +#: ../../guides/events-list.rst:625 ../../guides/events-list.rst:646 +#: ../../guides/events-list.rst:660 ../../guides/events-list.rst:680 +#: ../../guides/events-list.rst:735 ../../guides/events-list.rst:743 +#: ../../guides/events-list.rst:796 ../../guides/events-list.rst:806 +#: ../../guides/events-list.rst:829 ../../guides/events-list.rst:848 msgid "``$params`` array includes:" msgstr "le tableau ``$params`` comprend :" -#: ../../guides/events-list.rst:621 +#: ../../guides/events-list.rst:627 msgid "``entity`` - Entity that is being accessed" msgstr "``entity`` - Entité à laquelle on accède" -#: ../../guides/events-list.rst:622 +#: ../../guides/events-list.rst:628 msgid "``user`` - User accessing the entity (``null`` implies logged in user)" msgstr "" "``user`` - L’utilisateur qui accède à l’entité (``null`` implique " "l’utilisateur connecté)" -#: ../../guides/events-list.rst:625 +#: ../../guides/events-list.rst:631 msgid "Notifications events" msgstr "Événements des notifications" -#: ../../guides/events-list.rst:628 +#: ../../guides/events-list.rst:634 msgid "**dequeue, notifications**" msgstr "**dequeue, notifications**" -#: ../../guides/events-list.rst:628 +#: ../../guides/events-list.rst:634 msgid "" "Called when an ElggData object is removed from the notifications queue to be" " processed" @@ -5196,39 +5420,46 @@ msgstr "" "Appelé lorsqu'un objet ElggData est supprimé de la file d'attente des " "notifications pour être traité" -#: ../../guides/events-list.rst:631 +#: ../../guides/events-list.rst:637 msgid "**enqueue, notifications**" msgstr "**enqueue, notifications**" -#: ../../guides/events-list.rst:631 +#: ../../guides/events-list.rst:637 msgid "" "Called when an ElggData object is being added to the notifications queue" msgstr "" "Appelé lorsqu'un objet ElggData est en train d'être ajouté à la file " "d'attente des notifications" -#: ../../guides/events-list.rst:633 +#: ../../guides/events-list.rst:639 msgid "" "The following events are listed chronologically in the lifetime of the " "notification event. Note that not all events apply to instant notifications." msgstr "" +"Les événements suivants sont répertoriés chronologiquement au cours de la " +"durée de vie de l'événement de notification. Notez que tous les événements " +"ne s'appliquent pas aux notifications instantanées." -#: ../../guides/events-list.rst:643 +#: ../../guides/events-list.rst:649 msgid "**enqueue, notification** |results|" -msgstr "" +msgstr "**enqueue, notification** |results|" -#: ../../guides/events-list.rst:637 +#: ../../guides/events-list.rst:643 msgid "" "Can be used to prevent a notification event from sending **subscription** " "notifications. Event handler must return ``false`` to prevent a subscription" " notification event from being enqueued." msgstr "" +"Peut être utilisé pour empêcher un événement de notification d'envoyer des " +"notifications **subscription**. Le gestionnaire d'événements doit renvoyer " +"``false`` pour empêcher qu'un événement de notification d'abonnement ne soit" +" mis en file d'attente." -#: ../../guides/events-list.rst:642 +#: ../../guides/events-list.rst:648 msgid "``object`` - object of the notification event" msgstr "``object`` - objet de l’événement de notification" -#: ../../guides/events-list.rst:643 +#: ../../guides/events-list.rst:649 msgid "" "``action`` - action that triggered the notification event. E.g. corresponds " "to ``publish`` when ``elgg_trigger_event('publish', 'object', $object)`` is " @@ -5238,11 +5469,11 @@ msgstr "" "exemple, correspond à ``publish`` quand ``elgg_trigger_event('publish', " "'object', $object)`` est appelé" -#: ../../guides/events-list.rst:660 +#: ../../guides/events-list.rst:666 msgid "**get, subscriptions** |results|" -msgstr "" +msgstr "**get, subscriptions** |results|" -#: ../../guides/events-list.rst:646 +#: ../../guides/events-list.rst:652 msgid "" "Filters subscribers of the notification event. Applies to **subscriptions** " "and **instant** notifications. In case of a subscription event, by default, " @@ -5259,7 +5490,7 @@ msgstr "" "abonnés se compose des utilisateurs précédemment passés en tant que " "destinataires à ``notify_user()``" -#: ../../guides/events-list.rst:651 +#: ../../guides/events-list.rst:657 msgid "" "**IMPORTANT** Always validate the notification event, object and/or action " "types before adding any new recipients to ensure that you do not " @@ -5269,10 +5500,19 @@ msgid "" "validating an event or action type (e.g. including an owner of the original " "wire thread) might end up sending notifications to wrong users." msgstr "" - -#: ../../guides/events-list.rst:656 ../../guides/events-list.rst:676 -#: ../../guides/events-list.rst:687 ../../guides/events-list.rst:704 -#: ../../guides/events-list.rst:739 +"**IMPORTANT** Validez toujours les types d'événement, d'objet et/ou d'action" +" de notification avant d'ajouter de nouveaux destinataires pour vous assurer" +" que vous n'envoyez pas accidentellement des notifications à des " +"destinataires inattendus. Prenons une situation dans laquelle un plugin de " +"mentions envoie une notification instantanée à un utilisateur mentionné - " +"tout événement agissant sur un sujet ou un objet sans valider un événement " +"ou un type d'action (par exemple inclure un propriétaire du fil de " +"discussion d'origine) pourrait finir par envoyer des notifications aux " +"mauvais utilisateurs." + +#: ../../guides/events-list.rst:662 ../../guides/events-list.rst:682 +#: ../../guides/events-list.rst:693 ../../guides/events-list.rst:710 +#: ../../guides/events-list.rst:745 msgid "" "``event`` - ``\\Elgg\\Notifications\\NotificationEvent`` instance that " "describes the notification event" @@ -5280,27 +5520,27 @@ msgstr "" "``event`` - instance de ``\\Elgg\\Notifications\\NotificationEvent`` qui " "décrit l’événement de notification" -#: ../../guides/events-list.rst:657 ../../guides/events-list.rst:694 -#: ../../guides/events-list.rst:711 +#: ../../guides/events-list.rst:663 ../../guides/events-list.rst:700 +#: ../../guides/events-list.rst:717 msgid "``origin`` - ``subscriptions_service`` or ``instant_notifications``" msgstr "``origin`` - ``subscriptions_service`` ou ``instant_notifications``" -#: ../../guides/events-list.rst:658 +#: ../../guides/events-list.rst:664 msgid "" "``methods_override`` - delivery method preference for instant notifications" msgstr "" "``methods_override`` - préférence de méthode de remise pour les " "notifications instantanées" -#: ../../guides/events-list.rst:660 +#: ../../guides/events-list.rst:666 msgid "Handlers must return an array in the form:" msgstr "Les gestionnaires doivent renvoyer un tableau de la forme :" -#: ../../guides/events-list.rst:677 +#: ../../guides/events-list.rst:683 msgid "**send:before, notifications** |results|" -msgstr "" +msgstr "**send:before, notifications** |results|" -#: ../../guides/events-list.rst:671 +#: ../../guides/events-list.rst:677 msgid "" "Triggered before the notification event queue is processed. Can be used to " "terminate the notification event. Applies to **subscriptions** and " @@ -5311,17 +5551,19 @@ msgstr "" "notification. S’applique aux notifications d'abonnement **subscriptions** et" " instantanées **instant**." -#: ../../guides/events-list.rst:677 ../../guides/events-list.rst:740 +#: ../../guides/events-list.rst:683 ../../guides/events-list.rst:746 msgid "" "``subscriptions`` - a list of subscriptions. See ``'get', 'subscriptions'`` " "event for details" msgstr "" +"``subscriptions`` - une liste d'abonnements. Voir l'événement ``'get', " +"'subscriptions'`` pour plus de détails" -#: ../../guides/events-list.rst:694 +#: ../../guides/events-list.rst:700 msgid "**prepare, notification** |results|" -msgstr "" +msgstr "**prepare, notification** |results|" -#: ../../guides/events-list.rst:680 +#: ../../guides/events-list.rst:686 msgid "" "A high level event that can be used to alter an instance of " "``\\Elgg\\Notifications\\Notification`` before it is sent to the user. " @@ -5331,14 +5573,21 @@ msgid "" "``'send:before', 'notifications``. Event handler should return an altered " "notification object." msgstr "" +"Un événement de haut niveau qui peut être utilisé pour modifier une instance" +" de ``\\Elgg\\Notifications\\Notification`` avant qu'elle ne soit envoyée à " +"l'utilisateur. S'applique aux **abonnements** et aux notifications " +"**instantanées**. Cet événement est déclenché avant une ``'prepare', " +"'notification:::'`` plus granulaire et " +"après ``'send:before', 'notifications``. Le gestionnaire d'événements doit " +"renvoyer un objet de notification modifié." -#: ../../guides/events-list.rst:685 +#: ../../guides/events-list.rst:691 msgid "``$params`` may vary based on the notification type and may include:" msgstr "" "``$params`` peut varier en fonction du type de notification et peut " "comprendre :" -#: ../../guides/events-list.rst:688 ../../guides/events-list.rst:705 +#: ../../guides/events-list.rst:694 ../../guides/events-list.rst:711 msgid "" "``object`` - object of the notification ``event``. Can be ``null`` for " "instant notifications" @@ -5346,7 +5595,7 @@ msgstr "" "``object`` - objet de la notification ``event``. Peut être ``null`` pour les" " notifications instantanées" -#: ../../guides/events-list.rst:689 ../../guides/events-list.rst:706 +#: ../../guides/events-list.rst:695 ../../guides/events-list.rst:712 msgid "" "``action`` - action that triggered the notification ``event``. May default " "to ``notify_user`` for instant notifications" @@ -5354,28 +5603,29 @@ msgstr "" "``action`` - action qui a déclenché la notification ``event``. Peut avoir " "pour valeur par défaut ``notify_user`` pour les notifications instantanées" -#: ../../guides/events-list.rst:690 ../../guides/events-list.rst:707 +#: ../../guides/events-list.rst:696 ../../guides/events-list.rst:713 msgid "``method`` - delivery method (e.g. ``email``, ``site``)" msgstr "``method`` - méthode d'envoi (par ex. ``email``, ``site``)" -#: ../../guides/events-list.rst:691 ../../guides/events-list.rst:708 +#: ../../guides/events-list.rst:697 ../../guides/events-list.rst:714 msgid "``sender`` - sender" msgstr "``sender`` - expéditeur" -#: ../../guides/events-list.rst:692 ../../guides/events-list.rst:709 +#: ../../guides/events-list.rst:698 ../../guides/events-list.rst:715 msgid "``recipient`` - recipient" msgstr "``recipient`` - destinataire" -#: ../../guides/events-list.rst:693 ../../guides/events-list.rst:710 +#: ../../guides/events-list.rst:699 ../../guides/events-list.rst:716 msgid "``language`` - language of the notification (recipient's language)" msgstr "``language`` - langue de la notification (langue du destinataire)" -#: ../../guides/events-list.rst:711 +#: ../../guides/events-list.rst:717 msgid "" "**prepare, notification:::** |results|" msgstr "" +"**prepare, notification:::** |results|" -#: ../../guides/events-list.rst:697 +#: ../../guides/events-list.rst:703 msgid "" "A granular event that can be used to filter a notification " "``\\Elgg\\Notifications\\Notification`` before it is sent to the user. " @@ -5385,16 +5635,23 @@ msgid "" "notifications that have not received an action name, it will default to " "``notify_user``." msgstr "" +"Un événement granulaire qui peut être utilisé pour filtrer une notification " +"``\\Elgg\\Notifications\\Notification`` avant qu'elle ne soit envoyée à " +"l'utilisateur. S'applique aux **subscriptions** et aux notifications " +"**instant**. En cas de notifications instantanées qui n'ont pas reçu " +"d'objet, l'événement sera appelé ``'prepare', 'notification:'``. " +"Dans le cas de notifications instantanées qui n'ont pas reçu de nom " +"d'action, il sera par défaut ``notify_user``." -#: ../../guides/events-list.rst:702 +#: ../../guides/events-list.rst:708 msgid "``$params`` include:" msgstr "``$params`` comprend :" -#: ../../guides/events-list.rst:722 +#: ../../guides/events-list.rst:728 msgid "**format, notification:** |results|" -msgstr "" +msgstr "**format, notification:** |results|" -#: ../../guides/events-list.rst:714 +#: ../../guides/events-list.rst:720 msgid "" "This event can be used to format a notification before it is passed to the " "``'send', 'notification:'`` event. Applies to **subscriptions** and " @@ -5402,8 +5659,14 @@ msgid "" "``\\Elgg\\Notifications\\Notification``. The event does not receive any " "``$params``. Some of the use cases include:" msgstr "" +"Cet événement peut être utilisé pour formater une notification avant qu'elle" +" soit transmise à l'événement ``'send', 'notification:'``. " +"S'applique aux notifications **subscriptions** et **instant**. Le " +"gestionnaire d'événement doit renvoyer une instance de " +"``\\Elgg\\Notifications\\Notification``. L'événement ne reçoit aucun " +"``$params``. Quelques cas d'utilisation :" -#: ../../guides/events-list.rst:720 +#: ../../guides/events-list.rst:726 msgid "" "Strip tags from notification title and body for plaintext email " "notifications" @@ -5411,20 +5674,20 @@ msgstr "" "Supprime les balises du titre et du corps de la notification pour les " "notifications par e-mail en texte brut" -#: ../../guides/events-list.rst:721 +#: ../../guides/events-list.rst:727 msgid "Inline HTML styles for HTML email notifications" msgstr "Styles HTML en ligne pour les e-mails de notification HTML" -#: ../../guides/events-list.rst:722 +#: ../../guides/events-list.rst:728 msgid "Wrap notification in a template, add signature etc." msgstr "" "Envelopper la notification dans un modèle, ajouter une signature, etc." -#: ../../guides/events-list.rst:731 +#: ../../guides/events-list.rst:737 msgid "**send, notification:** |results|" -msgstr "" +msgstr "**send, notification:** |results|" -#: ../../guides/events-list.rst:725 +#: ../../guides/events-list.rst:731 msgid "" "Delivers a notification. Applies to **subscriptions** and **instant** " "notifications. The handler must return ``true`` or ``false`` indicating the " @@ -5434,7 +5697,7 @@ msgstr "" "**subscriptions** et instantanées **instant**. Le gestionnaire doit " "retourner ``true`` ou ``false`` pour indiquer le résultat de la remise." -#: ../../guides/events-list.rst:731 +#: ../../guides/events-list.rst:737 msgid "" "``notification`` - a notification object " "``\\Elgg\\Notifications\\Notification``" @@ -5442,11 +5705,11 @@ msgstr "" "``notification`` - un objet de notification " "``\\Elgg\\Notifications\\Notification``" -#: ../../guides/events-list.rst:741 +#: ../../guides/events-list.rst:747 msgid "**send:after, notifications** |results|" -msgstr "" +msgstr "**send:after, notifications** |results|" -#: ../../guides/events-list.rst:734 +#: ../../guides/events-list.rst:740 msgid "" "Triggered after all notifications in the queue for the notifications event " "have been processed. Applies to **subscriptions** and **instant** " @@ -5456,7 +5719,7 @@ msgstr "" "l’événement notifications ont été traitées. S’applique aux notifications " "d'abonnement **subscriptions** et instantanées **instant**." -#: ../../guides/events-list.rst:741 +#: ../../guides/events-list.rst:747 msgid "" "``deliveries`` - a matrix of delivery statuses by user for each delivery " "method" @@ -5464,15 +5727,15 @@ msgstr "" "``deliveries`` - une matrice des statuts de remise par utilisateur pour " "chaque méthode de livraison" -#: ../../guides/events-list.rst:744 +#: ../../guides/events-list.rst:750 msgid "Emails" msgstr "E-mails" -#: ../../guides/events-list.rst:752 +#: ../../guides/events-list.rst:758 msgid "**prepare, system:email** |results|" -msgstr "" +msgstr "**prepare, system:email** |results|" -#: ../../guides/events-list.rst:747 +#: ../../guides/events-list.rst:753 msgid "" "Triggered by ``elgg_send_email()``. Applies to all outgoing system and " "notification emails. This event allows you to alter an instance of " @@ -5480,8 +5743,14 @@ msgid "" " be used to alter the sender, recipient, subject, body, and/or headers of " "the email." msgstr "" +"Déclenché par ``elgg_send_email()``. S’applique à tous les emails système et" +" de notification sortants. Cet événement vous permet de modifier une " +"instance de ``\\Elgg\\Email`` avant qu'elle soit transmise à l'agent de " +"transport de courrier électronique. Cet événement peut être utilisé pour " +"modifier l'expéditeur, le destinataire, l'objet, le corps et/ou les entêtes " +"de l'email." -#: ../../guides/events-list.rst:752 +#: ../../guides/events-list.rst:758 msgid "" "``$params`` are empty. The ``$return`` value is an instance of " "``\\Elgg\\Email``." @@ -5489,11 +5758,11 @@ msgstr "" "``$params`` est vide. La valeur de retour ``$return`` est une instance de " "``\\Elgg\\Email``." -#: ../../guides/events-list.rst:762 +#: ../../guides/events-list.rst:768 msgid "**transport, system:email** |results|" -msgstr "" +msgstr "**transport, system:email** |results|" -#: ../../guides/events-list.rst:755 +#: ../../guides/events-list.rst:761 msgid "" "Triggered by ``elgg_send_email()``. Applies to all outgoing system and " "notification emails. This event allows you to implement a custom email " @@ -5501,34 +5770,44 @@ msgid "" "SendGrid or Mailgun. The handler must return ``true`` to indicate that the " "email was transported." msgstr "" +"Déclenché par ``elgg_send_email()``. S’applique à tous les emails système et" +" de notification sortants. Cet événement vous permet d'implémenter un " +"transport de courrier électronique personnalisé, par ex. envoyer des emails " +"via un service proxy tiers tel que SendGrid ou Mailgun. Le gestionnaire doit" +" retourner ``true`` pour indiquer que l'email a bien été transporté." -#: ../../guides/events-list.rst:760 ../../guides/events-list.rst:770 -#: ../../guides/events-list.rst:779 +#: ../../guides/events-list.rst:766 ../../guides/events-list.rst:776 +#: ../../guides/events-list.rst:785 msgid "``$params`` contains:" msgstr "``$params`` contient :" -#: ../../guides/events-list.rst:762 ../../guides/events-list.rst:772 -#: ../../guides/events-list.rst:781 +#: ../../guides/events-list.rst:768 ../../guides/events-list.rst:778 +#: ../../guides/events-list.rst:787 msgid "``email`` - An instance of ``\\Elgg\\Email``" msgstr "``email`` - Une instance de ``\\Elgg\\Email``" -#: ../../guides/events-list.rst:772 +#: ../../guides/events-list.rst:778 msgid "**validate, system:email** |results|" -msgstr "" +msgstr "**validate, system:email** |results|" -#: ../../guides/events-list.rst:765 +#: ../../guides/events-list.rst:771 msgid "" "Triggered by ``elgg_send_email()``. Applies to all outgoing system and " "notification emails. This event allows you to suppress or whitelist outgoing" " emails, e.g. when the site is in a development mode. The handler must " "return ``false`` to supress the email delivery." msgstr "" +"Déclenché par ``elgg_send_email()``. S’applique à tous les emails système et" +" de notification sortants. Cet événement vous permet de supprimer ou de " +"mettre sur liste blanche les emails sortants, par ex. lorsque le site est en" +" mode développement. Le gestionnaire doit retourner ``false`` pour supprimer" +" l'envoi du courrier électronique." -#: ../../guides/events-list.rst:781 +#: ../../guides/events-list.rst:787 msgid "**zend:message, system:email** |results|" -msgstr "" +msgstr "**zend:message, system:email** |results|" -#: ../../guides/events-list.rst:775 +#: ../../guides/events-list.rst:781 msgid "" "Triggered by the default email transport handler (Elgg uses " "``laminas/laminas-mail``). Applies to all outgoing system and notification " @@ -5537,58 +5816,68 @@ msgid "" "``\\Laminas\\Mail\\Message`` before it is passed to the Laminas email " "transport." msgstr "" +"Déclenché par le gestionnaire de transport de courrier électronique par " +"défaut (Elgg utilise ``laminas/laminas-mail``). S'applique à tous les emails" +" système et de notification sortants qui n'ont pas été transportés à l'aide " +"de l'événement **transport, system:email**. Cet événement vous permet de " +"modifier une instance de ``\\Laminas\\Mail\\Message`` avant qu'elle soit " +"transmise au transport de courrier électronique Laminas." -#: ../../guides/events-list.rst:784 +#: ../../guides/events-list.rst:790 msgid "File events" msgstr "Événements des fichiers" -#: ../../guides/events-list.rst:794 +#: ../../guides/events-list.rst:800 msgid "**download:url, file** |results|" -msgstr "" +msgstr "**download:url, file** |results|" -#: ../../guides/events-list.rst:788 +#: ../../guides/events-list.rst:794 msgid "Allows plugins to filter the download URL of the file." msgstr "Permet aux plugins de filtrer l’URL de téléchargement du fichier." -#: ../../guides/events-list.rst:788 +#: ../../guides/events-list.rst:794 msgid "By default, the download URL is generated by the file service." msgstr "" "Par défaut, l’URL de téléchargement est générée par le service de fichiers." -#: ../../guides/events-list.rst:792 ../../guides/events-list.rst:802 +#: ../../guides/events-list.rst:798 ../../guides/events-list.rst:808 msgid "``entity`` - instance of ``ElggFile``" msgstr "``entity`` - instance de ``ElggFile``" -#: ../../guides/events-list.rst:793 ../../guides/events-list.rst:803 +#: ../../guides/events-list.rst:799 ../../guides/events-list.rst:809 msgid "" "``use_cookie`` - whether or not to use a cookie to secure download link" msgstr "" +"``use_cookie`` - utiliser ou non un cookie pour sécuriser le lien de " +"téléchargement " -#: ../../guides/events-list.rst:794 ../../guides/events-list.rst:804 +#: ../../guides/events-list.rst:800 ../../guides/events-list.rst:810 msgid "" "``expires`` - a string representation of when the download link should " "expire" msgstr "" +"``expires`` - une représentation sous forme de chaîne indiquant quand le " +"lien de téléchargement doit expirer " -#: ../../guides/events-list.rst:804 +#: ../../guides/events-list.rst:810 msgid "**inline:url, file** |results|" -msgstr "" +msgstr "**inline:url, file** |results|" -#: ../../guides/events-list.rst:798 +#: ../../guides/events-list.rst:804 msgid "Allows plugins to filter the inline URL of the image file." msgstr "Permet aux plugins de filtrer l’URL en ligne du fichier image." -#: ../../guides/events-list.rst:798 +#: ../../guides/events-list.rst:804 msgid "By default, the inline URL is generated by the file service." msgstr "" "Par défaut, l’URL en ligne - inline - est générée par le service de " "fichiers." -#: ../../guides/events-list.rst:808 +#: ../../guides/events-list.rst:814 msgid "**mime_type, file** |results|" -msgstr "" +msgstr "**mime_type, file** |results|" -#: ../../guides/events-list.rst:807 +#: ../../guides/events-list.rst:813 msgid "" "Return the mimetype for the filename ``$params['filename']`` with original " "filename ``$params['original_filename']`` and with the default detected " @@ -5598,11 +5887,11 @@ msgstr "" "nom de fichier original ``$params['original_filename']`` et avec le type " "MIME détecté par défaut de ``$params['default']``." -#: ../../guides/events-list.rst:814 +#: ../../guides/events-list.rst:820 msgid "**simple_type, file** |results|" -msgstr "" +msgstr "**simple_type, file** |results|" -#: ../../guides/events-list.rst:811 +#: ../../guides/events-list.rst:817 msgid "" "The event provides ``$params['mime_type']`` (e.g. ``application/pdf`` or " "``image/jpeg``) and determines an overall category like ``document`` or " @@ -5610,12 +5899,18 @@ msgid "" "store ``simpletype`` metadata on file entities and make use of it when " "serving icons and constructing ``ege*`` filters and menus." msgstr "" +"L'événement fournit ``$params['mime_type']`` (par exemple " +"``application/pdf`` ou ``image/jpeg``) et détermine une catégorie globale " +"comme ``document`` ou ``image``. Le plugin file fourni et les autres plugins" +" tiers stockent généralement les métadonnées ``simpletype`` sur les entités " +"de fichiers et les utilisent lors du service d'icônes et de la construction " +"de filtres et de menus ``ege*``." -#: ../../guides/events-list.rst:826 +#: ../../guides/events-list.rst:832 msgid "**upload, file** |results|" -msgstr "" +msgstr "**upload, file** |results|" -#: ../../guides/events-list.rst:817 +#: ../../guides/events-list.rst:823 msgid "" "Allows plugins to implement custom logic for moving an uploaded file into an" " instance of ``ElggFile``. The handler must return ``true`` to indicate that" @@ -5632,19 +5927,19 @@ msgstr "" "``ElggFile::acceptUploadedFile`` devrait poursuivre la logique de " "téléchargement par défaut." -#: ../../guides/events-list.rst:825 +#: ../../guides/events-list.rst:831 msgid "``file`` - instance of ``ElggFile`` to write to" msgstr "``file`` - instance de ``ElggFile`` dans laquelle écrire" -#: ../../guides/events-list.rst:826 +#: ../../guides/events-list.rst:832 msgid "``upload`` - instance of Symfony's ``UploadedFile``" msgstr "``upload`` - instance de ``UploadedFile`` de Symfony" -#: ../../guides/events-list.rst:831 +#: ../../guides/events-list.rst:837 msgid "**upload:after, file**" msgstr "**upload:after, file**" -#: ../../guides/events-list.rst:829 +#: ../../guides/events-list.rst:835 msgid "" "Called after an uploaded file has been written to filestore. Receives an " "instance of ``ElggFile`` the uploaded file was written to. The ``ElggFile`` " @@ -5655,15 +5950,15 @@ msgstr "" "téléchargé a été écrit. Le ``ElggFile`` peut ou non être une entité avec un " "GUID." -#: ../../guides/events-list.rst:834 +#: ../../guides/events-list.rst:840 msgid "Action events" -msgstr "" +msgstr "Événements des actions" -#: ../../guides/events-list.rst:844 +#: ../../guides/events-list.rst:850 msgid "**action:validate, ** |results|" -msgstr "" +msgstr "**action:validate, ** |results|" -#: ../../guides/events-list.rst:837 +#: ../../guides/events-list.rst:843 msgid "" "Trigger before action script/controller is executed. This event should be " "used to validate/alter user input, before proceeding with the action. The " @@ -5671,16 +5966,22 @@ msgid "" "``\\Elgg\\Exceptions\\Http\\ValidationException`` or return ``false`` to " "terminate further execution." msgstr "" +"Déclenchement avant l'exécution du script d'action/du contrôleur. Cet " +"événement doit être utilisé pour valider/modifier la saisie de " +"l'utilisateur, avant de poursuivre l'action. Le gestionnaire d'événements " +"peut lancer une instance de " +"``\\Elgg\\Exceptions\\Http\\ValidationException`` ou renvoyer ``false`` pour" +" interrompre l'exécution." -#: ../../guides/events-list.rst:844 +#: ../../guides/events-list.rst:850 msgid "``request`` - instance of ``\\Elgg\\Request``" msgstr "``request`` - instance de ``\\Elgg\\Request``" -#: ../../guides/events-list.rst:847 +#: ../../guides/events-list.rst:853 msgid "**action_gatekeeper:permissions:check, all** |results|" -msgstr "" +msgstr "**action_gatekeeper:permissions:check, all** |results|" -#: ../../guides/events-list.rst:847 +#: ../../guides/events-list.rst:853 msgid "" "Triggered after a CSRF token is validated. Return false to prevent " "validation." @@ -5688,11 +5989,11 @@ msgstr "" "Déclenché après la validation d’un jeton CSRF. Renvoyez false pour empêcher " "la validation." -#: ../../guides/events-list.rst:851 +#: ../../guides/events-list.rst:857 msgid "**forward, ** |results|" -msgstr "" +msgstr "**forward, ** |results|" -#: ../../guides/events-list.rst:850 +#: ../../guides/events-list.rst:856 msgid "" "Filter the URL to forward a user to when ``forward($url, $reason)`` is " "called. In certain cases, the ``params`` array will contain an instance of " @@ -5703,11 +6004,11 @@ msgstr "" "une instance de ``\\Elgg\\Exceptions\\HttpException`` qui a déclenché " "l’erreur." -#: ../../guides/events-list.rst:857 +#: ../../guides/events-list.rst:863 msgid "**response, action:** |results|" -msgstr "" +msgstr "**response, action:** |results|" -#: ../../guides/events-list.rst:854 +#: ../../guides/events-list.rst:860 msgid "" "Filter an instance of ``\\Elgg\\Http\\ResponseBuilder`` before it is sent to" " the client. This event can be used to modify response content, status code," @@ -5716,63 +6017,73 @@ msgid "" "filter the responses of `action()` calls if they are nested within the " "another action script file." msgstr "" +"Filtrez une instance de ``\\Elgg\\Http\\ResponseBuilder`` avant qu'elle ne " +"soit envoyée au client. Cet événement peut être utilisé pour modifier le " +"contenu de la réponse, le code d'état, l'URL de transfert ou définir des en-" +"têtes de réponse supplémentaires. Notez que la valeur ```` est " +"analysée à partir de l'URL de la requête, vous ne pourrez donc peut-être pas" +" filtrer les réponses des appels `action()` si elles sont imbriquées dans un" +" autre fichier de script d'action." -#: ../../guides/events-list.rst:876 +#: ../../guides/events-list.rst:882 msgid "**ajax_response, \\*** |results|" -msgstr "" +msgstr "**ajax_response, \\*** |results|" -#: ../../guides/events-list.rst:865 +#: ../../guides/events-list.rst:871 msgid "" "When the ``elgg/Ajax`` AMD module is used, this event gives access to the " "response object (``\\Elgg\\Services\\AjaxResponse``) so it can be " "altered/extended. The event type depends on the method call:" msgstr "" +"Lorsque le module AMD ``elgg/Ajax`` est utilisé, cet événement donne accès à" +" l'objet de réponse (``\\Elgg\\Services\\AjaxResponse``) afin qu'il puisse " +"être modifié/étendu. Le type d'événement dépend de l'appel de méthode :" -#: ../../guides/events-list.rst:870 +#: ../../guides/events-list.rst:876 msgid "elgg/Ajax method" msgstr "méthode elgg/Ajax" -#: ../../guides/events-list.rst:870 +#: ../../guides/events-list.rst:876 msgid "event type" -msgstr "" +msgstr "type d'événement" -#: ../../guides/events-list.rst:872 +#: ../../guides/events-list.rst:878 msgid "action()" msgstr "action()" -#: ../../guides/events-list.rst:872 +#: ../../guides/events-list.rst:878 msgid "action:" msgstr "action:" -#: ../../guides/events-list.rst:873 +#: ../../guides/events-list.rst:879 msgid "path()" msgstr "path()" -#: ../../guides/events-list.rst:873 +#: ../../guides/events-list.rst:879 msgid "path:" msgstr "path:" -#: ../../guides/events-list.rst:874 +#: ../../guides/events-list.rst:880 msgid "view()" msgstr "view()" -#: ../../guides/events-list.rst:874 +#: ../../guides/events-list.rst:880 msgid "view:" msgstr "view:" -#: ../../guides/events-list.rst:875 +#: ../../guides/events-list.rst:881 msgid "form()" msgstr "form()" -#: ../../guides/events-list.rst:875 +#: ../../guides/events-list.rst:881 msgid "form:" msgstr "form:" -#: ../../guides/events-list.rst:879 +#: ../../guides/events-list.rst:885 msgid "**ajax_response, action:** |results|" -msgstr "" +msgstr "**ajax_response, action:** |results|" -#: ../../guides/events-list.rst:879 +#: ../../guides/events-list.rst:885 msgid "" "Filters ``action/`` responses before they're sent back to the ``elgg/Ajax`` " "module." @@ -5780,22 +6091,25 @@ msgstr "" "Filtre les réponses ``action/`` avant qu’elles soient renvoyées au module " "``elgg/Ajax``." -#: ../../guides/events-list.rst:883 +#: ../../guides/events-list.rst:889 msgid "**ajax_response, path:** |results|" -msgstr "" +msgstr "**ajax_response, path:** |results|" -#: ../../guides/events-list.rst:882 +#: ../../guides/events-list.rst:888 msgid "" "Filters ajax responses before they're sent back to the ``elgg/Ajax`` module." " This event type will only be used if the path did not start with " "\"action/\" or \"ajax/\"." msgstr "" +"Filtre les réponses ajax avant qu'elles soient renvoyées au module " +"``elgg/Ajax``. Ce type d'événement ne sera utilisé que si le chemin ne " +"commence pas par \"action/\" ou \"ajax/\"." -#: ../../guides/events-list.rst:886 +#: ../../guides/events-list.rst:892 msgid "**ajax_response, view:** |results|" -msgstr "" +msgstr "**ajax_response, view:** |results|" -#: ../../guides/events-list.rst:886 +#: ../../guides/events-list.rst:892 msgid "" "Filters ``ajax/view/`` responses before they're sent back to the " "``elgg/Ajax`` module." @@ -5803,11 +6117,11 @@ msgstr "" "Filtre les réponses ``ajax/view/`` avant qu’elles soient renvoyées au module" " ``elgg/Ajax``." -#: ../../guides/events-list.rst:889 +#: ../../guides/events-list.rst:895 msgid "**ajax_response, form:** |results|" -msgstr "" +msgstr "**ajax_response, form:** |results|" -#: ../../guides/events-list.rst:889 +#: ../../guides/events-list.rst:895 msgid "" "Filters ``ajax/form/`` responses before they're sent back to the " "``elgg/Ajax`` module." @@ -5815,15 +6129,15 @@ msgstr "" "Filtre les réponses ``ajax/form/`` avant qu’elles soient renvoyées au module" " ``elgg/Ajax``." -#: ../../guides/events-list.rst:892 ../../guides/routing.rst:2 +#: ../../guides/events-list.rst:898 ../../guides/routing.rst:2 msgid "Routing" msgstr "Routage" -#: ../../guides/events-list.rst:899 +#: ../../guides/events-list.rst:905 msgid "**response, path:** |results|" -msgstr "" +msgstr "**response, path:** |results|" -#: ../../guides/events-list.rst:895 +#: ../../guides/events-list.rst:901 msgid "" "Filter an instance of ``\\Elgg\\Http\\ResponseBuilder`` before it is sent to" " the client. This event type will only be used if the path did not start " @@ -5833,12 +6147,21 @@ msgid "" "using the ``route`` event should use the original ```` to filter the " "response, or switch to using the ``route:rewrite`` event." msgstr "" - -#: ../../guides/events-list.rst:904 +"Filtre une instance de ``\\Elgg\\Http\\ResponseBuilder`` avant qu'elle ne " +"soit envoyée au client. Ce type d'événement ne sera utilisé que si le chemin" +" ne commence pas par \"action/\" ou \"ajax/\". Cet événement peut être " +"utilisé pour modifier le contenu de la réponse, le code d'état, l'URL de " +"transfert ou définir des entêtes de réponse supplémentaires. Notez que la " +"valeur ```` est analysée à partir de l'URL de la requête, donc les " +"plugins utilisant l'événement ``route`` doivent utiliser le ```` " +"d'origine pour filtrer la réponse, ou passer à l'utilisation de " +"``route:rewrite`` événement. " + +#: ../../guides/events-list.rst:910 msgid "**route:config, ** |results|" -msgstr "" +msgstr "**route:config, ** |results|" -#: ../../guides/events-list.rst:902 +#: ../../guides/events-list.rst:908 msgid "" "Allows altering the route configuration before it is registered. This event " "can be used to alter the path, default values, requirements, as well as to " @@ -5846,64 +6169,79 @@ msgid "" " registered outside of the ``init`` event handler, as core routes are " "registered during ``plugins_boot`` event." msgstr "" +"Permet de modifier la configuration de la route avant son enregistrement. " +"Cet événement peut être utilisé pour modifier le chemin, les valeurs par " +"défaut, les pré-requis, ainsi que pour définir/supprimer un middleware. " +"Veuillez noter que le gestionnaire de cet événement doit être enregistré en " +"dehors du gestionnaire d'événement ``init``, car les routes principales sont" +" enregistrées lors de l'événement ``plugins_boot``." -#: ../../guides/events-list.rst:908 +#: ../../guides/events-list.rst:914 msgid "**route:rewrite, ** |results|" -msgstr "" +msgstr "**route:rewrite, ** |results|" -#: ../../guides/events-list.rst:907 +#: ../../guides/events-list.rst:913 msgid "" "Allows altering the site-relative URL path for an incoming request. See " ":doc:`routing` for details. Please note that the handler for this event " "should be registered outside of the ``init`` event handler, as route " "rewrites take place after ``plugins_boot`` event has completed." msgstr "" +"Permet de modifier le chemin de l'URL relative au site pour une demande " +"entrante. Voir :doc:`routing` pour plus de détails. Veuillez noter que le " +"gestionnaire de cet événement doit être enregistré en dehors du gestionnaire" +" d'événement ``init``, car les réécritures de route ont lieu après la fin de" +" l'événement ``plugins_boot``." -#: ../../guides/events-list.rst:913 +#: ../../guides/events-list.rst:919 #: ../../guides/plugins/plugin-skeleton.rst:141 ../../guides/views.rst:2 msgid "Views" msgstr "Vues" -#: ../../guides/events-list.rst:916 +#: ../../guides/events-list.rst:922 msgid "**attributes, htmlawed** |results|" -msgstr "" +msgstr "**attributes, htmlawed** |results|" -#: ../../guides/events-list.rst:916 +#: ../../guides/events-list.rst:922 msgid "Allows changes to individual attributes." -msgstr "" +msgstr "Permet de modifier des attributs individuels." -#: ../../guides/events-list.rst:919 +#: ../../guides/events-list.rst:925 msgid "**allowed_styles, htmlawed** |results|" -msgstr "" +msgstr "**allowed_styles, htmlawed** |results|" -#: ../../guides/events-list.rst:919 +#: ../../guides/events-list.rst:925 msgid "Configure allowed styles for HTMLawed." -msgstr "" +msgstr "Configure les styles autorisés pour HTMLawed." -#: ../../guides/events-list.rst:922 +#: ../../guides/events-list.rst:928 msgid "**config, htmlawed** |results|" -msgstr "" +msgstr "**config, htmlawed** |results|" -#: ../../guides/events-list.rst:922 +#: ../../guides/events-list.rst:928 msgid "Filter the HTMLawed ``$config`` array." msgstr "Filtre le tableau HTMLawed ``$config``." -#: ../../guides/events-list.rst:926 +#: ../../guides/events-list.rst:932 msgid "**form:prepare:fields, ** |results|" -msgstr "" +msgstr "**form:prepare:fields, ** |results|" -#: ../../guides/events-list.rst:925 +#: ../../guides/events-list.rst:931 msgid "" "Prepare field values for use in the form. Eg. when editing a blog, fill this" " with the current values of the blog. Sticky form values will automatically " "be added to the field values (when available)." msgstr "" +"Préparez les valeurs des champs à utiliser dans le formulaire. Par ex. lors " +"de la modification d'un blog, remplissez-le avec les valeurs actuelles du " +"blog. Les valeurs du formulaire collant seront automatiquement ajoutées aux " +"valeurs des champs (si disponibles)." -#: ../../guides/events-list.rst:934 +#: ../../guides/events-list.rst:940 msgid "**head, page** |results|" -msgstr "" +msgstr "**head, page** |results|" -#: ../../guides/events-list.rst:929 +#: ../../guides/events-list.rst:935 msgid "" "In ``elgg_view_page()``, filters ``$vars['head']`` Return value contains an " "array with ``title``, ``metas`` and ``links`` keys, where ``metas`` is an " @@ -5920,11 +6258,11 @@ msgstr "" "contient un ensemble de paires de clés/valeurs qui sont formatées en " "attributs de balise html, par ex." -#: ../../guides/events-list.rst:968 +#: ../../guides/events-list.rst:974 msgid "**layout, page** |results|" -msgstr "" +msgstr "**layout, page** |results|" -#: ../../guides/events-list.rst:963 +#: ../../guides/events-list.rst:969 msgid "" "In ``elgg_view_layout()``, filters the layout name. ``$params`` array " "includes:" @@ -5932,65 +6270,75 @@ msgstr "" "Dans ``elgg_view_layout()``, filtre le nom de la disposition. Le tableau " "``$params`` comprend :" -#: ../../guides/events-list.rst:966 +#: ../../guides/events-list.rst:972 msgid "``identifier`` - ID of the page being rendered" msgstr "``identifier`` - identifiant de la page en cours de rendu" -#: ../../guides/events-list.rst:967 +#: ../../guides/events-list.rst:973 msgid "``segments`` - URL segments of the page being rendered" msgstr "``segments`` - Segments d’URL de la page en cours de rendu" -#: ../../guides/events-list.rst:968 +#: ../../guides/events-list.rst:974 msgid "other ``$vars`` received by ``elgg_view_layout()``" msgstr "autres ``$vars`` reçues par ``elgg_view_layout()``" -#: ../../guides/events-list.rst:973 +#: ../../guides/events-list.rst:979 msgid "**response, form:** |results|" -msgstr "" +msgstr "**response, form:** |results|" -#: ../../guides/events-list.rst:971 +#: ../../guides/events-list.rst:977 msgid "" "Filter an instance of ``\\Elgg\\Http\\ResponseBuilder`` before it is sent to" " the client. Applies to request to ``/ajax/form/``. This event " "can be used to modify response content, status code, forward URL, or set " "additional response headers." msgstr "" +"Filtrez une instance de ``\\Elgg\\Http\\ResponseBuilder`` avant qu'elle ne " +"soit envoyée au client. S'applique à la demande adressée à " +"``/ajax/form/``. Cet événement peut être utilisé pour modifier le" +" contenu de la réponse, le code d'état, l'URL de transfert ou définir des " +"entêtes de réponse supplémentaires." -#: ../../guides/events-list.rst:978 +#: ../../guides/events-list.rst:984 msgid "**response, view:** |results|" -msgstr "" +msgstr "**response, view:** |results|" -#: ../../guides/events-list.rst:976 +#: ../../guides/events-list.rst:982 msgid "" "Filter an instance of ``\\Elgg\\Http\\ResponseBuilder`` before it is sent to" " the client. Applies to request to ``/ajax/view/``. This event " "can be used to modify response content, status code, forward URL, or set " "additional response headers." msgstr "" +"Filtrez une instance de ``\\Elgg\\Http\\ResponseBuilder`` avant qu'elle soit" +" envoyée au client. S'applique à la requête adressée à ``/ajax/view/``. Cet " +"événement peut être utilisé pour modifier le contenu de la réponse, le code " +"d'état, l'URL de transfert ou définir des entêtes de réponse " +"supplémentaires." -#: ../../guides/events-list.rst:981 +#: ../../guides/events-list.rst:987 msgid "**shell, page** |results|" -msgstr "" +msgstr "**shell, page** |results|" -#: ../../guides/events-list.rst:981 +#: ../../guides/events-list.rst:987 msgid "In ``elgg_view_page()``, filters the page shell name" msgstr "" "Dans ``elgg_view_page()``, filtre le nom de la coquille - page shell - de la" " page" -#: ../../guides/events-list.rst:984 +#: ../../guides/events-list.rst:990 msgid "**spec, htmlawed** |results|" -msgstr "" +msgstr "**spec, htmlawed** |results|" -#: ../../guides/events-list.rst:984 +#: ../../guides/events-list.rst:990 msgid "Filter the HTMLawed ``$spec`` string (default empty)." msgstr "Filtre la chaîne HTMLawed ``$spec`` (vide par défaut)." -#: ../../guides/events-list.rst:990 +#: ../../guides/events-list.rst:996 msgid "**table_columns:call, ** |results|" -msgstr "" +msgstr "**table_columns:call, ** |results|" -#: ../../guides/events-list.rst:987 +#: ../../guides/events-list.rst:993 msgid "" "When the method ``elgg()->table_columns->$name()`` is called, this event is " "called to allow plugins to override or provide an implementation. Handlers " @@ -5998,12 +6346,18 @@ msgid "" "an instance of ``Elgg\\Views\\TableColumn`` if they wish to specify the " "column directly." msgstr "" +"Lorsque la méthode ``elgg()->table_columns->$name()`` est appelée, cet " +"événement est appelé pour permettre aux plugins de remplacer ou de fournir " +"une implémentation. Les gestionnaires reçoivent les arguments de la méthode " +"via ``$params['arguments']`` et doivent renvoyer une instance de " +"``Elgg\\Views\\TableColumn`` s'ils souhaitent spécifier la colonne " +"directement." -#: ../../guides/events-list.rst:994 +#: ../../guides/events-list.rst:1000 msgid "**vars:compiler, css** |results|" -msgstr "" +msgstr "**vars:compiler, css** |results|" -#: ../../guides/events-list.rst:993 +#: ../../guides/events-list.rst:999 msgid "" "Allows plugins to alter CSS variables passed to CssCrush during compilation." " See `CSS variables <_guides/theming#css-vars>`." @@ -6012,31 +6366,31 @@ msgstr "" "pendant la compilation. Voyez les `variables CSS <_guides/theming#css-" "vars>`." -#: ../../guides/events-list.rst:997 +#: ../../guides/events-list.rst:1003 msgid "**view, ** |results|" -msgstr "" +msgstr "**view, ** |results|" -#: ../../guides/events-list.rst:997 +#: ../../guides/events-list.rst:1003 msgid "Filters the returned content of the view" msgstr "Filtre le contenu renvoyé par la vue" -#: ../../guides/events-list.rst:1000 +#: ../../guides/events-list.rst:1006 msgid "**view_vars, ** |results|" -msgstr "" +msgstr "**view_vars, ** |results|" -#: ../../guides/events-list.rst:1000 +#: ../../guides/events-list.rst:1006 msgid "Filters the ``$vars`` array passed to the view" msgstr "Filtre le tableau ``$vars`` passé à la vue" -#: ../../guides/events-list.rst:1005 ../../guides/search.rst:2 +#: ../../guides/events-list.rst:1011 ../../guides/search.rst:2 msgid "Search" msgstr "Recherche" -#: ../../guides/events-list.rst:1010 +#: ../../guides/events-list.rst:1016 msgid "**search:config, search_types** |results|" -msgstr "" +msgstr "**search:config, search_types** |results|" -#: ../../guides/events-list.rst:1008 +#: ../../guides/events-list.rst:1014 msgid "" "Implemented in the **search** plugin. Filters an array of custom search " "types. This allows plugins to add custom search types (e.g. tag or location " @@ -6050,11 +6404,11 @@ msgstr "" "permettra d’étendre l’interface utilisateur du plugin de recherche avec des " "liens et des listes appropriés." -#: ../../guides/events-list.rst:1015 +#: ../../guides/events-list.rst:1021 msgid "**search:config, type_subtype_pairs** |results|" -msgstr "" +msgstr "**search:config, type_subtype_pairs** |results|" -#: ../../guides/events-list.rst:1013 +#: ../../guides/events-list.rst:1019 msgid "" "Implemented in the **search** plugin. Filters entity type/subtype pairs " "before entity search is performed. Allows plugins to remove certain entity " @@ -6067,11 +6421,11 @@ msgstr "" " regrouper plusieurs sous-types, ou de réorganiser des sections de " "recherche." -#: ../../guides/events-list.rst:1020 +#: ../../guides/events-list.rst:1026 msgid "**search:fields, ** |results|" -msgstr "" +msgstr "**search:fields, ** |results|" -#: ../../guides/events-list.rst:1018 +#: ../../guides/events-list.rst:1024 msgid "" "Triggered by ``elgg_search()``. Filters search fields before search clauses " "are prepared. ``$return`` value contains an array of names for each entity " @@ -6086,23 +6440,23 @@ msgstr "" "tableau de paramètres de recherche transmis et filtrés par " "``elgg_search()``." -#: ../../guides/events-list.rst:1031 +#: ../../guides/events-list.rst:1037 msgid "**search:fields, :** |results|" -msgstr "" +msgstr "**search:fields, :** |results|" -#: ../../guides/events-list.rst:1031 ../../guides/events-list.rst:1034 +#: ../../guides/events-list.rst:1037 ../../guides/events-list.rst:1040 msgid "See **search:fields, **" msgstr "Voyez **search:fields, **" -#: ../../guides/events-list.rst:1034 +#: ../../guides/events-list.rst:1040 msgid "**search:fields, ** |results|" -msgstr "" +msgstr "**search:fields, ** |results|" -#: ../../guides/events-list.rst:1039 +#: ../../guides/events-list.rst:1045 msgid "**search:format, entity** |results|" -msgstr "" +msgstr "**search:format, entity** |results|" -#: ../../guides/events-list.rst:1037 +#: ../../guides/events-list.rst:1043 msgid "" "Implemented in the **search** plugin. Allows plugins to populate entity's " "volatile data before it's passed to search view. This is used for " @@ -6115,11 +6469,11 @@ msgstr "" "correspondances de la recherche, extraire les sous-chaînes pertinentes dans " "les champs de texte long, etc." -#: ../../guides/events-list.rst:1042 +#: ../../guides/events-list.rst:1048 msgid "**search:options, ** |results|" -msgstr "" +msgstr "**search:options, ** |results|" -#: ../../guides/events-list.rst:1042 +#: ../../guides/events-list.rst:1048 msgid "" "Triggered by ``elgg_search()``. Prepares search clauses (options) to be " "passed to ``elgg_get_entities()``." @@ -6127,23 +6481,23 @@ msgstr "" "Déclenché par ``elgg_search()``. Prépare les clauses de recherche (options) " "à transmettre à ``elgg_get_entities()``." -#: ../../guides/events-list.rst:1045 +#: ../../guides/events-list.rst:1051 msgid "**search:options, :** |results|" -msgstr "" +msgstr "**search:options, :** |results|" -#: ../../guides/events-list.rst:1045 ../../guides/events-list.rst:1048 +#: ../../guides/events-list.rst:1051 ../../guides/events-list.rst:1054 msgid "See **search:options, **" msgstr "Voyez **search:options, **" -#: ../../guides/events-list.rst:1048 +#: ../../guides/events-list.rst:1054 msgid "**search:options, ** |results|" -msgstr "" +msgstr "**search:options, ** |results|" -#: ../../guides/events-list.rst:1052 +#: ../../guides/events-list.rst:1058 msgid "**search:params, ** |results|" -msgstr "" +msgstr "**search:params, ** |results|" -#: ../../guides/events-list.rst:1051 +#: ../../guides/events-list.rst:1057 msgid "" "Triggered by ``elgg_search()``. Filters search parameters (query, sorting, " "search fields etc) before search clauses are prepared for a given search " @@ -6154,27 +6508,32 @@ msgstr "" " ne soient préparées pour un type de recherche donné. Le noyau de Elgg ne " "prend en charge que le type de recherche ``entities``." -#: ../../guides/events-list.rst:1056 +#: ../../guides/events-list.rst:1062 msgid "**search:results, ** |results|" -msgstr "" +msgstr "**search:results, ** |results|" -#: ../../guides/events-list.rst:1055 +#: ../../guides/events-list.rst:1061 msgid "" "Triggered by ``elgg_search()``. Receives normalized options suitable for " "``elgg_get_entities()`` call and must return an array of entities matching " "search options. This event is designed for use by plugins integrating third-" "party indexing services, such as Solr and Elasticsearch." msgstr "" +"Déclenché par ``elgg_search()``. Reçoit les options normalisées adaptées à " +"l'appel ``elgg_get_entities()`` et doit renvoyer un tableau d'entités " +"correspondant aux options de recherche. Cet événement est conçu pour être " +"utilisé par des plugins intégrant des services d'indexation tiers, tels que " +"Solr et Elasticsearch." -#: ../../guides/events-list.rst:1061 +#: ../../guides/events-list.rst:1067 msgid "Other" msgstr "Autres" -#: ../../guides/events-list.rst:1065 +#: ../../guides/events-list.rst:1071 msgid "**config, comments_per_page** |results|" -msgstr "" +msgstr "**config, comments_per_page** |results|" -#: ../../guides/events-list.rst:1064 +#: ../../guides/events-list.rst:1070 msgid "" "Filters the number of comments displayed per page. Default is 25. " "``$params['entity']`` will hold the containing entity or null if not " @@ -6185,11 +6544,11 @@ msgstr "" "n'est pas fournie. Utilisez ``elgg_comments_per_page()`` pour obtenir la " "valeur." -#: ../../guides/events-list.rst:1069 +#: ../../guides/events-list.rst:1075 msgid "**config, comments_latest_first** |results|" -msgstr "" +msgstr "**config, comments_latest_first** |results|" -#: ../../guides/events-list.rst:1068 +#: ../../guides/events-list.rst:1074 msgid "" "Filters the order of comments. Default is ``true`` for latest first. " "``$params['entity']`` will hold the containing entity or null if not " @@ -6199,11 +6558,11 @@ msgstr "" "récent en premier. ``$params['entity']`` indique l’entité contenante, ou " "null si elle n’est pas fournie." -#: ../../guides/events-list.rst:1076 +#: ../../guides/events-list.rst:1082 msgid "**default, access** |results|" -msgstr "" +msgstr "**default, access** |results|" -#: ../../guides/events-list.rst:1072 +#: ../../guides/events-list.rst:1078 msgid "" "In ``elgg_get_default_access()``, this event filters the return value, so it" " can be used to alter the default value in the input/access view. For core " @@ -6212,31 +6571,41 @@ msgid "" "\"container_guid\" (int) are provided. An empty entity value generally means" " the form is to create a new object." msgstr "" +"Dans ``elgg_get_default_access()``, cet événement filtre la valeur de " +"retour, afin de pouvoir l'utiliser pour modifier la valeur par défaut dans " +"la vue input/access. Pour les plugins principaux, la valeur \"input_params\"" +" fournit les clés \"entity\" (ElggEntity|false), \"entity_type\" (string), " +"\"entity_subtype\" (string), \"container_guid\" (int). Une valeur d'entité " +"vide signifie généralement que le formulaire doit créer un nouvel objet." -#: ../../guides/events-list.rst:1080 +#: ../../guides/events-list.rst:1086 msgid "**classes, icon** |results|" -msgstr "" +msgstr "**classes, icon** |results|" -#: ../../guides/events-list.rst:1079 +#: ../../guides/events-list.rst:1085 msgid "" "Can be used to filter CSS classes applied to icon glyphs. By default, Elgg " "uses FontAwesome. Plugins can use this event to switch to a different font " "family and remap icon classes." msgstr "" +"Peut être utilisé pour filtrer les classes CSS appliquées aux glyphes " +"d'icônes. Par défaut, Elgg utilise FontAwesome. Les plugins peuvent utiliser" +" cet événement pour passer à une autre famille de polices et remapper les " +"classes d'icônes." -#: ../../guides/events-list.rst:1083 +#: ../../guides/events-list.rst:1089 msgid "**config, amd** |results|" -msgstr "" +msgstr "**config, amd** |results|" -#: ../../guides/events-list.rst:1083 +#: ../../guides/events-list.rst:1089 msgid "Filter the AMD config for the requirejs library." msgstr "Filtre la configuration AMD pour la bibliothèque requirejs." -#: ../../guides/events-list.rst:1087 +#: ../../guides/events-list.rst:1093 msgid "**entity:icon:sizes, ** |results|" -msgstr "" +msgstr "**entity:icon:sizes, ** |results|" -#: ../../guides/events-list.rst:1086 +#: ../../guides/events-list.rst:1092 msgid "" "Triggered by ``elgg_get_icon_sizes()`` and sets entity type/subtype specific" " icon sizes. ``entity_subtype`` will be passed with the ``$params`` array to" @@ -6246,11 +6615,11 @@ msgstr "" "type de tailles d’icônes spécifiques. ``entity_subtype`` sera transmis dans " "le tableau ``$params`` à la fonction de rappel." -#: ../../guides/events-list.rst:1104 +#: ../../guides/events-list.rst:1110 msgid "**entity::sizes, ** |results|" -msgstr "" +msgstr "**entity::sizes, ** |results|" -#: ../../guides/events-list.rst:1090 +#: ../../guides/events-list.rst:1096 msgid "" "Allows filtering sizes for custom icon types, see ``entity:icon:sizes, " "``." @@ -6258,26 +6627,29 @@ msgstr "" "Permet de filtrer les tailles pour les types d’icônes personnalisés, voir " "``entity:icon:sizes, ``." -#: ../../guides/events-list.rst:1092 +#: ../../guides/events-list.rst:1098 msgid "" "The event must return an associative array where keys are the names of the " "icon sizes (e.g. \"large\"), and the values are arrays with the following " "keys:" msgstr "" +"L'événement doit renvoyer un tableau associatif où les clés sont les noms " +"des tailles d'icônes (par ex. \"large\") et les valeurs sont des tableaux " +"avec les clés suivantes :" -#: ../../guides/events-list.rst:1095 +#: ../../guides/events-list.rst:1101 msgid "``w`` - Width of the image in pixels" msgstr "``w`` - Largeur de l’image en pixels" -#: ../../guides/events-list.rst:1096 +#: ../../guides/events-list.rst:1102 msgid "``h`` - Height of the image in pixels" msgstr "``h`` - Hauteur de l’image en pixels" -#: ../../guides/events-list.rst:1097 +#: ../../guides/events-list.rst:1103 msgid "``square`` - Should the aspect ratio be a square (true/false)" msgstr "``square`` - Le ratio devrait-il être carré (true/false)" -#: ../../guides/events-list.rst:1098 +#: ../../guides/events-list.rst:1104 msgid "" "``upscale`` - Should the image be upscaled in case it is smaller than the " "given width and height (true/false)" @@ -6285,7 +6657,7 @@ msgstr "" "``upscale`` - L'image doit-elle être agrandie si elle est plus petite que la" " largeur et la hauteur indiquées (true/false)" -#: ../../guides/events-list.rst:1099 +#: ../../guides/events-list.rst:1105 msgid "" "``crop`` - Is cropping allowed on this image size (true/false, default: " "true)" @@ -6293,7 +6665,7 @@ msgstr "" "``crop`` - Est-ce que le recadrage est autorisé sur cette taille d’image " "(true/false, par défaut : true)" -#: ../../guides/events-list.rst:1101 +#: ../../guides/events-list.rst:1107 msgid "" "If the configuration array for an image size is empty, the image will be " "saved as an exact copy of the source without resizing or cropping." @@ -6302,17 +6674,17 @@ msgstr "" "enregistrée en tant que copie exacte de la source sans redimensionnement ni " "recadrage." -#: ../../guides/events-list.rst:1104 ../../guides/i18n.rst:51 +#: ../../guides/events-list.rst:1110 ../../guides/i18n.rst:51 #: ../../guides/notifications.rst:24 ../../guides/notifications.rst:309 #: ../../guides/notifications.rst:333 ../../guides/notifications.rst:381 msgid "Example:" msgstr "Exemple :" -#: ../../guides/events-list.rst:1136 +#: ../../guides/events-list.rst:1142 msgid "**entity:icon:url, ** |results|" -msgstr "" +msgstr "**entity:icon:url, ** |results|" -#: ../../guides/events-list.rst:1124 +#: ../../guides/events-list.rst:1130 msgid "" "Triggered when entity icon URL is requested, see :ref:`entity icons " "`. Callback should return URL for the icon of " @@ -6325,19 +6697,19 @@ msgstr "" "l’entité ``$params['entity']``. Les paramètres suivants sont disponibles via" " le tableau ``$params`` :" -#: ../../guides/events-list.rst:1128 +#: ../../guides/events-list.rst:1134 msgid "entity" msgstr "entity" -#: ../../guides/events-list.rst:1129 +#: ../../guides/events-list.rst:1135 msgid "Entity for which icon url is requested." msgstr "Entité pour laquelle l’url de l’icône est demandée." -#: ../../guides/events-list.rst:1130 +#: ../../guides/events-list.rst:1136 msgid "viewtype" msgstr "viewtype" -#: ../../guides/events-list.rst:1131 +#: ../../guides/events-list.rst:1137 msgid "" "The type of :ref:`view ` e.g. ``'default'`` " "or ``'json'``." @@ -6345,11 +6717,11 @@ msgstr "" "Le type de :ref:`vue `, par exemple " "``'default'`` ou ``'json'``." -#: ../../guides/events-list.rst:1133 +#: ../../guides/events-list.rst:1139 msgid "size" msgstr "size" -#: ../../guides/events-list.rst:1133 +#: ../../guides/events-list.rst:1139 msgid "" "Size requested, see :ref:`entity icons ` for " "possible values." @@ -6357,7 +6729,7 @@ msgstr "" "Dimension demandée, voir les :ref:`icônes des entités " "` pour les valeurs possibles." -#: ../../guides/events-list.rst:1135 +#: ../../guides/events-list.rst:1141 msgid "" "Example on how one could default to a Gravatar icon for users that have not " "yet uploaded an avatar:" @@ -6365,11 +6737,11 @@ msgstr "" "Exemple sur comment mettre en place une icône par défaut Gravatar pour les " "utilisateurs qui n’ont pas encore téléchargé un avatar :" -#: ../../guides/events-list.rst:1176 +#: ../../guides/events-list.rst:1182 msgid "**entity::url, ** |results|" -msgstr "" +msgstr "**entity::url, ** |results|" -#: ../../guides/events-list.rst:1176 +#: ../../guides/events-list.rst:1182 msgid "" "Allows filtering URLs for custom icon types, see ``entity:icon:url, " "``" @@ -6377,11 +6749,11 @@ msgstr "" "Permet de filtrer les URLs pour les types d’icônes personnalisés, voir " "``entity:icon:url, ``" -#: ../../guides/events-list.rst:1181 +#: ../../guides/events-list.rst:1187 msgid "**entity:icon:file, ** |results|" -msgstr "" +msgstr "**entity:icon:file, ** |results|" -#: ../../guides/events-list.rst:1179 +#: ../../guides/events-list.rst:1185 msgid "" "Triggered by ``ElggEntity::getIcon()`` and allows plugins to provide an " "alternative ``ElggIcon`` object that points to a custom location of the icon" @@ -6393,11 +6765,11 @@ msgstr "" "de l’icône dans le répertoire de fichiers. Le gestionnaire doit renvoyer une" " instance de ``ElggIcon`` ou une exception sera lancée." -#: ../../guides/events-list.rst:1184 +#: ../../guides/events-list.rst:1190 msgid "**entity::file, ** |results|" -msgstr "" +msgstr "**entity::file, ** |results|" -#: ../../guides/events-list.rst:1184 +#: ../../guides/events-list.rst:1190 msgid "" "Allows filtering icon file object for custom icon types, see " "``entity:icon:file, ``" @@ -6405,11 +6777,11 @@ msgstr "" "Permet de filtrer l’objet du fichier d’icône pour les types d’icônes " "personnalisés ; voyez ``entity:icon:file, ``" -#: ../../guides/events-list.rst:1196 +#: ../../guides/events-list.rst:1202 msgid "**entity::prepare, ** |results|" -msgstr "" +msgstr "**entity::prepare, ** |results|" -#: ../../guides/events-list.rst:1187 +#: ../../guides/events-list.rst:1193 msgid "" "Triggered by ``ElggEntity::saveIcon*()`` methods and can be used to prepare " "an image from uploaded/linked file. This event can be used to e.g. rotate " @@ -6419,27 +6791,38 @@ msgid "" "``$return`` value passed to the event is an instance of ``ElggFile`` that " "points to a temporary copy of the uploaded/linked file." msgstr "" - -#: ../../guides/events-list.rst:1193 ../../guides/events-list.rst:1289 -#: ../../guides/events-list.rst:1322 +"Déclenché par les méthodes ``ElggEntity::saveIcon*()`` et peut être utilisé " +"pour préparer une image à partir d'un fichier téléchargé ou lié. Cet " +"événement peut être utilisé par ex. pour faire pivoter l'image avant qu'elle" +" ne soit redimensionnée/recadrée, ou peut être utilisé pour extraire une " +"image si le fichier téléchargé est une vidéo. Le gestionnaire doit renvoyer " +"une instance de ``ElggFile`` avec un `simpletype` qui se résout en `image`. " +"La valeur ``$return`` transmise à l'événement est une instance de " +"``ElggFile`` qui pointe vers une copie temporaire du fichier téléchargé ou " +"lié." + +#: ../../guides/events-list.rst:1199 ../../guides/events-list.rst:1295 +#: ../../guides/events-list.rst:1328 msgid "The ``$params`` array contains:" msgstr "Le tableau ``$params`` contient :" -#: ../../guides/events-list.rst:1195 ../../guides/events-list.rst:1203 -#: ../../guides/events-list.rst:1213 ../../guides/events-list.rst:1221 +#: ../../guides/events-list.rst:1201 ../../guides/events-list.rst:1209 +#: ../../guides/events-list.rst:1219 ../../guides/events-list.rst:1227 msgid "``entity`` - entity that owns the icons" msgstr "``entity`` - entité propriétaire des icônes" -#: ../../guides/events-list.rst:1196 +#: ../../guides/events-list.rst:1202 msgid "" "``file`` - original input file before it has been modified by other events" msgstr "" +"``file`` - fichier d'entrée original avant qu'il ne soit modifié par " +"d'autres événements" -#: ../../guides/events-list.rst:1205 +#: ../../guides/events-list.rst:1211 msgid "**entity::save, ** |results|" -msgstr "" +msgstr "**entity::save, ** |results|" -#: ../../guides/events-list.rst:1199 +#: ../../guides/events-list.rst:1205 msgid "" "Triggered by ``ElggEntity::saveIcon*()`` methods and can be used to apply " "custom image manipulation logic to resizing/cropping icons. The handler must" @@ -6452,7 +6835,7 @@ msgstr "" "``true`` pour empêcher les API du noyau de redimensionner/rogner les icônes." " Le tableau ``$params`` contient :" -#: ../../guides/events-list.rst:1204 +#: ../../guides/events-list.rst:1210 msgid "" "``file`` - ``ElggFile`` object that points to the image file to be used as " "source for icons" @@ -6460,15 +6843,15 @@ msgstr "" "``file`` - objet ``ElggFile`` qui pointe vers le fichier image à utiliser " "comme source pour les icônes" -#: ../../guides/events-list.rst:1205 ../../guides/events-list.rst:1214 +#: ../../guides/events-list.rst:1211 ../../guides/events-list.rst:1220 msgid "``x1``, ``y1``, ``x2``, ``y2`` - cropping coordinates" msgstr "``x1``, ``y1``, ``x2``, ``y2`` - coordonnées de découpe" -#: ../../guides/events-list.rst:1214 +#: ../../guides/events-list.rst:1220 msgid "**entity::saved, ** |results|" -msgstr "" +msgstr "**entity::saved, ** |results|" -#: ../../guides/events-list.rst:1208 +#: ../../guides/events-list.rst:1214 msgid "" "Triggered by ``ElggEntity::saveIcon*()`` methods once icons have been " "created. This event can be used by plugins to create river items, update " @@ -6476,44 +6859,60 @@ msgid "" "created icons using ``ElggEntity::getIcon()``. The ``$params`` array " "contains:" msgstr "" +"Déclenché par les méthodes ``ElggEntity::saveIcon*()`` une fois les icônes " +"créées. Cet événement peut être utilisé par les plugins pour créer des " +"éléments dans la rivière, mettre à jour les coordonnées de recadrage pour " +"les types d'icônes personnalisés, etc. Le gestionnaire peut accéder aux " +"icônes créées en utilisant ``ElggEntity::getIcon()``. Le tableau ``$params``" +" contient :" -#: ../../guides/events-list.rst:1221 +#: ../../guides/events-list.rst:1227 msgid "**entity::delete, ** |results|" -msgstr "" +msgstr "**entity::delete, ** |results|" -#: ../../guides/events-list.rst:1217 +#: ../../guides/events-list.rst:1223 msgid "" "Triggered by ``ElggEntity::deleteIcon()`` method and can be used for clean " "up operations. This event is triggered before the icons are deleted. The " "handler can return ``false`` to prevent icons from being deleted. The " "``$params`` array contains:" msgstr "" +"Déclenché par la méthode ``ElggEntity::deleteIcon()`` et peut être utilisé " +"pour les opérations de nettoyage. Cet événement est déclenché avant la " +"suppression des icônes. Le gestionnaire peut renvoyer ``false`` pour " +"empêcher la suppression des icônes. Le tableau ``$params`` contient :" -#: ../../guides/events-list.rst:1226 +#: ../../guides/events-list.rst:1232 msgid "**entity:url, ** |results|" -msgstr "" +msgstr "**entity:url, ** |results|" -#: ../../guides/events-list.rst:1224 +#: ../../guides/events-list.rst:1230 msgid "" "Return the URL for the entity ``$params['entity']``. Note: Generally it is " "better to override the ``getUrl()`` method of ElggEntity. This event should " "be used when it's not possible to subclass (like if you want to extend a " "bundled plugin without overriding many views)." msgstr "" +"Renvoie l'URL de l'entité ``$params['entity']``. Remarque : Généralement, il" +" est préférable de remplacer la méthode ``getUrl()`` d'ElggEntity. Cet " +"événement doit être utilisé lorsqu'il n'est pas possible de sous-classer " +"(comme si vous souhaitez étendre un plugin fourni sans remplacer de " +"nombreuses vues)." -#: ../../guides/events-list.rst:1229 +#: ../../guides/events-list.rst:1235 msgid "**extender:url, ** |results|" -msgstr "" +msgstr "**extender:url, ** |results|" -#: ../../guides/events-list.rst:1229 +#: ../../guides/events-list.rst:1235 msgid "Return the URL for the annotation or metadata ``$params['extender']``." msgstr "" +"Renvoie l'URL de l'annotation ou les métadonnées ``$params['extender']``." -#: ../../guides/events-list.rst:1233 +#: ../../guides/events-list.rst:1239 msgid "**fields, :** |results|" -msgstr "" +msgstr "**fields, :** |results|" -#: ../../guides/events-list.rst:1232 +#: ../../guides/events-list.rst:1238 msgid "" "Return an array of fields usable for ``elgg_view_field()``. The result " "should be returned as an array of fields. It is required to provide ``name``" @@ -6523,11 +6922,11 @@ msgstr "" "résultat doit être renvoyé sous la forme d'un tableau de champs. Il est " "nécessaire de fournir ``name`` et ``#type`` pour chaque champ." -#: ../../guides/events-list.rst:1248 +#: ../../guides/events-list.rst:1254 msgid "**get_list, default_widgets** |results|" -msgstr "" +msgstr "**get_list, default_widgets** |results|" -#: ../../guides/events-list.rst:1247 +#: ../../guides/events-list.rst:1253 msgid "" "Filters a list of default widgets to add for newly registered users. The " "list is an array of arrays in the format:" @@ -6536,11 +6935,11 @@ msgstr "" "nouvellement enregistrés. La liste est un tableau de tableaux dans le format" " :" -#: ../../guides/events-list.rst:1266 +#: ../../guides/events-list.rst:1272 msgid "**handlers, widgets** |results|" -msgstr "" +msgstr "**handlers, widgets** |results|" -#: ../../guides/events-list.rst:1265 +#: ../../guides/events-list.rst:1271 msgid "" "Triggered when a list of available widgets is needed. Plugins can " "conditionally add or remove widgets from this list or modify attributes of " @@ -6551,11 +6950,11 @@ msgstr "" "conditionnelle, ou modifier des attributs de widgets existants comme " "``context`` ou ``multiple``." -#: ../../guides/events-list.rst:1270 +#: ../../guides/events-list.rst:1276 msgid "**maintenance:allow, url** |results|" -msgstr "" +msgstr "**maintenance:allow, url** |results|" -#: ../../guides/events-list.rst:1270 +#: ../../guides/events-list.rst:1276 msgid "" "Return boolean if the URL ``$params['current_url']`` and the path " "``$params['current_path']``" @@ -6563,21 +6962,21 @@ msgstr "" "Retourne un booléen si l'URL ``$params['current_url']`` et le chemin " "``$params['current_path']``" -#: ../../guides/events-list.rst:1270 +#: ../../guides/events-list.rst:1276 msgid "is allowed during maintenance mode." msgstr "sont autorisés pendant le mode de maintenance." -#: ../../guides/events-list.rst:1281 +#: ../../guides/events-list.rst:1287 msgid "**plugin_setting, ** |results|" -msgstr "" +msgstr "**plugin_setting, ** |results|" -#: ../../guides/events-list.rst:1273 +#: ../../guides/events-list.rst:1279 msgid "Can be used to change the value of the setting being saved" msgstr "" "Peut être utilisé pour modifier la valeur du paramètre en cours " "d'enregistrement" -#: ../../guides/events-list.rst:1275 +#: ../../guides/events-list.rst:1281 msgid "" "Params contains: - ``entity`` - The ``ElggEntity`` where the plugin setting " "is being saved - ``plugin_id`` - The ID of the plugin for which the setting " @@ -6589,7 +6988,7 @@ msgstr "" " enregistré - ``name`` - Le nom du paramètre en cours d'enregistrement - " "``valeur`` - La valeur d'origine du paramètre en cours d'enregistrement" -#: ../../guides/events-list.rst:1281 +#: ../../guides/events-list.rst:1287 msgid "" "Return value should be a scalar in order to be able to save it to the " "database. An error will be logged if this is not the case." @@ -6597,11 +6996,11 @@ msgstr "" "La valeur de retour doit être un scalaire afin de pouvoir l'enregistrer dans" " la base de données. Une erreur sera journalisée si ce n'est pas le cas." -#: ../../guides/events-list.rst:1291 +#: ../../guides/events-list.rst:1297 msgid "**public_pages, walled_garden** |results|" -msgstr "" +msgstr "**public_pages, walled_garden** |results|" -#: ../../guides/events-list.rst:1284 +#: ../../guides/events-list.rst:1290 msgid "" "Filters a list of URLs (paths) that can be seen by logged out users in a " "walled garden mode. Handlers must return an array of regex strings that will" @@ -6609,59 +7008,65 @@ msgid "" "as the default value to the event, and plugins must take care to not " "accidentally override these values." msgstr "" +"Filtre une liste d'URLs (chemins) qui peuvent être vues par les utilisateurs" +" déconnectés en mode jardin clos - walled garden. Les gestionnaires doivent " +"renvoyer un tableau de chaînes regex qui autoriseront l'accès si elles " +"correspondent. Veuillez noter que les routes publiques du système sont " +"transmises comme valeur par défaut à l'événement et que les plugins doivent " +"veiller à ne pas remplacer accidentellement ces valeurs." -#: ../../guides/events-list.rst:1291 +#: ../../guides/events-list.rst:1297 msgid "``url`` - URL of the page being tested for public accessibility" msgstr "``url`` - URL de la page testée pour l’accessibilité publique" -#: ../../guides/events-list.rst:1294 +#: ../../guides/events-list.rst:1300 msgid "**relationship:url, ** |results|" -msgstr "" +msgstr "**relationship:url, ** |results|" -#: ../../guides/events-list.rst:1294 +#: ../../guides/events-list.rst:1300 msgid "" "Filter the URL for the relationship object ``$params['relationship']``." msgstr "Filtre l’URL pour l’objet de la relation ``$params['relationship']``." -#: ../../guides/events-list.rst:1297 +#: ../../guides/events-list.rst:1303 msgid "**robots.txt, site** |results|" -msgstr "" +msgstr "**robots.txt, site** |results|" -#: ../../guides/events-list.rst:1297 +#: ../../guides/events-list.rst:1303 msgid "Filter the robots.txt values for ``$params['site']``." msgstr "Filtre les valeurs de robots.txt pour ``$params['site']``." -#: ../../guides/events-list.rst:1305 +#: ../../guides/events-list.rst:1311 msgid "**setting, plugin** |results|" -msgstr "" +msgstr "**setting, plugin** |results|" -#: ../../guides/events-list.rst:1300 +#: ../../guides/events-list.rst:1306 msgid "Filter plugin settings. ``$params`` contains:" msgstr "Filtre les paramètres du plugin. ``$params`` contient :" -#: ../../guides/events-list.rst:1302 +#: ../../guides/events-list.rst:1308 msgid "``plugin`` - An ElggPlugin instance" msgstr "``plugin`` - Une instance de ElggPlugin" -#: ../../guides/events-list.rst:1303 +#: ../../guides/events-list.rst:1309 msgid "``plugin_id`` - The plugin ID" msgstr "``plugin_id`` - L'ID du plugin" -#: ../../guides/events-list.rst:1304 +#: ../../guides/events-list.rst:1310 msgid "``name`` - The name of the setting" msgstr "``name`` - Le nom du paramètre" -#: ../../guides/events-list.rst:1305 +#: ../../guides/events-list.rst:1311 msgid "``value`` - The value to set" msgstr "``value`` - La valeur à définir" -#: ../../guides/events-list.rst:1309 +#: ../../guides/events-list.rst:1315 msgid "" "**to:object, **" msgstr "" "**to:object, **" -#: ../../guides/events-list.rst:1308 +#: ../../guides/events-list.rst:1314 msgid "" "Converts the entity ``$params['entity']`` to a StdClass object. This is used" " mostly for exporting entity properties for portable data formats like JSON " @@ -6671,25 +7076,25 @@ msgstr "" " principalement pour exporter des propriétés d’entité vers des formats de " "données portables comme JSON et XML." -#: ../../guides/events-list.rst:1312 ../../guides/helpers.rst:41 +#: ../../guides/events-list.rst:1318 ../../guides/helpers.rst:41 #: ../../guides/plugins.rst:2 msgid "Plugins" msgstr "Plugins" -#: ../../guides/events-list.rst:1315 +#: ../../guides/events-list.rst:1321 msgid "Groups" msgstr "Groupes" -#: ../../guides/events-list.rst:1324 +#: ../../guides/events-list.rst:1330 msgid "**tool_options, group** |results|" -msgstr "" +msgstr "**tool_options, group** |results|" -#: ../../guides/events-list.rst:1318 +#: ../../guides/events-list.rst:1324 msgid "Filters a collection of tools available within a specific group:" msgstr "" "Filtre une collection d’outils disponibles au sein d’un groupe spécifique :" -#: ../../guides/events-list.rst:1320 +#: ../../guides/events-list.rst:1326 msgid "" "The ``$return`` is " "``\\Elgg\\Collections\\Collection<\\Elgg\\Groups\\Tool>``, a collection of " @@ -6699,29 +7104,31 @@ msgstr "" "``\\Elgg\\Collections\\Collection<\\Elgg\\Groups\\Tool>``, une collection " "d'outils de groupe." -#: ../../guides/events-list.rst:1324 +#: ../../guides/events-list.rst:1330 msgid "``entity`` - ``\\ElggGroup``" msgstr "``entity`` - ``\\ElggGroup``" -#: ../../guides/events-list.rst:1327 +#: ../../guides/events-list.rst:1333 msgid "Web Services" msgstr "Web Services" -#: ../../guides/events-list.rst:1330 +#: ../../guides/events-list.rst:1336 msgid "**register, api_methods``** |results|" -msgstr "" +msgstr "**register, api_methods``** |results|" -#: ../../guides/events-list.rst:1330 +#: ../../guides/events-list.rst:1336 msgid "" "Triggered when the ApiRegistrationService is constructed which allows to " "add/remove/edit webservice configurations" msgstr "" +"Déclenché lors de la construction de l'ApiRegistrationService, ce qui permet" +" d'ajouter/supprimer/modifier des configurations de webservice " -#: ../../guides/events-list.rst:1334 +#: ../../guides/events-list.rst:1340 msgid "**rest, init** |results|" -msgstr "" +msgstr "**rest, init** |results|" -#: ../../guides/events-list.rst:1333 +#: ../../guides/events-list.rst:1339 msgid "" "Triggered by the web services rest handler. Plugins can set up their own " "authentication handlers, then return ``true`` to prevent the default " @@ -6731,11 +7138,11 @@ msgstr "" "configurer leurs propres gestionnaires d’authentification, puis renvoyer " "``true`` pour empêcher les gestionnaires par défaut d’être enregistrés." -#: ../../guides/events-list.rst:1338 +#: ../../guides/events-list.rst:1344 msgid "**rest:output, ** |results|" -msgstr "" +msgstr "**rest:output, ** |results|" -#: ../../guides/events-list.rst:1337 +#: ../../guides/events-list.rst:1343 msgid "Filter the result (and subsequently the output) of the API method" msgstr "Filtrer le résultat (et par la suite la sortie) de la méthode API" @@ -7175,7 +7582,7 @@ msgstr "page_handler/owner/" #: ../../guides/guidelines.rst:32 msgid "User friends'" -msgstr "" +msgstr "Contacts du membre" #: ../../guides/guidelines.rst:32 msgid "page_handler/friends/" @@ -7289,6 +7696,9 @@ msgid "" "Call ``elgg_push_entity_breadcrumbs()`` or " "``elgg_push_collection_breadcrumbs()`` in the page handler scripts." msgstr "" +"Appelle ``elgg_push_entity_breadcrumbs()`` ou " +"``elgg_push_collection_breadcrumbs()`` dans les scripts du gestionnaire de " +"page." #: ../../guides/guidelines.rst:57 msgid "" @@ -7324,6 +7734,10 @@ msgid "" "make sure it's the type entity you want. Return ``true`` to short circuit " "the view if the entity is missing or wrong." msgstr "" +"Recherchez l'objet dans ``$vars['entity']`` . Utilisez " +"``elgg_instance_of()`` pour vous assurer qu'il s'agit du type d'entité que " +"vous souhaitez. Renvoyez ``true`` pour court-circuiter la vue si l'entité " +"est manquante ou erronée." #: ../../guides/guidelines.rst:66 msgid "" @@ -7474,6 +7888,8 @@ msgstr "" msgid "" "Update the group profile 'widget' using blog or file plugins as example" msgstr "" +"Mettez à jour le 'widget' du profil de groupe en utilisant des plugins de " +"blog ou de fichiers comme exemple" #: ../../guides/guidelines.rst:112 msgid "Update the forms" @@ -7484,6 +7900,8 @@ msgid "" "Move form bodies to ``/forms//`` to use Evan's new " "``elgg_view_form()``" msgstr "" +"Déplacez les corps de formulaire vers la vue ``forms//`` " +"pour utiliser le nouveau ``elgg_view_form()`` d’Evan" #: ../../guides/guidelines.rst:111 msgid "Use input views in form bodies rather than html" @@ -7504,6 +7922,8 @@ msgid "" "Integrate sticky forms (see the file plugin's upload action and form prepare" " function)" msgstr "" +"Rendez vos formulaires persistants (voyez l’action de téléchargement du " +"plugin file et la fonction de préparation du formulaire)" #: ../../guides/guidelines.rst:114 msgid "Clean up CSS/HTML" @@ -7898,7 +8318,7 @@ msgstr "Guides de développement" msgid "Customize Elgg's behavior with plugins." msgstr "Personnalisez le comportement de Elgg avec des plugins." -#: ../../guides/javascript.rst:2 ../../guides/menus.rst:280 +#: ../../guides/javascript.rst:2 ../../guides/menus.rst:299 msgid "JavaScript" msgstr "JavaScript" @@ -7991,13 +8411,15 @@ msgstr "Passer des paramètres aux modules" #: ../../guides/javascript.rst:78 msgid "The ``elgg.data`` events" -msgstr "" +msgstr "Les événements ``elgg.data``" #: ../../guides/javascript.rst:80 msgid "" "The ``elgg`` module provides an object ``elgg.data`` which is populated from" " two server side events:" msgstr "" +"Le module ``elgg`` fournit un objet ``elgg.data`` qui est renseigné à partir" +" de deux événements côté serveur :" #: ../../guides/javascript.rst:82 msgid "" @@ -8243,13 +8665,15 @@ msgstr "Voir la page :doc:`ajax` pour plus de détails." #: ../../guides/javascript.rst:304 msgid "Module ``elgg/hooks``" -msgstr "" +msgstr "Module ``elgg/hooks``" #: ../../guides/javascript.rst:306 msgid "" "The ``elgg/hooks`` module can be used to have plugins interact with " "eachother." msgstr "" +"Le module ``elgg/hooks`` peut être utilisé pour faire interagir les plugins " +"entre eux." #: ../../guides/javascript.rst:308 ../../guides/javascript.rst:322 msgid "Translate interface text" @@ -8529,6 +8953,10 @@ msgid "" " loading the scripts, you can register scripts in a event handler to add " "elements to the head links;" msgstr "" +"Bien que nous recommandons fortement d'utiliser les modules AMD et qu'il n'y" +" ait pas d'API Elgg pour charger les scripts, vous pouvez enregistrer des " +"scripts dans un gestionnaire d'événements pour ajouter des éléments aux " +"liens principaux ;" #: ../../guides/javascript.rst:626 msgid "Hooks" @@ -8540,6 +8968,9 @@ msgid "" "are triggered and plugins can register functions to react or alter " "information." msgstr "" +"Le moteur JS dispose d'un système de hooks similaire aux événements du " +"moteur PHP : les hooks sont déclenchés et les plugins peuvent enregistrer " +"des fonctions pour réagir ou modifier des informations." #: ../../guides/javascript.rst:631 msgid "Registering hook handlers" @@ -8550,6 +8981,9 @@ msgid "" "Handler functions are registered using ``hooks.register()``. Multiple " "handlers can be registered for the same hook." msgstr "" +"Les fonctions du gestionnaire sont enregistrées en utilisant " +"``hooks.register()``. Plusieurs gestionnaires peuvent être enregistrés pour " +"le même hook." #: ../../guides/javascript.rst:642 msgid "The handler function" @@ -8754,6 +9188,9 @@ msgid "" " required in order to allow easy overriding and manipulation, as well as to " "provide events for theming." msgstr "" +"Chaque menu nécessite un nom, tout comme chaque élément de menu. Ceux-ci " +"sont nécessaires pour permettre un remplacement et une manipulation faciles," +" ainsi que pour fournir des événements pour les thèmes." #: ../../guides/menus.rst:15 msgid "Basic usage" @@ -8779,7 +9216,7 @@ msgstr "" "Vous voudrez normalement les appeler à partir de la fonction " "d'initialisation de votre plugin." -#: ../../guides/menus.rst:25 ../../guides/menus.rst:76 +#: ../../guides/menus.rst:25 ../../guides/menus.rst:95 msgid "Examples" msgstr "Exemples" @@ -8803,10 +9240,10 @@ msgstr "" #: ../../guides/menus.rst:47 msgid "" -"``administer`` for daily tasks, usermanagement and other actionable tasks" +"``administer`` for daily tasks, user management and other actionable tasks" msgstr "" "``administer`` pour les tâches quotidiennes, la gestion des utilisateurs et " -"d’autres tâches concrètes" +"d’autres tâches pratiques" #: ../../guides/menus.rst:48 msgid "" @@ -8825,17 +9262,54 @@ msgstr "" msgid "Advanced usage" msgstr "Utilisation avancée" -#: ../../guides/menus.rst:55 +#: ../../guides/menus.rst:56 +msgid "Headers" +msgstr "Entêtes" + +#: ../../guides/menus.rst:58 +msgid "" +"For accessibility reasons each menu will get an ``aria-label`` which " +"defaults to the menu name, but can be translated by making sure the language" +" key ``menu::header`` is available." +msgstr "" +"Pour des raisons d'accessibilité, chaque menu recevra un ``aria-label`` qui " +"par défaut est le nom du menu, mais peut être traduit en s'assurant que la " +"clef de traduction ``menu::header`` est disponible." + +#: ../../guides/menus.rst:61 +msgid "" +"It's also possible to show menu section headers by setting " +"``show_section_headers`` to ``true`` in ``elgg_view_menu()``" +msgstr "" +"Il est également possible d'afficher les entêtes des sections de menu en " +"définissant ``show_section_headers`` sur ``true`` dans ``elgg_view_menu()``" + +#: ../../guides/menus.rst:69 +msgid "" +"The headers have a magic language key available ``menu::header:
`` in order to be able to translate the headers." +msgstr "" +"Les entêtes utilisent une clé de langage magique disponible ``menu::header:
`` afin de pouvoir traduire les entêtes." + +#: ../../guides/menus.rst:72 +msgid "Events" +msgstr "Événements" + +#: ../../guides/menus.rst:74 msgid "" "You can get more control over menus by using :doc:`events ` " "and the public methods provided by the ``ElggMenuItem`` class." msgstr "" +"Vous pouvez obtenir plus de contrôle sur les menus en utilisant :doc:`events" +" ` et les méthodes publiques fournies par la classe " +"``ElggMenuItem``." -#: ../../guides/menus.rst:61 +#: ../../guides/menus.rst:80 msgid "There are three events that can be used to modify a menu:" -msgstr "" +msgstr "Trois événements peuvent être utilisés pour modifier un menu : " -#: ../../guides/menus.rst:59 +#: ../../guides/menus.rst:78 msgid "" "``'parameters', 'menu:'`` to add or modify parameters use for the" " menu building (eg. sorting)" @@ -8843,7 +9317,7 @@ msgstr "" "``'parameters', 'menu:'`` pour ajouter ou modifier les paramètres utilisés " "pour construire le menu (par exemple l'ordre de tri)" -#: ../../guides/menus.rst:60 +#: ../../guides/menus.rst:79 msgid "" "``'register', 'menu:'`` to add or modify items (especially in " "dynamic menus)" @@ -8851,7 +9325,7 @@ msgstr "" "``'register', 'menu:'`` pour ajouter ou modifier des éléments (en " "particulier dans les menus dynamiques)" -#: ../../guides/menus.rst:61 +#: ../../guides/menus.rst:80 msgid "" "``'prepare', 'menu:'`` to modify the structure of the menu before" " it is displayed" @@ -8859,13 +9333,15 @@ msgstr "" "``'prepare', 'menu:'`` pour modifier la structure du menu avant qu’il soit " "affiché" -#: ../../guides/menus.rst:63 +#: ../../guides/menus.rst:82 msgid "" "When you register an event handler, replace the ```` part with " "the internal name of the menu." msgstr "" +"Lorsque vous enregistrez un gestionnaire d'événements, remplacez la partie " +"```` par le nom interne du menu." -#: ../../guides/menus.rst:66 +#: ../../guides/menus.rst:85 msgid "" "The third parameter passed into a menu handler contains all the menu items " "that have been registered so far by Elgg core and other enabled plugins. In " @@ -8878,7 +9354,7 @@ msgstr "" "une boucle à travers les éléments de menu et utiliser les méthodes de classe" " pour interagir avec les propriétés de l’élément de menu." -#: ../../guides/menus.rst:71 +#: ../../guides/menus.rst:90 msgid "" "In some cases a more granular version of the ``register`` and ``prepare`` " "menu events exist with ``menu:::``, this applies " @@ -8886,8 +9362,14 @@ msgid "" "an ``\\ElggAnnotation`` in ``$params['annotation']`` or an " "``\\ElggRelationship`` in ``$params['relationship']``." msgstr "" +"Dans certains cas, une version plus granulaire des événements de menu " +"``register`` et ``prepare`` existe avec ``menu:::``, cela s'applique lorsque le menu reçoit un " +"``\\ElggEntity`` dans `` $params['entity']`` ou un ``\\ElggAnnotation`` dans" +" ``$params['annotation']`` ou un ``\\ElggRelationship`` dans " +"``$params['relationship']``." -#: ../../guides/menus.rst:78 +#: ../../guides/menus.rst:97 msgid "" "**Example 1:** Change the URL for menu item called \"albums\" in the " "``owner_block`` menu:" @@ -8895,24 +9377,24 @@ msgstr "" "**Exemple 1 :** Modifier l’URL de l’élément de menu appelé \"albums\" dans " "le menu ``owner_block`` :" -#: ../../guides/menus.rst:117 +#: ../../guides/menus.rst:136 msgid "**Example 2:** Modify the ``entity`` menu for the ``ElggBlog`` objects" msgstr "" "**Exemple 2 :** Modifier le menu ``entity`` pour les objets ``ElggBlog``" -#: ../../guides/menus.rst:116 +#: ../../guides/menus.rst:135 msgid "Remove the thumb icon" msgstr "Supprimer l’icône du pouce" -#: ../../guides/menus.rst:117 +#: ../../guides/menus.rst:136 msgid "Change the \"Edit\" text into a custom icon" msgstr "Modifier le texte \"Modifier\" en une icône personnalisée" -#: ../../guides/menus.rst:155 +#: ../../guides/menus.rst:174 msgid "Creating a new menu" msgstr "Créer un nouveau menu" -#: ../../guides/menus.rst:157 +#: ../../guides/menus.rst:176 msgid "" "Elgg provides multiple different menus by default. Sometimes you may however" " need some menu items that don't fit in any of the existing menus. If this " @@ -8926,7 +9408,7 @@ msgstr "" " la fonction ``elgg_view_menu()``. Vous devez appeler la fonction à partir " "de la vue dans laquelle vous souhaitez afficher le menu." -#: ../../guides/menus.rst:163 +#: ../../guides/menus.rst:182 msgid "" "**Example:** Display a menu called \"my_menu\" that displays it's menu items" " in alphapetical order:" @@ -8934,22 +9416,24 @@ msgstr "" "**Exemple:** Afficher un menu appelé « my_menu » qui affiche ses éléments de" " menu dans l’ordre alphabétique :" -#: ../../guides/menus.rst:171 +#: ../../guides/menus.rst:190 msgid "You can now add new items to the menu like this:" msgstr "" "Vous pouvez maintenant ajouter de nouveaux éléments au menu comme ceci :" -#: ../../guides/menus.rst:182 +#: ../../guides/menus.rst:201 msgid "" "Furthermore it is now possible to modify the menu using the events " "``'register', 'menu:my_menu'`` and ``'prepare', 'menu:my_menu'``." msgstr "" +"De plus il est désormais possible de modifier le menu à l'aide des " +"événements ``'register', 'menu:my_menu'`` et ``'prepare', 'menu:my_menu'``." -#: ../../guides/menus.rst:186 +#: ../../guides/menus.rst:205 msgid "Child Dropdown Menus" msgstr "Sous-menus déroulants" -#: ../../guides/menus.rst:188 +#: ../../guides/menus.rst:207 msgid "" "Child menus can be configured using ``child_menu`` factory option on the " "parent item." @@ -8957,7 +9441,7 @@ msgstr "" "Les sous-menus peuvent être configurés à l’aide de l’option ``child_menu`` " "de l’élément parent." -#: ../../guides/menus.rst:190 +#: ../../guides/menus.rst:209 msgid "" "``child_menu`` options array accepts ``display`` parameter, which can be " "used to set the child menu to open as ``dropdown`` or be displayed via " @@ -8970,11 +9454,11 @@ msgstr "" "Toutes les autres paires de clefs/valeurs seront transmises en tant " "qu’attributs à l’élément ``ul``." -#: ../../guides/menus.rst:231 +#: ../../guides/menus.rst:250 msgid "Theming" msgstr "Création de thèmes" -#: ../../guides/menus.rst:233 +#: ../../guides/menus.rst:252 msgid "" "The menu name, section names, and item names are all embedded into the HTML " "as CSS classes (normalized to contain only hyphens, rather that underscores " @@ -8988,7 +9472,7 @@ msgstr "" "intégrateurs un haut degré de contrôle et de flexibilité lors de la mise en " "forme du site." -#: ../../guides/menus.rst:238 +#: ../../guides/menus.rst:257 msgid "" "**Example:** The following would be the output of the ``foo`` menu with " "sections ``alt`` and ``default`` containing items ``baz`` and ``bar`` " @@ -8997,11 +9481,11 @@ msgstr "" "**Exemple :** Voici la sortie du menu ``foo`` avec les sections ``alt`` et " "``default`` contenant respectivement les éléments ``baz`` et ``bar``." -#: ../../guides/menus.rst:251 +#: ../../guides/menus.rst:270 msgid "Toggling Menu Items" msgstr "Basculer des éléments de menu" -#: ../../guides/menus.rst:253 +#: ../../guides/menus.rst:272 msgid "" "There are situations where you wish to toggle menu items that are actions " "that are the opposite of each other and ajaxify them. E.g. like/unlike, " @@ -9018,7 +9502,7 @@ msgstr "" "menu (dans le même menu) qui doit être basculé. Un appel ajax sera fait en " "utilisant le href de l’élément de menu." -#: ../../guides/menus.rst:276 +#: ../../guides/menus.rst:295 msgid "" "The menu items are optimistically toggled. This means the menu items are " "toggled before the actions finish. If the actions fail, the menu items will " @@ -9028,7 +9512,7 @@ msgstr "" "les éléments de menu sont basculés avant la fin des actions. Si les actions " "échouent, les éléments de menu seront rétablis." -#: ../../guides/menus.rst:282 +#: ../../guides/menus.rst:301 msgid "" "It is common that menu items rely on JavaScript. You can bind client-side " "events to menu items by placing your JavaScript into AMD module and defining" @@ -9178,6 +9662,8 @@ msgid "" "When the event handler for the one-minute interval gets triggered, the event" " is taken from the queue and it gets processed" msgstr "" +"Lorsque le gestionnaire d'événements pour l'intervalle d'une minute est " +"déclenché, l'événement est retiré de la file d'attente et traité." #: ../../guides/notifications.rst:87 msgid "Subscriptions are fetched for the user who triggered the event" @@ -9199,30 +9685,42 @@ msgid "" "Plugins are allowed to alter the subscriptions using the ``[get, " "subscriptions]`` event" msgstr "" +"Les plugins sont autorisés à modifier les abonnements en utilisant " +"l'événement ``[get, souscriptions]``" #: ../../guides/notifications.rst:90 msgid "" "Plugins are allowed to terminate notifications queue processing with the " "``[send:before, notifications]`` event" msgstr "" +"Les plugins sont autorisés à interrompre le traitement de la file d'attente " +"des notifications avec l'événement ``[send:before, notifications]`` " #: ../../guides/notifications.rst:91 msgid "" "Plugins are allowed to alter the notification parameters with the " "``[prepare, notification]`` event" msgstr "" +"Les plugins sont autorisés à modifier les paramètres de notification avec " +"l'événement ``[send:before, notifications]`` " #: ../../guides/notifications.rst:92 msgid "" "Plugins are allowed to alter the notification subject/message/summary with " "the ``[prepare, notification:::]`` event" msgstr "" +"Les plugins sont autorisés à modifier le subject/message/summary de la " +"notification avec l'événement ``[prepare, " +"notification:::]`` " #: ../../guides/notifications.rst:93 msgid "" "Plugins are allowed to format notification subject/message/summary for " "individual delivery methods with ``[format, notification:]`` event" msgstr "" +"Les plugins sont autorisés à formater le sujet/message/résumé de " +"notification pour des méthodes de livraison individuelles avec l'événement " +"``[format, notification:]``" #: ../../guides/notifications.rst:94 msgid "" @@ -9236,12 +9734,16 @@ msgid "" "Plugins can take over or prevent sending of each individual notification " "with the ``[send, notification:]`` event" msgstr "" +"Les plugins peuvent remplacer ou empêcher l'envoi de chaque notification " +"individuelle avec l'événement ``[send, notification:]``" #: ../../guides/notifications.rst:96 msgid "" "The ``[send:after, notifications]`` event is triggered for the event after " "all notifications have been sent" msgstr "" +"L'événement ``[send:after, notifications]`` est déclenché pour l'événement " +"après que toutes les notifications ont été envoyées" #: ../../guides/notifications.rst:99 msgid "Notification event registration example" @@ -9272,6 +9774,8 @@ msgid "" "Contents of the notification message can be defined with the ``'prepare', " "'notification:[action]:[type]:[subtype]'`` event." msgstr "" +"Le contenu du message de notification peut être défini avec l'événement " +"``'prepare', 'notification:[action]:[type]:[subtype]'``." #: ../../guides/notifications.rst:134 msgid "Custom notification event registration example" @@ -9312,6 +9816,8 @@ msgid "" "Make sure the notification will be in the correct language by passing the " "recipient's language into the ``elgg_echo()`` function." msgstr "" +"Assurez-vous que la notification sera dans la bonne langue en passant la " +"langue du destinataire dans la fonction ``elgg_echo()``." #: ../../guides/notifications.rst:267 msgid "Notification salutation and sign-off" @@ -9328,6 +9834,16 @@ msgid "" "parameters in ``notify_user()`` or in the ``prepare, notifications`` event. " "You can change the salutation and sign-off texts in the translations." msgstr "" +"Elgg ajoutera par défaut une formule de salutation au corps du message des " +"notifications sortantes. Une signature sera également annexée. Cela signifie" +" que vous n'aurez pas besoin d'ajouter du texte comme ``Bonjour " +"Administrateur`` ou ``Cordialement, votre sympathique administrateur de " +"site`` dans le corps de vos notifications. Si pour une raison quelconque " +"vous n'avez pas besoin que cette magie se produise, vous pouvez l'empêcher " +"en définissant le paramètre de notification ``add_salutation`` à ``false``. " +"Vous pouvez le faire dans le cadre des paramètres de ``notify_user()`` ou de" +" l'événement ``prepare, notifications``. Vous pouvez modifier les textes de " +"salutation et de signature dans les traductions." #: ../../guides/notifications.rst:275 msgid "" @@ -9428,6 +9944,10 @@ msgid "" "handler that takes care of actually sending the SMS notifications. This " "happens with the ``'send', 'notification:[method]'`` event." msgstr "" +"Outre l'enregistrement de la méthode de notification, vous devez également " +"enregistrer un gestionnaire qui se charge d'envoyer réellement les " +"notifications SMS. Cela se produit avec l'événement ``'send', " +"'notification:[method]'``." #: ../../guides/notifications.rst:370 msgid "Subscriptions" @@ -9460,6 +9980,8 @@ msgid "" "It's possible to modify the recipients of a notification dynamically with " "the ``'get', 'subscriptions'`` event." msgstr "" +"Il est possible de modifier dynamiquement les destinataires d'une " +"notification avec l'événement ``'get', 'subscriptions'``." #: ../../guides/notifications.rst:415 msgid "Muted notifications" @@ -9605,6 +10127,14 @@ msgid "" "``\\ElggEntity`` in ``$params['entity']`` is provided. This will work for " "most ``elgg_view_menu()`` calls." msgstr "" +"Un gestionnaire d'événements de menu générique est fourni pour gérer " +"l'abonnement aux notifications et la mise en sourdine. Si vous souhaitez " +"permettre aux utilisateurs de s'abonner facilement à vos entités, " +"enregistrez un événement de menu sur ``register`` ``menu:::`` avec le callback " +"``Elgg\\Notifications\\RegisterSubscriptionMenuItemsHandler`` assurez-vous " +"de fournir un ``\\ ElggEntity`` dans ``$params['entity']``. Cela " +"fonctionnera pour la plupart des appels ``elgg_view_menu()``." #: ../../guides/page-owner.rst:2 msgid "Page ownership" @@ -9704,14 +10234,22 @@ msgid "" "access settings. Entities that are hidden, however, will still be " "unavailable to the plugin." msgstr "" +"Elgg fournit un mécanisme permettant de remplacer la vérification des " +"autorisations d'écriture via l'événement :ref:`permissions_check " +"` . Ceci est utile pour permettre l'écriture" +" du plugin sur toutes les entités accessibles, quels que soient les " +"paramètres d'accès. Cependant, les entités masquées ne seront toujours pas " +"disponibles pour le plugin." #: ../../guides/permissions-check.rst:11 msgid "Extending permissions_check" -msgstr "" +msgstr "Étendre permissions_check" #: ../../guides/permissions-check.rst:13 msgid "In your plugin, you must register the event for ``permissions_check``." msgstr "" +"Dans votre plugin, vous devez enregistrer l'événement pour " +"``permissions_check``." #: ../../guides/permissions-check.rst:20 msgid "The override function" @@ -9727,6 +10265,15 @@ msgid "" "the entity has write access, false if the entity does not, and null if this " "plugin doesn't care and the security system should consult other plugins." msgstr "" +"Créez maintenant la fonction qui sera appelée par l'événement de " +"vérification des autorisations. Dans cette fonction, nous déterminons si " +"l'entité (dans les paramètres) a un accès en écriture. Puisqu'il est " +"important de garantir la sécurité d'Elgg, l'accès en écriture ne doit être " +"accordé qu'après avoir vérifié diverses situations, notamment le contexte de" +" la page, l'utilisateur connecté, etc. Notez que cette fonction peut " +"renvoyer 3 valeurs : true si l'entité a un accès en écriture, false si " +"l'entité ne l'a pas, et null si ce plugin ne s'en préoccupe pas et que le " +"système de sécurité devrait consulter d'autres plugins." #: ../../guides/permissions-check.rst:40 msgid "Full Example" @@ -9872,6 +10419,8 @@ msgid "" "``web_services`` - an array of exposed web service (used by the Web Services" " plugin)" msgstr "" +"``web_services`` - un tableau de webservices exposés (utilisés par le plugin" +" Web Services)" #: ../../guides/plugins.rst:246 msgid "Bootstrap class" @@ -9937,7 +10486,7 @@ msgstr "" #: ../../guides/plugins.rst:277 msgid "" "See `PHP-DI documentation `_ for a comprehensive list of " -"definition and invokation possibilities." +"definition and invocation possibilities." msgstr "" "Voyez la `documentation PHP-DI `_ pour une liste " "complète des possibilités de définition et d’invocation." @@ -9990,26 +10539,18 @@ msgstr "" "``type`` : indique à Composer où installer votre plugin, laissez TOUJOURS " "ceci sur ``elgg-plugin``" -#: ../../guides/plugins.rst:297 -msgid "" -"``require``: the ``composer/installers`` requirement is to make sure " -"Composer knows where to install your plugin" -msgstr "" -"``require`` : l'exigence ``composer/installers`` vise à s'assurer que " -"Composer sait où installer votre plugin" - -#: ../../guides/plugins.rst:299 +#: ../../guides/plugins.rst:298 msgid "" "As a suggestion, include a ``conflict`` rule with any Elgg version below " -"your mininal required version, this will help prevent the accidental " +"your minimal required version, this will help prevent the accidental " "installation of your plugin on an incompatible Elgg version." msgstr "" -"À titre de suggestion, incluez une règle de ``conflict`` avec n’importe " -"quelle version de Elgg inférieure à votre version minimale requise, cela " -"aidera à éviter l’installation accidentelle de votre plugin sur une version " -"de Elgg incompatible." +"À titre de suggestion, incluez une règle ``conflict`` avec toute version " +"d'Elgg inférieure à votre version minimale requise, cela aidera à empêcher " +"l'installation accidentelle de votre plugin sur une version d'Elgg " +"incompatible." -#: ../../guides/plugins.rst:302 +#: ../../guides/plugins.rst:301 msgid "" "After adding a ``composer.json`` file to your plugin project, you need to " "register your project on `Packagist`_ in order for other people to be able " @@ -10019,11 +10560,11 @@ msgstr "" "vous devez enregistrer votre projet sur `Packagist`_ afin que d’autres " "personnes puissent installer votre plugin." -#: ../../guides/plugins.rst:306 +#: ../../guides/plugins.rst:305 msgid "Tests" msgstr "Tests" -#: ../../guides/plugins.rst:308 +#: ../../guides/plugins.rst:307 msgid "" "It's encouraged to create PHPUnit test for your plugin. All tests should be " "located in ``tests/phpunit/unit`` for unit tests and " @@ -10033,32 +10574,68 @@ msgstr "" "tests devraient être situés dans ``tests/phpunit/unit`` pour les tests " "unitaires et ``tests/phpunit/integration`` pour les tests d'intégration." -#: ../../guides/plugins.rst:311 +#: ../../guides/plugins.rst:310 +msgid "" +"Unit tests should extend the ``Elgg\\UnitTestCase`` class. Integration tests" +" should extend the ``Elgg\\Plugins\\IntegrationTestCase``." +msgstr "" +"Les tests unitaires devraient étendre la classe ``Elgg\\UnitTestCase``. Les " +"tests d'intégration devraient étendre " +"``Elgg\\Plugins\\IntegrationTestCase``." + +#: ../../guides/plugins.rst:312 +msgid "" +"There are a set of global plugin integration tests that run on all active " +"plugins. These tests are:" +msgstr "" +"Il existe un ensemble de tests d'intégration de plugins globaux qui " +"s'exécutent sur tous les plugins actifs. Ces tests sont :" + +#: ../../guides/plugins.rst:314 +msgid "" +"``Elgg\\Plugins\\ActionRegistrationIntegrationTest`` will test all " +"registered actions of the plugin without supplying data" +msgstr "" +"``Elgg\\Plugins\\ActionRegistrationIntegrationTest`` testera toutes les " +"actions enregistrées du plugin sans fournir de données" + +#: ../../guides/plugins.rst:315 +msgid "" +"``Elgg\\Plugins\\ComposerIntegrationTest`` will test if the " +"``composer.json`` is considered valid" +msgstr "" +"``Elgg\\Plugins\\ComposerIntegrationTest`` va tester si ``composer.json`` " +"est considéré comme valide" + +#: ../../guides/plugins.rst:316 +msgid "" +"``Elgg\\Plugins\\StaticConfigIntegrationTest`` will test the sections of the" +" ``elgg-plugin.php`` and check for the correct format" +msgstr "" +"``Elgg\\Plugins\\StaticConfigIntegrationTest`` testera les sections de " +"``elgg-plugin.php`` et vérifiera que le format est correct" + +#: ../../guides/plugins.rst:317 msgid "" -"An easy example of adding test is the ``ViewStackTest``, this will test that" -" the views in your plugin are registered correctly and have no syntax " -"errors. To add this test create a file ``ViewStackTest.php`` in the folder " -"``tests/phpunit/unit///`` with the content:" +"``Elgg\\Plugins\\TranslationsIntegrationTest`` will test all language files " +"for the correct format and encoding" msgstr "" -"Un exemple simple d'ajout de test est le test ``ViewStackTest``, qui va " -"vérifier que les vues de votre plugin sont enregistrées correctement et " -"n’ont pas d’erreurs de syntaxe. Pour ajouter ce test, créez un fichier " -"``ViewStackTest.php`` dans le dossier " -"``tests/phpunit/unit///`` avec le contenu " -"suivant :" +"``Elgg\\Plugins\\TranslationsIntegrationTest`` testera tous les fichiers de " +"langue pour le format et l'encodage corrects" -#: ../../guides/plugins.rst:328 +#: ../../guides/plugins.rst:318 msgid "" -"If you wish to see a better example, look in any of the Elgg core plugins." +"``Elgg\\Plugins\\ViewStackIntegrationTest`` will test all views of the " +"plugin if there are any PHP parsing errors" msgstr "" -"Si vous souhaitez voir un meilleur exemple, regardez dans l’un des plugins " -"du noyau de Elgg." +"``Elgg\\Plugins\\ViewStackIntegrationTest`` testera toutes les vues du " +"plugin s'il y a des erreurs d'analyse PHP" -#: ../../guides/plugins.rst:332 +#: ../../guides/plugins.rst:322 msgid ":doc:`/contribute/tests`" msgstr ":doc:`/contribute/tests`" -#: ../../guides/plugins.rst:335 ../../guides/views.rst:647 +#: ../../guides/plugins.rst:325 ../../guides/views.rst:647 #: ../../guides/web-services.rst:398 msgid "Related" msgstr "Connexe" @@ -10242,6 +10819,8 @@ msgid "" "Returns Elgg's public DI container. This can be helpfull if you wish to " "register event listeners." msgstr "" +"Renvoie le conteneur DI public de Elgg. Cela peut être utile si vous " +"souhaitez enregistrer des écouteurs d'événements." #: ../../guides/plugins/bootstrap.rst:99 msgid "->plugin()" @@ -11233,31 +11812,37 @@ msgstr "Ce gestionnaire d'accès empêchera l’accès à toute demande non-XHR. #: ../../guides/routing.rst:215 msgid "PageOwnerGatekeeper" -msgstr "" +msgstr "PageOwnerGatekeeper" #: ../../guides/routing.rst:217 msgid "This gatekeeper will prevent access if there is no pageowner entity." msgstr "" +"Ce contrôleur d'accès empêchera l'accès s'il n'y a pas d'entité propriétaire" +" de la page." #: ../../guides/routing.rst:220 msgid "GroupPageOwnerGatekeeper" -msgstr "" +msgstr "GroupPageOwnerGatekeeper" #: ../../guides/routing.rst:222 msgid "" "This gatekeeper extends the ``PageOwnerGatekeeper`` but also requires the " "pageowner to be a ``ElggGroup`` entity." msgstr "" +"Ce contrôleur d'accès étend ``PageOwnerGatekeeper`` et requiert également " +"que le propriétaire de la page soit une entité ``ElggGroup``." #: ../../guides/routing.rst:225 msgid "UserPageOwnerGatekeeper" -msgstr "" +msgstr "UserPageOwnerGatekeeper" #: ../../guides/routing.rst:227 msgid "" "This gatekeeper extends the ``PageOwnerGatekeeper`` but also requires the " "pageowner to be an ``ElggUser`` entity." msgstr "" +"Ce contrôleur d'accès étend le ``PageOwnerGatekeeper`` et requiert également" +" que le propriétaire de la page soit une entité ``ElggUser``." #: ../../guides/routing.rst:230 msgid "PageOwnerCanEditGatekeeper" @@ -11268,6 +11853,8 @@ msgid "" "This gatekeeper will prevent access if there is no pageowner detected and " "the pageowner can't be editted." msgstr "" +"Ce contrôleur d'accès bloquera l'accès si aucun propriétaire de page n'est " +"détecté et que le propriétaire de la page ne peut pas être modifié." #: ../../guides/routing.rst:235 msgid "GroupPageOwnerCanEditGatekeeper" @@ -11398,7 +11985,7 @@ msgstr "" #: ../../guides/routing.rst:329 msgid "The ``route:rewrite`` event" -msgstr "" +msgstr "L'événement ``route:rewrite``" #: ../../guides/routing.rst:331 msgid "" @@ -11406,6 +11993,9 @@ msgid "" "``route``) is triggered very early, and allows modifying the request URL " "path (relative to the Elgg site)." msgstr "" +"Pour la réécriture d'URL, l'événement ``route:rewrite`` (avec des arguments " +"similaires à ``route``) est déclenché très tôt, et permet de modifier le " +"chemin de l'URL de la requête (par rapport au site Elgg)." #: ../../guides/routing.rst:334 msgid "Here we rewrite requests for ``news/*`` to ``blog/*``:" @@ -11416,6 +12006,8 @@ msgid "" "The event must be registered directly in your plugin Bootstrap ``boot`` " "function. The ``init`` function is too late." msgstr "" +"L'événement doit être enregistré directement dans la fonction ``boot`` du " +"Bootstrap de votre plugin. La fonction ``init`` arrive trop tard." #: ../../guides/routing.rst:353 msgid "Routing overview" @@ -11445,7 +12037,7 @@ msgstr "" #: ../../guides/routing.rst:360 msgid "Elgg triggers the event ``route:rewrite, news`` (see above)." -msgstr "" +msgstr "Elgg déclenche l'événement ``route:rewrite, news`` (voir ci-dessus)." #: ../../guides/routing.rst:361 msgid "" @@ -11582,6 +12174,8 @@ msgid "" "You can customize search fields for each entity type/subtype, using " "``search:fields`` event:" msgstr "" +"Vous pouvez personnaliser les champs de recherche pour chaque type/sous-type" +" d'entité, en utilisant l'événement ``search:fields`` :" #: ../../guides/search.rst:73 msgid "Searchable types" @@ -11610,6 +12204,9 @@ msgid "" "To combine search results or filter how search results are presented in the " "search plugin, use ``'search:config', 'type_subtype_pairs'`` event." msgstr "" +"Pour combiner les résultats de recherche ou filtrer la façon dont les " +"résultats de recherche sont présentés dans le plugin de recherche, utilisez " +"l'événement ``'search:config', 'type_subtype_pairs'``." #: ../../guides/search.rst:135 msgid "Custom search types" @@ -11633,11 +12230,12 @@ msgstr "Points de terminaison pour l'autocomplétion et la recherche en direct" #: ../../guides/search.rst:186 msgid "" "Core provides a JSON endpoint for searching users and groups. These " -"endpoints are used by ``input/autocomplete`` and ``input/userpicker`` views." +"endpoints are used by ``input/autocomplete`` and ``input/entitypicker`` " +"views." msgstr "" -"Le noyau fournit un point de terminaison JSON pour la recherche " -"d’utilisateurs et de groupes. Ces points de terminaison sont utilisés par " -"les vues ``input/autocomplete`` et ``input/userpicker``." +"Le coeur de Elgg fournit un point de terminaison JSON pour rechercher des " +"utilisateurs et des groupes. Ces points de terminaison sont utilisés par les" +" vues ``input/autocomplete`` et ``input/entitypicker``." #: ../../guides/search.rst:194 msgid "" @@ -11717,6 +12315,12 @@ msgid "" "``params[myparameter]`` your plugin (which is also passed to this view as " "``$vars['entity']``) will be called ``$vars['entity']->myparameter``" msgstr "" +"Définissez l'attribut name dans vos composants de formulaire sur " +"``params[`varname`]`` où ``varname`` est le nom de la variable. Ceux-ci " +"seront enregistrés sous forme de métadonnées attachées à une entité de " +"plugin. Ainsi, si votre variable s'appelle ``params[myparameter]``, votre " +"plugin (qui est également passé à cette vue sous le nom ``$vars['entity']``)" +" s'appellera ``$vars['entity'] ->myparameter``" #: ../../guides/settings.rst:17 msgid "An example ``settings.php`` would look like:" @@ -11980,6 +12584,8 @@ msgid "" "Flexbox provides simplicity in stacking elements into grids. Flexbox is used" " for everything from menus to layout elements." msgstr "" +"Flexbox offre une simplicité d'empilement d'éléments dans des grilles. " +"Flexbox est utilisé pour tout, des menus aux éléments de mise en page." #: ../../guides/themes.rst:131 msgid "**Symmetrical**" @@ -12220,6 +12826,9 @@ msgid "" "To add or alter variables, use the ``vars:compiler, css`` event. Note that " "you may need to flush the cache to see your changes in action." msgstr "" +"Pour ajouter ou modifier des variables, utilisez l'événement " +"``vars:compiler, css``. Notez que vous devrez peut-être vider le cache pour " +"voir vos modifications en action." #: ../../guides/themes.rst:255 msgid "For a list of default core variables, see ``engine/theme.php``." @@ -12394,6 +13003,10 @@ msgid "" "``Elgg\\Upgrade\\AsynchronousUpgrade`` class that can be used for " "implementing long-running upgrades." msgstr "" +"De telles migrations et conversions peuvent prendre beaucoup de temps s'il y" +" a beaucoup de données à traiter. C'est pourquoi Elgg fournit la classe " +"``Elgg\\Upgrade\\AsynchronousUpgrade`` qui peut être utilisée pour " +"implémenter des mises à niveau de longue durée." #: ../../guides/upgrading-data.rst:16 msgid "Declaring a plugin upgrade" @@ -12406,6 +13019,10 @@ msgid "" "qualified name of an upgrade class that extends the " "``Elgg\\Upgrade\\AsynchronousUpgrade`` class." msgstr "" +"Le plugin peut communiquer la nécessité d'une mise à niveau avec la clé " +"``upgrades`` dans le fichier ``elgg-plugin.php``. Chaque valeur du tableau " +"doit être le nom complet d'une classe de mise à niveau qui étend la classe " +"``Elgg\\Upgrade\\AsynchronousUpgrade``." #: ../../guides/upgrading-data.rst:22 msgid "Example from ``mod/blog/elgg-plugin.php`` file:" @@ -12442,6 +13059,11 @@ msgid "" "must however declare some constant variables and also take care of marking " "whether each processed item was upgraded successfully or not." msgstr "" +"Une classe qui étend la classe ``Elgg\\Upgrade\\AsynchronousUpgrade`` a " +"beaucoup de liberté sur la façon dont elle souhaite gérer le traitement réel" +" des données. Elle doit cependant déclarer certaines variables constantes et" +" également prendre soin de marquer si chaque élément traité a été mis à " +"niveau avec succès ou non." #: ../../guides/upgrading-data.rst:47 msgid "The basic structure of the class is the following:" @@ -12634,13 +13256,15 @@ msgstr "" #: ../../guides/upgrading-data.rst:212 msgid "getUpgrade()" -msgstr "" +msgstr "getUpgrade()" #: ../../guides/upgrading-data.rst:214 msgid "" "Use this function to get the related ``ElggUpgrade`` entity that is related " "to this upgrade." msgstr "" +"Utilisez cette fonction pour obtenir l'entité ``ElggUpgrade`` associée à " +"cette mise à niveau." #: ../../guides/upgrading-data.rst:218 msgid "Administration interface" @@ -12652,6 +13276,10 @@ msgid "" " listed in the admin panel after triggering the site upgrade from the " "Administration dashboard." msgstr "" +"Chaque mise à niveau étendant la classe " +"``Elgg\\Upgrade\\AsynchronousUpgrade`` est répertoriée dans le panneau " +"d'administration après avoir déclenché la mise à niveau du site depuis le " +"tableau de bord d'administration." #: ../../guides/upgrading-data.rst:224 msgid "While running the upgrades Elgg provides:" @@ -13101,10 +13729,14 @@ msgstr "" #: ../../guides/views.rst:264 msgid "You can `alter a view's inputs <#altering-view-input>`_ by event." msgstr "" +"Vous pouvez `modifier les entrées d'une vue <#altering-view-input>`_ par " +"événement." #: ../../guides/views.rst:265 msgid "You can `alter a view's output <#altering-view-output>`_ by event." msgstr "" +"Vous pouvez `modifier la sortie d'une vue <#altering-view-output>`_ via un " +"événement." #: ../../guides/views.rst:268 msgid "Overriding views" @@ -13148,6 +13780,9 @@ msgid "" "input>` or :ref:`the output ` of the view" " via events." msgstr "" +"Vous souhaiterez peut-être plutôt modifier :ref:`l'entrée input " +"` ou :ref:`la sortie output " +"` de la vue via des événements." #: ../../guides/views.rst:291 msgid "" @@ -13226,10 +13861,13 @@ msgid "" ":ref:`event ` ``[\"view_vars\", $view_name]``. " "Each registered handler function is passed these arguments:" msgstr "" +"Avant le rendu de chaque vue, le tableau ``$vars`` est filtré par l' " +":ref:`événement ` ``[\"view_vars\", $view_name]``." +" Chaque fonction de gestionnaire enregistrée reçoit ces arguments :" #: ../../guides/views.rst:342 msgid "``$event`` - the string ``\"view_vars\"``" -msgstr "" +msgstr "``$event`` - la chaîne ``\"view_vars\"``" #: ../../guides/views.rst:343 ../../guides/views.rst:381 msgid "" @@ -13290,10 +13928,14 @@ msgid "" "list#views>` ``[\"view\", $view_name]`` before being returned by " "``elgg_view()``. Each registered handler function is passed these arguments:" msgstr "" +"La sortie de chaque vue est exécutée via l':ref:`événement ` ``[\"view\", $view_name]`` avant d'être renvoyée par " +"``elgg_view()``. Chaque fonction de gestionnaire enregistrée reçoit ces " +"arguments :" #: ../../guides/views.rst:380 msgid "``$event`` - the string ``\"view\"``" -msgstr "" +msgstr "``$event`` - la chaîne ``\"view\"``" #: ../../guides/views.rst:382 msgid "``$result`` - the modified output of the view" @@ -13326,12 +13968,19 @@ msgid "" "value will be returned as a string. View extensions will not be used and the" " ``view`` event will not be triggered." msgstr "" +"Vous pouvez prédéfinir la sortie de la vue en définissant " +"``$vars['__view_output']``. La valeur sera renvoyée sous forme de chaîne. " +"Les extensions de vue ne seront pas utilisées et l'événement ``view`` ne " +"sera pas déclenché." #: ../../guides/views.rst:430 msgid "" "For ease of use you can also use a already existing default event callback " "to prevent output ``\\Elgg\\Values::preventViewOutput``" msgstr "" +"Pour plus de facilité d'utilisation, vous pouvez également utiliser un " +"callback d'événement par défaut déjà existant pour bloquer la sortie " +"``\\Elgg\\Values::preventViewOutput``" #: ../../guides/views.rst:435 msgid "" @@ -13472,6 +14121,11 @@ msgid "" "(which is used by the header) in order to provide RSS autodiscovery, which " "is why you can see the orange RSS icon on those pages in some browsers." msgstr "" +"Elgg sait qu'il peut fournir automatiquement un flux RSS sur les pages qui " +"utilisent ``elgg_list_entities``. Il initialise l'événement " +"``[\"head\",\"page\"]`` (qui est utilisé par l'entête) afin de fournir une " +"découverte automatique RSS, c'est pourquoi vous pouvez voir l'icône RSS " +"orange sur ces pages dans certains navigateurs." #: ../../guides/views.rst:499 msgid "" @@ -13639,6 +14293,11 @@ msgid "" "wish to replace an icon with another icon you can write a ``view_vars``, " "``output/icon`` event to replace the icon name with your replacement." msgstr "" +"``elgg_view_icon()`` appelle la vue ``output/icon`` avec le nom d'icône " +"donné et affiche toutes les classes correctes pour restituer l'icône " +"FontAwesome. Si vous souhaitez remplacer une icône par une autre icône, vous" +" pouvez écrire un événement ``view_vars``, ``output/icon`` pour remplacer le" +" nom de l'icône par votre remplacement." #: ../../guides/views.rst:611 msgid "" @@ -13967,6 +14626,10 @@ msgid "" "` to manage which pages are visible through the Walled " "Garden." msgstr "" +"De nombreux plugins étendent Elgg en ajoutant des pages. Le mode Walled " +"Garden empêchera ces pages d’être consultées par les utilisateurs " +"déconnectés. Elgg utilise :doc:`events ` pour gérer quelles " +"pages sont visibles à travers le Walled Garden." #: ../../guides/walled-garden.rst:21 msgid "" @@ -13985,6 +14648,9 @@ msgid "" "by responding to the ``public_pages``, ``walled_garden`` event. The returned" " value is an array of regexp expressions for public pages." msgstr "" +"en répondant à l'événement ``public_pages``, ``walled_garden``. La valeur " +"renvoyée est un tableau d'expressions rationnelles regexp pour les pages " +"publiques." #: ../../guides/walled-garden.rst:26 msgid "" @@ -14094,12 +14760,18 @@ msgid "" "section in the ``elgg-plugin.php`` file of your plugin - during the " "``'register', 'api_methods'`` event" msgstr "" +"Les méthodes API peuvent être exposées de l'une des deux manières : - en " +"utilisant la section ``web_services`` dans le fichier ``elgg-plugin.php`` de" +" votre plugin - ou lors de l'événement ``'register', 'api_methods'`` " #: ../../guides/web-services.rst:48 msgid "" "As an example, let's assume you want to expose a function that echos text " "back to the calling application. The function could look like this" msgstr "" +"À titre d'exemple, supposons que vous souhaitiez exposer une fonction qui " +"renvoie du texte à l'application appelante. La fonction pourrait ressembler " +"à ceci" #: ../../guides/web-services.rst:57 msgid "" @@ -14118,6 +14790,9 @@ msgid "" "will check for the existence of the language key " "``web_services:api_methods:::description``" msgstr "" +"Si aucune ``description`` n'est fournie dans la définition de la méthode " +"API, le système vérifiera l'existence de la clé de langage " +"``web_services:api_methods:::description``" #: ../../guides/web-services.rst:100 msgid "" @@ -14128,12 +14803,21 @@ msgid "" "http://yoursite.com/services/api/rest/json/?method=test.echo&string=testing " "and you should see JSON data like this:" msgstr "" +"Si vous ajoutez ce code à un plugin puis allez sur " +"http://yoursite.com/services/api/rest/json/?method=system.api.list, vous " +"devriez maintenant voir votre méthode ``test.echo`` répertoriée comme un " +"appel API. De plus, pour tester la méthode exposée à partir d'un navigateur " +"Web, vous pouvez accéder à l'URL : " +"http://yoursite.com/services/api/rest/json/?method=test.echo&string=testing " +"et vous devriez voir des données JSON comme celles-ci :" #: ../../guides/web-services.rst:114 msgid "" "Plugins can filter the output of individual API methods by registering a " "handler for ``'rest:output',$method`` event." msgstr "" +"Les plugins peuvent filtrer la sortie de méthodes API individuelles en " +"enregistrant un gestionnaire pour l'événement ``'rest:output',$method``." #: ../../guides/web-services.rst:118 msgid "Response formats" @@ -14153,6 +14837,8 @@ msgstr "" msgid "" "You can also add additional response formats by defining new view types." msgstr "" +"Vous pouvez également ajouter des formats de réponse supplémentaires en " +"définissant de nouveaux types de vues." #: ../../guides/web-services.rst:126 msgid "Parameters" @@ -14314,6 +15000,8 @@ msgstr "" msgid "" "Now, let's expose it and make the number of minutes a required parameter:" msgstr "" +"Maintenant, exposons-le et faisons du nombre de minutes un paramètre " +"obligatoire :" #: ../../guides/web-services.rst:273 msgid "" @@ -14476,6 +15164,8 @@ msgid "" "The first step is registering a callback function for the ``'rest', 'init'``" " event:" msgstr "" +"La première étape consiste à enregistrer une fonction de rappel pour " +"l'événement ``'rest', 'init'`` :" #: ../../guides/web-services.rst:381 msgid "" @@ -14971,13 +15661,16 @@ msgstr "" #: ../../guides/widgets.rst:142 msgid "Register widgets in an event" -msgstr "" +msgstr "Enregistrez des widgets dans un événement " #: ../../guides/widgets.rst:143 msgid "" "If, for example, you wish to conditionally register widgets you can also use" " an event to register widgets." msgstr "" +"Si, par exemple, vous souhaitez enregistrer des widgets de manière " +"conditionnelle, vous pouvez également utiliser un événement pour enregistrer" +" des widgets." #: ../../guides/widgets.rst:166 msgid "Modify widget properties of existing widget registration" @@ -14992,6 +15685,12 @@ msgid "" " definition. If you want even more control you can also use the ``handlers, " "widgets`` event to change the widget definition." msgstr "" +"Si, par exemple, vous souhaitez modifier les contextes autorisés d'un widget" +" déjà enregistré, vous pouvez le faire en ré-enregistrant le widget avec " +"``elgg_register_widget_type``, car cela remplacera une définition de widget " +"déjà existante. Si vous souhaitez encore plus de contrôle, vous pouvez " +"également utiliser l'événement ``handlers, widgets`` pour modifier la " +"définition du widget." #: ../../guides/widgets.rst:188 msgid "Default widgets" @@ -15011,6 +15710,8 @@ msgid "" "To announce default widget support in your plugin, register for the " "``get_list, default_widgets`` event:" msgstr "" +"Pour annoncer le support des widgets par défaut dans votre plugin, " +"enregistrez-vous à l'événement ``get_list, default_widgets`` :" #: ../../guides/widgets.rst:215 msgid "" @@ -15018,6 +15719,10 @@ msgid "" "default widget support and when to create default widgets. Arrays require " "the following keys to be defined:" msgstr "" +"Dans le gestionnaire d'événements, poussez un tableau dans la valeur de " +"retour définissant votre prise en charge de widget par défaut et quand créer" +" des widgets par défaut. Les tableaux nécessitent la définition des clés " +"suivantes :" #: ../../guides/widgets.rst:217 msgid "" @@ -15067,7 +15772,7 @@ msgstr "" #: ../../guides/widgets.rst:225 msgid "To have widgets be created you need to register the following event:" -msgstr "" +msgstr "Pour créer des widgets, vous devez enregistrer l'événement suivant :" #: ../../guides/widgets.rst:231 msgid "" diff --git a/docs/locale/fr/LC_MESSAGES/index.mo b/docs/locale/fr/LC_MESSAGES/index.mo index 4c11e9de880..8d035390a62 100644 Binary files a/docs/locale/fr/LC_MESSAGES/index.mo and b/docs/locale/fr/LC_MESSAGES/index.mo differ diff --git a/docs/locale/fr/LC_MESSAGES/index.po b/docs/locale/fr/LC_MESSAGES/index.po index 4f296400cce..34f7006d4aa 100644 --- a/docs/locale/fr/LC_MESSAGES/index.po +++ b/docs/locale/fr/LC_MESSAGES/index.po @@ -12,7 +12,7 @@ msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-31 15:46+0200\n" +"POT-Creation-Date: 2023-12-15 13:56+0100\n" "PO-Revision-Date: 2023-04-05 07:42+0000\n" "Last-Translator: Florian DANIEL aka Facyla , 2023\n" "Language-Team: French (https://app.transifex.com/elgg/teams/11337/fr/)\n" @@ -48,7 +48,7 @@ msgid "" "**Well-documented core API** that allows developers to kick start their new " "project with a simple learning curve" msgstr "" -"**Une API bien documentée** qui permet aux développeurs d'accélérer leurs " +"**Une API bien documentée** qui permet aux développeurs de démarrer leurs " "nouveaux projets avec une courbe d'apprentissage simple" #: ../../index.rst:11 @@ -64,7 +64,7 @@ msgid "" "**Flexible system of events** that allows plugins to extend and modify most " "aspects of application's functionality and behavior" msgstr "" -"**Système flexible d'événements** qui permet aux plugins d'étendre et de " +"Un **Système flexible d'événements** qui permet aux plugins d'étendre et de " "modifier la plupart des fonctionnalités et le comportement de l'application" #: ../../index.rst:13 @@ -140,16 +140,16 @@ msgstr "" #: ../../index.rst:21 msgid "**Groups** - out of the box support for user groups" -msgstr "**Groupes** - support intégré pour des groupes d'utilisateurs" +msgstr "Des **Groupes** - support natif de groupes d'utilisateurs" #: ../../index.rst:22 msgid "" "**File storage** powered by flexible API that allows plugins to store user-" "generated files and serve/stream them without booting the engine" msgstr "" -"**Stockage de fichiers** supporté par une API flexible qui permet aux " -"plugins de stocker les fichiers créés par les utilisateurs et de les " -"servir/streamer sans démarrer le moteur" +"Un système de **Stockage de fichiers** fourni par une API flexible qui " +"permet aux plugins de stocker les fichiers créés par les utilisateurs et de " +"les servir/streamer sans démarrer le moteur" #: ../../index.rst:23 msgid "" @@ -157,16 +157,16 @@ msgid "" "site and email notifications and implement integrations with other their-" "party services" msgstr "" -"**Un Service de Notifications** qui permet aux applications d'abonner des " -"utilisateurs aux notifications sur le site ou par e-mail, et d'implémenter " -"l'intégration avec d'autres services tierce-partie" +"Un **Service de Notifications** qui permet aux applications d'abonner des " +"utilisateurs à des notifications sur le site ou par e-mail, et d'implémenter" +" l'intégration avec d'autres services tierce-partie" #: ../../index.rst:24 msgid "" "**RPC web services** that can be used for complex integrations with external" " applications and mobile clients" msgstr "" -"**Des Services Web RPC** qui peuvent être utilisés pour des intégrations " +"Des **Services Web RPC** qui peuvent être utilisés pour des intégrations " "complexes avec des applications externes et des clients mobiles" #: ../../index.rst:25 @@ -174,7 +174,7 @@ msgid "" "**Internationalization** and localization of Elgg applications is simple and" " can be integrated with third-party services such as Transifex" msgstr "" -"**L'Internationalisation** et la localisation des applications Elgg est " +"L'**Internationalisation** et la localisation des applications Elgg est " "simple et peut être intégrée avec des services tierce-partie tels que " "Transifex" @@ -183,8 +183,8 @@ msgid "" "**Elgg community** that can help with any arising issues and hosts a " "repository of **1000+ open source plugins**" msgstr "" -"**La communauté Elgg** peut aider sur n'importe quelle problématique, et " -"héberge un répertoire de **plus de 1000 plugins open source**" +"La **Communauté Elgg** peut aider sur n'importe quelle problématique, et " +"héberge un répertoire de **plusieurs milliersde plugins open source**" #: ../../index.rst:28 msgid "Under the hood:" @@ -214,7 +214,7 @@ msgstr "Laminas Mail gère les e-mails sortants" #: ../../index.rst:35 msgid "htmLawed XSS filters" -msgstr "Filtres XSS htmLawed" +msgstr "Des Filtres XSS htmLawed" #: ../../index.rst:36 msgid "DBAL" @@ -222,7 +222,7 @@ msgstr "DBAL" #: ../../index.rst:37 msgid "Phinx database migrations" -msgstr "Migrations de base de donnée Phinx" +msgstr "Migrations de base de donnée avec Phinx" #: ../../index.rst:38 msgid "CSS-Crush for CSS preprocessing" @@ -263,11 +263,11 @@ msgstr "intranets privés ou professionnels" #: ../../index.rst:53 msgid "dating" -msgstr "rencontres" +msgstr "sites de rencontres" #: ../../index.rst:54 msgid "educational" -msgstr "éducatifs" +msgstr "plateformes éducatives" #: ../../index.rst:55 msgid "company blog" diff --git a/docs/locale/fr/LC_MESSAGES/intro.mo b/docs/locale/fr/LC_MESSAGES/intro.mo index 72d213d9ed2..f1c1053e58c 100644 Binary files a/docs/locale/fr/LC_MESSAGES/intro.mo and b/docs/locale/fr/LC_MESSAGES/intro.mo differ diff --git a/docs/locale/fr/LC_MESSAGES/intro.po b/docs/locale/fr/LC_MESSAGES/intro.po index 85fcc9c5d6d..c78156373dd 100644 --- a/docs/locale/fr/LC_MESSAGES/intro.po +++ b/docs/locale/fr/LC_MESSAGES/intro.po @@ -12,7 +12,7 @@ msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-31 15:46+0200\n" +"POT-Creation-Date: 2023-12-15 13:56+0100\n" "PO-Revision-Date: 2023-04-05 07:42+0000\n" "Last-Translator: Florian DANIEL aka Facyla , 2023\n" "Language-Team: French (https://app.transifex.com/elgg/teams/11337/fr/)\n" @@ -251,11 +251,11 @@ msgstr "" msgid "Available commands" msgstr "Commandes disponibles" -#: ../../intro/elgg-cli.rst:94 +#: ../../intro/elgg-cli.rst:108 msgid "Adding custom commands" msgstr "Ajouter des commandes personnalisées" -#: ../../intro/elgg-cli.rst:96 +#: ../../intro/elgg-cli.rst:110 msgid "" "Plugins can add their commands to the CLI application, by adding command " "class name via a configuration in ``elgg-plugin.php`` or via the " @@ -267,7 +267,7 @@ msgstr "" "plugin.php`` ou via l'événement ``'commands','cli'``. La classe de la " "commande doit étendre ``\\Elgg\\CLI\\Command``." -#: ../../intro/elgg-cli.rst:114 +#: ../../intro/elgg-cli.rst:128 msgid "" "Custom commands are based on `Symfony Console Commands`_. Please refer to " "their documentation for more details." diff --git a/docs/locale/fr/LC_MESSAGES/plugins.mo b/docs/locale/fr/LC_MESSAGES/plugins.mo index 277aad6e08f..acfc6cf14b0 100644 Binary files a/docs/locale/fr/LC_MESSAGES/plugins.mo and b/docs/locale/fr/LC_MESSAGES/plugins.mo differ diff --git a/docs/locale/fr/LC_MESSAGES/plugins.po b/docs/locale/fr/LC_MESSAGES/plugins.po index c23d1863bda..ba44b139cf4 100644 --- a/docs/locale/fr/LC_MESSAGES/plugins.po +++ b/docs/locale/fr/LC_MESSAGES/plugins.po @@ -12,7 +12,7 @@ msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-31 15:46+0200\n" +"POT-Creation-Date: 2023-12-15 13:56+0100\n" "PO-Revision-Date: 2023-04-05 07:42+0000\n" "Last-Translator: Florian DANIEL aka Facyla , 2023\n" "Language-Team: French (https://app.transifex.com/elgg/teams/11337/fr/)\n" @@ -488,6 +488,10 @@ msgid "tagcloud" msgstr "tagcloud" #: ../../plugins/index.rst:40 +msgid "theme_sandbox" +msgstr "theme_sandbox" + +#: ../../plugins/index.rst:41 msgid "web_services" msgstr "web_services" diff --git a/docs/locale/fr/LC_MESSAGES/tutorials.mo b/docs/locale/fr/LC_MESSAGES/tutorials.mo index 5eca73cfebf..54aed2f9f47 100644 Binary files a/docs/locale/fr/LC_MESSAGES/tutorials.mo and b/docs/locale/fr/LC_MESSAGES/tutorials.mo differ diff --git a/docs/locale/fr/LC_MESSAGES/tutorials.po b/docs/locale/fr/LC_MESSAGES/tutorials.po index 7d794dd57d5..47ca559c38d 100644 --- a/docs/locale/fr/LC_MESSAGES/tutorials.po +++ b/docs/locale/fr/LC_MESSAGES/tutorials.po @@ -5,15 +5,16 @@ # # Translators: # Jerôme Bakker, 2023 +# Florian DANIEL aka Facyla , 2023 # #, fuzzy msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-31 15:46+0200\n" +"POT-Creation-Date: 2023-12-15 13:56+0100\n" "PO-Revision-Date: 2023-04-05 07:42+0000\n" -"Last-Translator: Jerôme Bakker, 2023\n" +"Last-Translator: Florian DANIEL aka Facyla , 2023\n" "Language-Team: French (https://app.transifex.com/elgg/teams/11337/fr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -476,11 +477,11 @@ msgstr "" " devrait être placé dans le répertoire ``mod/`` situé dans le répertoire " "d'installation de Elgg. Dans notre cas, créez ``mod/hello/``." -#: ../../tutorials/hello_world.rst:13 +#: ../../tutorials/hello_world.rst:14 msgid "Composer file" msgstr "Fichier composer" -#: ../../tutorials/hello_world.rst:15 +#: ../../tutorials/hello_world.rst:16 msgid "" "Elgg requires that your plugin has a composer file that contains information" " about the plugin. Therefore, in the directory you just created, create a " @@ -491,11 +492,11 @@ msgstr "" "``composer.json`` dans le répertoire de votre plugin et copiez ce code " "dedans :" -#: ../../tutorials/hello_world.rst:31 +#: ../../tutorials/hello_world.rst:30 msgid "Registering a route" msgstr "Enregistrer une route" -#: ../../tutorials/hello_world.rst:33 +#: ../../tutorials/hello_world.rst:32 msgid "" "The next step is to register a route which has the purpose of handling " "request that users make to the URL ``https://elgg.example.com/hello``." @@ -504,11 +505,11 @@ msgstr "" "les requêtes que les utilisateurs font vers l'URL " "``https://elgg.example.com/hello``." -#: ../../tutorials/hello_world.rst:36 +#: ../../tutorials/hello_world.rst:35 msgid "Update ``elgg-plugin.php`` to look like this:" msgstr "Mettez à jour ``elgg-plugin.php`` pour qu'il ressemble à ceci :" -#: ../../tutorials/hello_world.rst:51 +#: ../../tutorials/hello_world.rst:50 msgid "" "This registration tells Elgg that it should call the resource view ``hello``" " when a user navigates to ``https://elgg.example.com/hello``." @@ -517,17 +518,17 @@ msgstr "" "``hello`` quand un utilisateur navigue vers " "``https://elgg.example.com/hello``." -#: ../../tutorials/hello_world.rst:55 +#: ../../tutorials/hello_world.rst:54 msgid "View file" msgstr "Fichier de la vue d'affichage" -#: ../../tutorials/hello_world.rst:57 +#: ../../tutorials/hello_world.rst:56 msgid "" "Create ``mod/hello/views/default/resources/hello.php`` with this content:" msgstr "" "Créez ``mod/hello/views/default/resources/hello.php`` avec ce contenu :" -#: ../../tutorials/hello_world.rst:69 +#: ../../tutorials/hello_world.rst:68 msgid "" "The code creates an array of parameters to be given to the " "``elgg_view_layout()`` function, including:" @@ -535,20 +536,20 @@ msgstr "" "Le code crée un tableau de paramètres à passer à la fonction " "``elgg_view_layout()``, comprenant :" -#: ../../tutorials/hello_world.rst:71 +#: ../../tutorials/hello_world.rst:70 msgid "The title of the page" msgstr "Le titre de la page" -#: ../../tutorials/hello_world.rst:72 +#: ../../tutorials/hello_world.rst:71 msgid "The contents of the page" msgstr "Le contenu de la page" -#: ../../tutorials/hello_world.rst:73 +#: ../../tutorials/hello_world.rst:72 msgid "Filter which is left empty because there's currently nothing to filter" msgstr "" "Un filter qui est laissé vide puisqu'il n'y a pour le moment rien à filtrer" -#: ../../tutorials/hello_world.rst:75 +#: ../../tutorials/hello_world.rst:74 msgid "" "This creates the basic layout for the page. The layout is then run through " "``elgg_view_page()`` which assembles and outputs the full page." @@ -557,11 +558,11 @@ msgstr "" "mise en page est ensuite passée à travers ``elgg_view_page()`` qui assemble " "et génère la page complète." -#: ../../tutorials/hello_world.rst:79 +#: ../../tutorials/hello_world.rst:78 msgid "Last step" msgstr "Dernière étape" -#: ../../tutorials/hello_world.rst:81 +#: ../../tutorials/hello_world.rst:80 msgid "" "Finally, activate the plugin through your Elgg administrator page: " "``https://elgg.example.com/admin/plugins`` (the new plugin appears at the " @@ -806,9 +807,9 @@ msgid "" "TinyMCE_ support. However, if you have a wysiwyg that you prefer, you could " "use this tutorial to help you build your own." msgstr "" -"Elgg est distribué avec un plugin pour CKEditor_, et était précédemment " -"distribué avec le support de TinyMCE_. Cependant, s'il y a un éditeur " -"wysiwyg que vous préférez, vous pourriez utiliser ce tutoriel pour " +"Elgg est actuellement distribué avec un plugin pour CKEditor_, et était " +"précédemment distribué avec le support de TinyMCE_. Cependant, s'il y a un " +"éditeur wysiwyg que vous préférez, vous pourriez utiliser ce tutoriel pour " "construire le vôtre." #: ../../tutorials/wysiwyg.rst:12 @@ -821,7 +822,7 @@ msgstr "" "Tous les formulaires dans Elgg devraient essayer d'utiliser les vues de " "saisie situées dans ``views/default/input``. Si ces vues sont utilisées, il " "est plus aisé pour les auteurs de plugins de remplacer une vue, ici " -"``input/longtext``, par leur vue avec wysiwyg." +"``input/longtext``, par une vue avec leur wysiwyg." #: ../../tutorials/wysiwyg.rst:17 msgid "Add the WYSIWYG library code" @@ -836,7 +837,7 @@ msgstr "" "Vous devez maintenant télécharger TinyMCE dans un répertoire de votre " "plugin. Nous vous encourageons fortement à utiliser ``composer`` pour gérer " "les dépendances tierces, car il est tellement plus facile de mettre à niveau" -" et de maintenir de cette façon :" +" et de maintenir de cette façon :" #: ../../tutorials/wysiwyg.rst:28 msgid "Tell Elgg when and how to load TinyMCE" @@ -871,7 +872,7 @@ msgid "" "following code:" msgstr "" "Nous allons le faire en étendant la vue ``input/longtext`` et en incluant du" -" javascript. Créez une vue ``tinymce/longtext`` et ajoutez le code suivant :" +" javascript. Créez une vue ``tinymce/longtext`` et ajoutez le code suivant :" #: ../../tutorials/wysiwyg.rst:70 msgid "" @@ -879,12 +880,12 @@ msgid "" "``input/longtext`` view:" msgstr "" "Ensuite, dans le fichier ``elgg-plugin.php`` de votre plugin étendez la vue " -"``input/longtext`` :" +"``input/longtext`` :" #: ../../tutorials/wysiwyg.rst:82 msgid "" "That's it! Now every time someone uses ``input/longtext`` TinyMCE will be " "loaded and applied to that textarea." msgstr "" -"C'est ça! Maintenant, chaque fois que quelqu'un utilise ``input/longtext`` " -"TinyMCE sera chargé et appliqué à ce textarea." +"Et voilà ! Maintenant, chaque fois que quelqu'un utilise ``input/longtext`` " +"TinyMCE sera chargé et appliqué à ce champ de saisie de texte." diff --git a/docs/locale/pot/admin.pot b/docs/locale/pot/admin.pot index 8f7e8abb1c7..e1f401d3a52 100644 --- a/docs/locale/pot/admin.pot +++ b/docs/locale/pot/admin.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-19 13:11+0200\n" +"POT-Creation-Date: 2024-03-21 10:41+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -1403,119 +1403,119 @@ msgstr "" msgid "Uncomment and populate the following sections in ``settings.php``" msgstr "" -#: ../../admin/performance.rst:195 +#: ../../admin/performance.rst:201 msgid "Optionaly if you run multiple Elgg installations but use ony one Memcache server, you may want to add a namespace prefix. In order to do this, uncomment the following line" msgstr "" -#: ../../admin/performance.rst:203 +#: ../../admin/performance.rst:209 msgid "Squid" msgstr "" -#: ../../admin/performance.rst:205 +#: ../../admin/performance.rst:211 msgid "We have had good results by using `Squid`_ to cache images for us." msgstr "" -#: ../../admin/performance.rst:211 +#: ../../admin/performance.rst:217 msgid "Bytecode caching" msgstr "" -#: ../../admin/performance.rst:213 +#: ../../admin/performance.rst:219 msgid "There are numerous PHP code caches available on the market. These speed up your site by caching the compiled byte code from your script meaning that your server doesn't have to compile the PHP code each time it is executed." msgstr "" -#: ../../admin/performance.rst:219 +#: ../../admin/performance.rst:225 msgid "Direct file serving" msgstr "" -#: ../../admin/performance.rst:221 +#: ../../admin/performance.rst:227 msgid "If your server can be configured to support the X-Sendfile or X-Accel headers, you can configure it to be used in ``settings.php``. This allows your web server to directly stream files to the client instead of using PHP's ``readfile()``." msgstr "" -#: ../../admin/performance.rst:226 +#: ../../admin/performance.rst:232 msgid "Composer Autoloader Optimization" msgstr "" -#: ../../admin/performance.rst:228 +#: ../../admin/performance.rst:234 msgid "The Composer autoloader is responsible for loading classes provided by dependencies of Elgg. The way the autoloader works is it searches for a classname in the installed dependencies. While this is mostly a fast process it can be optimized." msgstr "" -#: ../../admin/performance.rst:231 +#: ../../admin/performance.rst:237 msgid "You can optimize the autoloader 2 different ways. The first is in the commandline, the other is in the ``composer.json`` of your project." msgstr "" -#: ../../admin/performance.rst:233 +#: ../../admin/performance.rst:239 msgid "If you want to optimize the autoloader using the commandline use the ``-o`` flag. The disadvantage is you have to add the ``-o`` flag every time you run Composer." msgstr "" -#: ../../admin/performance.rst:244 +#: ../../admin/performance.rst:250 msgid "The second option is to add the optimization to your ``composer.json`` file, that way you never forget it." msgstr "" -#: ../../admin/performance.rst:257 +#: ../../admin/performance.rst:263 msgid "Check out the `Autoloader Optimization`__ page for more information about how to optimize the Composer autoloader." msgstr "" -#: ../../admin/performance.rst:263 +#: ../../admin/performance.rst:269 msgid "As of Elgg 3.0 all the `downloads`__ of Elgg from the website have the optimized autoloader." msgstr "" -#: ../../admin/performance.rst:268 +#: ../../admin/performance.rst:274 msgid "Hosting" msgstr "" -#: ../../admin/performance.rst:270 +#: ../../admin/performance.rst:276 msgid "Don't expect to run a site catering for millions of users on a cheap shared host. You will need to have your own host hardware and access over the configuration, as well as lots of bandwidth and memory available." msgstr "" -#: ../../admin/performance.rst:275 +#: ../../admin/performance.rst:281 msgid "Memory, CPU and bandwidth" msgstr "" -#: ../../admin/performance.rst:277 +#: ../../admin/performance.rst:283 msgid "Due to the nature of caching, all caching solutions will require memory. It is a fairly cheap return to throw memory and CPU at the problem." msgstr "" -#: ../../admin/performance.rst:280 +#: ../../admin/performance.rst:286 msgid "On advanced hardware it is likely that bandwidth is going to be your bottleneck before the server itself. Ensure that your host can support the load you are suggesting." msgstr "" -#: ../../admin/performance.rst:284 +#: ../../admin/performance.rst:290 msgid "Configuration" msgstr "" -#: ../../admin/performance.rst:286 +#: ../../admin/performance.rst:292 msgid "Lastly, take a look at your configuration as there are a few gotchas that can catch people." msgstr "" -#: ../../admin/performance.rst:288 +#: ../../admin/performance.rst:294 msgid "For example, out of the box, Apache can handle quite a high load. However, most distros of Linux come with mysql configured for small sites. This can result in Apache processes getting stalled waiting to talk to one very overloaded MySQL process." msgstr "" -#: ../../admin/performance.rst:293 +#: ../../admin/performance.rst:299 msgid "Check for poorly-behaved plugins" msgstr "" -#: ../../admin/performance.rst:295 +#: ../../admin/performance.rst:301 msgid "Plugins can be programmed in a very naive way and this can cause your whole site to feel slow." msgstr "" -#: ../../admin/performance.rst:297 +#: ../../admin/performance.rst:303 msgid "Try disabling some plugins to see if that noticeably improves performance. Once you've found a likely offender, go to the original plugin author and report your findings." msgstr "" -#: ../../admin/performance.rst:301 +#: ../../admin/performance.rst:307 msgid "Use client-rendered HTML" msgstr "" -#: ../../admin/performance.rst:303 +#: ../../admin/performance.rst:309 msgid "We've found that at a certain point, much of the time spent on the server is simply building the HTML of the page with Elgg's views system." msgstr "" -#: ../../admin/performance.rst:306 +#: ../../admin/performance.rst:312 msgid "It's very difficult to cache the output of templates since they can generally take arbitrary inputs. Instead of trying to cache the HTML output of certain pages or views, the suggestion is to switch to an HTML-based templating system so that the user's browser can cache the templates themselves. Then have the user's computer do the work of generating the output by applying JSON data to those templates." msgstr "" -#: ../../admin/performance.rst:311 +#: ../../admin/performance.rst:317 msgid "This can be very effective, but has the downside of being significant extra development cost. The Elgg team is looking to integrate this strategy into Elgg directly, since it is so effective especially on pages with repeated or hidden content." msgstr "" diff --git a/docs/locale/pot/appendix.pot b/docs/locale/pot/appendix.pot index 5ba2d8060b1..86762927d2e 100644 --- a/docs/locale/pot/appendix.pot +++ b/docs/locale/pot/appendix.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-19 13:11+0200\n" +"POT-Creation-Date: 2024-03-21 10:41+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -44,6 +44,7 @@ msgstr "" #: ../../appendix/upgrade-notes/4.1-to-4.2.rst:6 #: ../../appendix/upgrade-notes/4.2-to-4.3.rst:6 #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:6 +#: ../../appendix/upgrade-notes/5.0-to-5.1.rst:6 msgid "Contents" msgstr "" @@ -1364,26 +1365,34 @@ msgid "``upgrade``" msgstr "" #: ../../appendix/releases.rst:116 -msgid "Views" +msgid "Test suite" msgstr "" #: ../../appendix/releases.rst:118 +msgid "The Elgg PHPUnit test suite files are not considered part of the public API and can be changed / removed at any time." +msgstr "" + +#: ../../appendix/releases.rst:121 +msgid "Views" +msgstr "" + +#: ../../appendix/releases.rst:123 msgid "View names are API." msgstr "" -#: ../../appendix/releases.rst:119 +#: ../../appendix/releases.rst:124 msgid "View arguments ($vars array) are API." msgstr "" -#: ../../appendix/releases.rst:120 +#: ../../appendix/releases.rst:125 msgid "Removing views or renaming views follows API deprecation policies." msgstr "" -#: ../../appendix/releases.rst:121 +#: ../../appendix/releases.rst:126 msgid "Adding new views requires a minor version change." msgstr "" -#: ../../appendix/releases.rst:122 +#: ../../appendix/releases.rst:127 msgid "View output is not API and can be changed between patch releases." msgstr "" @@ -1708,11 +1717,20 @@ msgstr "" msgid "5.0" msgstr "" +#: ../../appendix/support.rst:79 #: ../../appendix/support.rst:81 -msgid "6.0" +msgid "October 2023" msgstr "" #: ../../appendix/support.rst:81 +msgid "5.1" +msgstr "" + +#: ../../appendix/support.rst:83 +msgid "6.0" +msgstr "" + +#: ../../appendix/support.rst:83 msgid "TBD" msgstr "" @@ -3440,6 +3458,7 @@ msgstr "" #: ../../appendix/upgrade-notes/2.1-to-2.2.rst:19 #: ../../appendix/upgrade-notes/2.2-to-2.3.rst:38 +#: ../../appendix/upgrade-notes/5.0-to-5.1.rst:15 msgid "Deprecated Views" msgstr "" @@ -6807,6 +6826,7 @@ msgid "The legacy style hook and event callback arguments are deprecated. You sh msgstr "" #: ../../appendix/upgrade-notes/3.0-to-3.1.rst:76 +#: ../../appendix/upgrade-notes/5.0-to-5.1.rst:22 msgid "Deprecated Routes" msgstr "" @@ -10273,7 +10293,7 @@ msgid "``elgg.set_triggered_hook``" msgstr "" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:102 -msgid "``elgg.trigger_hook`` use the ``trigger`` function provide by the ``elgg\\hooks`` module" +msgid "``elgg.trigger_hook`` use the ``trigger`` function provided by the ``elgg\\hooks`` module" msgstr "" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:105 @@ -10385,7 +10405,7 @@ msgid "``elgg_get_system_cache()`` now returns an instance of ``\\Elgg\\Cache\\B msgstr "" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:186 -msgid "``elgg_get_uploaded_file()`` now returns ``null`` no file could be found or the file was invalid" +msgid "``elgg_get_uploaded_file()`` now returns ``null`` if no file could be found or the file was invalid" msgstr "" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:187 @@ -11345,7 +11365,7 @@ msgid "``elgg_register_plugin_hook_handler`` use ``elgg_register_event_handler`` msgstr "" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:443 -msgid "``elgg_trigger_plugin_hook`` use ``elgg_trigger_event_result``" +msgid "``elgg_trigger_plugin_hook`` use ``elgg_trigger_event_results``" msgstr "" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:444 @@ -11465,3 +11485,31 @@ msgstr "" #: ../../appendix/upgrade-notes/4.x-to-5.0.rst:495 msgid "The ``REFERRER`` constant has been changed to a string with the value ``__elgg_referrer``" msgstr "" + +#: ../../appendix/upgrade-notes/5.0-to-5.1.rst:2 +msgid "From 5.0 to 5.1" +msgstr "" + +#: ../../appendix/upgrade-notes/5.0-to-5.1.rst:9 +msgid "Changes in the DOM structure" +msgstr "" + +#: ../../appendix/upgrade-notes/5.0-to-5.1.rst:11 +msgid "In order to improve accessibility the HTML DOM structure has been changed slightly. Some sections of the page have been changed from a ``div`` to ``header``, ``main`` or ``footer``. The classes or place in the DOM has not been changed." +msgstr "" + +#: ../../appendix/upgrade-notes/5.0-to-5.1.rst:17 +msgid "``page/elements/
/after`` is deprecated: Extend the correct ``page/elements/
``" +msgstr "" + +#: ../../appendix/upgrade-notes/5.0-to-5.1.rst:18 +msgid "``page/elements/
/before`` is deprecated: Prepend the correct ``page/elements/
``" +msgstr "" + +#: ../../appendix/upgrade-notes/5.0-to-5.1.rst:19 +msgid "``resources/comments/edit`` is deprecated: This resource is no longer in use" +msgstr "" + +#: ../../appendix/upgrade-notes/5.0-to-5.1.rst:24 +msgid "``edit:object:comment`` is deprecated: Editing comments uses an inline form" +msgstr "" diff --git a/docs/locale/pot/contribute.pot b/docs/locale/pot/contribute.pot index b2c9af50e1a..50db3a619f8 100644 --- a/docs/locale/pot/contribute.pot +++ b/docs/locale/pot/contribute.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-19 13:11+0200\n" +"POT-Creation-Date: 2024-03-21 10:41+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -729,7 +729,7 @@ msgid "Compliance with `PSR-1`__ is encouraged, but not strictly required." msgstr "" #: ../../contribute/code.rst:479 -#: ../../contribute/core/move_plugin.rst:124 +#: ../../contribute/core/move_plugin.rst:121 msgid "Documentation" msgstr "" @@ -993,73 +993,73 @@ msgstr "" msgid "Make sure the ``composer.json`` of the plugin contains all the relevant information. Here is an example:" msgstr "" -#: ../../contribute/core/move_plugin.rst:80 +#: ../../contribute/core/move_plugin.rst:77 msgid "The ``conflict`` rule is there to help prevent the installation of this plugin in an unsupported Elgg version." msgstr "" -#: ../../contribute/core/move_plugin.rst:82 +#: ../../contribute/core/move_plugin.rst:79 msgid "Add the repository to `Packagist`_, for the existing repositories this was already done. Make sure `Packagist`_ is updated correctly with all the commits." msgstr "" -#: ../../contribute/core/move_plugin.rst:86 +#: ../../contribute/core/move_plugin.rst:83 msgid "Tag a release" msgstr "" -#: ../../contribute/core/move_plugin.rst:88 +#: ../../contribute/core/move_plugin.rst:85 msgid "In order for Composer to be able to cache the plugin for faster installation, a release has to be made on the repository. Probably the first version that needs to be tagged is the same version as mentioned in the ``elgg-plugin.php`` or ``composer.json``. After this development can begin, following the `Semver`_ versioning scheme." msgstr "" -#: ../../contribute/core/move_plugin.rst:93 -#: ../../contribute/core/move_plugin.rst:109 +#: ../../contribute/core/move_plugin.rst:90 +#: ../../contribute/core/move_plugin.rst:106 #: ../../contribute/i18n.rst:2 msgid "Translations" msgstr "" -#: ../../contribute/core/move_plugin.rst:95 +#: ../../contribute/core/move_plugin.rst:92 msgid "If the translations for the plugin need to be managed by `Transifex`_, add the plugin to `Transifex`_." msgstr "" -#: ../../contribute/core/move_plugin.rst:98 +#: ../../contribute/core/move_plugin.rst:95 msgid "Elgg core cleanup" msgstr "" -#: ../../contribute/core/move_plugin.rst:100 +#: ../../contribute/core/move_plugin.rst:97 msgid "Now that the plugin has been moved to it's own repository, it's time to make a Pull Request on Elgg core to remove the original code." msgstr "" -#: ../../contribute/core/move_plugin.rst:103 +#: ../../contribute/core/move_plugin.rst:100 msgid "Remove the plugin" msgstr "" -#: ../../contribute/core/move_plugin.rst:105 +#: ../../contribute/core/move_plugin.rst:102 msgid "Delete the ``mod`` folder for the plugin" msgstr "" -#: ../../contribute/core/move_plugin.rst:106 +#: ../../contribute/core/move_plugin.rst:103 msgid "Search for the plugin name in core to find any references which also need to be removed (eg. old docs, special tests, etc.)" msgstr "" -#: ../../contribute/core/move_plugin.rst:111 +#: ../../contribute/core/move_plugin.rst:108 msgid "Since the plugin no longer is part of Elgg core, make sure the configuration of `Transifex`_ no longer contains the plugin." msgstr "" -#: ../../contribute/core/move_plugin.rst:114 +#: ../../contribute/core/move_plugin.rst:111 msgid "Bundled" msgstr "" -#: ../../contribute/core/move_plugin.rst:116 +#: ../../contribute/core/move_plugin.rst:113 msgid "If the plugin still comes bundled with the release of a new Elgg version, make sure to add the plugin to the ``composer.json``." msgstr "" -#: ../../contribute/core/move_plugin.rst:119 +#: ../../contribute/core/move_plugin.rst:116 msgid "Composer" msgstr "" -#: ../../contribute/core/move_plugin.rst:121 +#: ../../contribute/core/move_plugin.rst:118 msgid "Check the core composer dependencies if requirements that were specific for the removed plugin can also be removed in the core dependencies." msgstr "" -#: ../../contribute/core/move_plugin.rst:126 +#: ../../contribute/core/move_plugin.rst:123 msgid "Add a mention in the :doc:`/appendix/upgrade-notes` documentation that the plugin was removed from Elgg core." msgstr "" @@ -1180,12 +1180,11 @@ msgid "Make a PR with translation updates" msgstr "" #: ../../contribute/core/releases.rst:75 -#: ../../contribute/core/releases.rst:113 msgid "Install the prerequisites:" msgstr "" #: ../../contribute/core/releases.rst:85 -#: ../../contribute/core/releases.rst:121 +#: ../../contribute/core/releases.rst:115 msgid "On Windows you need to run these command in a console with admin privileges" msgstr "" @@ -1217,196 +1216,196 @@ msgstr "" msgid "Visit ``https://github.com/Elgg/Elgg/compare/...`` and submit the PR if there is anything that needs to be merged up." msgstr "" -#: ../../contribute/core/releases.rst:123 +#: ../../contribute/core/releases.rst:117 msgid "Run the ``release.php`` script. For example, to release 1.12.5:" msgstr "" -#: ../../contribute/core/releases.rst:130 +#: ../../contribute/core/releases.rst:124 msgid "This creates a ``release-1.12.5`` branch in your local repo." msgstr "" -#: ../../contribute/core/releases.rst:132 +#: ../../contribute/core/releases.rst:126 msgid "Next, submit a pull request via GitHub for automated testing and approval by another developer:" msgstr "" -#: ../../contribute/core/releases.rst:139 +#: ../../contribute/core/releases.rst:133 msgid "Tag the release" msgstr "" -#: ../../contribute/core/releases.rst:141 +#: ../../contribute/core/releases.rst:135 msgid "Once approved and merged, create a release on GitHub:" msgstr "" -#: ../../contribute/core/releases.rst:143 +#: ../../contribute/core/releases.rst:137 msgid "Goto releases" msgstr "" -#: ../../contribute/core/releases.rst:144 +#: ../../contribute/core/releases.rst:138 msgid "Click 'Draft a new release'" msgstr "" -#: ../../contribute/core/releases.rst:145 +#: ../../contribute/core/releases.rst:139 msgid "Enter the version" msgstr "" -#: ../../contribute/core/releases.rst:146 +#: ../../contribute/core/releases.rst:140 msgid "Select the correct branch (eg 1.12 for a 1.12.x release, 2.3 for a 2.3.x release, etc)" msgstr "" -#: ../../contribute/core/releases.rst:147 +#: ../../contribute/core/releases.rst:141 msgid "Set the release title as 'Elgg {version}'" msgstr "" -#: ../../contribute/core/releases.rst:148 +#: ../../contribute/core/releases.rst:142 msgid "Paste the CHANGELOG.md part related to this release in the description" msgstr "" -#: ../../contribute/core/releases.rst:152 +#: ../../contribute/core/releases.rst:146 msgid "GitHub is setup to listen to the creation of a new release to automaticly make the ZIP release of Elgg. After the release was created wait a few minutes and the ZIP should be added to the release." msgstr "" -#: ../../contribute/core/releases.rst:155 +#: ../../contribute/core/releases.rst:149 msgid "Some final administration" msgstr "" -#: ../../contribute/core/releases.rst:157 +#: ../../contribute/core/releases.rst:151 msgid "Mark GitHub release milestones as completed" msgstr "" -#: ../../contribute/core/releases.rst:158 +#: ../../contribute/core/releases.rst:152 msgid "Move unresolved tickets in released milestones to later milestones" msgstr "" -#: ../../contribute/core/releases.rst:161 +#: ../../contribute/core/releases.rst:155 msgid "Additional actions for the first new minor / major" msgstr "" -#: ../../contribute/core/releases.rst:163 +#: ../../contribute/core/releases.rst:157 msgid "Make a new branch on GitHub (for example 3.3)" msgstr "" -#: ../../contribute/core/releases.rst:164 +#: ../../contribute/core/releases.rst:158 msgid "Set the new branch as the default branch (optional, but suggested for stable releases)" msgstr "" -#: ../../contribute/core/releases.rst:165 +#: ../../contribute/core/releases.rst:159 msgid "Configure `Read The Docs`_ to build the new branch (not the new tag)" msgstr "" -#: ../../contribute/core/releases.rst:166 +#: ../../contribute/core/releases.rst:160 msgid "Configure `Scrutinizer`_ to build the new branch" msgstr "" -#: ../../contribute/core/releases.rst:167 +#: ../../contribute/core/releases.rst:161 msgid "Check the Elgg starter project for potential requirement / config changes in the ``composer.json``" msgstr "" -#: ../../contribute/core/releases.rst:168 +#: ../../contribute/core/releases.rst:162 msgid "Add the new minor / major version to the ``Elgg/community_plugins`` repository so developers can upload plugins for the new release" msgstr "" -#: ../../contribute/core/releases.rst:169 +#: ../../contribute/core/releases.rst:163 msgid "Update the build configuration for the `Elgg reference`_ (on the Elgg.org webserver)" msgstr "" -#: ../../contribute/core/releases.rst:179 +#: ../../contribute/core/releases.rst:173 msgid "Additional action for the first new major" msgstr "" -#: ../../contribute/core/releases.rst:181 +#: ../../contribute/core/releases.rst:175 msgid "On GitHub add a branch protection rule (for example ``4.*``)" msgstr "" -#: ../../contribute/core/releases.rst:182 +#: ../../contribute/core/releases.rst:176 msgid "Configure Scrutinizer to track the new major branches (for example ``4.*``)" msgstr "" -#: ../../contribute/core/releases.rst:185 +#: ../../contribute/core/releases.rst:179 msgid "Update the website" msgstr "" -#: ../../contribute/core/releases.rst:188 +#: ../../contribute/core/releases.rst:182 msgid "Update elgg.org download page" msgstr "" -#: ../../contribute/core/releases.rst:190 +#: ../../contribute/core/releases.rst:184 msgid "Clone https://github.com/Elgg/community" msgstr "" -#: ../../contribute/core/releases.rst:191 +#: ../../contribute/core/releases.rst:185 msgid "Add the new version to ``classes/Elgg/Releases.php``" msgstr "" -#: ../../contribute/core/releases.rst:192 -#: ../../contribute/core/releases.rst:212 +#: ../../contribute/core/releases.rst:186 +#: ../../contribute/core/releases.rst:206 msgid "Commit and push the changes" msgstr "" -#: ../../contribute/core/releases.rst:193 +#: ../../contribute/core/releases.rst:187 msgid "Download the ZIP release from GitHub" msgstr "" -#: ../../contribute/core/releases.rst:194 +#: ../../contribute/core/releases.rst:188 msgid "Upload the ZIP to the elgg.org webserver" msgstr "" -#: ../../contribute/core/releases.rst:202 +#: ../../contribute/core/releases.rst:196 msgid "Update elgg.org" msgstr "" -#: ../../contribute/core/releases.rst:204 +#: ../../contribute/core/releases.rst:198 msgid "Clone https://github.com/Elgg/www.elgg.org" msgstr "" -#: ../../contribute/core/releases.rst:205 +#: ../../contribute/core/releases.rst:199 msgid "(optional) Change the required Elgg version in ``composer.json``" msgstr "" -#: ../../contribute/core/releases.rst:206 +#: ../../contribute/core/releases.rst:200 msgid "Update vendors" msgstr "" -#: ../../contribute/core/releases.rst:213 +#: ../../contribute/core/releases.rst:207 msgid "Pull to live site" msgstr "" -#: ../../contribute/core/releases.rst:222 +#: ../../contribute/core/releases.rst:216 msgid "Go to community admin panel" msgstr "" -#: ../../contribute/core/releases.rst:223 +#: ../../contribute/core/releases.rst:217 msgid "Flush APC cache" msgstr "" -#: ../../contribute/core/releases.rst:224 +#: ../../contribute/core/releases.rst:218 msgid "Run upgrade" msgstr "" -#: ../../contribute/core/releases.rst:227 +#: ../../contribute/core/releases.rst:221 msgid "Make the announcement" msgstr "" -#: ../../contribute/core/releases.rst:229 +#: ../../contribute/core/releases.rst:223 msgid "This should be the very last thing you do." msgstr "" -#: ../../contribute/core/releases.rst:231 +#: ../../contribute/core/releases.rst:225 msgid "Open ``https://github.com/Elgg/Elgg/blob//CHANGELOG.md`` and copy the contents for that version" msgstr "" -#: ../../contribute/core/releases.rst:232 +#: ../../contribute/core/releases.rst:226 msgid "Sign in at https://elgg.org/blog and compose a new blog with a summary" msgstr "" -#: ../../contribute/core/releases.rst:233 +#: ../../contribute/core/releases.rst:227 msgid "Copy in the CHANGELOG contents, clear formatting, and manually remove the SVG anchors" msgstr "" -#: ../../contribute/core/releases.rst:234 +#: ../../contribute/core/releases.rst:228 msgid "Add tags ``release`` and ``elgg2.x`` where x is whatever branch is being released" msgstr "" -#: ../../contribute/core/releases.rst:235 +#: ../../contribute/core/releases.rst:229 msgid "Tweet from the elgg `Twitter account`_" msgstr "" diff --git a/docs/locale/pot/design.pot b/docs/locale/pot/design.pot index cd712ec8dc7..e9b2217dd69 100644 --- a/docs/locale/pot/design.pot +++ b/docs/locale/pot/design.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-19 13:11+0200\n" +"POT-Creation-Date: 2024-03-21 10:41+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/docs/locale/pot/guides.pot b/docs/locale/pot/guides.pot index 08770df09fb..fe07e534c75 100644 --- a/docs/locale/pot/guides.pot +++ b/docs/locale/pot/guides.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-19 13:11+0200\n" +"POT-Creation-Date: 2024-03-21 10:41+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -565,281 +565,289 @@ msgid "``input/userpicker`` - renders an Elgg user autocomplete" msgstr "" #: ../../guides/actions.rst:381 +msgid "``input/grouppicker`` - renders an Elgg group autocomplete" +msgstr "" + +#: ../../guides/actions.rst:382 +msgid "``input/objectpicker`` - renders an Elgg object autocomplete" +msgstr "" + +#: ../../guides/actions.rst:383 msgid "``input/location`` renders an Elgg location input" msgstr "" -#: ../../guides/actions.rst:384 +#: ../../guides/actions.rst:386 msgid "Files and images" msgstr "" -#: ../../guides/actions.rst:386 +#: ../../guides/actions.rst:388 msgid "Use the ``input/file`` view in your form’s content view." msgstr "" -#: ../../guides/actions.rst:393 +#: ../../guides/actions.rst:395 msgid "If you wish to upload an icon for entity you can use the helper view ``entity/edit/icon``. This view shows a file input for uploading a new icon for the entity, an thumbnail of the current icon and the option to remove the current icon." msgstr "" -#: ../../guides/actions.rst:397 +#: ../../guides/actions.rst:399 msgid "The view supports some variables to control the output" msgstr "" -#: ../../guides/actions.rst:399 +#: ../../guides/actions.rst:401 msgid "``entity`` - the entity to add/remove the icon for. If provided based on this entity the thumbnail and remove option wil be shown" msgstr "" -#: ../../guides/actions.rst:400 +#: ../../guides/actions.rst:402 msgid "``entity_type`` - the entity type for which the icon will be uploaded. Plugins could find this useful, maybe to validate icon sizes" msgstr "" -#: ../../guides/actions.rst:401 +#: ../../guides/actions.rst:403 msgid "``entity_subtype`` - the entity subtype for which the icon will be uploaded. Plugins could find this useful, maybe to validate icon sizes" msgstr "" -#: ../../guides/actions.rst:402 +#: ../../guides/actions.rst:404 msgid "``icon_type`` - the type of the icon (default: icon)" msgstr "" -#: ../../guides/actions.rst:403 +#: ../../guides/actions.rst:405 msgid "``name`` - name of the input/file (default: icon)" msgstr "" -#: ../../guides/actions.rst:404 +#: ../../guides/actions.rst:406 msgid "``remove_name`` - name of the remove icon toggle (default: $vars['name'] . '_remove')" msgstr "" -#: ../../guides/actions.rst:405 +#: ../../guides/actions.rst:407 msgid "``required`` - is icon upload required (default: false)" msgstr "" -#: ../../guides/actions.rst:406 +#: ../../guides/actions.rst:408 msgid "``cropper_enabled`` - is icon cropping allowed (default: true)" msgstr "" -#: ../../guides/actions.rst:407 +#: ../../guides/actions.rst:409 msgid "``show_remove`` - show the remove icon option (default: true)" msgstr "" -#: ../../guides/actions.rst:408 +#: ../../guides/actions.rst:410 msgid "``show_thumb`` - show the thumb of the entity if available (default: true)" msgstr "" -#: ../../guides/actions.rst:409 +#: ../../guides/actions.rst:411 msgid "``thumb_size`` - the icon size to use as the thumb (default: medium)" msgstr "" -#: ../../guides/actions.rst:411 +#: ../../guides/actions.rst:413 msgid "If using the helper view you can use the following code in you action to save the icon to the entity or remove the current icon." msgstr "" -#: ../../guides/actions.rst:421 +#: ../../guides/actions.rst:423 msgid "Set the enctype of the form to ``multipart/form-data``:" msgstr "" -#: ../../guides/actions.rst:431 +#: ../../guides/actions.rst:433 msgid "The ``enctype`` of all forms that use the method ``POST`` defaults to ``multipart/form-data``." msgstr "" -#: ../../guides/actions.rst:433 +#: ../../guides/actions.rst:435 msgid "In your action file, use ``elgg_get_uploaded_file('your-input-name')`` to access the uploaded file:" msgstr "" -#: ../../guides/actions.rst:440 +#: ../../guides/actions.rst:442 msgid "Sticky forms" msgstr "" -#: ../../guides/actions.rst:442 +#: ../../guides/actions.rst:444 msgid "Sticky forms are forms that retain user input if saving fails. They are \"sticky\" because the user's data \"sticks\" in the form after submitting, though it was never saved to the database. This greatly improves the user experience by minimizing data loss. Elgg includes helper functions so you can make any form sticky." msgstr "" -#: ../../guides/actions.rst:447 +#: ../../guides/actions.rst:449 #: ../../guides/helpers.rst:2 msgid "Helper functions" msgstr "" -#: ../../guides/actions.rst:449 +#: ../../guides/actions.rst:451 msgid "Sticky forms are implemented in Elgg by the following functions:" msgstr "" -#: ../../guides/actions.rst:451 +#: ../../guides/actions.rst:453 msgid "``elgg_make_sticky_form($name)`` - Tells the engine to make all input on a form sticky." msgstr "" -#: ../../guides/actions.rst:452 +#: ../../guides/actions.rst:454 msgid "``elgg_clear_sticky_form($name)`` - Tells the engine to discard all sticky input on a form." msgstr "" -#: ../../guides/actions.rst:453 +#: ../../guides/actions.rst:455 msgid "``elgg_is_sticky_form($name)`` - Checks if ``$name`` is a valid sticky form." msgstr "" -#: ../../guides/actions.rst:454 +#: ../../guides/actions.rst:456 msgid "``elgg_get_sticky_values($name)`` - Returns all sticky values saved for ``$name`` by ``elgg_make_sticky_form($name)``." msgstr "" -#: ../../guides/actions.rst:457 +#: ../../guides/actions.rst:459 #: ../../guides/ajax.rst:11 #: ../../guides/i18n.rst:15 #: ../../guides/plugins/dependencies.rst:11 msgid "Overview" msgstr "" -#: ../../guides/actions.rst:459 +#: ../../guides/actions.rst:461 msgid "The basic flow of using sticky forms is:" msgstr "" -#: ../../guides/actions.rst:461 +#: ../../guides/actions.rst:463 msgid "Call ``elgg_make_sticky_form($name)`` at the top of actions for forms you want to be sticky." msgstr "" -#: ../../guides/actions.rst:462 +#: ../../guides/actions.rst:464 msgid "Use ``elgg_is_sticky_form($name)`` and ``elgg_get_sticky_values($name)`` to get sticky values when rendering a form view." msgstr "" -#: ../../guides/actions.rst:463 +#: ../../guides/actions.rst:465 msgid "Call ``elgg_clear_sticky_form($name)`` after the action has completed successfully or after data has been loaded by ``elgg_get_sticky_values($name)``." msgstr "" -#: ../../guides/actions.rst:467 +#: ../../guides/actions.rst:469 msgid "As of Elgg 5.0 forms rendered with ``elgg_view_form()`` can set the ``$form_vars['sticky_enabled'] = true`` flag to automatically get sticky form support. The submitted values to the action will automatically be filled in the ``$body_vars`` when an error occured in the action." msgstr "" -#: ../../guides/actions.rst:470 +#: ../../guides/actions.rst:472 msgid "``elgg_view_form()`` supports the following ``$form_vars`` to help with sticky form support:" msgstr "" -#: ../../guides/actions.rst:472 +#: ../../guides/actions.rst:474 msgid "``sticky_enabled``: a ``bool`` to enable automatic sticky form support" msgstr "" -#: ../../guides/actions.rst:473 +#: ../../guides/actions.rst:475 msgid "``sticky_form_name``: an optional ``string`` to set where the sticky form values are saved. This defaults to the ``$action_name`` and should only be changed if the ``$action_name`` is different from the actual action" msgstr "" -#: ../../guides/actions.rst:474 -msgid "``sticky_ignored_fields: an ``array`` with the names fo the form fields that should be saved. For example password fields" +#: ../../guides/actions.rst:476 +msgid "``sticky_ignored_fields``: an ``array`` with the names fo the form fields that should be saved. For example password fields" msgstr "" -#: ../../guides/actions.rst:477 +#: ../../guides/actions.rst:479 msgid "Example: User registration" msgstr "" -#: ../../guides/actions.rst:479 +#: ../../guides/actions.rst:481 msgid "Simple sticky forms require little logic to determine the input values for the form. This logic is placed at the top of the form body view itself." msgstr "" -#: ../../guides/actions.rst:482 +#: ../../guides/actions.rst:484 msgid "The registration form view first sets default values for inputs, then checks if there are sticky values. If so, it loads the sticky values before clearing the sticky form:" msgstr "" -#: ../../guides/actions.rst:498 +#: ../../guides/actions.rst:500 msgid "The registration action sets creates the sticky form and clears it once the action is completed:" msgstr "" -#: ../../guides/actions.rst:516 +#: ../../guides/actions.rst:518 msgid "The function ``elgg_make_sticky_form()`` supports an optional second argument ``$ignored_field_names``. This needs to be an ``array`` of the field names you don't wish to be made sticky. This is usefull for fields which contain sensitive data, like passwords." msgstr "" -#: ../../guides/actions.rst:520 +#: ../../guides/actions.rst:522 msgid "Example: Bookmarks" msgstr "" -#: ../../guides/actions.rst:522 +#: ../../guides/actions.rst:524 msgid "The bundled plugin Bookmarks' save form and action is an example of a complex sticky form." msgstr "" -#: ../../guides/actions.rst:524 +#: ../../guides/actions.rst:526 msgid "The form view for the save bookmark action uses ``elgg_extract()`` to pull values from the ``$vars`` array:" msgstr "" -#: ../../guides/actions.rst:538 +#: ../../guides/actions.rst:540 msgid "The page handler scripts enables sticky form support by passing the correct values to ``elgg_view_form()``:" msgstr "" -#: ../../guides/actions.rst:545 +#: ../../guides/actions.rst:547 msgid "Similarly, ``mod/bookmarks/pages/edit.php`` uses the same sticky support, but passes the entity that is being edited:" msgstr "" -#: ../../guides/actions.rst:556 +#: ../../guides/actions.rst:558 msgid "The plugin has an event listener on the ``'form:prepare:fields', 'bookmarks/save'`` event and the handler does 2 things:" msgstr "" -#: ../../guides/actions.rst:558 +#: ../../guides/actions.rst:560 msgid "Defines the input names and default values for form inputs." msgstr "" -#: ../../guides/actions.rst:559 +#: ../../guides/actions.rst:561 msgid "Extracts the values from a bookmark object if it's passed." msgstr "" -#: ../../guides/actions.rst:606 +#: ../../guides/actions.rst:608 msgid "The save action doesn't need to do anything with sticky form support as this is all handled by the system." msgstr "" -#: ../../guides/actions.rst:609 +#: ../../guides/actions.rst:611 #: ../../guides/ajax.rst:2 -#: ../../guides/events-list.rst:862 +#: ../../guides/events-list.rst:868 msgid "Ajax" msgstr "" -#: ../../guides/actions.rst:611 +#: ../../guides/actions.rst:613 msgid "See the :doc:`Ajax guide` for instructions on calling actions from JavaScript." msgstr "" -#: ../../guides/actions.rst:614 +#: ../../guides/actions.rst:616 #: ../../guides/web-services.rst:27 msgid "Security" msgstr "" -#: ../../guides/actions.rst:616 +#: ../../guides/actions.rst:618 msgid "For enhanced security, all actions require an CSRF token. Calls to action URLs that do not include security tokens will be ignored and a warning will be generated." msgstr "" -#: ../../guides/actions.rst:619 +#: ../../guides/actions.rst:621 msgid "A few views and functions automatically generate security tokens:" msgstr "" -#: ../../guides/actions.rst:628 +#: ../../guides/actions.rst:630 msgid "In rare cases, you may need to generate tokens manually:" msgstr "" -#: ../../guides/actions.rst:635 +#: ../../guides/actions.rst:637 msgid "You can also access the tokens from javascript:" msgstr "" -#: ../../guides/actions.rst:642 +#: ../../guides/actions.rst:644 msgid "These are refreshed periodically so should always be up-to-date." msgstr "" -#: ../../guides/actions.rst:645 +#: ../../guides/actions.rst:647 msgid "Security Tokens" msgstr "" -#: ../../guides/actions.rst:647 +#: ../../guides/actions.rst:649 msgid "On occasion we need to pass data through an untrusted party or generate an \"unguessable token\" based on some data. The industry-standard `HMAC `_ algorithm is the right tool for this. It allows us to verify that received data were generated by our site, and were not tampered with. Note that even strong hash functions like SHA-2 should *not* be used without HMAC for these tasks." msgstr "" -#: ../../guides/actions.rst:652 +#: ../../guides/actions.rst:654 msgid "Elgg provides ``elgg_build_hmac()`` to generate and validate HMAC message authentication codes that are unguessable without the site's private key." msgstr "" -#: ../../guides/actions.rst:676 +#: ../../guides/actions.rst:678 msgid "Note: If you use a non-string as HMAC data, you must use types consistently. Consider the following:" msgstr "" -#: ../../guides/actions.rst:689 +#: ../../guides/actions.rst:691 msgid "Signed URLs" msgstr "" -#: ../../guides/actions.rst:691 +#: ../../guides/actions.rst:693 msgid "Signed URLs offer a limited level of security for situations where action tokens are not suitable, for example when sending a confirmation link via email. URL signatures verify that the URL has been generated by your Elgg installation (using site secret) and that the URL query elements were not tampered with." msgstr "" -#: ../../guides/actions.rst:695 +#: ../../guides/actions.rst:697 msgid "URLs a signed with an unguessable SHA-256 HMAC key. See `Security Tokens`_ for more details." msgstr "" -#: ../../guides/actions.rst:709 +#: ../../guides/actions.rst:711 msgid "Signed URLs do not offer CSRF protection and should not be used instead of action tokens." msgstr "" @@ -2097,7 +2105,7 @@ msgstr "" msgid "Allows plugins to register their own commands executable via ``elgg-cli`` binary. Handlers must return an array of command class names. Commands must extend ``\\Elgg\\Cli\\Command`` to be executable." msgstr "" -#: ../../guides/events-list.rst:42 +#: ../../guides/events-list.rst:48 msgid "**cron, ** |results|" msgstr "" @@ -2105,1971 +2113,1984 @@ msgstr "" msgid "Triggered by cron for each period." msgstr "" -#: ../../guides/events-list.rst:45 +#: ../../guides/events-list.rst:44 +#: ../../guides/events-list.rst:110 +#: ../../guides/events-list.rst:135 +#: ../../guides/events-list.rst:256 +#: ../../guides/events-list.rst:297 +#: ../../guides/events-list.rst:330 +#: ../../guides/events-list.rst:473 +#: ../../guides/events-list.rst:480 +#: ../../guides/events-list.rst:560 +#: ../../guides/events-list.rst:574 +#: ../../guides/events-list.rst:593 +msgid "The ``$params`` array will contain:" +msgstr "" + +#: ../../guides/events-list.rst:46 +msgid "``time`` - the timestamp of when the cron command was started" +msgstr "" + +#: ../../guides/events-list.rst:47 +msgid "``dt`` - the ``\\DateTime`` object of when the cron command was started" +msgstr "" + +#: ../../guides/events-list.rst:48 +msgid "``logger`` - instance of ``\\Elgg\\Logger\\Cron`` to log any information to the cron log" +msgstr "" + +#: ../../guides/events-list.rst:51 msgid "**cron:intervals, system** |results|" msgstr "" -#: ../../guides/events-list.rst:45 +#: ../../guides/events-list.rst:51 msgid "Allow the configuration of custom cron intervals" msgstr "" -#: ../../guides/events-list.rst:48 +#: ../../guides/events-list.rst:54 msgid "**deactivate, plugin**" msgstr "" -#: ../../guides/events-list.rst:48 +#: ../../guides/events-list.rst:54 msgid "Return false to prevent deactivation of the plugin." msgstr "" -#: ../../guides/events-list.rst:51 +#: ../../guides/events-list.rst:57 msgid "**diagnostics:report, system** |results|" msgstr "" -#: ../../guides/events-list.rst:51 +#: ../../guides/events-list.rst:57 msgid "Filter the output for the diagnostics report download." msgstr "" -#: ../../guides/events-list.rst:54 +#: ../../guides/events-list.rst:60 msgid "**elgg.data, page** |results|" msgstr "" -#: ../../guides/events-list.rst:54 +#: ../../guides/events-list.rst:60 msgid "Filters uncached, page-specific configuration data to pass to the client. :ref:`More info `" msgstr "" -#: ../../guides/events-list.rst:57 +#: ../../guides/events-list.rst:63 msgid "**elgg.data, site** |results|" msgstr "" -#: ../../guides/events-list.rst:57 +#: ../../guides/events-list.rst:63 msgid "Filters cached configuration data to pass to the client. :ref:`More info `" msgstr "" -#: ../../guides/events-list.rst:60 +#: ../../guides/events-list.rst:66 msgid "**format, friendly:title** |results|" msgstr "" -#: ../../guides/events-list.rst:60 +#: ../../guides/events-list.rst:66 msgid "Formats the \"friendly\" title for strings. This is used for generating URLs." msgstr "" -#: ../../guides/events-list.rst:63 +#: ../../guides/events-list.rst:69 msgid "**format, friendly:time** |results|" msgstr "" -#: ../../guides/events-list.rst:63 +#: ../../guides/events-list.rst:69 msgid "Formats the \"friendly\" time for the timestamp ``$params['time']``." msgstr "" -#: ../../guides/events-list.rst:67 +#: ../../guides/events-list.rst:73 msgid "**format, strip_tags** |results|" msgstr "" -#: ../../guides/events-list.rst:66 +#: ../../guides/events-list.rst:72 msgid "Filters a string to remove tags. The original string is passed as ``$params['original_string']`` and an optional set of allowed tags is passed as ``$params['allowed_tags']``." msgstr "" -#: ../../guides/events-list.rst:70 +#: ../../guides/events-list.rst:76 msgid "**gc, system** |results|" msgstr "" -#: ../../guides/events-list.rst:70 +#: ../../guides/events-list.rst:76 msgid "Allows plugins to run garbage collection for ``$params['period']``." msgstr "" -#: ../../guides/events-list.rst:73 +#: ../../guides/events-list.rst:79 msgid "**generate, password** |results|" msgstr "" -#: ../../guides/events-list.rst:73 +#: ../../guides/events-list.rst:79 msgid "Allows plugins to generate new random cleartext passwords." msgstr "" -#: ../../guides/events-list.rst:76 +#: ../../guides/events-list.rst:82 msgid "**init:cookie, **" msgstr "" -#: ../../guides/events-list.rst:76 +#: ../../guides/events-list.rst:82 msgid "Return false to override setting a cookie." msgstr "" -#: ../../guides/events-list.rst:79 +#: ../../guides/events-list.rst:85 msgid "**init, system** |sequence|" msgstr "" -#: ../../guides/events-list.rst:79 +#: ../../guides/events-list.rst:85 msgid "Plugins tend to use this event for initialization (extending views, registering callbacks, etc.)" msgstr "" -#: ../../guides/events-list.rst:82 +#: ../../guides/events-list.rst:88 msgid "**languages, translations** |results|" msgstr "" -#: ../../guides/events-list.rst:82 +#: ../../guides/events-list.rst:88 msgid "Allows plugins to add/remove languages from the configurable languages in the system." msgstr "" -#: ../../guides/events-list.rst:86 +#: ../../guides/events-list.rst:92 msgid "**log, systemlog**" msgstr "" -#: ../../guides/events-list.rst:85 +#: ../../guides/events-list.rst:91 msgid "Called for all triggered events by ``system_log`` plugin. Used internally by ``Elgg\\SystemLog\\Logger::log()`` to populate the ``system_log`` table." msgstr "" -#: ../../guides/events-list.rst:91 +#: ../../guides/events-list.rst:97 msgid "**login_url, site** |results|" msgstr "" -#: ../../guides/events-list.rst:89 +#: ../../guides/events-list.rst:95 msgid "Filters site's login URL. ``$params`` array contains an array of query elements added to the login URL by the invoking script. The event must return an absolute URL of the login page." msgstr "" -#: ../../guides/events-list.rst:96 +#: ../../guides/events-list.rst:102 msgid "**output:before, page** |results|" msgstr "" -#: ../../guides/events-list.rst:94 +#: ../../guides/events-list.rst:100 msgid "In ``elgg_view_page()``, this filters ``$vars`` before it's passed to the page shell view (``page/``). To stop sending the X-Frame-Options header, unregister the handler ``Elgg\\Page\\SetXFrameOptionsHeaderHandler::class`` from this event." msgstr "" -#: ../../guides/events-list.rst:99 +#: ../../guides/events-list.rst:105 msgid "**output, page** |results|" msgstr "" -#: ../../guides/events-list.rst:99 +#: ../../guides/events-list.rst:105 msgid "In ``elgg_view_page()``, this filters the output return value." msgstr "" -#: ../../guides/events-list.rst:108 +#: ../../guides/events-list.rst:114 msgid "**parameters, menu:** |results|" msgstr "" -#: ../../guides/events-list.rst:102 +#: ../../guides/events-list.rst:108 msgid "Triggered by ``elgg_view_menu()``. Used to change menu variables (like sort order) before rendering." msgstr "" -#: ../../guides/events-list.rst:104 -#: ../../guides/events-list.rst:129 -#: ../../guides/events-list.rst:250 -#: ../../guides/events-list.rst:291 -#: ../../guides/events-list.rst:324 -#: ../../guides/events-list.rst:467 -#: ../../guides/events-list.rst:474 -#: ../../guides/events-list.rst:554 -#: ../../guides/events-list.rst:568 -#: ../../guides/events-list.rst:587 -msgid "The ``$params`` array will contain:" -msgstr "" - -#: ../../guides/events-list.rst:106 +#: ../../guides/events-list.rst:112 msgid "``name`` - name of the menu" msgstr "" -#: ../../guides/events-list.rst:107 +#: ../../guides/events-list.rst:113 msgid "``sort_by`` - preferring sorting parameter" msgstr "" -#: ../../guides/events-list.rst:108 +#: ../../guides/events-list.rst:114 msgid "other parameters passed to ``elgg_view_menu()``" msgstr "" -#: ../../guides/events-list.rst:111 +#: ../../guides/events-list.rst:117 msgid "**plugins_load, system** |sequence|" msgstr "" -#: ../../guides/events-list.rst:111 +#: ../../guides/events-list.rst:117 msgid "Triggered before the plugins are loaded. Rarely used. init, system is used instead. Can be used to load additional libraries." msgstr "" -#: ../../guides/events-list.rst:114 +#: ../../guides/events-list.rst:120 msgid "**plugins_boot, system** |sequence|" msgstr "" -#: ../../guides/events-list.rst:114 +#: ../../guides/events-list.rst:120 msgid "Triggered just after the plugins are loaded. Rarely used. init, system is used instead." msgstr "" -#: ../../guides/events-list.rst:122 +#: ../../guides/events-list.rst:128 msgid "**prepare, html** |results|" msgstr "" -#: ../../guides/events-list.rst:117 +#: ../../guides/events-list.rst:123 msgid "Triggered by ``elgg_format_html()`` and used to prepare untrusted HTML." msgstr "" -#: ../../guides/events-list.rst:119 +#: ../../guides/events-list.rst:125 msgid "The ``$return`` value is an array:" msgstr "" -#: ../../guides/events-list.rst:121 +#: ../../guides/events-list.rst:127 msgid "``html`` - HTML string being prepared" msgstr "" -#: ../../guides/events-list.rst:122 +#: ../../guides/events-list.rst:128 msgid "``options`` - Preparation options" msgstr "" -#: ../../guides/events-list.rst:134 +#: ../../guides/events-list.rst:140 msgid "**prepare, menu:** |results|" msgstr "" -#: ../../guides/events-list.rst:125 +#: ../../guides/events-list.rst:131 msgid "Filters the array of menu sections before they're displayed. Each section is a string key mapping to an area of menu items. This is a good event to sort, add, remove, and modify menu items. Triggered by ``elgg_view_menu()`` and ``elgg()->menus->prepareMenu()``." msgstr "" -#: ../../guides/events-list.rst:131 +#: ../../guides/events-list.rst:137 msgid "``selected_item`` - ``ElggMenuItem`` selected in the menu, if any" msgstr "" -#: ../../guides/events-list.rst:133 +#: ../../guides/events-list.rst:139 msgid "The return value is an instance of ``\\Elgg\\Menu\\PreparedMenu``. The prepared menu is a collection of ``\\Elgg\\Menu\\MenuSection``, which in turn are collections of ``\\ElggMenuItem`` objects." msgstr "" -#: ../../guides/events-list.rst:142 +#: ../../guides/events-list.rst:148 msgid "**prepare, menu:::** |results|" msgstr "" -#: ../../guides/events-list.rst:137 +#: ../../guides/events-list.rst:143 msgid "More granular version of the menu event triggered before the **prepare, menu:** event." msgstr "" -#: ../../guides/events-list.rst:139 -#: ../../guides/events-list.rst:168 +#: ../../guides/events-list.rst:145 +#: ../../guides/events-list.rst:174 msgid "Only applied if menu params contain - params['entity'] with an ``\\ElggEntity`` (```` is ``\\ElggEntity::type`` and ```` is ``\\ElggEntity::subtype``) or - params['annotation'] with an ``\\ElggAnnotation`` (```` is ``\\ElggAnnotation::getType()`` and ```` is ``\\ElggAnnotation::getSubtype()``) or - params['relationship'] with an ``\\ElggRelationship`` (```` is ``\\ElggRelationship::getType()`` and ```` is ``\\ElggRelationship::getSubtype()``)" msgstr "" -#: ../../guides/events-list.rst:146 +#: ../../guides/events-list.rst:152 msgid "**ready, system** |sequence|" msgstr "" -#: ../../guides/events-list.rst:145 +#: ../../guides/events-list.rst:151 msgid "Triggered after the ``init, system`` event. All plugins are fully loaded and the engine is ready to serve pages." msgstr "" -#: ../../guides/events-list.rst:150 +#: ../../guides/events-list.rst:156 msgid "**regenerate_site_secret:before, system**" msgstr "" -#: ../../guides/events-list.rst:149 +#: ../../guides/events-list.rst:155 msgid "Return false to cancel regenerating the site secret. You should also provide a message to the user." msgstr "" -#: ../../guides/events-list.rst:153 +#: ../../guides/events-list.rst:159 msgid "**regenerate_site_secret:after, system**" msgstr "" -#: ../../guides/events-list.rst:153 +#: ../../guides/events-list.rst:159 msgid "Triggered after the site secret has been regenerated." msgstr "" -#: ../../guides/events-list.rst:163 +#: ../../guides/events-list.rst:169 msgid "**register, menu:** |results|" msgstr "" -#: ../../guides/events-list.rst:156 +#: ../../guides/events-list.rst:162 msgid "Filters the initial list of menu items pulled from configuration, before the menu has been split into sections. Triggered by ``elgg_view_menu()`` and ``elgg()->menus->getMenu()``." msgstr "" -#: ../../guides/events-list.rst:159 +#: ../../guides/events-list.rst:165 msgid "The ``$params`` array will contain parameters returned by ``parameters, menu:`` event." msgstr "" -#: ../../guides/events-list.rst:161 +#: ../../guides/events-list.rst:167 msgid "The return value is an instance of ``\\Elgg\\Menu\\MenuItems`` containing ``\\ElggMenuItem`` objects." msgstr "" -#: ../../guides/events-list.rst:163 +#: ../../guides/events-list.rst:169 msgid "Event handlers can add/remove items to the collection using the collection API, as well as array access operations." msgstr "" -#: ../../guides/events-list.rst:171 +#: ../../guides/events-list.rst:177 msgid "**register, menu:::** |results|" msgstr "" -#: ../../guides/events-list.rst:166 +#: ../../guides/events-list.rst:172 msgid "More granular version of the menu event triggered before the **register, menu:** event." msgstr "" -#: ../../guides/events-list.rst:191 +#: ../../guides/events-list.rst:197 msgid "**register, menu:filter:** |results|" msgstr "" -#: ../../guides/events-list.rst:174 +#: ../../guides/events-list.rst:180 msgid "Allows plugins to modify layout filter tabs on layouts that specify ```` parameter. Parameters and return values are same as in ``register, menu:`` event." msgstr "" -#: ../../guides/events-list.rst:177 +#: ../../guides/events-list.rst:183 msgid "If ``filter_id`` is ``filter`` (the default) then the ``all``, ``mine`` and ``friends`` tabs will be generated base on some provided information or be tried for routes similar to the current route." msgstr "" -#: ../../guides/events-list.rst:180 +#: ../../guides/events-list.rst:186 msgid "params['all_link'] will be used for the ``all`` tab" msgstr "" -#: ../../guides/events-list.rst:181 +#: ../../guides/events-list.rst:187 msgid "params['mine_link'] will be used for the ``mine`` tab" msgstr "" -#: ../../guides/events-list.rst:182 +#: ../../guides/events-list.rst:188 msgid "params['friends_link'] will be used for the ``friend`` tab" msgstr "" -#: ../../guides/events-list.rst:184 +#: ../../guides/events-list.rst:190 msgid "If the above are not provided than a route will be tried based on ``params['entity_type']`` and ``params['entity_subtype']``. If not provided ``entity_type`` and ``entity_subtype`` will be based on route detection of the current route. For example if the current route is ``collection:object:blog:all`` ``entity_type`` will be ``object`` and ``entity_subtype`` will be ``blog``. - The ``all`` tab will be based on the route ``collection:::all`` - The ``mine`` tab will be based on the route ``collection:::owner`` - The ``friend`` tab will be based on the route ``collection:::friends``" msgstr "" -#: ../../guides/events-list.rst:191 +#: ../../guides/events-list.rst:197 msgid "If the routes aren't registered the tabs will not appear." msgstr "" -#: ../../guides/events-list.rst:196 +#: ../../guides/events-list.rst:202 msgid "**registration_url, site** |results|" msgstr "" -#: ../../guides/events-list.rst:194 +#: ../../guides/events-list.rst:200 msgid "Filters site's registration URL. Can be used by plugins to attach invitation codes, referrer codes etc. to the registration URL. ``$params`` array contains an array of query elements added to the registration URL by the invoking script. The event must return an absolute URL to the registration page." msgstr "" -#: ../../guides/events-list.rst:199 +#: ../../guides/events-list.rst:205 msgid "**reload:after, translations**" msgstr "" -#: ../../guides/events-list.rst:199 +#: ../../guides/events-list.rst:205 msgid "Triggered after the translations are (re)loaded." msgstr "" -#: ../../guides/events-list.rst:202 +#: ../../guides/events-list.rst:208 msgid "**sanitize, input** |results|" msgstr "" -#: ../../guides/events-list.rst:202 +#: ../../guides/events-list.rst:208 msgid "Filter GET and POST input. This is used by ``get_input()`` to sanitize user input." msgstr "" -#: ../../guides/events-list.rst:206 +#: ../../guides/events-list.rst:212 msgid "**seeds, database** |results|" msgstr "" -#: ../../guides/events-list.rst:205 +#: ../../guides/events-list.rst:211 msgid "Allows plugins to register their own database seeds. Seeds populate the database with fake entities for testing purposes. Seeds must extend ``\\Elgg\\Database\\Seeds\\Seed`` class to be executable via ``elgg-cli database:seed``." msgstr "" -#: ../../guides/events-list.rst:210 +#: ../../guides/events-list.rst:216 msgid "**send:before, http_response**" msgstr "" -#: ../../guides/events-list.rst:209 +#: ../../guides/events-list.rst:215 msgid "Triggered before an HTTP response is sent. Handlers will receive an instance of `\\Symfony\\Component\\HttpFoundation\\Response` that is to be sent to the requester. Handlers can terminate the event and prevent the response from being sent by returning `false`." msgstr "" -#: ../../guides/events-list.rst:214 +#: ../../guides/events-list.rst:220 msgid "**send:after, http_response**" msgstr "" -#: ../../guides/events-list.rst:213 +#: ../../guides/events-list.rst:219 msgid "Triggered after an HTTP response is sent. Handlers will receive an instance of `\\Symfony\\Component\\HttpFoundation\\Response` that was sent to the requester." msgstr "" -#: ../../guides/events-list.rst:218 +#: ../../guides/events-list.rst:224 msgid "**shutdown, system**" msgstr "" -#: ../../guides/events-list.rst:217 +#: ../../guides/events-list.rst:223 msgid "Triggered after the page has been sent to the user. Expensive operations could be done here and not make the user wait." msgstr "" -#: ../../guides/events-list.rst:220 +#: ../../guides/events-list.rst:226 msgid "Depending upon your server configuration the PHP output might not be shown until after the process is completed. This means that any long-running processes will still delay the page load." msgstr "" -#: ../../guides/events-list.rst:224 +#: ../../guides/events-list.rst:230 msgid "This event is prefered above using ``register_shutdown_function`` as you may not have access to all the Elgg services (eg. database) in the shutdown function but you will in the event." msgstr "" -#: ../../guides/events-list.rst:227 +#: ../../guides/events-list.rst:233 msgid "The Elgg session is already closed before this event. Manipulating session is not possible." msgstr "" -#: ../../guides/events-list.rst:230 +#: ../../guides/events-list.rst:236 msgid "**simplecache:generate, ** |results|" msgstr "" -#: ../../guides/events-list.rst:230 +#: ../../guides/events-list.rst:236 msgid "Filters the view output for a ``/cache`` URL when simplecache is enabled." msgstr "" -#: ../../guides/events-list.rst:234 +#: ../../guides/events-list.rst:240 msgid "**upgrade, system**" msgstr "" -#: ../../guides/events-list.rst:233 +#: ../../guides/events-list.rst:239 msgid "Triggered after a system upgrade has finished. All upgrade scripts have run, but the caches are not cleared." msgstr "" -#: ../../guides/events-list.rst:237 +#: ../../guides/events-list.rst:243 msgid "**upgrade:execute, system** |sequence|" msgstr "" -#: ../../guides/events-list.rst:237 +#: ../../guides/events-list.rst:243 msgid "Triggered when executing an ``ElggUpgrade``. The ``$object`` of the event is the ``ElggUpgrade``." msgstr "" -#: ../../guides/events-list.rst:240 +#: ../../guides/events-list.rst:246 msgid "User events" msgstr "" -#: ../../guides/events-list.rst:243 +#: ../../guides/events-list.rst:249 msgid "**ban, user**" msgstr "" -#: ../../guides/events-list.rst:243 +#: ../../guides/events-list.rst:249 msgid "Triggered before a user is banned. Return false to prevent." msgstr "" -#: ../../guides/events-list.rst:254 +#: ../../guides/events-list.rst:260 msgid "**change:email, user** |results|" msgstr "" -#: ../../guides/events-list.rst:246 +#: ../../guides/events-list.rst:252 msgid "Triggered before the user email is changed. Allows plugins to implement additional logic required to change email, e.g. additional email validation. The event handler must return false to prevent the email from being changed right away." msgstr "" -#: ../../guides/events-list.rst:252 -#: ../../guides/events-list.rst:326 +#: ../../guides/events-list.rst:258 +#: ../../guides/events-list.rst:332 msgid "``user`` - ``\\ElggUser``, whose settings are being saved" msgstr "" -#: ../../guides/events-list.rst:253 +#: ../../guides/events-list.rst:259 msgid "``email`` - Email address that passes sanity checks" msgstr "" -#: ../../guides/events-list.rst:254 -#: ../../guides/events-list.rst:327 +#: ../../guides/events-list.rst:260 +#: ../../guides/events-list.rst:333 msgid "``request`` - ``\\Elgg\\Request`` to the action controller" msgstr "" -#: ../../guides/events-list.rst:257 +#: ../../guides/events-list.rst:263 msgid "**invalidate:after, user**" msgstr "" -#: ../../guides/events-list.rst:257 +#: ../../guides/events-list.rst:263 msgid "Triggered when user's account validation has been revoked." msgstr "" -#: ../../guides/events-list.rst:260 +#: ../../guides/events-list.rst:266 msgid "**login:after, user**" msgstr "" -#: ../../guides/events-list.rst:260 +#: ../../guides/events-list.rst:266 msgid "Triggered after the user logs in." msgstr "" -#: ../../guides/events-list.rst:263 +#: ../../guides/events-list.rst:269 msgid "**login:before, user**" msgstr "" -#: ../../guides/events-list.rst:263 +#: ../../guides/events-list.rst:269 msgid "Triggered during login. Returning false prevents the user from logging" msgstr "" -#: ../../guides/events-list.rst:266 +#: ../../guides/events-list.rst:272 msgid "**login:forward, user** |results|" msgstr "" -#: ../../guides/events-list.rst:266 +#: ../../guides/events-list.rst:272 msgid "Filters the URL to which the user will be forwarded after login." msgstr "" -#: ../../guides/events-list.rst:269 +#: ../../guides/events-list.rst:275 msgid "**login:first, user**" msgstr "" -#: ../../guides/events-list.rst:269 +#: ../../guides/events-list.rst:275 msgid "Triggered after a successful login. Only if there is no previous login." msgstr "" -#: ../../guides/events-list.rst:272 +#: ../../guides/events-list.rst:278 msgid "**logout:after, user**" msgstr "" -#: ../../guides/events-list.rst:272 +#: ../../guides/events-list.rst:278 msgid "Triggered after the user logouts." msgstr "" -#: ../../guides/events-list.rst:275 +#: ../../guides/events-list.rst:281 msgid "**logout:before, user**" msgstr "" -#: ../../guides/events-list.rst:275 +#: ../../guides/events-list.rst:281 msgid "Triggered during logout. Returning false should prevent the user from logging out." msgstr "" -#: ../../guides/events-list.rst:278 +#: ../../guides/events-list.rst:284 msgid "**make_admin, user**" msgstr "" -#: ../../guides/events-list.rst:278 +#: ../../guides/events-list.rst:284 msgid "Triggered before a user is promoted to an admin. Return false to prevent." msgstr "" -#: ../../guides/events-list.rst:281 +#: ../../guides/events-list.rst:287 msgid "**profileiconupdate, user**" msgstr "" -#: ../../guides/events-list.rst:281 +#: ../../guides/events-list.rst:287 msgid "User has changed profile icon" msgstr "" -#: ../../guides/events-list.rst:284 +#: ../../guides/events-list.rst:290 msgid "**profileupdate, user**" msgstr "" -#: ../../guides/events-list.rst:284 +#: ../../guides/events-list.rst:290 msgid "User has changed profile" msgstr "" -#: ../../guides/events-list.rst:294 +#: ../../guides/events-list.rst:300 msgid "**register, user** |results|" msgstr "" -#: ../../guides/events-list.rst:287 +#: ../../guides/events-list.rst:293 msgid "Triggered by the ``register`` action after the user registers. Return ``false`` to delete the user. Note the function ``register_user`` does *not* trigger this event. Event handlers can throw ``\\Elgg\\Exceptions\\Configuration\\RegistrationException`` with an error message to be displayed to the user." msgstr "" -#: ../../guides/events-list.rst:293 +#: ../../guides/events-list.rst:299 msgid "``user`` - Newly registered user entity" msgstr "" -#: ../../guides/events-list.rst:294 +#: ../../guides/events-list.rst:300 msgid "All parameters sent with the request to the action (incl. ``password``, ``friend_guid``, ``invitecode`` etc)" msgstr "" -#: ../../guides/events-list.rst:298 +#: ../../guides/events-list.rst:304 msgid "**registeruser:validate:email, all** |results|" msgstr "" -#: ../../guides/events-list.rst:297 +#: ../../guides/events-list.rst:303 msgid "Return boolean for if the string in ``$params['email']`` is valid for an email address. Event handler can throw ``\\Elgg\\Exceptions\\Configuration\\RegistrationException`` with an error message to be shown to the user." msgstr "" -#: ../../guides/events-list.rst:302 +#: ../../guides/events-list.rst:308 msgid "**registeruser:validate:password, all** |results|" msgstr "" -#: ../../guides/events-list.rst:301 +#: ../../guides/events-list.rst:307 msgid "Return boolean for if the string in ``$params['password']`` is valid for a password. Event handler can throw ``\\Elgg\\Exceptions\\Configuration\\RegistrationException`` with an error message to be shown to the user." msgstr "" -#: ../../guides/events-list.rst:306 +#: ../../guides/events-list.rst:312 msgid "**registeruser:validate:username, all** |results|" msgstr "" -#: ../../guides/events-list.rst:305 +#: ../../guides/events-list.rst:311 msgid "Return boolean for if the string in ``$params['username']`` is valid for a username. Event handler can throw ``\\Elgg\\Exceptions\\Configuration\\RegistrationException`` with an error message to be shown to the user." msgstr "" -#: ../../guides/events-list.rst:309 +#: ../../guides/events-list.rst:315 msgid "**remove_admin, user**" msgstr "" -#: ../../guides/events-list.rst:309 +#: ../../guides/events-list.rst:315 msgid "Triggered before a user is demoted from an admin. Return false to prevent." msgstr "" -#: ../../guides/events-list.rst:312 +#: ../../guides/events-list.rst:318 msgid "**unban, user**" msgstr "" -#: ../../guides/events-list.rst:312 +#: ../../guides/events-list.rst:318 msgid "Triggered before a user is unbanned. Return false to prevent." msgstr "" -#: ../../guides/events-list.rst:317 +#: ../../guides/events-list.rst:323 msgid "**username:character_blacklist, user** |results|" msgstr "" -#: ../../guides/events-list.rst:315 +#: ../../guides/events-list.rst:321 msgid "Filters the string of blacklisted characters used to validate username during registration. The return value should be a string consisting of the disallowed characters. The default string can be found from ``$params['blacklist']``." msgstr "" -#: ../../guides/events-list.rst:327 +#: ../../guides/events-list.rst:333 msgid "**usersettings:save, user** |results|" msgstr "" -#: ../../guides/events-list.rst:320 +#: ../../guides/events-list.rst:326 msgid "Triggered in the aggregate action to save user settings. The event handler must return ``false`` to prevent sticky forms from being cleared (i.e. to indicate that some of the values were not saved). Do not return ``true`` from your event handler, as you will override other events' output, instead return ``null`` to indicate successful operation." msgstr "" -#: ../../guides/events-list.rst:332 +#: ../../guides/events-list.rst:338 msgid "**validate, user**" msgstr "" -#: ../../guides/events-list.rst:330 +#: ../../guides/events-list.rst:336 msgid "When a user registers, the user's account is disabled. This event is triggered to allow a plugin to determine how the user should be validated (for example, through an email with a validation link)." msgstr "" -#: ../../guides/events-list.rst:335 +#: ../../guides/events-list.rst:341 msgid "**validate:after, user**" msgstr "" -#: ../../guides/events-list.rst:335 +#: ../../guides/events-list.rst:341 msgid "Triggered when user's account has been validated." msgstr "" -#: ../../guides/events-list.rst:338 +#: ../../guides/events-list.rst:344 msgid "Relationship events" msgstr "" -#: ../../guides/events-list.rst:342 +#: ../../guides/events-list.rst:348 msgid "**create, relationship**" msgstr "" -#: ../../guides/events-list.rst:341 +#: ../../guides/events-list.rst:347 msgid "Triggered after a relationship has been created. Returning false deletes the relationship that was just created." msgstr "" -#: ../../guides/events-list.rst:346 +#: ../../guides/events-list.rst:352 msgid "**delete, relationship**" msgstr "" -#: ../../guides/events-list.rst:345 +#: ../../guides/events-list.rst:351 msgid "Triggered before a relationship is deleted. Return false to prevent it from being deleted." msgstr "" -#: ../../guides/events-list.rst:349 +#: ../../guides/events-list.rst:355 msgid "**join, group**" msgstr "" -#: ../../guides/events-list.rst:349 +#: ../../guides/events-list.rst:355 msgid "Triggered after the user ``$params['user']`` has joined the group ``$params['group']``." msgstr "" -#: ../../guides/events-list.rst:352 +#: ../../guides/events-list.rst:358 msgid "**leave, group**" msgstr "" -#: ../../guides/events-list.rst:352 +#: ../../guides/events-list.rst:358 msgid "Triggered before the user ``$params['user']`` has left the group ``$params['group']``." msgstr "" -#: ../../guides/events-list.rst:355 +#: ../../guides/events-list.rst:361 msgid "Entity events" msgstr "" -#: ../../guides/events-list.rst:359 +#: ../../guides/events-list.rst:365 msgid "**comments, ** |results|" msgstr "" -#: ../../guides/events-list.rst:358 +#: ../../guides/events-list.rst:364 msgid "Triggered in ``elgg_view_comments()``. If returning content, this overrides the ``page/elements/comments`` view." msgstr "" -#: ../../guides/events-list.rst:362 +#: ../../guides/events-list.rst:368 msgid "**comments:count, ** |results|" msgstr "" -#: ../../guides/events-list.rst:362 +#: ../../guides/events-list.rst:368 msgid "Return the number of comments on ``$params['entity']``." msgstr "" -#: ../../guides/events-list.rst:366 +#: ../../guides/events-list.rst:372 msgid "**create, **" msgstr "" -#: ../../guides/events-list.rst:365 +#: ../../guides/events-list.rst:371 msgid "Triggered for user, group, object, and site entities after creation. Triggered just before the ``create:after`` event, mostly for BC reasons. The use of the ``create:after`` event is preferred." msgstr "" -#: ../../guides/events-list.rst:369 +#: ../../guides/events-list.rst:375 msgid "**create:after, **" msgstr "" -#: ../../guides/events-list.rst:369 +#: ../../guides/events-list.rst:375 msgid "Triggered for user, group, object, and site entities after creation." msgstr "" -#: ../../guides/events-list.rst:372 +#: ../../guides/events-list.rst:378 msgid "**create:before, **" msgstr "" -#: ../../guides/events-list.rst:372 +#: ../../guides/events-list.rst:378 msgid "Triggered for user, group, object, and site entities before creation. Return false to prevent creating the entity." msgstr "" -#: ../../guides/events-list.rst:375 +#: ../../guides/events-list.rst:381 msgid "**delete, **" msgstr "" -#: ../../guides/events-list.rst:375 +#: ../../guides/events-list.rst:381 msgid "Triggered before entity deletion." msgstr "" -#: ../../guides/events-list.rst:378 +#: ../../guides/events-list.rst:384 msgid "**delete:after, **" msgstr "" -#: ../../guides/events-list.rst:378 +#: ../../guides/events-list.rst:384 msgid "Triggered after entity deletion." msgstr "" -#: ../../guides/events-list.rst:381 +#: ../../guides/events-list.rst:387 msgid "**delete:before, **" msgstr "" -#: ../../guides/events-list.rst:381 +#: ../../guides/events-list.rst:387 msgid "Triggered before entity deletion. Return false to prevent deletion." msgstr "" -#: ../../guides/events-list.rst:384 +#: ../../guides/events-list.rst:390 msgid "**disable, **" msgstr "" -#: ../../guides/events-list.rst:384 +#: ../../guides/events-list.rst:390 msgid "Triggered before the entity is disabled. Return false to prevent disabling." msgstr "" -#: ../../guides/events-list.rst:387 +#: ../../guides/events-list.rst:393 msgid "**disable:after, **" msgstr "" -#: ../../guides/events-list.rst:387 +#: ../../guides/events-list.rst:393 msgid "Triggered after the entity is disabled." msgstr "" -#: ../../guides/events-list.rst:390 +#: ../../guides/events-list.rst:396 msgid "**enable, **" msgstr "" -#: ../../guides/events-list.rst:390 +#: ../../guides/events-list.rst:396 msgid "Return false to prevent enabling." msgstr "" -#: ../../guides/events-list.rst:393 +#: ../../guides/events-list.rst:399 msgid "**enable:after, **" msgstr "" -#: ../../guides/events-list.rst:393 +#: ../../guides/events-list.rst:399 msgid "Triggered after the entity is enabled." msgstr "" -#: ../../guides/events-list.rst:396 +#: ../../guides/events-list.rst:402 msgid "**likes:count, ** |results|" msgstr "" -#: ../../guides/events-list.rst:396 +#: ../../guides/events-list.rst:402 msgid "Return the number of likes for ``$params['entity']``." msgstr "" -#: ../../guides/events-list.rst:401 +#: ../../guides/events-list.rst:407 msgid "**update, **" msgstr "" -#: ../../guides/events-list.rst:399 +#: ../../guides/events-list.rst:405 msgid "Triggered before an update for the user, group, object, and site entities. Return false to prevent update. The entity method ``getOriginalAttributes()`` can be used to identify which attributes have changed since the entity was last saved." msgstr "" -#: ../../guides/events-list.rst:406 +#: ../../guides/events-list.rst:412 msgid "**update:after, **" msgstr "" -#: ../../guides/events-list.rst:404 +#: ../../guides/events-list.rst:410 msgid "Triggered after an update for the user, group, object, and site entities. The entity method ``getOriginalAttributes()`` can be used to identify which attributes have changed since the entity was last saved." msgstr "" -#: ../../guides/events-list.rst:409 +#: ../../guides/events-list.rst:415 msgid "Metadata events" msgstr "" -#: ../../guides/events-list.rst:413 +#: ../../guides/events-list.rst:419 msgid "**create, metadata**" msgstr "" -#: ../../guides/events-list.rst:412 +#: ../../guides/events-list.rst:418 msgid "Called after the metadata has been created. Return false to delete the metadata that was just created." msgstr "" -#: ../../guides/events-list.rst:416 +#: ../../guides/events-list.rst:422 msgid "**delete, metadata**" msgstr "" -#: ../../guides/events-list.rst:416 +#: ../../guides/events-list.rst:422 msgid "Called before metadata is deleted. Return false to prevent deletion." msgstr "" -#: ../../guides/events-list.rst:419 +#: ../../guides/events-list.rst:425 msgid "**update, metadata**" msgstr "" -#: ../../guides/events-list.rst:419 +#: ../../guides/events-list.rst:425 msgid "Called after the metadata has been updated. Return false to *delete the metadata.*" msgstr "" -#: ../../guides/events-list.rst:422 +#: ../../guides/events-list.rst:428 msgid "Annotation events" msgstr "" -#: ../../guides/events-list.rst:426 +#: ../../guides/events-list.rst:432 msgid "**annotate, **" msgstr "" -#: ../../guides/events-list.rst:425 +#: ../../guides/events-list.rst:431 msgid "Called before the annotation has been created. Return false to prevent annotation of this entity." msgstr "" -#: ../../guides/events-list.rst:430 +#: ../../guides/events-list.rst:436 msgid "**create, annotation**" msgstr "" -#: ../../guides/events-list.rst:429 +#: ../../guides/events-list.rst:435 msgid "Called after the annotation has been created. Return false to delete the annotation." msgstr "" -#: ../../guides/events-list.rst:433 +#: ../../guides/events-list.rst:439 msgid "**delete, annotation**" msgstr "" -#: ../../guides/events-list.rst:433 +#: ../../guides/events-list.rst:439 msgid "Called before annotation is deleted. Return false to prevent deletion." msgstr "" -#: ../../guides/events-list.rst:436 +#: ../../guides/events-list.rst:442 msgid "**disable, annotations**" msgstr "" -#: ../../guides/events-list.rst:436 +#: ../../guides/events-list.rst:442 msgid "Called when disabling annotations. Return false to prevent disabling." msgstr "" -#: ../../guides/events-list.rst:439 +#: ../../guides/events-list.rst:445 msgid "**enable, annotation**" msgstr "" -#: ../../guides/events-list.rst:439 +#: ../../guides/events-list.rst:445 msgid "Called when enabling annotations. Return false to prevent enabling." msgstr "" -#: ../../guides/events-list.rst:442 +#: ../../guides/events-list.rst:448 msgid "**update, annotation**" msgstr "" -#: ../../guides/events-list.rst:442 +#: ../../guides/events-list.rst:448 msgid "Called after the annotation has been updated. Return false to *delete the annotation.*" msgstr "" -#: ../../guides/events-list.rst:445 +#: ../../guides/events-list.rst:451 msgid "River events" msgstr "" -#: ../../guides/events-list.rst:448 +#: ../../guides/events-list.rst:454 msgid "**create:after, river**" msgstr "" -#: ../../guides/events-list.rst:448 +#: ../../guides/events-list.rst:454 msgid "Called after a river item is created." msgstr "" -#: ../../guides/events-list.rst:451 +#: ../../guides/events-list.rst:457 msgid "**create:before, river**" msgstr "" -#: ../../guides/events-list.rst:451 +#: ../../guides/events-list.rst:457 msgid "Called before the river item is saved to the database. Return ``false`` to prevent the item from being created." msgstr "" -#: ../../guides/events-list.rst:454 +#: ../../guides/events-list.rst:460 msgid "**delete:after, river**" msgstr "" -#: ../../guides/events-list.rst:454 +#: ../../guides/events-list.rst:460 msgid "Triggered after a river item was deleted." msgstr "" -#: ../../guides/events-list.rst:457 +#: ../../guides/events-list.rst:463 msgid "**delete:before, river**" msgstr "" -#: ../../guides/events-list.rst:457 +#: ../../guides/events-list.rst:463 msgid "Triggered before a river item is deleted. Returning false cancels the deletion." msgstr "" -#: ../../guides/events-list.rst:462 +#: ../../guides/events-list.rst:468 msgid "Access events" msgstr "" -#: ../../guides/events-list.rst:469 +#: ../../guides/events-list.rst:475 msgid "**access_collection:url, access_collection** |results|" msgstr "" -#: ../../guides/events-list.rst:465 +#: ../../guides/events-list.rst:471 msgid "Can be used to filter the URL of the access collection." msgstr "" -#: ../../guides/events-list.rst:469 -#: ../../guides/events-list.rst:476 +#: ../../guides/events-list.rst:475 +#: ../../guides/events-list.rst:482 msgid "``access_collection`` - `ElggAccessCollection`" msgstr "" -#: ../../guides/events-list.rst:476 +#: ../../guides/events-list.rst:482 msgid "**access_collection:name, access_collection** |results|" msgstr "" -#: ../../guides/events-list.rst:472 +#: ../../guides/events-list.rst:478 msgid "Can be used to filter the display name (readable access level) of the access collection." msgstr "" -#: ../../guides/events-list.rst:483 +#: ../../guides/events-list.rst:489 msgid "**access:collections:read, user** |results|" msgstr "" -#: ../../guides/events-list.rst:479 +#: ../../guides/events-list.rst:485 msgid "Filters an array of access IDs that the user ``$params['user_id']`` can see." msgstr "" -#: ../../guides/events-list.rst:482 -#: ../../guides/events-list.rst:494 +#: ../../guides/events-list.rst:488 +#: ../../guides/events-list.rst:500 msgid "The handler needs to either not use parts of the API that use the access system (triggering the event again) or to ignore the second call. Otherwise, an infinite loop will be created." msgstr "" -#: ../../guides/events-list.rst:495 +#: ../../guides/events-list.rst:501 msgid "**access:collections:write, user** |results|" msgstr "" -#: ../../guides/events-list.rst:486 +#: ../../guides/events-list.rst:492 msgid "Filters an array of access IDs that the user ``$params['user_id']`` can write to. In ``elgg_get_write_access_array()``, this event filters the return value, so it can be used to alter the available options in the ``input/access`` view. For core plugins, the value \"input_params\" has the keys \"entity\" (ElggEntity|false), \"entity_type\" (string), \"entity_subtype\" (string), \"container_guid\" (int) are provided. An empty entity value generally means the form is to create a new object." msgstr "" -#: ../../guides/events-list.rst:499 +#: ../../guides/events-list.rst:505 msgid "**access:collections:write:subtypes, user** |results|" msgstr "" -#: ../../guides/events-list.rst:498 +#: ../../guides/events-list.rst:504 msgid "Returns an array of access collection subtypes to be used when retrieving access collections owned by a user as part of the ``elgg_get_write_access_array()`` function." msgstr "" -#: ../../guides/events-list.rst:503 +#: ../../guides/events-list.rst:509 msgid "**access:collections:add_user, collection** |results|" msgstr "" -#: ../../guides/events-list.rst:502 +#: ../../guides/events-list.rst:508 msgid "Triggered before adding user ``$params['user_id']`` to collection ``$params['collection_id']``. Return false to prevent adding." msgstr "" -#: ../../guides/events-list.rst:507 +#: ../../guides/events-list.rst:513 msgid "**access:collections:remove_user, collection** |results|" msgstr "" -#: ../../guides/events-list.rst:506 +#: ../../guides/events-list.rst:512 msgid "Triggered before removing user ``$params['user_id']`` to collection ``$params['collection_id']``. Return false to prevent removal." msgstr "" -#: ../../guides/events-list.rst:510 +#: ../../guides/events-list.rst:516 msgid "**create, access_collection** |sequence|" msgstr "" -#: ../../guides/events-list.rst:510 +#: ../../guides/events-list.rst:516 msgid "Triggered during the creation of an ``ElggAccessCollection``." msgstr "" -#: ../../guides/events-list.rst:513 +#: ../../guides/events-list.rst:519 msgid "**delete, access_collection** |sequence|" msgstr "" -#: ../../guides/events-list.rst:513 +#: ../../guides/events-list.rst:519 msgid "Triggered during the deletion of an ``ElggAccessCollection``." msgstr "" -#: ../../guides/events-list.rst:534 +#: ../../guides/events-list.rst:540 msgid "**get_sql, access** |results|" msgstr "" -#: ../../guides/events-list.rst:516 +#: ../../guides/events-list.rst:522 msgid "Filters SQL clauses restricting/allowing access to entities and annotations." msgstr "" -#: ../../guides/events-list.rst:519 +#: ../../guides/events-list.rst:525 msgid "**The event is triggered regardless if the access is ignored**. The handlers may need to check if access is ignored and return early, if appended clauses should only apply to access controlled contexts." msgstr "" -#: ../../guides/events-list.rst:523 +#: ../../guides/events-list.rst:529 msgid "``$return`` value is a nested array of ``ands`` and ``ors``." msgstr "" -#: ../../guides/events-list.rst:525 +#: ../../guides/events-list.rst:531 msgid "``$params`` includes:" msgstr "" -#: ../../guides/events-list.rst:527 +#: ../../guides/events-list.rst:533 msgid "``table_alias`` - alias of the main table used in select clause" msgstr "" -#: ../../guides/events-list.rst:528 +#: ../../guides/events-list.rst:534 msgid "``ignore_access`` - whether ignored access is enabled" msgstr "" -#: ../../guides/events-list.rst:529 +#: ../../guides/events-list.rst:535 msgid "``use_enabled_clause`` - whether disabled entities are shown/hidden" msgstr "" -#: ../../guides/events-list.rst:530 +#: ../../guides/events-list.rst:536 msgid "``access_column`` - column in the main table containing the access collection ID value" msgstr "" -#: ../../guides/events-list.rst:531 +#: ../../guides/events-list.rst:537 msgid "``owner_guid_column`` - column in the main table referencing the GUID of the owner" msgstr "" -#: ../../guides/events-list.rst:532 +#: ../../guides/events-list.rst:538 msgid "``guid_column`` - column in the main table referencing the GUID of the entity" msgstr "" -#: ../../guides/events-list.rst:533 +#: ../../guides/events-list.rst:539 msgid "``enabled_column`` - column in the main table referencing the enabled status of the entity" msgstr "" -#: ../../guides/events-list.rst:534 +#: ../../guides/events-list.rst:540 msgid "``query_builder`` - an instance of the ``QueryBuilder``" msgstr "" -#: ../../guides/events-list.rst:537 +#: ../../guides/events-list.rst:543 msgid "**update, access_collection** |sequence|" msgstr "" -#: ../../guides/events-list.rst:537 +#: ../../guides/events-list.rst:543 msgid "Triggered during the update of an ``ElggAccessCollection``." msgstr "" -#: ../../guides/events-list.rst:542 +#: ../../guides/events-list.rst:548 msgid "Permission events" msgstr "" -#: ../../guides/events-list.rst:558 +#: ../../guides/events-list.rst:564 msgid "**container_logic_check, ** |results|" msgstr "" -#: ../../guides/events-list.rst:545 +#: ../../guides/events-list.rst:551 msgid "Triggered by ``ElggEntity:canWriteToContainer()`` before triggering ``permissions_check`` and ``container_permissions_check`` events. Unlike permissions events, logic check can be used to prevent certain entity types from being contained by other entity types, e.g. discussion replies should only be contained by discussions. This event can also be used to apply status logic, e.g. do disallow new replies for closed discussions." msgstr "" -#: ../../guides/events-list.rst:550 +#: ../../guides/events-list.rst:556 msgid "The handler should return ``false`` to prevent an entity from containing another entity. The default value passed to the event is ``null``, so the handler can check if another event has modified the value by checking if return value is set. Should this event return ``false``, ``container_permissions_check`` and ``permissions_check`` events will not be triggered." msgstr "" -#: ../../guides/events-list.rst:556 -#: ../../guides/events-list.rst:570 +#: ../../guides/events-list.rst:562 +#: ../../guides/events-list.rst:576 msgid "``container`` - An entity that will be used as a container" msgstr "" -#: ../../guides/events-list.rst:557 -#: ../../guides/events-list.rst:571 +#: ../../guides/events-list.rst:563 +#: ../../guides/events-list.rst:577 msgid "``user`` - User who will own the entity to be written to container" msgstr "" -#: ../../guides/events-list.rst:558 -#: ../../guides/events-list.rst:572 +#: ../../guides/events-list.rst:564 +#: ../../guides/events-list.rst:578 msgid "``subtype`` - Subtype of the entity to be written to container (entity type is assumed from event type)" msgstr "" -#: ../../guides/events-list.rst:572 +#: ../../guides/events-list.rst:578 msgid "**container_permissions_check, ** |results|" msgstr "" -#: ../../guides/events-list.rst:561 +#: ../../guides/events-list.rst:567 msgid "Return boolean for if the user ``$params['user']`` can use the entity ``$params['container']`` as a container for an entity of ```` and subtype ``$params['subtype']``." msgstr "" -#: ../../guides/events-list.rst:564 +#: ../../guides/events-list.rst:570 msgid "In the rare case where an entity is created with neither the ``container_guid`` nor the ``owner_guid`` matching the logged in user, this event is called *twice*, and in the first call ``$params['container']`` will be the *owner*, not the entity's real container." msgstr "" -#: ../../guides/events-list.rst:575 +#: ../../guides/events-list.rst:581 msgid "**permissions_check, ** |results|" msgstr "" -#: ../../guides/events-list.rst:575 +#: ../../guides/events-list.rst:581 msgid "Return boolean for if the user ``$params['user']`` can edit the entity ``$params['entity']``." msgstr "" -#: ../../guides/events-list.rst:578 +#: ../../guides/events-list.rst:584 msgid "**permissions_check:delete, ** |results|" msgstr "" -#: ../../guides/events-list.rst:578 +#: ../../guides/events-list.rst:584 msgid "Return boolean for if the user ``$params['user']`` can delete the entity ``$params['entity']``. Defaults to ``$entity->canEdit()``." msgstr "" -#: ../../guides/events-list.rst:582 +#: ../../guides/events-list.rst:588 msgid "**permissions_check:delete, river** |results|" msgstr "" -#: ../../guides/events-list.rst:581 +#: ../../guides/events-list.rst:587 msgid "Return boolean for if the user ``$params['user']`` can delete the river item ``$params['item']``. Defaults to ``true`` for admins and ``false`` for other users." msgstr "" -#: ../../guides/events-list.rst:590 +#: ../../guides/events-list.rst:596 msgid "**permissions_check:download, file** |results|" msgstr "" -#: ../../guides/events-list.rst:585 +#: ../../guides/events-list.rst:591 msgid "Return boolean for if the user ``$params['user']`` can download the file in ``$params['entity']``." msgstr "" -#: ../../guides/events-list.rst:589 +#: ../../guides/events-list.rst:595 msgid "``entity`` - Instance of ``ElggFile``" msgstr "" -#: ../../guides/events-list.rst:590 +#: ../../guides/events-list.rst:596 msgid "``user`` - User who will download the file" msgstr "" -#: ../../guides/events-list.rst:594 +#: ../../guides/events-list.rst:600 msgid "**permissions_check, widget_layout** |results|" msgstr "" -#: ../../guides/events-list.rst:593 +#: ../../guides/events-list.rst:599 msgid "Return boolean for if ``$params['user']`` can edit the widgets in the context passed as ``$params['context']`` and with a page owner of ``$params['page_owner']``." msgstr "" -#: ../../guides/events-list.rst:597 +#: ../../guides/events-list.rst:603 msgid "**permissions_check:comment, ** |results|" msgstr "" -#: ../../guides/events-list.rst:597 +#: ../../guides/events-list.rst:603 msgid "Return boolean for if the user ``$params['user']`` can comment on the entity ``$params['entity']``." msgstr "" -#: ../../guides/events-list.rst:603 +#: ../../guides/events-list.rst:609 msgid "**permissions_check:annotate:, ** |results|" msgstr "" -#: ../../guides/events-list.rst:600 +#: ../../guides/events-list.rst:606 msgid "Return boolean for if the user ``$params['user']`` can create an annotation ```` on the entity ``$params['entity']``. If logged in, the default is true." msgstr "" -#: ../../guides/events-list.rst:603 +#: ../../guides/events-list.rst:609 msgid "This is called before the more general ``permissions_check:annotate`` event, and its return value is that event's initial value." msgstr "" -#: ../../guides/events-list.rst:607 +#: ../../guides/events-list.rst:613 msgid "**permissions_check:annotate, ** |results|" msgstr "" -#: ../../guides/events-list.rst:606 +#: ../../guides/events-list.rst:612 msgid "Return boolean for if the user ``$params['user']`` can create an annotation ``$params['annotation_name']`` on the entity ``$params['entity']``. if logged in, the default is true." msgstr "" -#: ../../guides/events-list.rst:610 +#: ../../guides/events-list.rst:616 msgid "**api_key, use** |results|" msgstr "" -#: ../../guides/events-list.rst:610 +#: ../../guides/events-list.rst:616 msgid "Triggered in the class ``\\Elgg\\WebServices\\PAM\\API\\APIKey``. Returning false prevents the key from being authenticated." msgstr "" -#: ../../guides/events-list.rst:622 +#: ../../guides/events-list.rst:628 msgid "**gatekeeper, :** |results|" msgstr "" -#: ../../guides/events-list.rst:613 +#: ../../guides/events-list.rst:619 msgid "Filters the result of ``elgg_entity_gatekeeper()`` to prevent or allow access to an entity that user would otherwise have or not have access to. A handler can return ``false`` or an instance of ``\\Elgg\\Exceptions\\HttpException`` to prevent access to an entity. A handler can return ``true`` to override the result of the gatekeeper. **Important** that the entity received by this event is fetched with ignored access and including disabled entities, so you have to be careful to not bypass the access system." msgstr "" -#: ../../guides/events-list.rst:619 -#: ../../guides/events-list.rst:640 -#: ../../guides/events-list.rst:654 -#: ../../guides/events-list.rst:674 -#: ../../guides/events-list.rst:729 -#: ../../guides/events-list.rst:737 -#: ../../guides/events-list.rst:790 -#: ../../guides/events-list.rst:800 -#: ../../guides/events-list.rst:823 -#: ../../guides/events-list.rst:842 +#: ../../guides/events-list.rst:625 +#: ../../guides/events-list.rst:646 +#: ../../guides/events-list.rst:660 +#: ../../guides/events-list.rst:680 +#: ../../guides/events-list.rst:735 +#: ../../guides/events-list.rst:743 +#: ../../guides/events-list.rst:796 +#: ../../guides/events-list.rst:806 +#: ../../guides/events-list.rst:829 +#: ../../guides/events-list.rst:848 msgid "``$params`` array includes:" msgstr "" -#: ../../guides/events-list.rst:621 +#: ../../guides/events-list.rst:627 msgid "``entity`` - Entity that is being accessed" msgstr "" -#: ../../guides/events-list.rst:622 +#: ../../guides/events-list.rst:628 msgid "``user`` - User accessing the entity (``null`` implies logged in user)" msgstr "" -#: ../../guides/events-list.rst:625 +#: ../../guides/events-list.rst:631 msgid "Notifications events" msgstr "" -#: ../../guides/events-list.rst:628 +#: ../../guides/events-list.rst:634 msgid "**dequeue, notifications**" msgstr "" -#: ../../guides/events-list.rst:628 +#: ../../guides/events-list.rst:634 msgid "Called when an ElggData object is removed from the notifications queue to be processed" msgstr "" -#: ../../guides/events-list.rst:631 +#: ../../guides/events-list.rst:637 msgid "**enqueue, notifications**" msgstr "" -#: ../../guides/events-list.rst:631 +#: ../../guides/events-list.rst:637 msgid "Called when an ElggData object is being added to the notifications queue" msgstr "" -#: ../../guides/events-list.rst:633 +#: ../../guides/events-list.rst:639 msgid "The following events are listed chronologically in the lifetime of the notification event. Note that not all events apply to instant notifications." msgstr "" -#: ../../guides/events-list.rst:643 +#: ../../guides/events-list.rst:649 msgid "**enqueue, notification** |results|" msgstr "" -#: ../../guides/events-list.rst:637 +#: ../../guides/events-list.rst:643 msgid "Can be used to prevent a notification event from sending **subscription** notifications. Event handler must return ``false`` to prevent a subscription notification event from being enqueued." msgstr "" -#: ../../guides/events-list.rst:642 +#: ../../guides/events-list.rst:648 msgid "``object`` - object of the notification event" msgstr "" -#: ../../guides/events-list.rst:643 +#: ../../guides/events-list.rst:649 msgid "``action`` - action that triggered the notification event. E.g. corresponds to ``publish`` when ``elgg_trigger_event('publish', 'object', $object)`` is called" msgstr "" -#: ../../guides/events-list.rst:660 +#: ../../guides/events-list.rst:666 msgid "**get, subscriptions** |results|" msgstr "" -#: ../../guides/events-list.rst:646 +#: ../../guides/events-list.rst:652 msgid "Filters subscribers of the notification event. Applies to **subscriptions** and **instant** notifications. In case of a subscription event, by default, the subscribers list consists of the users subscribed to the container entity of the event object. In case of an instant notification event, the subscribers list consists of the users passed as recipients to ``notify_user()``" msgstr "" -#: ../../guides/events-list.rst:651 +#: ../../guides/events-list.rst:657 msgid "**IMPORTANT** Always validate the notification event, object and/or action types before adding any new recipients to ensure that you do not accidentally dispatch notifications to unintended recipients. Consider a situation, where a mentions plugin sends out an instant notification to a mentioned user - any event acting on a subject or an object without validating an event or action type (e.g. including an owner of the original wire thread) might end up sending notifications to wrong users." msgstr "" -#: ../../guides/events-list.rst:656 -#: ../../guides/events-list.rst:676 -#: ../../guides/events-list.rst:687 -#: ../../guides/events-list.rst:704 -#: ../../guides/events-list.rst:739 +#: ../../guides/events-list.rst:662 +#: ../../guides/events-list.rst:682 +#: ../../guides/events-list.rst:693 +#: ../../guides/events-list.rst:710 +#: ../../guides/events-list.rst:745 msgid "``event`` - ``\\Elgg\\Notifications\\NotificationEvent`` instance that describes the notification event" msgstr "" -#: ../../guides/events-list.rst:657 -#: ../../guides/events-list.rst:694 -#: ../../guides/events-list.rst:711 +#: ../../guides/events-list.rst:663 +#: ../../guides/events-list.rst:700 +#: ../../guides/events-list.rst:717 msgid "``origin`` - ``subscriptions_service`` or ``instant_notifications``" msgstr "" -#: ../../guides/events-list.rst:658 +#: ../../guides/events-list.rst:664 msgid "``methods_override`` - delivery method preference for instant notifications" msgstr "" -#: ../../guides/events-list.rst:660 +#: ../../guides/events-list.rst:666 msgid "Handlers must return an array in the form:" msgstr "" -#: ../../guides/events-list.rst:677 +#: ../../guides/events-list.rst:683 msgid "**send:before, notifications** |results|" msgstr "" -#: ../../guides/events-list.rst:671 +#: ../../guides/events-list.rst:677 msgid "Triggered before the notification event queue is processed. Can be used to terminate the notification event. Applies to **subscriptions** and **instant** notifications." msgstr "" -#: ../../guides/events-list.rst:677 -#: ../../guides/events-list.rst:740 +#: ../../guides/events-list.rst:683 +#: ../../guides/events-list.rst:746 msgid "``subscriptions`` - a list of subscriptions. See ``'get', 'subscriptions'`` event for details" msgstr "" -#: ../../guides/events-list.rst:694 +#: ../../guides/events-list.rst:700 msgid "**prepare, notification** |results|" msgstr "" -#: ../../guides/events-list.rst:680 +#: ../../guides/events-list.rst:686 msgid "A high level event that can be used to alter an instance of ``\\Elgg\\Notifications\\Notification`` before it is sent to the user. Applies to **subscriptions** and **instant** notifications. This event is triggered before a more granular ``'prepare', 'notification:::'`` and after ``'send:before', 'notifications``. Event handler should return an altered notification object." msgstr "" -#: ../../guides/events-list.rst:685 +#: ../../guides/events-list.rst:691 msgid "``$params`` may vary based on the notification type and may include:" msgstr "" -#: ../../guides/events-list.rst:688 -#: ../../guides/events-list.rst:705 +#: ../../guides/events-list.rst:694 +#: ../../guides/events-list.rst:711 msgid "``object`` - object of the notification ``event``. Can be ``null`` for instant notifications" msgstr "" -#: ../../guides/events-list.rst:689 -#: ../../guides/events-list.rst:706 +#: ../../guides/events-list.rst:695 +#: ../../guides/events-list.rst:712 msgid "``action`` - action that triggered the notification ``event``. May default to ``notify_user`` for instant notifications" msgstr "" -#: ../../guides/events-list.rst:690 -#: ../../guides/events-list.rst:707 +#: ../../guides/events-list.rst:696 +#: ../../guides/events-list.rst:713 msgid "``method`` - delivery method (e.g. ``email``, ``site``)" msgstr "" -#: ../../guides/events-list.rst:691 -#: ../../guides/events-list.rst:708 +#: ../../guides/events-list.rst:697 +#: ../../guides/events-list.rst:714 msgid "``sender`` - sender" msgstr "" -#: ../../guides/events-list.rst:692 -#: ../../guides/events-list.rst:709 +#: ../../guides/events-list.rst:698 +#: ../../guides/events-list.rst:715 msgid "``recipient`` - recipient" msgstr "" -#: ../../guides/events-list.rst:693 -#: ../../guides/events-list.rst:710 +#: ../../guides/events-list.rst:699 +#: ../../guides/events-list.rst:716 msgid "``language`` - language of the notification (recipient's language)" msgstr "" -#: ../../guides/events-list.rst:711 +#: ../../guides/events-list.rst:717 msgid "**prepare, notification:::** |results|" msgstr "" -#: ../../guides/events-list.rst:697 +#: ../../guides/events-list.rst:703 msgid "A granular event that can be used to filter a notification ``\\Elgg\\Notifications\\Notification`` before it is sent to the user. Applies to **subscriptions** and **instant** notifications. In case of instant notifications that have not received an object, the event will be called as ``'prepare', 'notification:'``. In case of instant notifications that have not received an action name, it will default to ``notify_user``." msgstr "" -#: ../../guides/events-list.rst:702 +#: ../../guides/events-list.rst:708 msgid "``$params`` include:" msgstr "" -#: ../../guides/events-list.rst:722 +#: ../../guides/events-list.rst:728 msgid "**format, notification:** |results|" msgstr "" -#: ../../guides/events-list.rst:714 +#: ../../guides/events-list.rst:720 msgid "This event can be used to format a notification before it is passed to the ``'send', 'notification:'`` event. Applies to **subscriptions** and **instant** notifications. The event handler should return an instance of ``\\Elgg\\Notifications\\Notification``. The event does not receive any ``$params``. Some of the use cases include:" msgstr "" -#: ../../guides/events-list.rst:720 +#: ../../guides/events-list.rst:726 msgid "Strip tags from notification title and body for plaintext email notifications" msgstr "" -#: ../../guides/events-list.rst:721 +#: ../../guides/events-list.rst:727 msgid "Inline HTML styles for HTML email notifications" msgstr "" -#: ../../guides/events-list.rst:722 +#: ../../guides/events-list.rst:728 msgid "Wrap notification in a template, add signature etc." msgstr "" -#: ../../guides/events-list.rst:731 +#: ../../guides/events-list.rst:737 msgid "**send, notification:** |results|" msgstr "" -#: ../../guides/events-list.rst:725 +#: ../../guides/events-list.rst:731 msgid "Delivers a notification. Applies to **subscriptions** and **instant** notifications. The handler must return ``true`` or ``false`` indicating the success of the delivery." msgstr "" -#: ../../guides/events-list.rst:731 +#: ../../guides/events-list.rst:737 msgid "``notification`` - a notification object ``\\Elgg\\Notifications\\Notification``" msgstr "" -#: ../../guides/events-list.rst:741 +#: ../../guides/events-list.rst:747 msgid "**send:after, notifications** |results|" msgstr "" -#: ../../guides/events-list.rst:734 +#: ../../guides/events-list.rst:740 msgid "Triggered after all notifications in the queue for the notifications event have been processed. Applies to **subscriptions** and **instant** notifications." msgstr "" -#: ../../guides/events-list.rst:741 +#: ../../guides/events-list.rst:747 msgid "``deliveries`` - a matrix of delivery statuses by user for each delivery method" msgstr "" -#: ../../guides/events-list.rst:744 +#: ../../guides/events-list.rst:750 msgid "Emails" msgstr "" -#: ../../guides/events-list.rst:752 +#: ../../guides/events-list.rst:758 msgid "**prepare, system:email** |results|" msgstr "" -#: ../../guides/events-list.rst:747 +#: ../../guides/events-list.rst:753 msgid "Triggered by ``elgg_send_email()``. Applies to all outgoing system and notification emails. This event allows you to alter an instance of ``\\Elgg\\Email`` before it is passed to the email transport. This event can be used to alter the sender, recipient, subject, body, and/or headers of the email." msgstr "" -#: ../../guides/events-list.rst:752 +#: ../../guides/events-list.rst:758 msgid "``$params`` are empty. The ``$return`` value is an instance of ``\\Elgg\\Email``." msgstr "" -#: ../../guides/events-list.rst:762 +#: ../../guides/events-list.rst:768 msgid "**transport, system:email** |results|" msgstr "" -#: ../../guides/events-list.rst:755 +#: ../../guides/events-list.rst:761 msgid "Triggered by ``elgg_send_email()``. Applies to all outgoing system and notification emails. This event allows you to implement a custom email transport, e.g. delivering emails via a third-party proxy service such as SendGrid or Mailgun. The handler must return ``true`` to indicate that the email was transported." msgstr "" -#: ../../guides/events-list.rst:760 -#: ../../guides/events-list.rst:770 -#: ../../guides/events-list.rst:779 +#: ../../guides/events-list.rst:766 +#: ../../guides/events-list.rst:776 +#: ../../guides/events-list.rst:785 msgid "``$params`` contains:" msgstr "" -#: ../../guides/events-list.rst:762 -#: ../../guides/events-list.rst:772 -#: ../../guides/events-list.rst:781 +#: ../../guides/events-list.rst:768 +#: ../../guides/events-list.rst:778 +#: ../../guides/events-list.rst:787 msgid "``email`` - An instance of ``\\Elgg\\Email``" msgstr "" -#: ../../guides/events-list.rst:772 +#: ../../guides/events-list.rst:778 msgid "**validate, system:email** |results|" msgstr "" -#: ../../guides/events-list.rst:765 +#: ../../guides/events-list.rst:771 msgid "Triggered by ``elgg_send_email()``. Applies to all outgoing system and notification emails. This event allows you to suppress or whitelist outgoing emails, e.g. when the site is in a development mode. The handler must return ``false`` to supress the email delivery." msgstr "" -#: ../../guides/events-list.rst:781 +#: ../../guides/events-list.rst:787 msgid "**zend:message, system:email** |results|" msgstr "" -#: ../../guides/events-list.rst:775 +#: ../../guides/events-list.rst:781 msgid "Triggered by the default email transport handler (Elgg uses ``laminas/laminas-mail``). Applies to all outgoing system and notification emails that were not transported using the **transport, system:email** event. This event allows you to alter an instance of ``\\Laminas\\Mail\\Message`` before it is passed to the Laminas email transport." msgstr "" -#: ../../guides/events-list.rst:784 +#: ../../guides/events-list.rst:790 msgid "File events" msgstr "" -#: ../../guides/events-list.rst:794 +#: ../../guides/events-list.rst:800 msgid "**download:url, file** |results|" msgstr "" -#: ../../guides/events-list.rst:788 +#: ../../guides/events-list.rst:794 msgid "Allows plugins to filter the download URL of the file." msgstr "" -#: ../../guides/events-list.rst:788 +#: ../../guides/events-list.rst:794 msgid "By default, the download URL is generated by the file service." msgstr "" -#: ../../guides/events-list.rst:792 -#: ../../guides/events-list.rst:802 +#: ../../guides/events-list.rst:798 +#: ../../guides/events-list.rst:808 msgid "``entity`` - instance of ``ElggFile``" msgstr "" -#: ../../guides/events-list.rst:793 -#: ../../guides/events-list.rst:803 +#: ../../guides/events-list.rst:799 +#: ../../guides/events-list.rst:809 msgid "``use_cookie`` - whether or not to use a cookie to secure download link" msgstr "" -#: ../../guides/events-list.rst:794 -#: ../../guides/events-list.rst:804 +#: ../../guides/events-list.rst:800 +#: ../../guides/events-list.rst:810 msgid "``expires`` - a string representation of when the download link should expire" msgstr "" -#: ../../guides/events-list.rst:804 +#: ../../guides/events-list.rst:810 msgid "**inline:url, file** |results|" msgstr "" -#: ../../guides/events-list.rst:798 +#: ../../guides/events-list.rst:804 msgid "Allows plugins to filter the inline URL of the image file." msgstr "" -#: ../../guides/events-list.rst:798 +#: ../../guides/events-list.rst:804 msgid "By default, the inline URL is generated by the file service." msgstr "" -#: ../../guides/events-list.rst:808 +#: ../../guides/events-list.rst:814 msgid "**mime_type, file** |results|" msgstr "" -#: ../../guides/events-list.rst:807 +#: ../../guides/events-list.rst:813 msgid "Return the mimetype for the filename ``$params['filename']`` with original filename ``$params['original_filename']`` and with the default detected mimetype of ``$params['default']``." msgstr "" -#: ../../guides/events-list.rst:814 +#: ../../guides/events-list.rst:820 msgid "**simple_type, file** |results|" msgstr "" -#: ../../guides/events-list.rst:811 +#: ../../guides/events-list.rst:817 msgid "The event provides ``$params['mime_type']`` (e.g. ``application/pdf`` or ``image/jpeg``) and determines an overall category like ``document`` or ``image``. The bundled file plugin and other-third party plugins usually store ``simpletype`` metadata on file entities and make use of it when serving icons and constructing ``ege*`` filters and menus." msgstr "" -#: ../../guides/events-list.rst:826 +#: ../../guides/events-list.rst:832 msgid "**upload, file** |results|" msgstr "" -#: ../../guides/events-list.rst:817 +#: ../../guides/events-list.rst:823 msgid "Allows plugins to implement custom logic for moving an uploaded file into an instance of ``ElggFile``. The handler must return ``true`` to indicate that the uploaded file was moved. The handler must return ``false`` to indicate that the uploaded file could not be moved. Other returns will indicate that ``ElggFile::acceptUploadedFile`` should proceed with the default upload logic." msgstr "" -#: ../../guides/events-list.rst:825 +#: ../../guides/events-list.rst:831 msgid "``file`` - instance of ``ElggFile`` to write to" msgstr "" -#: ../../guides/events-list.rst:826 +#: ../../guides/events-list.rst:832 msgid "``upload`` - instance of Symfony's ``UploadedFile``" msgstr "" -#: ../../guides/events-list.rst:831 +#: ../../guides/events-list.rst:837 msgid "**upload:after, file**" msgstr "" -#: ../../guides/events-list.rst:829 +#: ../../guides/events-list.rst:835 msgid "Called after an uploaded file has been written to filestore. Receives an instance of ``ElggFile`` the uploaded file was written to. The ``ElggFile`` may or may not be an entity with a GUID." msgstr "" -#: ../../guides/events-list.rst:834 +#: ../../guides/events-list.rst:840 msgid "Action events" msgstr "" -#: ../../guides/events-list.rst:844 +#: ../../guides/events-list.rst:850 msgid "**action:validate, ** |results|" msgstr "" -#: ../../guides/events-list.rst:837 +#: ../../guides/events-list.rst:843 msgid "Trigger before action script/controller is executed. This event should be used to validate/alter user input, before proceeding with the action. The event handler can throw an instance of ``\\Elgg\\Exceptions\\Http\\ValidationException`` or return ``false`` to terminate further execution." msgstr "" -#: ../../guides/events-list.rst:844 +#: ../../guides/events-list.rst:850 msgid "``request`` - instance of ``\\Elgg\\Request``" msgstr "" -#: ../../guides/events-list.rst:847 +#: ../../guides/events-list.rst:853 msgid "**action_gatekeeper:permissions:check, all** |results|" msgstr "" -#: ../../guides/events-list.rst:847 +#: ../../guides/events-list.rst:853 msgid "Triggered after a CSRF token is validated. Return false to prevent validation." msgstr "" -#: ../../guides/events-list.rst:851 +#: ../../guides/events-list.rst:857 msgid "**forward, ** |results|" msgstr "" -#: ../../guides/events-list.rst:850 +#: ../../guides/events-list.rst:856 msgid "Filter the URL to forward a user to when ``forward($url, $reason)`` is called. In certain cases, the ``params`` array will contain an instance of ``\\Elgg\\Exceptions\\HttpException`` that triggered the error." msgstr "" -#: ../../guides/events-list.rst:857 +#: ../../guides/events-list.rst:863 msgid "**response, action:** |results|" msgstr "" -#: ../../guides/events-list.rst:854 +#: ../../guides/events-list.rst:860 msgid "Filter an instance of ``\\Elgg\\Http\\ResponseBuilder`` before it is sent to the client. This event can be used to modify response content, status code, forward URL, or set additional response headers. Note that the ```` value is parsed from the request URL, therefore you may not be able to filter the responses of `action()` calls if they are nested within the another action script file." msgstr "" -#: ../../guides/events-list.rst:876 +#: ../../guides/events-list.rst:882 msgid "**ajax_response, \\*** |results|" msgstr "" -#: ../../guides/events-list.rst:865 +#: ../../guides/events-list.rst:871 msgid "When the ``elgg/Ajax`` AMD module is used, this event gives access to the response object (``\\Elgg\\Services\\AjaxResponse``) so it can be altered/extended. The event type depends on the method call:" msgstr "" -#: ../../guides/events-list.rst:870 +#: ../../guides/events-list.rst:876 msgid "elgg/Ajax method" msgstr "" -#: ../../guides/events-list.rst:870 +#: ../../guides/events-list.rst:876 msgid "event type" msgstr "" -#: ../../guides/events-list.rst:872 +#: ../../guides/events-list.rst:878 msgid "action()" msgstr "" -#: ../../guides/events-list.rst:872 +#: ../../guides/events-list.rst:878 msgid "action:" msgstr "" -#: ../../guides/events-list.rst:873 +#: ../../guides/events-list.rst:879 msgid "path()" msgstr "" -#: ../../guides/events-list.rst:873 +#: ../../guides/events-list.rst:879 msgid "path:" msgstr "" -#: ../../guides/events-list.rst:874 +#: ../../guides/events-list.rst:880 msgid "view()" msgstr "" -#: ../../guides/events-list.rst:874 +#: ../../guides/events-list.rst:880 msgid "view:" msgstr "" -#: ../../guides/events-list.rst:875 +#: ../../guides/events-list.rst:881 msgid "form()" msgstr "" -#: ../../guides/events-list.rst:875 +#: ../../guides/events-list.rst:881 msgid "form:" msgstr "" -#: ../../guides/events-list.rst:879 +#: ../../guides/events-list.rst:885 msgid "**ajax_response, action:** |results|" msgstr "" -#: ../../guides/events-list.rst:879 +#: ../../guides/events-list.rst:885 msgid "Filters ``action/`` responses before they're sent back to the ``elgg/Ajax`` module." msgstr "" -#: ../../guides/events-list.rst:883 +#: ../../guides/events-list.rst:889 msgid "**ajax_response, path:** |results|" msgstr "" -#: ../../guides/events-list.rst:882 +#: ../../guides/events-list.rst:888 msgid "Filters ajax responses before they're sent back to the ``elgg/Ajax`` module. This event type will only be used if the path did not start with \"action/\" or \"ajax/\"." msgstr "" -#: ../../guides/events-list.rst:886 +#: ../../guides/events-list.rst:892 msgid "**ajax_response, view:** |results|" msgstr "" -#: ../../guides/events-list.rst:886 +#: ../../guides/events-list.rst:892 msgid "Filters ``ajax/view/`` responses before they're sent back to the ``elgg/Ajax`` module." msgstr "" -#: ../../guides/events-list.rst:889 +#: ../../guides/events-list.rst:895 msgid "**ajax_response, form:** |results|" msgstr "" -#: ../../guides/events-list.rst:889 +#: ../../guides/events-list.rst:895 msgid "Filters ``ajax/form/`` responses before they're sent back to the ``elgg/Ajax`` module." msgstr "" -#: ../../guides/events-list.rst:892 +#: ../../guides/events-list.rst:898 #: ../../guides/routing.rst:2 msgid "Routing" msgstr "" -#: ../../guides/events-list.rst:899 +#: ../../guides/events-list.rst:905 msgid "**response, path:** |results|" msgstr "" -#: ../../guides/events-list.rst:895 +#: ../../guides/events-list.rst:901 msgid "Filter an instance of ``\\Elgg\\Http\\ResponseBuilder`` before it is sent to the client. This event type will only be used if the path did not start with \"action/\" or \"ajax/\". This event can be used to modify response content, status code, forward URL, or set additional response headers. Note that the ```` value is parsed from the request URL, therefore plugins using the ``route`` event should use the original ```` to filter the response, or switch to using the ``route:rewrite`` event." msgstr "" -#: ../../guides/events-list.rst:904 +#: ../../guides/events-list.rst:910 msgid "**route:config, ** |results|" msgstr "" -#: ../../guides/events-list.rst:902 +#: ../../guides/events-list.rst:908 msgid "Allows altering the route configuration before it is registered. This event can be used to alter the path, default values, requirements, as well as to set/remove middleware. Please note that the handler for this event should be registered outside of the ``init`` event handler, as core routes are registered during ``plugins_boot`` event." msgstr "" -#: ../../guides/events-list.rst:908 +#: ../../guides/events-list.rst:914 msgid "**route:rewrite, ** |results|" msgstr "" -#: ../../guides/events-list.rst:907 +#: ../../guides/events-list.rst:913 msgid "Allows altering the site-relative URL path for an incoming request. See :doc:`routing` for details. Please note that the handler for this event should be registered outside of the ``init`` event handler, as route rewrites take place after ``plugins_boot`` event has completed." msgstr "" -#: ../../guides/events-list.rst:913 +#: ../../guides/events-list.rst:919 #: ../../guides/plugins/plugin-skeleton.rst:141 #: ../../guides/views.rst:2 msgid "Views" msgstr "" -#: ../../guides/events-list.rst:916 +#: ../../guides/events-list.rst:922 msgid "**attributes, htmlawed** |results|" msgstr "" -#: ../../guides/events-list.rst:916 +#: ../../guides/events-list.rst:922 msgid "Allows changes to individual attributes." msgstr "" -#: ../../guides/events-list.rst:919 +#: ../../guides/events-list.rst:925 msgid "**allowed_styles, htmlawed** |results|" msgstr "" -#: ../../guides/events-list.rst:919 +#: ../../guides/events-list.rst:925 msgid "Configure allowed styles for HTMLawed." msgstr "" -#: ../../guides/events-list.rst:922 +#: ../../guides/events-list.rst:928 msgid "**config, htmlawed** |results|" msgstr "" -#: ../../guides/events-list.rst:922 +#: ../../guides/events-list.rst:928 msgid "Filter the HTMLawed ``$config`` array." msgstr "" -#: ../../guides/events-list.rst:926 +#: ../../guides/events-list.rst:932 msgid "**form:prepare:fields, ** |results|" msgstr "" -#: ../../guides/events-list.rst:925 +#: ../../guides/events-list.rst:931 msgid "Prepare field values for use in the form. Eg. when editing a blog, fill this with the current values of the blog. Sticky form values will automatically be added to the field values (when available)." msgstr "" -#: ../../guides/events-list.rst:934 +#: ../../guides/events-list.rst:940 msgid "**head, page** |results|" msgstr "" -#: ../../guides/events-list.rst:929 +#: ../../guides/events-list.rst:935 msgid "In ``elgg_view_page()``, filters ``$vars['head']`` Return value contains an array with ``title``, ``metas`` and ``links`` keys, where ``metas`` is an array of elements to be formatted as ```` head tags, and ``links`` is an array of elements to be formatted as ```` head tags. Each meta and link element contains a set of key/value pairs that are formatted into html tag attributes, e.g." msgstr "" -#: ../../guides/events-list.rst:968 +#: ../../guides/events-list.rst:974 msgid "**layout, page** |results|" msgstr "" -#: ../../guides/events-list.rst:963 +#: ../../guides/events-list.rst:969 msgid "In ``elgg_view_layout()``, filters the layout name. ``$params`` array includes:" msgstr "" -#: ../../guides/events-list.rst:966 +#: ../../guides/events-list.rst:972 msgid "``identifier`` - ID of the page being rendered" msgstr "" -#: ../../guides/events-list.rst:967 +#: ../../guides/events-list.rst:973 msgid "``segments`` - URL segments of the page being rendered" msgstr "" -#: ../../guides/events-list.rst:968 +#: ../../guides/events-list.rst:974 msgid "other ``$vars`` received by ``elgg_view_layout()``" msgstr "" -#: ../../guides/events-list.rst:973 +#: ../../guides/events-list.rst:979 msgid "**response, form:** |results|" msgstr "" -#: ../../guides/events-list.rst:971 +#: ../../guides/events-list.rst:977 msgid "Filter an instance of ``\\Elgg\\Http\\ResponseBuilder`` before it is sent to the client. Applies to request to ``/ajax/form/``. This event can be used to modify response content, status code, forward URL, or set additional response headers." msgstr "" -#: ../../guides/events-list.rst:978 +#: ../../guides/events-list.rst:984 msgid "**response, view:** |results|" msgstr "" -#: ../../guides/events-list.rst:976 +#: ../../guides/events-list.rst:982 msgid "Filter an instance of ``\\Elgg\\Http\\ResponseBuilder`` before it is sent to the client. Applies to request to ``/ajax/view/``. This event can be used to modify response content, status code, forward URL, or set additional response headers." msgstr "" -#: ../../guides/events-list.rst:981 +#: ../../guides/events-list.rst:987 msgid "**shell, page** |results|" msgstr "" -#: ../../guides/events-list.rst:981 +#: ../../guides/events-list.rst:987 msgid "In ``elgg_view_page()``, filters the page shell name" msgstr "" -#: ../../guides/events-list.rst:984 +#: ../../guides/events-list.rst:990 msgid "**spec, htmlawed** |results|" msgstr "" -#: ../../guides/events-list.rst:984 +#: ../../guides/events-list.rst:990 msgid "Filter the HTMLawed ``$spec`` string (default empty)." msgstr "" -#: ../../guides/events-list.rst:990 +#: ../../guides/events-list.rst:996 msgid "**table_columns:call, ** |results|" msgstr "" -#: ../../guides/events-list.rst:987 +#: ../../guides/events-list.rst:993 msgid "When the method ``elgg()->table_columns->$name()`` is called, this event is called to allow plugins to override or provide an implementation. Handlers receive the method arguments via ``$params['arguments']`` and should return an instance of ``Elgg\\Views\\TableColumn`` if they wish to specify the column directly." msgstr "" -#: ../../guides/events-list.rst:994 +#: ../../guides/events-list.rst:1000 msgid "**vars:compiler, css** |results|" msgstr "" -#: ../../guides/events-list.rst:993 +#: ../../guides/events-list.rst:999 msgid "Allows plugins to alter CSS variables passed to CssCrush during compilation. See `CSS variables <_guides/theming#css-vars>`." msgstr "" -#: ../../guides/events-list.rst:997 +#: ../../guides/events-list.rst:1003 msgid "**view, ** |results|" msgstr "" -#: ../../guides/events-list.rst:997 +#: ../../guides/events-list.rst:1003 msgid "Filters the returned content of the view" msgstr "" -#: ../../guides/events-list.rst:1000 +#: ../../guides/events-list.rst:1006 msgid "**view_vars, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1000 +#: ../../guides/events-list.rst:1006 msgid "Filters the ``$vars`` array passed to the view" msgstr "" -#: ../../guides/events-list.rst:1005 +#: ../../guides/events-list.rst:1011 #: ../../guides/search.rst:2 msgid "Search" msgstr "" -#: ../../guides/events-list.rst:1010 +#: ../../guides/events-list.rst:1016 msgid "**search:config, search_types** |results|" msgstr "" -#: ../../guides/events-list.rst:1008 +#: ../../guides/events-list.rst:1014 msgid "Implemented in the **search** plugin. Filters an array of custom search types. This allows plugins to add custom search types (e.g. tag or location search). Adding a custom search type will extend the search plugin user interface with appropriate links and lists." msgstr "" -#: ../../guides/events-list.rst:1015 +#: ../../guides/events-list.rst:1021 msgid "**search:config, type_subtype_pairs** |results|" msgstr "" -#: ../../guides/events-list.rst:1013 +#: ../../guides/events-list.rst:1019 msgid "Implemented in the **search** plugin. Filters entity type/subtype pairs before entity search is performed. Allows plugins to remove certain entity types/subtypes from search results, group multiple subtypes together, or to reorder search sections." msgstr "" -#: ../../guides/events-list.rst:1020 +#: ../../guides/events-list.rst:1026 msgid "**search:fields, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1018 +#: ../../guides/events-list.rst:1024 msgid "Triggered by ``elgg_search()``. Filters search fields before search clauses are prepared. ``$return`` value contains an array of names for each entity property type, which should be matched against the search query. ``$params`` array contains an array of search params passed to and filtered by ``elgg_search()``." msgstr "" -#: ../../guides/events-list.rst:1031 +#: ../../guides/events-list.rst:1037 msgid "**search:fields, :** |results|" msgstr "" -#: ../../guides/events-list.rst:1031 -#: ../../guides/events-list.rst:1034 +#: ../../guides/events-list.rst:1037 +#: ../../guides/events-list.rst:1040 msgid "See **search:fields, **" msgstr "" -#: ../../guides/events-list.rst:1034 +#: ../../guides/events-list.rst:1040 msgid "**search:fields, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1039 +#: ../../guides/events-list.rst:1045 msgid "**search:format, entity** |results|" msgstr "" -#: ../../guides/events-list.rst:1037 +#: ../../guides/events-list.rst:1043 msgid "Implemented in the **search** plugin. Allows plugins to populate entity's volatile data before it's passed to search view. This is used for highlighting search hit, extracting relevant substrings in long text fields etc." msgstr "" -#: ../../guides/events-list.rst:1042 +#: ../../guides/events-list.rst:1048 msgid "**search:options, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1042 +#: ../../guides/events-list.rst:1048 msgid "Triggered by ``elgg_search()``. Prepares search clauses (options) to be passed to ``elgg_get_entities()``." msgstr "" -#: ../../guides/events-list.rst:1045 +#: ../../guides/events-list.rst:1051 msgid "**search:options, :** |results|" msgstr "" -#: ../../guides/events-list.rst:1045 -#: ../../guides/events-list.rst:1048 +#: ../../guides/events-list.rst:1051 +#: ../../guides/events-list.rst:1054 msgid "See **search:options, **" msgstr "" -#: ../../guides/events-list.rst:1048 +#: ../../guides/events-list.rst:1054 msgid "**search:options, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1052 +#: ../../guides/events-list.rst:1058 msgid "**search:params, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1051 +#: ../../guides/events-list.rst:1057 msgid "Triggered by ``elgg_search()``. Filters search parameters (query, sorting, search fields etc) before search clauses are prepared for a given search type. Elgg core only provides support for ``entities`` search type." msgstr "" -#: ../../guides/events-list.rst:1056 +#: ../../guides/events-list.rst:1062 msgid "**search:results, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1055 +#: ../../guides/events-list.rst:1061 msgid "Triggered by ``elgg_search()``. Receives normalized options suitable for ``elgg_get_entities()`` call and must return an array of entities matching search options. This event is designed for use by plugins integrating third-party indexing services, such as Solr and Elasticsearch." msgstr "" -#: ../../guides/events-list.rst:1061 +#: ../../guides/events-list.rst:1067 msgid "Other" msgstr "" -#: ../../guides/events-list.rst:1065 +#: ../../guides/events-list.rst:1071 msgid "**config, comments_per_page** |results|" msgstr "" -#: ../../guides/events-list.rst:1064 +#: ../../guides/events-list.rst:1070 msgid "Filters the number of comments displayed per page. Default is 25. ``$params['entity']`` will hold the containing entity or null if not provided. Use ``elgg_comments_per_page()`` to get the value." msgstr "" -#: ../../guides/events-list.rst:1069 +#: ../../guides/events-list.rst:1075 msgid "**config, comments_latest_first** |results|" msgstr "" -#: ../../guides/events-list.rst:1068 +#: ../../guides/events-list.rst:1074 msgid "Filters the order of comments. Default is ``true`` for latest first. ``$params['entity']`` will hold the containing entity or null if not provided." msgstr "" -#: ../../guides/events-list.rst:1076 +#: ../../guides/events-list.rst:1082 msgid "**default, access** |results|" msgstr "" -#: ../../guides/events-list.rst:1072 +#: ../../guides/events-list.rst:1078 msgid "In ``elgg_get_default_access()``, this event filters the return value, so it can be used to alter the default value in the input/access view. For core plugins, the value \"input_params\" has the keys \"entity\" (ElggEntity|false), \"entity_type\" (string), \"entity_subtype\" (string), \"container_guid\" (int) are provided. An empty entity value generally means the form is to create a new object." msgstr "" -#: ../../guides/events-list.rst:1080 +#: ../../guides/events-list.rst:1086 msgid "**classes, icon** |results|" msgstr "" -#: ../../guides/events-list.rst:1079 +#: ../../guides/events-list.rst:1085 msgid "Can be used to filter CSS classes applied to icon glyphs. By default, Elgg uses FontAwesome. Plugins can use this event to switch to a different font family and remap icon classes." msgstr "" -#: ../../guides/events-list.rst:1083 +#: ../../guides/events-list.rst:1089 msgid "**config, amd** |results|" msgstr "" -#: ../../guides/events-list.rst:1083 +#: ../../guides/events-list.rst:1089 msgid "Filter the AMD config for the requirejs library." msgstr "" -#: ../../guides/events-list.rst:1087 +#: ../../guides/events-list.rst:1093 msgid "**entity:icon:sizes, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1086 +#: ../../guides/events-list.rst:1092 msgid "Triggered by ``elgg_get_icon_sizes()`` and sets entity type/subtype specific icon sizes. ``entity_subtype`` will be passed with the ``$params`` array to the callback." msgstr "" -#: ../../guides/events-list.rst:1104 +#: ../../guides/events-list.rst:1110 msgid "**entity::sizes, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1090 +#: ../../guides/events-list.rst:1096 msgid "Allows filtering sizes for custom icon types, see ``entity:icon:sizes, ``." msgstr "" -#: ../../guides/events-list.rst:1092 +#: ../../guides/events-list.rst:1098 msgid "The event must return an associative array where keys are the names of the icon sizes (e.g. \"large\"), and the values are arrays with the following keys:" msgstr "" -#: ../../guides/events-list.rst:1095 +#: ../../guides/events-list.rst:1101 msgid "``w`` - Width of the image in pixels" msgstr "" -#: ../../guides/events-list.rst:1096 +#: ../../guides/events-list.rst:1102 msgid "``h`` - Height of the image in pixels" msgstr "" -#: ../../guides/events-list.rst:1097 +#: ../../guides/events-list.rst:1103 msgid "``square`` - Should the aspect ratio be a square (true/false)" msgstr "" -#: ../../guides/events-list.rst:1098 +#: ../../guides/events-list.rst:1104 msgid "``upscale`` - Should the image be upscaled in case it is smaller than the given width and height (true/false)" msgstr "" -#: ../../guides/events-list.rst:1099 +#: ../../guides/events-list.rst:1105 msgid "``crop`` - Is cropping allowed on this image size (true/false, default: true)" msgstr "" -#: ../../guides/events-list.rst:1101 +#: ../../guides/events-list.rst:1107 msgid "If the configuration array for an image size is empty, the image will be saved as an exact copy of the source without resizing or cropping." msgstr "" -#: ../../guides/events-list.rst:1104 +#: ../../guides/events-list.rst:1110 #: ../../guides/i18n.rst:51 #: ../../guides/notifications.rst:24 #: ../../guides/notifications.rst:309 @@ -4078,303 +4099,303 @@ msgstr "" msgid "Example:" msgstr "" -#: ../../guides/events-list.rst:1136 +#: ../../guides/events-list.rst:1142 msgid "**entity:icon:url, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1124 +#: ../../guides/events-list.rst:1130 msgid "Triggered when entity icon URL is requested, see :ref:`entity icons `. Callback should return URL for the icon of size ``$params['size']`` for the entity ``$params['entity']``. Following parameters are available through the ``$params`` array:" msgstr "" -#: ../../guides/events-list.rst:1128 +#: ../../guides/events-list.rst:1134 msgid "entity" msgstr "" -#: ../../guides/events-list.rst:1129 +#: ../../guides/events-list.rst:1135 msgid "Entity for which icon url is requested." msgstr "" -#: ../../guides/events-list.rst:1130 +#: ../../guides/events-list.rst:1136 msgid "viewtype" msgstr "" -#: ../../guides/events-list.rst:1131 +#: ../../guides/events-list.rst:1137 msgid "The type of :ref:`view ` e.g. ``'default'`` or ``'json'``." msgstr "" -#: ../../guides/events-list.rst:1133 +#: ../../guides/events-list.rst:1139 msgid "size" msgstr "" -#: ../../guides/events-list.rst:1133 +#: ../../guides/events-list.rst:1139 msgid "Size requested, see :ref:`entity icons ` for possible values." msgstr "" -#: ../../guides/events-list.rst:1135 +#: ../../guides/events-list.rst:1141 msgid "Example on how one could default to a Gravatar icon for users that have not yet uploaded an avatar:" msgstr "" -#: ../../guides/events-list.rst:1176 +#: ../../guides/events-list.rst:1182 msgid "**entity::url, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1176 +#: ../../guides/events-list.rst:1182 msgid "Allows filtering URLs for custom icon types, see ``entity:icon:url, ``" msgstr "" -#: ../../guides/events-list.rst:1181 +#: ../../guides/events-list.rst:1187 msgid "**entity:icon:file, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1179 +#: ../../guides/events-list.rst:1185 msgid "Triggered by ``ElggEntity::getIcon()`` and allows plugins to provide an alternative ``ElggIcon`` object that points to a custom location of the icon on filestore. The handler must return an instance of ``ElggIcon`` or an exception will be thrown." msgstr "" -#: ../../guides/events-list.rst:1184 +#: ../../guides/events-list.rst:1190 msgid "**entity::file, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1184 +#: ../../guides/events-list.rst:1190 msgid "Allows filtering icon file object for custom icon types, see ``entity:icon:file, ``" msgstr "" -#: ../../guides/events-list.rst:1196 +#: ../../guides/events-list.rst:1202 msgid "**entity::prepare, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1187 +#: ../../guides/events-list.rst:1193 msgid "Triggered by ``ElggEntity::saveIcon*()`` methods and can be used to prepare an image from uploaded/linked file. This event can be used to e.g. rotate the image before it is resized/cropped, or it can be used to extract an image frame if the uploaded file is a video. The handler must return an instance of ``ElggFile`` with a `simpletype` that resolves to `image`. The ``$return`` value passed to the event is an instance of ``ElggFile`` that points to a temporary copy of the uploaded/linked file." msgstr "" -#: ../../guides/events-list.rst:1193 -#: ../../guides/events-list.rst:1289 -#: ../../guides/events-list.rst:1322 +#: ../../guides/events-list.rst:1199 +#: ../../guides/events-list.rst:1295 +#: ../../guides/events-list.rst:1328 msgid "The ``$params`` array contains:" msgstr "" -#: ../../guides/events-list.rst:1195 -#: ../../guides/events-list.rst:1203 -#: ../../guides/events-list.rst:1213 -#: ../../guides/events-list.rst:1221 +#: ../../guides/events-list.rst:1201 +#: ../../guides/events-list.rst:1209 +#: ../../guides/events-list.rst:1219 +#: ../../guides/events-list.rst:1227 msgid "``entity`` - entity that owns the icons" msgstr "" -#: ../../guides/events-list.rst:1196 +#: ../../guides/events-list.rst:1202 msgid "``file`` - original input file before it has been modified by other events" msgstr "" -#: ../../guides/events-list.rst:1205 +#: ../../guides/events-list.rst:1211 msgid "**entity::save, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1199 +#: ../../guides/events-list.rst:1205 msgid "Triggered by ``ElggEntity::saveIcon*()`` methods and can be used to apply custom image manipulation logic to resizing/cropping icons. The handler must return ``true`` to prevent the core APIs from resizing/cropping icons. The ``$params`` array contains:" msgstr "" -#: ../../guides/events-list.rst:1204 +#: ../../guides/events-list.rst:1210 msgid "``file`` - ``ElggFile`` object that points to the image file to be used as source for icons" msgstr "" -#: ../../guides/events-list.rst:1205 -#: ../../guides/events-list.rst:1214 +#: ../../guides/events-list.rst:1211 +#: ../../guides/events-list.rst:1220 msgid "``x1``, ``y1``, ``x2``, ``y2`` - cropping coordinates" msgstr "" -#: ../../guides/events-list.rst:1214 +#: ../../guides/events-list.rst:1220 msgid "**entity::saved, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1208 +#: ../../guides/events-list.rst:1214 msgid "Triggered by ``ElggEntity::saveIcon*()`` methods once icons have been created. This event can be used by plugins to create river items, update cropping coordinates for custom icon types etc. The handler can access the created icons using ``ElggEntity::getIcon()``. The ``$params`` array contains:" msgstr "" -#: ../../guides/events-list.rst:1221 +#: ../../guides/events-list.rst:1227 msgid "**entity::delete, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1217 +#: ../../guides/events-list.rst:1223 msgid "Triggered by ``ElggEntity::deleteIcon()`` method and can be used for clean up operations. This event is triggered before the icons are deleted. The handler can return ``false`` to prevent icons from being deleted. The ``$params`` array contains:" msgstr "" -#: ../../guides/events-list.rst:1226 +#: ../../guides/events-list.rst:1232 msgid "**entity:url, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1224 +#: ../../guides/events-list.rst:1230 msgid "Return the URL for the entity ``$params['entity']``. Note: Generally it is better to override the ``getUrl()`` method of ElggEntity. This event should be used when it's not possible to subclass (like if you want to extend a bundled plugin without overriding many views)." msgstr "" -#: ../../guides/events-list.rst:1229 +#: ../../guides/events-list.rst:1235 msgid "**extender:url, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1229 +#: ../../guides/events-list.rst:1235 msgid "Return the URL for the annotation or metadata ``$params['extender']``." msgstr "" -#: ../../guides/events-list.rst:1233 +#: ../../guides/events-list.rst:1239 msgid "**fields, :** |results|" msgstr "" -#: ../../guides/events-list.rst:1232 +#: ../../guides/events-list.rst:1238 msgid "Return an array of fields usable for ``elgg_view_field()``. The result should be returned as an array of fields. It is required to provide ``name`` and ``#type`` for each field." msgstr "" -#: ../../guides/events-list.rst:1248 +#: ../../guides/events-list.rst:1254 msgid "**get_list, default_widgets** |results|" msgstr "" -#: ../../guides/events-list.rst:1247 +#: ../../guides/events-list.rst:1253 msgid "Filters a list of default widgets to add for newly registered users. The list is an array of arrays in the format:" msgstr "" -#: ../../guides/events-list.rst:1266 +#: ../../guides/events-list.rst:1272 msgid "**handlers, widgets** |results|" msgstr "" -#: ../../guides/events-list.rst:1265 +#: ../../guides/events-list.rst:1271 msgid "Triggered when a list of available widgets is needed. Plugins can conditionally add or remove widgets from this list or modify attributes of existing widgets like ``context`` or ``multiple``." msgstr "" -#: ../../guides/events-list.rst:1270 +#: ../../guides/events-list.rst:1276 msgid "**maintenance:allow, url** |results|" msgstr "" -#: ../../guides/events-list.rst:1270 +#: ../../guides/events-list.rst:1276 msgid "Return boolean if the URL ``$params['current_url']`` and the path ``$params['current_path']``" msgstr "" -#: ../../guides/events-list.rst:1270 +#: ../../guides/events-list.rst:1276 msgid "is allowed during maintenance mode." msgstr "" -#: ../../guides/events-list.rst:1281 +#: ../../guides/events-list.rst:1287 msgid "**plugin_setting, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1273 +#: ../../guides/events-list.rst:1279 msgid "Can be used to change the value of the setting being saved" msgstr "" -#: ../../guides/events-list.rst:1275 +#: ../../guides/events-list.rst:1281 msgid "Params contains: - ``entity`` - The ``ElggEntity`` where the plugin setting is being saved - ``plugin_id`` - The ID of the plugin for which the setting is being saved - ``name`` - The name of the setting being saved - ``value`` - The original value of the setting being saved" msgstr "" -#: ../../guides/events-list.rst:1281 +#: ../../guides/events-list.rst:1287 msgid "Return value should be a scalar in order to be able to save it to the database. An error will be logged if this is not the case." msgstr "" -#: ../../guides/events-list.rst:1291 +#: ../../guides/events-list.rst:1297 msgid "**public_pages, walled_garden** |results|" msgstr "" -#: ../../guides/events-list.rst:1284 +#: ../../guides/events-list.rst:1290 msgid "Filters a list of URLs (paths) that can be seen by logged out users in a walled garden mode. Handlers must return an array of regex strings that will allow access if matched. Please note that system public routes are passed as the default value to the event, and plugins must take care to not accidentally override these values." msgstr "" -#: ../../guides/events-list.rst:1291 +#: ../../guides/events-list.rst:1297 msgid "``url`` - URL of the page being tested for public accessibility" msgstr "" -#: ../../guides/events-list.rst:1294 +#: ../../guides/events-list.rst:1300 msgid "**relationship:url, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1294 +#: ../../guides/events-list.rst:1300 msgid "Filter the URL for the relationship object ``$params['relationship']``." msgstr "" -#: ../../guides/events-list.rst:1297 +#: ../../guides/events-list.rst:1303 msgid "**robots.txt, site** |results|" msgstr "" -#: ../../guides/events-list.rst:1297 +#: ../../guides/events-list.rst:1303 msgid "Filter the robots.txt values for ``$params['site']``." msgstr "" -#: ../../guides/events-list.rst:1305 +#: ../../guides/events-list.rst:1311 msgid "**setting, plugin** |results|" msgstr "" -#: ../../guides/events-list.rst:1300 +#: ../../guides/events-list.rst:1306 msgid "Filter plugin settings. ``$params`` contains:" msgstr "" -#: ../../guides/events-list.rst:1302 +#: ../../guides/events-list.rst:1308 msgid "``plugin`` - An ElggPlugin instance" msgstr "" -#: ../../guides/events-list.rst:1303 +#: ../../guides/events-list.rst:1309 msgid "``plugin_id`` - The plugin ID" msgstr "" -#: ../../guides/events-list.rst:1304 +#: ../../guides/events-list.rst:1310 msgid "``name`` - The name of the setting" msgstr "" -#: ../../guides/events-list.rst:1305 +#: ../../guides/events-list.rst:1311 msgid "``value`` - The value to set" msgstr "" -#: ../../guides/events-list.rst:1309 +#: ../../guides/events-list.rst:1315 msgid "**to:object, **" msgstr "" -#: ../../guides/events-list.rst:1308 +#: ../../guides/events-list.rst:1314 msgid "Converts the entity ``$params['entity']`` to a StdClass object. This is used mostly for exporting entity properties for portable data formats like JSON and XML." msgstr "" -#: ../../guides/events-list.rst:1312 +#: ../../guides/events-list.rst:1318 #: ../../guides/helpers.rst:41 #: ../../guides/plugins.rst:2 msgid "Plugins" msgstr "" -#: ../../guides/events-list.rst:1315 +#: ../../guides/events-list.rst:1321 msgid "Groups" msgstr "" -#: ../../guides/events-list.rst:1324 +#: ../../guides/events-list.rst:1330 msgid "**tool_options, group** |results|" msgstr "" -#: ../../guides/events-list.rst:1318 +#: ../../guides/events-list.rst:1324 msgid "Filters a collection of tools available within a specific group:" msgstr "" -#: ../../guides/events-list.rst:1320 +#: ../../guides/events-list.rst:1326 msgid "The ``$return`` is ``\\Elgg\\Collections\\Collection<\\Elgg\\Groups\\Tool>``, a collection of group tools." msgstr "" -#: ../../guides/events-list.rst:1324 +#: ../../guides/events-list.rst:1330 msgid "``entity`` - ``\\ElggGroup``" msgstr "" -#: ../../guides/events-list.rst:1327 +#: ../../guides/events-list.rst:1333 msgid "Web Services" msgstr "" -#: ../../guides/events-list.rst:1330 +#: ../../guides/events-list.rst:1336 msgid "**register, api_methods``** |results|" msgstr "" -#: ../../guides/events-list.rst:1330 +#: ../../guides/events-list.rst:1336 msgid "Triggered when the ApiRegistrationService is constructed which allows to add/remove/edit webservice configurations" msgstr "" -#: ../../guides/events-list.rst:1334 +#: ../../guides/events-list.rst:1340 msgid "**rest, init** |results|" msgstr "" -#: ../../guides/events-list.rst:1333 +#: ../../guides/events-list.rst:1339 msgid "Triggered by the web services rest handler. Plugins can set up their own authentication handlers, then return ``true`` to prevent the default handlers from being registered." msgstr "" -#: ../../guides/events-list.rst:1338 +#: ../../guides/events-list.rst:1344 msgid "**rest:output, ** |results|" msgstr "" -#: ../../guides/events-list.rst:1337 +#: ../../guides/events-list.rst:1343 msgid "Filter the result (and subsequently the output) of the API method" msgstr "" @@ -5091,7 +5112,7 @@ msgid "Customize Elgg's behavior with plugins." msgstr "" #: ../../guides/javascript.rst:2 -#: ../../guides/menus.rst:280 +#: ../../guides/menus.rst:299 msgid "JavaScript" msgstr "" @@ -5658,7 +5679,7 @@ msgid "You normally want to call them from your plugin's init function." msgstr "" #: ../../guides/menus.rst:25 -#: ../../guides/menus.rst:76 +#: ../../guides/menus.rst:95 msgid "Examples" msgstr "" @@ -5671,7 +5692,7 @@ msgid "You can also register ``page`` menu items to the admin backend menu. When msgstr "" #: ../../guides/menus.rst:47 -msgid "``administer`` for daily tasks, usermanagement and other actionable tasks" +msgid "``administer`` for daily tasks, user management and other actionable tasks" msgstr "" #: ../../guides/menus.rst:48 @@ -5686,111 +5707,131 @@ msgstr "" msgid "Advanced usage" msgstr "" -#: ../../guides/menus.rst:55 -msgid "You can get more control over menus by using :doc:`events ` and the public methods provided by the ``ElggMenuItem`` class." +#: ../../guides/menus.rst:56 +msgid "Headers" +msgstr "" + +#: ../../guides/menus.rst:58 +msgid "For accessibility reasons each menu will get an ``aria-label`` which defaults to the menu name, but can be translated by making sure the language key ``menu::header`` is available." msgstr "" #: ../../guides/menus.rst:61 +msgid "It's also possible to show menu section headers by setting ``show_section_headers`` to ``true`` in ``elgg_view_menu()``" +msgstr "" + +#: ../../guides/menus.rst:69 +msgid "The headers have a magic language key available ``menu::header:
`` in order to be able to translate the headers." +msgstr "" + +#: ../../guides/menus.rst:72 +msgid "Events" +msgstr "" + +#: ../../guides/menus.rst:74 +msgid "You can get more control over menus by using :doc:`events ` and the public methods provided by the ``ElggMenuItem`` class." +msgstr "" + +#: ../../guides/menus.rst:80 msgid "There are three events that can be used to modify a menu:" msgstr "" -#: ../../guides/menus.rst:59 +#: ../../guides/menus.rst:78 msgid "``'parameters', 'menu:'`` to add or modify parameters use for the menu building (eg. sorting)" msgstr "" -#: ../../guides/menus.rst:60 +#: ../../guides/menus.rst:79 msgid "``'register', 'menu:'`` to add or modify items (especially in dynamic menus)" msgstr "" -#: ../../guides/menus.rst:61 +#: ../../guides/menus.rst:80 msgid "``'prepare', 'menu:'`` to modify the structure of the menu before it is displayed" msgstr "" -#: ../../guides/menus.rst:63 +#: ../../guides/menus.rst:82 msgid "When you register an event handler, replace the ```` part with the internal name of the menu." msgstr "" -#: ../../guides/menus.rst:66 +#: ../../guides/menus.rst:85 msgid "The third parameter passed into a menu handler contains all the menu items that have been registered so far by Elgg core and other enabled plugins. In the handler we can loop through the menu items and use the class methods to interact with the properties of the menu item." msgstr "" -#: ../../guides/menus.rst:71 +#: ../../guides/menus.rst:90 msgid "In some cases a more granular version of the ``register`` and ``prepare`` menu events exist with ``menu:::``, this applies when the menu gets provided an ``\\ElggEntity`` in ``$params['entity']`` or an ``\\ElggAnnotation`` in ``$params['annotation']`` or an ``\\ElggRelationship`` in ``$params['relationship']``." msgstr "" -#: ../../guides/menus.rst:78 +#: ../../guides/menus.rst:97 msgid "**Example 1:** Change the URL for menu item called \"albums\" in the ``owner_block`` menu:" msgstr "" -#: ../../guides/menus.rst:117 +#: ../../guides/menus.rst:136 msgid "**Example 2:** Modify the ``entity`` menu for the ``ElggBlog`` objects" msgstr "" -#: ../../guides/menus.rst:116 +#: ../../guides/menus.rst:135 msgid "Remove the thumb icon" msgstr "" -#: ../../guides/menus.rst:117 +#: ../../guides/menus.rst:136 msgid "Change the \"Edit\" text into a custom icon" msgstr "" -#: ../../guides/menus.rst:155 +#: ../../guides/menus.rst:174 msgid "Creating a new menu" msgstr "" -#: ../../guides/menus.rst:157 +#: ../../guides/menus.rst:176 msgid "Elgg provides multiple different menus by default. Sometimes you may however need some menu items that don't fit in any of the existing menus. If this is the case, you can create your very own menu with the ``elgg_view_menu()`` function. You must call the function from the view, where you want to menu to be displayed." msgstr "" -#: ../../guides/menus.rst:163 +#: ../../guides/menus.rst:182 msgid "**Example:** Display a menu called \"my_menu\" that displays it's menu items in alphapetical order:" msgstr "" -#: ../../guides/menus.rst:171 +#: ../../guides/menus.rst:190 msgid "You can now add new items to the menu like this:" msgstr "" -#: ../../guides/menus.rst:182 +#: ../../guides/menus.rst:201 msgid "Furthermore it is now possible to modify the menu using the events ``'register', 'menu:my_menu'`` and ``'prepare', 'menu:my_menu'``." msgstr "" -#: ../../guides/menus.rst:186 +#: ../../guides/menus.rst:205 msgid "Child Dropdown Menus" msgstr "" -#: ../../guides/menus.rst:188 +#: ../../guides/menus.rst:207 msgid "Child menus can be configured using ``child_menu`` factory option on the parent item." msgstr "" -#: ../../guides/menus.rst:190 +#: ../../guides/menus.rst:209 msgid "``child_menu`` options array accepts ``display`` parameter, which can be used to set the child menu to open as ``dropdown`` or be displayed via ``toggle``. All other key value pairs will be passed as attributes to the ``ul`` element." msgstr "" -#: ../../guides/menus.rst:231 +#: ../../guides/menus.rst:250 msgid "Theming" msgstr "" -#: ../../guides/menus.rst:233 +#: ../../guides/menus.rst:252 msgid "The menu name, section names, and item names are all embedded into the HTML as CSS classes (normalized to contain only hyphens, rather that underscores or colons). This increases the size of the markup slightly but provides themers with a high degree of control and flexibility when styling the site." msgstr "" -#: ../../guides/menus.rst:238 +#: ../../guides/menus.rst:257 msgid "**Example:** The following would be the output of the ``foo`` menu with sections ``alt`` and ``default`` containing items ``baz`` and ``bar`` respectively." msgstr "" -#: ../../guides/menus.rst:251 +#: ../../guides/menus.rst:270 msgid "Toggling Menu Items" msgstr "" -#: ../../guides/menus.rst:253 +#: ../../guides/menus.rst:272 msgid "There are situations where you wish to toggle menu items that are actions that are the opposite of each other and ajaxify them. E.g. like/unlike, friend/unfriend, ban/unban, etc. Elgg has built-in support for this kind of actions. When you register a menu item you can provide a name of the menu item (in the same menu) that should be toggled. An ajax call will be made using the href of the menu item." msgstr "" -#: ../../guides/menus.rst:276 +#: ../../guides/menus.rst:295 msgid "The menu items are optimistically toggled. This means the menu items are toggled before the actions finish. If the actions fail, the menu items will be toggled back." msgstr "" -#: ../../guides/menus.rst:282 +#: ../../guides/menus.rst:301 msgid "It is common that menu items rely on JavaScript. You can bind client-side events to menu items by placing your JavaScript into AMD module and defining the requirement during the registration." msgstr "" @@ -6292,7 +6333,7 @@ msgid "Plugins can then use PHP-DI API to autowire and call the service:" msgstr "" #: ../../guides/plugins.rst:277 -msgid "See `PHP-DI documentation `_ for a comprehensive list of definition and invokation possibilities." +msgid "See `PHP-DI documentation `_ for a comprehensive list of definition and invocation possibilities." msgstr "" #: ../../guides/plugins.rst:280 @@ -6323,39 +6364,55 @@ msgstr "" msgid "``type``: this will tell Composer where to install your plugin, ALWAYS keep this as ``elgg-plugin``" msgstr "" -#: ../../guides/plugins.rst:297 -msgid "``require``: the ``composer/installers`` requirement is to make sure Composer knows where to install your plugin" +#: ../../guides/plugins.rst:298 +msgid "As a suggestion, include a ``conflict`` rule with any Elgg version below your minimal required version, this will help prevent the accidental installation of your plugin on an incompatible Elgg version." msgstr "" -#: ../../guides/plugins.rst:299 -msgid "As a suggestion, include a ``conflict`` rule with any Elgg version below your mininal required version, this will help prevent the accidental installation of your plugin on an incompatible Elgg version." -msgstr "" - -#: ../../guides/plugins.rst:302 +#: ../../guides/plugins.rst:301 msgid "After adding a ``composer.json`` file to your plugin project, you need to register your project on `Packagist`_ in order for other people to be able to install your plugin." msgstr "" -#: ../../guides/plugins.rst:306 +#: ../../guides/plugins.rst:305 msgid "Tests" msgstr "" -#: ../../guides/plugins.rst:308 +#: ../../guides/plugins.rst:307 msgid "It's encouraged to create PHPUnit test for your plugin. All tests should be located in ``tests/phpunit/unit`` for unit tests and ``tests/phpunit/integration`` for integration tests." msgstr "" -#: ../../guides/plugins.rst:311 -msgid "An easy example of adding test is the ``ViewStackTest``, this will test that the views in your plugin are registered correctly and have no syntax errors. To add this test create a file ``ViewStackTest.php`` in the folder ``tests/phpunit/unit///`` with the content:" +#: ../../guides/plugins.rst:310 +msgid "Unit tests should extend the ``Elgg\\UnitTestCase`` class. Integration tests should extend the ``Elgg\\Plugins\\IntegrationTestCase``." +msgstr "" + +#: ../../guides/plugins.rst:312 +msgid "There are a set of global plugin integration tests that run on all active plugins. These tests are:" +msgstr "" + +#: ../../guides/plugins.rst:314 +msgid "``Elgg\\Plugins\\ActionRegistrationIntegrationTest`` will test all registered actions of the plugin without supplying data" +msgstr "" + +#: ../../guides/plugins.rst:315 +msgid "``Elgg\\Plugins\\ComposerIntegrationTest`` will test if the ``composer.json`` is considered valid" +msgstr "" + +#: ../../guides/plugins.rst:316 +msgid "``Elgg\\Plugins\\StaticConfigIntegrationTest`` will test the sections of the ``elgg-plugin.php`` and check for the correct format" +msgstr "" + +#: ../../guides/plugins.rst:317 +msgid "``Elgg\\Plugins\\TranslationsIntegrationTest`` will test all language files for the correct format and encoding" msgstr "" -#: ../../guides/plugins.rst:328 -msgid "If you wish to see a better example, look in any of the Elgg core plugins." +#: ../../guides/plugins.rst:318 +msgid "``Elgg\\Plugins\\ViewStackIntegrationTest`` will test all views of the plugin if there are any PHP parsing errors" msgstr "" -#: ../../guides/plugins.rst:332 +#: ../../guides/plugins.rst:322 msgid ":doc:`/contribute/tests`" msgstr "" -#: ../../guides/plugins.rst:335 +#: ../../guides/plugins.rst:325 #: ../../guides/views.rst:647 #: ../../guides/web-services.rst:398 msgid "Related" @@ -7295,7 +7352,7 @@ msgid "Autocomplete and livesearch endpoint" msgstr "" #: ../../guides/search.rst:186 -msgid "Core provides a JSON endpoint for searching users and groups. These endpoints are used by ``input/autocomplete`` and ``input/userpicker`` views." +msgid "Core provides a JSON endpoint for searching users and groups. These endpoints are used by ``input/autocomplete`` and ``input/entitypicker`` views." msgstr "" #: ../../guides/search.rst:194 diff --git a/docs/locale/pot/index.pot b/docs/locale/pot/index.pot index 43da384daf7..4e158acff69 100644 --- a/docs/locale/pot/index.pot +++ b/docs/locale/pot/index.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-19 13:11+0200\n" +"POT-Creation-Date: 2024-03-21 10:41+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/docs/locale/pot/intro.pot b/docs/locale/pot/intro.pot index d35ce4a172a..8e32b46064e 100644 --- a/docs/locale/pot/intro.pot +++ b/docs/locale/pot/intro.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-19 13:11+0200\n" +"POT-Creation-Date: 2024-03-21 10:41+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -149,15 +149,15 @@ msgstr "" msgid "Available commands" msgstr "" -#: ../../intro/elgg-cli.rst:94 +#: ../../intro/elgg-cli.rst:108 msgid "Adding custom commands" msgstr "" -#: ../../intro/elgg-cli.rst:96 +#: ../../intro/elgg-cli.rst:110 msgid "Plugins can add their commands to the CLI application, by adding command class name via a configuration in ``elgg-plugin.php`` or via the ``'commands','cli'`` event. Command class must extend ``\\Elgg\\CLI\\Command``." msgstr "" -#: ../../intro/elgg-cli.rst:114 +#: ../../intro/elgg-cli.rst:128 msgid "Custom commands are based on `Symfony Console Commands`_. Please refer to their documentation for more details." msgstr "" diff --git a/docs/locale/pot/plugins.pot b/docs/locale/pot/plugins.pot index 3f9586de0ba..1dfa186d97a 100644 --- a/docs/locale/pot/plugins.pot +++ b/docs/locale/pot/plugins.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-19 13:11+0200\n" +"POT-Creation-Date: 2024-03-21 10:41+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -278,6 +278,10 @@ msgid "tagcloud" msgstr "" #: ../../plugins/index.rst:40 +msgid "theme_sandbox" +msgstr "" + +#: ../../plugins/index.rst:41 msgid "web_services" msgstr "" diff --git a/docs/locale/pot/tutorials.pot b/docs/locale/pot/tutorials.pot index 3006add9e3f..0913004cf44 100644 --- a/docs/locale/pot/tutorials.pot +++ b/docs/locale/pot/tutorials.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Elgg master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-19 13:11+0200\n" +"POT-Creation-Date: 2024-03-21 10:41+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -225,63 +225,63 @@ msgstr "" msgid "First, create a directory that will contain the plugin's files. It should be located under the ``mod/`` directory which is located in your Elgg installation directory. So in this case, create ``mod/hello/``." msgstr "" -#: ../../tutorials/hello_world.rst:13 +#: ../../tutorials/hello_world.rst:14 msgid "Composer file" msgstr "" -#: ../../tutorials/hello_world.rst:15 +#: ../../tutorials/hello_world.rst:16 msgid "Elgg requires that your plugin has a composer file that contains information about the plugin. Therefore, in the directory you just created, create a file called ``composer.json`` and copy this code into it:" msgstr "" -#: ../../tutorials/hello_world.rst:31 +#: ../../tutorials/hello_world.rst:30 msgid "Registering a route" msgstr "" -#: ../../tutorials/hello_world.rst:33 +#: ../../tutorials/hello_world.rst:32 msgid "The next step is to register a route which has the purpose of handling request that users make to the URL ``https://elgg.example.com/hello``." msgstr "" -#: ../../tutorials/hello_world.rst:36 +#: ../../tutorials/hello_world.rst:35 msgid "Update ``elgg-plugin.php`` to look like this:" msgstr "" -#: ../../tutorials/hello_world.rst:51 +#: ../../tutorials/hello_world.rst:50 msgid "This registration tells Elgg that it should call the resource view ``hello`` when a user navigates to ``https://elgg.example.com/hello``." msgstr "" -#: ../../tutorials/hello_world.rst:55 +#: ../../tutorials/hello_world.rst:54 msgid "View file" msgstr "" -#: ../../tutorials/hello_world.rst:57 +#: ../../tutorials/hello_world.rst:56 msgid "Create ``mod/hello/views/default/resources/hello.php`` with this content:" msgstr "" -#: ../../tutorials/hello_world.rst:69 +#: ../../tutorials/hello_world.rst:68 msgid "The code creates an array of parameters to be given to the ``elgg_view_layout()`` function, including:" msgstr "" -#: ../../tutorials/hello_world.rst:71 +#: ../../tutorials/hello_world.rst:70 msgid "The title of the page" msgstr "" -#: ../../tutorials/hello_world.rst:72 +#: ../../tutorials/hello_world.rst:71 msgid "The contents of the page" msgstr "" -#: ../../tutorials/hello_world.rst:73 +#: ../../tutorials/hello_world.rst:72 msgid "Filter which is left empty because there's currently nothing to filter" msgstr "" -#: ../../tutorials/hello_world.rst:75 +#: ../../tutorials/hello_world.rst:74 msgid "This creates the basic layout for the page. The layout is then run through ``elgg_view_page()`` which assembles and outputs the full page." msgstr "" -#: ../../tutorials/hello_world.rst:79 +#: ../../tutorials/hello_world.rst:78 msgid "Last step" msgstr "" -#: ../../tutorials/hello_world.rst:81 +#: ../../tutorials/hello_world.rst:80 msgid "Finally, activate the plugin through your Elgg administrator page: ``https://elgg.example.com/admin/plugins`` (the new plugin appears at the bottom)." msgstr "" diff --git a/docs/pip-requirements.txt b/docs/pip-requirements.txt index 195d12c3ce8..aa85b279b3e 100644 --- a/docs/pip-requirements.txt +++ b/docs/pip-requirements.txt @@ -1,2 +1,3 @@ docutils<0.18 sphinxcontrib.phpdomain +sphinx_rtd_theme < 2.0 diff --git a/docs/plugins/index.rst b/docs/plugins/index.rst index dfa054d2cf2..04933883426 100644 --- a/docs/plugins/index.rst +++ b/docs/plugins/index.rst @@ -37,4 +37,5 @@ The following plugins are also bundled with Elgg, but are not (yet) documented - search - system_log - tagcloud +- theme_sandbox - web_services diff --git a/docs/requirements.txt b/docs/requirements.txt index 43228802693..d937e6262c8 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,3 +1,4 @@ docutils<0.18 sphinxcontrib.phpdomain sphinx-intl +sphinx_rtd_theme < 2.0 diff --git a/docs/tutorials/hello_world.rst b/docs/tutorials/hello_world.rst index 48b9c351e19..99287c04f22 100644 --- a/docs/tutorials/hello_world.rst +++ b/docs/tutorials/hello_world.rst @@ -7,12 +7,14 @@ Before anything else, you need to :doc:`install Elgg`. In this tutorial we will pretend your site's URL is ``https://elgg.example.com``. -First, create a directory that will contain the plugin's files. It should be located under the ``mod/`` directory which is located in your Elgg installation directory. So in this case, create ``mod/hello/``. +First, create a directory that will contain the plugin's files. It should be located under the ``mod/`` directory +which is located in your Elgg installation directory. So in this case, create ``mod/hello/``. Composer file ============= -Elgg requires that your plugin has a composer file that contains information about the plugin. Therefore, in the directory you just created, create a file called ``composer.json`` and copy this code into it: +Elgg requires that your plugin has a composer file that contains information about the plugin. Therefore, in the +directory you just created, create a file called ``composer.json`` and copy this code into it: .. code-block:: json @@ -21,9 +23,6 @@ Elgg requires that your plugin has a composer file that contains information abo "type": "elgg-plugin", "description": "Hello World plugin", "license": "GPL-2.0-only", - "require": { - "composer/installers": "^1.0.8" - } } @@ -78,6 +77,7 @@ This creates the basic layout for the page. The layout is then run through Last step ========= -Finally, activate the plugin through your Elgg administrator page: ``https://elgg.example.com/admin/plugins`` (the new plugin appears at the bottom). +Finally, activate the plugin through your Elgg administrator page: ``https://elgg.example.com/admin/plugins`` (the new +plugin appears at the bottom). You can now go to the address ``https://elgg.example.com/hello/`` and you should see your new page! diff --git a/elgg-config/settings.example.php b/elgg-config/settings.example.php index 437700d5976..edbd4dabfd8 100644 --- a/elgg-config/settings.example.php +++ b/elgg-config/settings.example.php @@ -261,6 +261,8 @@ * * To use, uncomment the appropriate sections below and update for your site. * + * @see https://www.php.net/manual/en/function.session-get-cookie-params.php + * * @global array $CONFIG->cookies */ // get the default parameters from php.ini @@ -271,6 +273,7 @@ //$CONFIG->cookies['session']['domain'] = ""; //$CONFIG->cookies['session']['secure'] = false; //$CONFIG->cookies['session']['httponly'] = false; +//$CONFIG->cookies['session']['samesite'] = ''; // 'Strict' or 'Lax' // extended session cookie //$CONFIG->cookies['remember_me'] = session_get_cookie_params(); @@ -281,6 +284,7 @@ //$CONFIG->cookies['remember_me']['domain'] = ""; //$CONFIG->cookies['remember_me']['secure'] = false; //$CONFIG->cookies['remember_me']['httponly'] = false; +//$CONFIG->cookies['remember_me']['samesite'] = ''; // 'Strict' or 'Lax' /** * Disable the database query cache diff --git a/engine/actions.php b/engine/actions.php index ceff5560563..a7765814991 100644 --- a/engine/actions.php +++ b/engine/actions.php @@ -8,6 +8,7 @@ 'admin/plugins/deactivate' => ['access' => 'admin'], 'admin/plugins/deactivate_all' => ['access' => 'admin'], 'admin/plugins/set_priority' => ['access' => 'admin'], + 'admin/security/security_txt' => ['access' => 'admin'], 'admin/security/settings' => ['access' => 'admin'], 'admin/security/regenerate_site_secret' => ['access' => 'admin'], 'admin/site/cache/invalidate' => ['access' => 'admin'], @@ -15,6 +16,7 @@ 'admin/site/icons' => ['access' => 'admin'], 'admin/site/set_maintenance_mode' => ['access' => 'admin'], 'admin/site/set_robots' => ['access' => 'admin'], + 'admin/site/theme' => ['access' => 'admin'], 'admin/site/unlock_upgrade' => ['access' => 'admin'], 'admin/site/settings' => ['access' => 'admin'], 'admin/upgrade' => ['access' => 'admin'], @@ -37,9 +39,12 @@ 'avatar/upload' => [], 'comment/save' => [], 'diagnostics/download' => ['access' => 'admin'], + 'entity/chooserestoredestination' => [], 'entity/delete' => [], 'entity/mute' => [], + 'entity/restore' => [], 'entity/subscribe' => [], + 'entity/trash' => [], 'entity/unmute' => [], 'entity/unsubscribe' => [], 'login' => ['access' => 'logged_out'], diff --git a/engine/classes/Elgg/ActionsService.php b/engine/classes/Elgg/ActionsService.php index 50b561bd151..f48c29c99c4 100644 --- a/engine/classes/Elgg/ActionsService.php +++ b/engine/classes/Elgg/ActionsService.php @@ -35,25 +35,13 @@ class ActionsService { 'logout', ]; - /** - * @var RouteRegistrationService - */ - protected $routes; - - /** - * @var HandlersService - */ - protected $handlers; - /** * Constructor * * @param RouteRegistrationService $routes Routes * @param HandlersService $handlers Handlers service */ - public function __construct(RouteRegistrationService $routes, HandlersService $handlers) { - $this->routes = $routes; - $this->handlers = $handlers; + public function __construct(protected RouteRegistrationService $routes, protected HandlersService $handlers) { } /** diff --git a/engine/classes/Elgg/Ajax/Controller.php b/engine/classes/Elgg/Ajax/Controller.php index 35ae1ea06e5..3ce7e273899 100644 --- a/engine/classes/Elgg/Ajax/Controller.php +++ b/engine/classes/Elgg/Ajax/Controller.php @@ -56,7 +56,7 @@ public function __invoke(Request $request) { $allowed_views = $ajax_api->getViews(); // cacheable views are always allowed - if (!in_array($view, $allowed_views) && !_elgg_services()->views->isCacheableView($view)) { + if (!in_array($view, $allowed_views) && !_elgg_services()->simpleCache->isCacheableView($view)) { return elgg_error_response("Ajax view '{$view}' was not registered", REFERRER, ELGG_HTTP_FORBIDDEN); } @@ -83,24 +83,15 @@ public function __invoke(Request $request) { $output = elgg_view($view, $vars); // Try to guess the mime-type - switch ($segments[1]) { - case 'js': - $content_type = 'text/javascript;charset=utf-8'; - break; - case 'css': - $content_type = 'text/css;charset=utf-8'; - break; - default: - if (_elgg_services()->views->isCacheableView($view)) { - $file = _elgg_services()->views->findViewFile($view, elgg_get_viewtype()); - $content_type = 'text/html'; - try { - $content_type = _elgg_services()->mimetype->getMimeType($file, $content_type); - } catch (InvalidArgumentException $e) { - // nothing for now - } - } - break; + if (_elgg_services()->simpleCache->isCacheableView($view)) { + $file = _elgg_services()->views->findViewFile($view, elgg_get_viewtype()); + $content_type = 'text/html'; + + try { + $content_type = _elgg_services()->mimetype->getMimeType($file, $content_type); + } catch (InvalidArgumentException $e) { + // nothing for now + } } } else { $action = implode('/', array_slice($segments, 1)); diff --git a/engine/classes/Elgg/Ajax/Service.php b/engine/classes/Elgg/Ajax/Service.php index 861047c541b..baf1bb23383 100644 --- a/engine/classes/Elgg/Ajax/Service.php +++ b/engine/classes/Elgg/Ajax/Service.php @@ -2,10 +2,10 @@ namespace Elgg\Ajax; -use Elgg\Amd\Config; use Elgg\EventsService; use Elgg\Exceptions\RuntimeException; use Elgg\Http\Request; +use Elgg\Javascript\ESMService; use Elgg\Services\AjaxResponse; use Elgg\SystemMessagesService; use Symfony\Component\HttpFoundation\JsonResponse; @@ -18,50 +18,24 @@ */ class Service { - /** - * @var EventsService - */ - private $events; + protected bool $response_sent = false; - /** - * @var SystemMessagesService - */ - private $msgs; - - /** - * @var Request - */ - private $request; - - /** - * @var Config - */ - private $amd_config; - - /** - * @var bool - */ - private $response_sent = false; - - /** - * @var array - */ - private $allowed_views = []; + protected array $allowed_views = []; /** * Constructor * - * @param EventsService $events Events service - * @param SystemMessagesService $msgs System messages service - * @param Request $request Http Request - * @param Config $amdConfig AMD config + * @param EventsService $events Events service + * @param SystemMessagesService $msgs System messages service + * @param Request $request Http Request + * @param ESMService $esm ESM service */ - public function __construct(EventsService $events, SystemMessagesService $msgs, Request $request, Config $amdConfig) { - $this->events = $events; - $this->msgs = $msgs; - $this->request = $request; - $this->amd_config = $amdConfig; - + public function __construct( + protected EventsService $events, + protected SystemMessagesService $msgs, + protected Request $request, + protected ESMService $esm + ) { $message_filter = [$this, 'prepareResponse']; $this->events->registerHandler(AjaxResponse::RESPONSE_EVENT, 'all', $message_filter, 999); } @@ -222,7 +196,7 @@ private function buildHttpResponse(AjaxResponse $api_response): JsonResponse { } /** - * Prepare the response with additional metadata, like system messages and required AMD modules + * Prepare the response with additional metadata, like system messages and required ES modules * * @param \Elgg\Event $event "ajax_response", "all" * @@ -247,7 +221,7 @@ public function prepareResponse(\Elgg\Event $event) { } if ($this->request->getParam('elgg_fetch_deps', true)) { - $response->getData()->_elgg_deps = (array) $this->amd_config->getDependencies(); + $response->getData()->_elgg_deps = $this->esm->getImports(); } return $response; diff --git a/engine/classes/Elgg/Amd/Config.php b/engine/classes/Elgg/Amd/Config.php deleted file mode 100644 index 35fd57d7e57..00000000000 --- a/engine/classes/Elgg/Amd/Config.php +++ /dev/null @@ -1,273 +0,0 @@ -events = $events; - } - - /** - * Set the base URL for the site - * - * @param string $url URL - * - * @return void - */ - public function setBaseUrl($url) { - $this->baseUrl = $url; - } - - /** - * Add a path mapping for a module. If a path is already defined, sets - * current path as preferred. - * - * @param string $name Module name - * @param string $path Full URL of the module - * - * @return void - */ - public function addPath(string $name, string $path): void { - if (preg_match('/\.js$/', $path)) { - $path = preg_replace('/\.js$/', '', $path); - } - - if (!isset($this->paths[$name])) { - $this->paths[$name] = []; - } - - array_unshift($this->paths[$name], $path); - } - - /** - * Remove a path for a module - * - * @param string $name Module name - * @param mixed $path The path to remove. If null, removes all paths (default). - * - * @return void - */ - public function removePath($name, $path = null) { - if (!$path) { - unset($this->paths[$name]); - } else { - if (preg_match('/\.js$/', $path)) { - $path = preg_replace('/\.js$/', '', $path); - } - - $key = array_search($path, $this->paths[$name]); - unset($this->paths[$name][$key]); - - if (empty($this->paths[$name])) { - unset($this->paths[$name]); - } - } - } - - /** - * Configures a shimmed module - * - * @param string $name Module name - * @param array $config Configuration for the module - * - deps: array Dependencies - * - exports: string Name of the shimmed module to export - * - * @return void - * @throws InvalidArgumentException - */ - public function addShim(string $name, array $config): void { - $deps = elgg_extract('deps', $config, []); - $exports = elgg_extract('exports', $config); - - if (empty($deps) && empty($exports)) { - throw new InvalidArgumentException('Shimmed modules must have deps or exports'); - } - - $this->shim[$name] = []; - - if (!empty($deps)) { - $this->shim[$name]['deps'] = $deps; - } - - if (!empty($exports)) { - $this->shim[$name]['exports'] = $exports; - } - } - - /** - * Is this shim defined - * - * @param string $name The name of the shim - * - * @return bool - */ - public function hasShim($name) { - return isset($this->shim[$name]); - } - - /** - * Unregister the shim config for a module - * - * @param string $name Module name - * - * @return void - */ - public function removeShim($name) { - unset($this->shim[$name]); - } - - /** - * Add a dependency - * - * @param string $name Name of the dependency - * - * @return void - */ - public function addDependency(string $name): void { - $this->dependencies[$name] = true; - } - - /** - * Removes a dependency - * - * @param string $name Name of the dependency - * - * @return void - */ - public function removeDependency(string $name): void { - unset($this->dependencies[$name]); - } - - /** - * Get registered dependencies - * - * @return array - */ - public function getDependencies() { - return array_keys($this->dependencies); - } - - /** - * Is this dependency registered - * - * @param string $name Module name - * - * @return bool - */ - public function hasDependency($name) { - return isset($this->dependencies[$name]); - } - - /** - * Adds a standard AMD or shimmed module to the config. - * - * @param string $name The name of the module - * @param array $config Configuration for the module - * - url: string The full URL for the module if not resolvable from baseUrl - * - deps: array Shimmed module's dependencies - * - exports: string Name of the shimmed module to export - * - * @return void - */ - public function addModule($name, array $config = []) { - $url = elgg_extract('url', $config); - $deps = elgg_extract('deps', $config, []); - $exports = elgg_extract('exports', $config); - - if (!empty($url)) { - $this->addPath($name, $url); - } - - // this is a shimmed module - // some jQuery modules don't need to export anything when shimmed, - // so check for deps too - if (!empty($deps) || !empty($exports)) { - $this->addShim($name, $config); - } else { - $this->addDependency($name); - } - } - - /** - * Removes all config for a module - * - * @param string $name The module name - * - * @return void - */ - public function removeModule($name) { - $this->removeDependency($name); - $this->removeShim($name); - $this->removePath($name); - } - - /** - * Is module configured? - * - * @param string $name Module name - * - * @return bool - */ - public function hasModule($name) { - if (in_array($name, $this->getDependencies())) { - return true; - } - - if (isset($this->shim[$name])) { - return true; - } - - if (isset($this->paths[$name])) { - return true; - } - - return false; - } - - /** - * Get the configuration of AMD - * - * @return array - */ - public function getConfig() { - $defaults = [ - 'baseUrl' => $this->baseUrl, - 'paths' => $this->paths, - 'shim' => $this->shim, - 'deps' => $this->getDependencies(), - 'waitSeconds' => 20, - ]; - - $params = [ - 'defaults' => $defaults - ]; - - return $this->events->triggerResults('config', 'amd', $params, $defaults); - } -} diff --git a/engine/classes/Elgg/Amd/ViewFilter.php b/engine/classes/Elgg/Amd/ViewFilter.php deleted file mode 100644 index 473071e0990..00000000000 --- a/engine/classes/Elgg/Amd/ViewFilter.php +++ /dev/null @@ -1,59 +0,0 @@ -getAmdName($viewName); - - if (!empty($amdName)) { - $content = preg_replace('/^(\s*)define\(([^\'"])/m', "\${1}define(\"$amdName\", \$2", $content, 1); - } - - return $content; - } -} diff --git a/engine/classes/Elgg/Application.php b/engine/classes/Elgg/Application.php index cbfc203c014..5a4e23fc8e9 100644 --- a/engine/classes/Elgg/Application.php +++ b/engine/classes/Elgg/Application.php @@ -15,8 +15,6 @@ use Elgg\Exceptions\Http\GatekeeperException; use Elgg\Exceptions\Http\PageNotFoundException; use Elgg\Exceptions\InvalidArgumentException; -use Elgg\Filesystem\Directory; -use Elgg\Filesystem\Directory\Local; use Elgg\Http\ErrorResponse; use Elgg\Http\OkResponse; use Elgg\Http\RedirectResponse; @@ -43,6 +41,7 @@ * * The full path is necessary to work around this: https://bugs.php.net/bug.php?id=55726 * + * @internal * @since 2.0.0 */ class Application { @@ -478,25 +477,6 @@ public function run() { return $this->internal_services->responseFactory->getSentResponse(); } - /** - * Returns a directory that points to the root of Elgg, but not necessarily - * the install root. See `self::root()` for that. - * - * @return Directory - */ - public static function elggDir() { - return Local::elggRoot(); - } - - /** - * Returns a directory that points to the project root, where composer is installed. - * - * @return Directory - */ - public static function projectDir() { - return Local::projectRoot(); - } - /** * Renders a web UI for installing Elgg. * @@ -572,10 +552,10 @@ public static function upgrade() { */ public static function migrate() { - $constants = self::elggDir()->getPath('engine/lib/constants.php'); + $constants = Paths::elgg() . 'engine/lib/constants.php'; Includer::requireFileOnce($constants); - $conf = self::elggDir()->getPath('engine/schema/migrations.php'); + $conf = Paths::elgg() . 'engine/schema/migrations.php'; if (!$conf) { throw new InstallationException('Settings file is required to run database migrations.'); } @@ -618,7 +598,7 @@ public static function getMigrationSettings() { ], 'environments' => [ 'default_migration_table' => "{$conn['prefix']}migrations", - 'default_database' => 'prod', + 'default_environment' => 'prod', 'prod' => [ 'adapter' => 'mysql', 'host' => $conn['host'], @@ -753,7 +733,6 @@ private static function getEngineLibs() { 'configuration.php', 'constants.php', 'context.php', - 'deprecated-5.0.php', 'entities.php', 'external_files.php', 'filestore.php', diff --git a/engine/classes/Elgg/Application/BootHandler.php b/engine/classes/Elgg/Application/BootHandler.php index e9a088ef8e8..3524ebf4b23 100644 --- a/engine/classes/Elgg/Application/BootHandler.php +++ b/engine/classes/Elgg/Application/BootHandler.php @@ -11,18 +11,12 @@ */ class BootHandler { - /** - * @var Application - */ - protected $app; - /** * Constructor * * @param Application $app Unbooted application */ - public function __construct(Application $app) { - $this->app = $app; + public function __construct(protected Application $app) { } /** @@ -133,7 +127,6 @@ public function bootApplication(): void { $events = $this->app->internal_services->events; - $this->app->internal_services->views->clampViewtypeToPopulatedViews(); $this->app->allowPathRewrite(); // Complete the boot process for both engine and plugins diff --git a/engine/classes/Elgg/Application/CacheHandler.php b/engine/classes/Elgg/Application/CacheHandler.php index e2c412cbb93..d03109e7ad6 100644 --- a/engine/classes/Elgg/Application/CacheHandler.php +++ b/engine/classes/Elgg/Application/CacheHandler.php @@ -26,9 +26,10 @@ class CacheHandler { 'ico' => 'image/x-icon', 'jpeg' => 'image/jpeg', 'jpg' => 'image/jpeg', - 'js' => 'application/javascript', + 'js' => 'text/javascript', 'json' => 'application/json', 'map' => 'application/json', + 'mjs' => 'text/javascript', 'otf' => 'application/font-otf', 'png' => 'image/png', 'svg' => 'image/svg+xml', @@ -44,31 +45,13 @@ class CacheHandler { public static $utf8_content_types = [ 'text/css', 'text/html', - 'application/javascript', + 'text/javascript', 'application/json', 'image/svg+xml', 'text/xml', ]; - - /** - * @var Config - */ - protected $config; - - /** - * @var Request - */ - protected $request; - - /** - * @var SimpleCache - */ - protected $simplecache; - /** - * @var bool - */ - protected $simplecache_enabled; + protected bool $simplecache_enabled; /** * Constructor @@ -78,11 +61,12 @@ class CacheHandler { * @param SimpleCache $simplecache Simplecache * @param ConfigTable $config_table Config table */ - public function __construct(Config $config, Request $request, SimpleCache $simplecache, ConfigTable $config_table) { - $this->config = $config; - $this->request = $request; - $this->simplecache = $simplecache; - + public function __construct( + protected Config $config, + protected Request $request, + protected SimpleCache $simplecache, + ConfigTable $config_table + ) { $this->simplecache_enabled = $config->simplecache_enabled; if (!$this->config->hasInitialValue('simplecache_enabled')) { $db_value = $config_table->get('simplecache_enabled'); @@ -189,6 +173,9 @@ public function handleRequest(Request $request, Application $app) { $this->simplecache->cacheAsset($viewtype, $view, $content); } else { // if wrong timestamp, don't send HTTP cache + // also report that the resource has gone away + $response->setStatusCode(ELGG_HTTP_GONE); + $content = $this->getProcessedView($view, $viewtype); } @@ -241,7 +228,7 @@ protected function isCacheableView($view) { return in_array($matches[1], _elgg_services()->locale->getLanguageCodes()); } - return _elgg_services()->views->isCacheableView($view); + return _elgg_services()->simpleCache->isCacheableView($view); } /** @@ -352,6 +339,12 @@ protected function getProcessedView($view, $viewtype) { $name = $this->simplecache_enabled ? 'simplecache:generate' : 'cache:generate'; $type = $this->getViewFileType($view); + + // treat mjs as js + if ($type === 'mjs') { + $type = 'js'; + } + $params = [ 'view' => $view, 'viewtype' => $viewtype, diff --git a/engine/classes/Elgg/Application/Database.php b/engine/classes/Elgg/Application/Database.php index 706a3a21b18..bcfce581700 100644 --- a/engine/classes/Elgg/Application/Database.php +++ b/engine/classes/Elgg/Application/Database.php @@ -15,20 +15,12 @@ */ class Database { - /** - * The "real" database instance - * - * @var ElggDb - */ - private $db; - /** * Constructor * * @param ElggDb $db The Elgg database */ - public function __construct(ElggDb $db) { - $this->db = $db; + public function __construct(protected ElggDb $db) { } /** diff --git a/engine/classes/Elgg/Application/ExceptionHandler.php b/engine/classes/Elgg/Application/ExceptionHandler.php index 84963d23df5..f85266a5d4c 100644 --- a/engine/classes/Elgg/Application/ExceptionHandler.php +++ b/engine/classes/Elgg/Application/ExceptionHandler.php @@ -32,14 +32,11 @@ class ExceptionHandler { * * @see http://www.php.net/set-exception-handler * - * @param \Exception|\Error $exception The exception/error being handled + * @param \Throwable $exception The exception/error being handled * * @return void */ - public function __invoke($exception) { - $exception->timestamp = time(); - $exception->uncaught = true; - + public function __invoke(\Throwable $exception): void { $this->log(LogLevel::CRITICAL, $exception); // Wipe any existing output buffer @@ -61,9 +58,10 @@ public function __invoke($exception) { } $app = Application::$_instance; + $now = time(); if (!$app || !$app->internal_services) { - $msg = "Exception loading Elgg core. Check log at time {$exception->timestamp}"; + $msg = "Exception loading Elgg core. Check log at time {$now}"; $response = new Response($msg, ELGG_HTTP_INTERNAL_SERVER_ERROR, $headers); $response->prepare($request); @@ -117,20 +115,18 @@ public function __invoke($exception) { $body = elgg_view('messages/exceptions/exception', [ 'object' => $exception, - 'ts' => $exception->timestamp, + 'ts' => $now, ]); $response->prepare($services->request); $response->setContent(elgg_view_page(elgg_echo('exception:title'), $body)); $response->send(); - } catch (\Exception $e) { - $timestamp = time(); - - $e->timestamp = $timestamp; + } catch (\Throwable $e) { + $now = time(); $this->log(LogLevel::CRITICAL, $e); - $msg = "Fatal error in exception handler. Check log for Exception at time $timestamp"; + $msg = "Fatal error in exception handler. Check log for Exception at time {$now}"; $response = new Response($msg, ELGG_HTTP_INTERNAL_SERVER_ERROR, $headers); $response->prepare($request); diff --git a/engine/classes/Elgg/Application/ServeFileHandler.php b/engine/classes/Elgg/Application/ServeFileHandler.php index 4eaa64b6a6d..4c025e59773 100644 --- a/engine/classes/Elgg/Application/ServeFileHandler.php +++ b/engine/classes/Elgg/Application/ServeFileHandler.php @@ -2,10 +2,10 @@ namespace Elgg\Application; -use DateTime; use Elgg\Config; use Elgg\Filesystem\MimeTypeService; use Elgg\Http\Request; +use Elgg\Values; use Symfony\Component\HttpFoundation\BinaryFileResponse; use Symfony\Component\HttpFoundation\Response; use Elgg\Security\Base64Url; @@ -18,21 +18,6 @@ */ class ServeFileHandler { - /** - * @var HmacFactory - */ - private $hmac; - - /** - * @var Config - */ - private $config; - - /** - * @var MimeTypeService - */ - protected $mimetype; - /** * Constructor * @@ -40,10 +25,11 @@ class ServeFileHandler { * @param Config $config Config service * @param MimeTypeService $mimetype MimeType service */ - public function __construct(HmacFactory $hmac, Config $config, MimeTypeService $mimetype) { - $this->hmac = $hmac; - $this->config = $config; - $this->mimetype = $mimetype; + public function __construct( + protected HmacFactory $hmac, + protected Config $config, + protected MimeTypeService $mimetype + ) { } /** @@ -144,7 +130,7 @@ public function getResponse(Request $request) { $expires = strtotime('+1 year'); } - $expires_dt = (new DateTime())->setTimestamp($expires); + $expires_dt = Values::normalizeTime($expires); $response->setExpires($expires_dt); $response->setEtag($etag); diff --git a/engine/classes/Elgg/Application/ShutdownHandler.php b/engine/classes/Elgg/Application/ShutdownHandler.php index 08660e0b59f..9733a6fbd76 100644 --- a/engine/classes/Elgg/Application/ShutdownHandler.php +++ b/engine/classes/Elgg/Application/ShutdownHandler.php @@ -15,18 +15,12 @@ class ShutdownHandler { use Loggable; - /** - * @var Application - */ - protected $app; - /** * Constructor * * @param Application $app Application */ - public function __construct(Application $app) { - $this->app = $app; + public function __construct(protected Application $app) { } /** diff --git a/engine/classes/Elgg/Application/SystemEventHandlers.php b/engine/classes/Elgg/Application/SystemEventHandlers.php index fc4d6924fe8..dfed389e75c 100644 --- a/engine/classes/Elgg/Application/SystemEventHandlers.php +++ b/engine/classes/Elgg/Application/SystemEventHandlers.php @@ -50,9 +50,12 @@ public static function init() { elgg_register_ajax_view('admin/users/listing/details'); elgg_register_ajax_view('core/ajax/edit_comment'); elgg_register_ajax_view('forms/admin/user/change_email'); + elgg_register_ajax_view('forms/comment/save'); + elgg_register_ajax_view('forms/entity/chooserestoredestination'); elgg_register_ajax_view('navigation/menu/user_hover/contents'); elgg_register_ajax_view('notifications/subscriptions/details'); elgg_register_ajax_view('object/plugin/details'); + elgg_register_ajax_view('object/widget/edit'); elgg_register_ajax_view('page/elements/comments'); elgg_register_ajax_view('river/elements/responses'); @@ -116,7 +119,7 @@ public static function initLate() { * @return void */ public static function ready() { - _elgg_services()->systemCache->init(); + _elgg_services()->views->cacheConfiguration(); } /** diff --git a/engine/classes/Elgg/Assets/CssCompiler.php b/engine/classes/Elgg/Assets/CssCompiler.php index 74d90aa3419..6146a1b61a2 100644 --- a/engine/classes/Elgg/Assets/CssCompiler.php +++ b/engine/classes/Elgg/Assets/CssCompiler.php @@ -15,25 +15,13 @@ */ class CssCompiler { - /** - * @var Config - */ - protected $config; - - /** - * @var EventsService - */ - protected $events; - /** * Constructor * * @param Config $config Config * @param EventsService $events Events service */ - public function __construct(Config $config, EventsService $events) { - $this->config = $config; - $this->events = $events; + public function __construct(protected Config $config, protected EventsService $events) { } /** @@ -44,7 +32,7 @@ public function __construct(Config $config, EventsService $events) { * * @return string */ - public function compile($css, array $options = []) { + public function compile($css, array $options = []): string { $defaults = [ 'minify' => false, // minify handled by \Elgg\Views\MinifyHandler::class 'formatter' => 'single-line', // shows lowest byte size @@ -56,31 +44,50 @@ public function compile($css, array $options = []) { $config = (array) $this->config->css_compiler_options; $options = array_merge($defaults, $config, $options); - - $default_vars = array_merge($this->getCoreVars(), $this->getPluginVars()); - $custom_vars = (array) elgg_extract('vars', $options, []); - $vars = array_merge($default_vars, $custom_vars); - - $options['vars'] = $this->events->triggerResults('vars:compiler', 'css', $options, $vars); + $options['vars'] = $this->getCssVars($options); Crush::$process = new CssCrushProcess($options, ['type' => 'filter', 'data' => $css]); return Crush::$process->compile()->__toString(); } + + /** + * Fetches a combined set of CSS variables and their value + * + * @param array $compiler_options compiler arguments with potential custom variables + * @param bool $load_config_vars (internal) determines if config values are being loaded + * + * @return array + */ + public function getCssVars(array $compiler_options = [], bool $load_config_vars = true): array { + $default_vars = array_merge($this->getCoreVars(), $this->getPluginVars()); + $custom_vars = (array) elgg_extract('vars', $compiler_options, []); + $vars = array_merge($default_vars, $custom_vars); + + $results = (array) $this->events->triggerResults('vars:compiler', 'css', $compiler_options, $vars); + + if (!$load_config_vars) { + return $results; + } + + return array_merge($results, (array) elgg_get_config('custom_theme_vars', [])); + } /** * Default Elgg theme variables + * * @return array */ - protected function getCoreVars() { + protected function getCoreVars(): array { $file = Paths::elgg() . 'engine/theme.php'; return Includer::includeFile($file); } /** * Plugin theme variables + * * @return array */ - protected function getPluginVars() { + protected function getPluginVars(): array { $return = []; $plugins = elgg_get_plugins('active'); diff --git a/engine/classes/Elgg/Assets/ExternalFiles.php b/engine/classes/Elgg/Assets/ExternalFiles.php index 74b97b14f83..a5648d020e4 100644 --- a/engine/classes/Elgg/Assets/ExternalFiles.php +++ b/engine/classes/Elgg/Assets/ExternalFiles.php @@ -16,10 +16,7 @@ */ class ExternalFiles { - /** - * @var array - */ - protected $files = []; + protected array $files = []; /** * Subresource integrity data (loaded on first use) @@ -28,31 +25,6 @@ class ExternalFiles { */ protected $sri; - /** - * @var Config - */ - protected $config; - - /** - * @var Urls - */ - protected $urls; - - /** - * @var ViewsService - */ - protected $views; - - /** - * @var SimpleCache - */ - protected $simpleCache; - - /** - * @var SystemCache - */ - protected $serverCache; - /** * Constructor * @@ -62,12 +34,13 @@ class ExternalFiles { * @param SimpleCache $simpleCache simplecache * @param SystemCache $serverCache server cache */ - public function __construct(Config $config, Urls $urls, ViewsService $views, SimpleCache $simpleCache, SystemCache $serverCache) { - $this->config = $config; - $this->urls = $urls; - $this->views = $views; - $this->simpleCache = $simpleCache; - $this->serverCache = $serverCache; + public function __construct( + protected Config $config, + protected Urls $urls, + protected ViewsService $views, + protected SimpleCache $simpleCache, + protected SystemCache $serverCache + ) { } /** diff --git a/engine/classes/Elgg/Assets/ImageFetcherService.php b/engine/classes/Elgg/Assets/ImageFetcherService.php index a6766255dbd..27a75fca4fd 100644 --- a/engine/classes/Elgg/Assets/ImageFetcherService.php +++ b/engine/classes/Elgg/Assets/ImageFetcherService.php @@ -17,26 +17,11 @@ class ImageFetcherService { protected const CACHE_PREFIX = 'image_fetcher_'; - - /** - * @var SystemCache - */ - protected $cache; /** * @var \Elgg\Http\Client */ protected $client; - - /** - * @var Config - */ - protected $config; - - /** - * @var \ElggSession - */ - protected $session; /** * Constructor @@ -45,11 +30,11 @@ class ImageFetcherService { * @param SystemCache $cache the system cache * @param \ElggSession $session the current session */ - public function __construct(Config $config, SystemCache $cache, \ElggSession $session) { - $this->config = $config; - $this->cache = $cache; - $this->session = $session; - + public function __construct( + protected Config $config, + protected SystemCache $cache, + protected \ElggSession $session + ) { $this->client = elgg_get_http_client(); } diff --git a/engine/classes/Elgg/AuthenticationService.php b/engine/classes/Elgg/AuthenticationService.php index 7ded6182525..034b5c67479 100644 --- a/engine/classes/Elgg/AuthenticationService.php +++ b/engine/classes/Elgg/AuthenticationService.php @@ -20,20 +20,14 @@ class AuthenticationService { * * @var array */ - protected $handlers = []; - - /** - * @var HandlersService - */ - protected $handlerService; + protected array $handlers = []; /** * Create new service * * @param HandlersService $handlerService handler service */ - public function __construct(HandlersService $handlerService) { - $this->handlerService = $handlerService; + public function __construct(protected HandlersService $handlerService) { } /** diff --git a/engine/classes/Elgg/AutoloadManager.php b/engine/classes/Elgg/AutoloadManager.php index de35377d1d4..9b993ad7889 100644 --- a/engine/classes/Elgg/AutoloadManager.php +++ b/engine/classes/Elgg/AutoloadManager.php @@ -17,20 +17,15 @@ class AutoloadManager { const KEY_CLASSES = 'classes'; const KEY_SCANNED_DIRS = 'scannedDirs'; - /** - * @var \Elgg\ClassLoader - */ - protected $loader; - /** * @var array directories that have already been scanned for classes */ - protected $scannedDirs = []; + protected array $scannedDirs = []; /** * @var bool was data in the manager altered? */ - protected $altered = false; + protected bool $altered = false; /** * Constructor @@ -39,9 +34,7 @@ class AutoloadManager { * @param \Elgg\Config $config Config * @param \Elgg\Cache\BaseCache $cache local file cache */ - public function __construct(\Elgg\ClassLoader $loader, \Elgg\Config $config, \Elgg\Cache\BaseCache $cache) { - $this->loader = $loader; - + public function __construct(protected \Elgg\ClassLoader $loader, \Elgg\Config $config, \Elgg\Cache\BaseCache $cache) { if (!$config->AutoloaderManager_skip_storage) { $this->setCache($cache); $this->loadCache(); diff --git a/engine/classes/Elgg/BootData.php b/engine/classes/Elgg/BootData.php index 8b7957f72cf..777e43f3113 100644 --- a/engine/classes/Elgg/BootData.php +++ b/engine/classes/Elgg/BootData.php @@ -47,23 +47,15 @@ public function populate(EntityTable $entities, Plugins $plugins, bool $installe throw new InstallationException('Unable to handle this request. This site is not configured or the database is down.'); } - // get plugins $this->active_plugins = $plugins->find('active'); - - // get plugin settings if (empty($this->active_plugins)) { return; } + + _elgg_services()->metadataCache->populateFromEntities($this->active_plugins); - // find GUIDs with not too many settings - $guids = array_map(function (\ElggPlugin $plugin) { - return $plugin->guid; - }, $this->active_plugins); - - _elgg_services()->metadataCache->populateFromEntities($guids); - - foreach ($guids as $guid) { - $this->plugin_metadata[$guid] = _elgg_services()->metadataCache->getEntityMetadata($guid); + foreach ($this->active_plugins as $plugin) { + $this->plugin_metadata[$plugin->guid] = _elgg_services()->metadataCache->getEntityMetadata($plugin->guid); } } diff --git a/engine/classes/Elgg/BootService.php b/engine/classes/Elgg/BootService.php index c09109af066..7faee165eed 100644 --- a/engine/classes/Elgg/BootService.php +++ b/engine/classes/Elgg/BootService.php @@ -79,9 +79,7 @@ public function boot(InternalContainer $services) { $debug = $config->getInitialValue('debug') ?? ($config->debug ?: LogLevel::CRITICAL); $services->logger->setLevel($debug); - if ($config->system_cache_enabled) { - $config->system_cache_loaded = $services->views->configureFromCache($services->serverCache); - } + $services->views->configureFromCache(); } /** @@ -92,7 +90,6 @@ public function boot(InternalContainer $services) { public function clearCache() { $this->cache->clear(); _elgg_services()->plugins->setBootPlugins(null); - _elgg_services()->config->system_cache_loaded = false; _elgg_services()->config->_boot_cache_hit = false; } diff --git a/engine/classes/Elgg/Cache/CacheCollection.php b/engine/classes/Elgg/Cache/CacheCollection.php index c58b0ac789e..ee880a8ca65 100644 --- a/engine/classes/Elgg/Cache/CacheCollection.php +++ b/engine/classes/Elgg/Cache/CacheCollection.php @@ -12,20 +12,14 @@ abstract class CacheCollection { /** * @var CompositeCache[] */ - protected $caches = []; - - /** - * @var Config - */ - protected $config; + protected array $caches = []; /** * Constructor * * @param Config $config Elgg config */ - public function __construct(Config $config) { - $this->config = $config; + public function __construct(protected Config $config) { } /** diff --git a/engine/classes/Elgg/Cache/CompositeCache.php b/engine/classes/Elgg/Cache/CompositeCache.php index 54c98adb991..21f08a1e9d3 100644 --- a/engine/classes/Elgg/Cache/CompositeCache.php +++ b/engine/classes/Elgg/Cache/CompositeCache.php @@ -252,7 +252,6 @@ protected function createPool() { $cluster_driver = $cluster->getCluster(); $cluster_driver->setConfig(new ConfigurationOption([ - 'preventCacheSlams' => true, 'useStaticItemCaching' => true, 'itemDetailedDate' => true, ])); @@ -361,12 +360,12 @@ protected function buildEphemeralDriver() { return null; } - $config = new \Phpfastcache\Drivers\Memstatic\Config(); + $config = new \Phpfastcache\Drivers\Memory\Config(); $config->setUseStaticItemCaching(true); $config->setItemDetailedDate(true); - return CacheManager::getInstance('Memstatic', $config, $this->prefixInstanceId('memstatic')); + return CacheManager::getInstance('Memory', $config, $this->prefixInstanceId('memory')); } /** diff --git a/engine/classes/Elgg/Cache/Config/Memcached.php b/engine/classes/Elgg/Cache/Config/Memcached.php index 4a15c9bea1d..dd345212ecf 100644 --- a/engine/classes/Elgg/Cache/Config/Memcached.php +++ b/engine/classes/Elgg/Cache/Config/Memcached.php @@ -43,7 +43,6 @@ public static function fromElggConfig(string $namespace, \Elgg\Config $config): return new self([ 'servers' => $servers, - 'preventCacheSlams' => true, 'useStaticItemCaching' => true, 'itemDetailedDate' => true, 'optPrefix' => $opt_prefix, diff --git a/engine/classes/Elgg/Cache/Config/Redis.php b/engine/classes/Elgg/Cache/Config/Redis.php index 3d7699740e8..76af0d77555 100644 --- a/engine/classes/Elgg/Cache/Config/Redis.php +++ b/engine/classes/Elgg/Cache/Config/Redis.php @@ -27,7 +27,6 @@ public static function fromElggConfig(string $namespace, \Elgg\Config $config): } $options = [ - 'preventCacheSlams' => true, 'useStaticItemCaching' => true, 'itemDetailedDate' => true, 'optPrefix' => $namespace, diff --git a/engine/classes/Elgg/Cache/EntityCache.php b/engine/classes/Elgg/Cache/EntityCache.php index c2ad1d1fe96..01cb15ed809 100644 --- a/engine/classes/Elgg/Cache/EntityCache.php +++ b/engine/classes/Elgg/Cache/EntityCache.php @@ -9,25 +9,12 @@ */ class EntityCache { - const MAX_SIZE = 256; - - /** - * @var BaseCache - */ - protected $cache; - - /** - * @var int - */ - protected $size = 0; - /** * Constructor * * @param BaseCache $cache Cache */ - public function __construct(BaseCache $cache) { - $this->cache = $cache; + public function __construct(protected BaseCache $cache) { } /** @@ -53,13 +40,7 @@ public function save(\ElggEntity $entity): void { return; } - if ($this->size > self::MAX_SIZE) { - // Don't store too many or we'll have memory problems - return; - } - $this->cache->save($entity->guid, $entity); - $this->size++; } /** @@ -70,17 +51,7 @@ public function save(\ElggEntity $entity): void { * @return void */ public function delete(int $guid): void { - if (!$guid) { - return; - } - - $entity = $this->cache->load($guid); - if (!$entity instanceof \ElggEntity) { - return; - } - $this->cache->delete($guid); - $this->size--; } /** @@ -90,6 +61,5 @@ public function delete(int $guid): void { */ public function clear(): void { $this->cache->clear(); - $this->size = 0; } } diff --git a/engine/classes/Elgg/Cache/EventHandlers.php b/engine/classes/Elgg/Cache/EventHandlers.php index 53e20422fb9..cc98d7d87b8 100644 --- a/engine/classes/Elgg/Cache/EventHandlers.php +++ b/engine/classes/Elgg/Cache/EventHandlers.php @@ -16,7 +16,7 @@ class EventHandlers { */ public static function disable() { _elgg_services()->boot->getCache()->disable(); - _elgg_services()->plugins->getCache()->disable(); + _elgg_services()->pluginsCache->disable(); _elgg_services()->sessionCache->disable(); _elgg_services()->dataCache->disable(); _elgg_services()->autoloadManager->getCache()->disable(); @@ -31,7 +31,7 @@ public static function disable() { */ public static function enable() { _elgg_services()->boot->getCache()->enable(); - _elgg_services()->plugins->getCache()->enable(); + _elgg_services()->pluginsCache->enable(); _elgg_services()->sessionCache->enable(); _elgg_services()->dataCache->enable(); _elgg_services()->autoloadManager->getCache()->enable(); @@ -45,7 +45,7 @@ public static function enable() { */ public static function purge() { _elgg_services()->boot->getCache()->purge(); - _elgg_services()->plugins->getCache()->purge(); + _elgg_services()->pluginsCache->purge(); _elgg_services()->sessionCache->purge(); _elgg_services()->dataCache->purge(); _elgg_services()->simpleCache->purge(); @@ -60,7 +60,7 @@ public static function purge() { */ public static function invalidate() { _elgg_services()->boot->getCache()->invalidate(); - _elgg_services()->plugins->invalidate(); + _elgg_services()->pluginsCache->invalidate(); _elgg_services()->sessionCache->invalidate(); _elgg_services()->dataCache->invalidate(); _elgg_services()->fileCache->invalidate(); @@ -74,7 +74,7 @@ public static function invalidate() { */ public static function clear() { _elgg_services()->boot->clearCache(); - _elgg_services()->plugins->clear(); + _elgg_services()->pluginsCache->clear(); _elgg_services()->sessionCache->clear(); _elgg_services()->dataCache->clear(); _elgg_services()->simpleCache->clear(); diff --git a/engine/classes/Elgg/Cache/MetadataCache.php b/engine/classes/Elgg/Cache/MetadataCache.php index 94b40a4ebbf..bca9c0ad4bd 100644 --- a/engine/classes/Elgg/Cache/MetadataCache.php +++ b/engine/classes/Elgg/Cache/MetadataCache.php @@ -4,6 +4,7 @@ use Elgg\Database\Clauses\GroupByClause; use Elgg\Database\Clauses\OrderByClause; +use Elgg\Database\MetadataTable; use Elgg\Exceptions\DataFormatException; use Elgg\Values; @@ -14,18 +15,12 @@ */ class MetadataCache { - /** - * @var BaseCache - */ - protected $cache; - /** * Constructor * * @param BaseCache $cache Cache */ - public function __construct(BaseCache $cache) { - $this->cache = $cache; + public function __construct(protected BaseCache $cache) { } /** @@ -222,7 +217,7 @@ public function invalidateByOptions(array $options) { /** * Populate the cache from a set of entities * - * @param int[] ...$guids Array of or single GUIDs + * @param mixed ...$guids Array of entities or GUIDs * @return array|null [guid => [metadata]] */ public function populateFromEntities(...$guids) { @@ -279,22 +274,24 @@ public function populateFromEntities(...$guids) { * @return array */ public function filterMetadataHeavyEntities(array $guids, $limit = 1024000) { + $main_alias = MetadataTable::DEFAULT_JOIN_ALIAS; + $guids = _elgg_services()->metadataTable->getAll([ 'guids' => $guids, 'limit' => false, 'callback' => function($e) { return (int) $e->entity_guid; }, - 'selects' => ['SUM(LENGTH(n_table.value)) AS bytes'], + 'selects' => ["SUM(LENGTH({$main_alias}.value)) AS bytes"], 'order_by' => [ - new OrderByClause('n_table.entity_guid'), - new OrderByClause('n_table.time_created'), + new OrderByClause("{$main_alias}.entity_guid"), + new OrderByClause("{$main_alias}.time_created"), ], 'group_by' => [ - new GroupByClause('n_table.entity_guid'), + new GroupByClause("{$main_alias}.entity_guid"), ], 'having' => [ - "bytes < $limit", + "bytes < {$limit}", ] ]); diff --git a/engine/classes/Elgg/Cache/SimpleCache.php b/engine/classes/Elgg/Cache/SimpleCache.php index 13a72c97b92..39444b7b28b 100644 --- a/engine/classes/Elgg/Cache/SimpleCache.php +++ b/engine/classes/Elgg/Cache/SimpleCache.php @@ -13,16 +13,13 @@ * @since 1.10.0 */ class SimpleCache { - - /** - * @var Config - */ - protected $config; - + /** - * @var ViewsService + * @var array Simplecache views (view names are keys) + * + * [view] = true */ - protected $views; + protected array $simplecache_views = []; /** * Constructor @@ -31,53 +28,27 @@ class SimpleCache { * @param ViewsService $views Views service */ public function __construct( - Config $config, - ViewsService $views + protected Config $config, + protected ViewsService $views ) { - $this->config = $config; - $this->views = $views; } /** * Get the URL for the cached view. * - * Recommended usage is to just pass the entire view name as the first and only arg: - * * ``` * $blog_js = $simpleCache->getUrl('blog/save_draft.js'); * $favicon = $simpleCache->getUrl('graphics/favicon.ico'); * ``` * - * For backwards compatibility with older versions of Elgg, you can also pass - * "js" or "css" as the first arg, with the rest of the view name as the second arg: - * - * ``` - * $blog_js = $simpleCache->getUrl('js', 'blog/save_draft.js'); - * ``` - * * This automatically registers the view with Elgg's simplecache. * - * @param string $view The full view name - * @param string $subview If the first arg is "css" or "js", the rest of the view name + * @param string $view The full view name * * @return string */ - public function getUrl(string $view, string $subview = ''): string { - // handle `getUrl('js', 'js/blog/save_draft')` - if (($view === 'js' || $view === 'css') && str_starts_with($subview, $view . '/')) { - $view = $subview; - $subview = ''; - } - - // handle `getUrl('js', 'blog/save_draft')` - if (!empty($subview)) { - $view = "{$view}/{$subview}"; - } - - $view = ViewsService::canonicalizeViewName($view); - - // should be normalized to canonical form by now: `getUrl('blog/save_draft.js')` - $this->views->registerCacheableView($view); + public function getUrl(string $view): string { + $this->registerCacheableView($view); return $this->getRoot() . $view; } @@ -87,7 +58,7 @@ public function getUrl(string $view, string $subview = ''): string { * * @return string The simplecache root url for the current viewtype */ - public function getRoot() { + public function getRoot(): string { $viewtype = $this->views->getViewtype(); if ($this->isEnabled()) { $lastcache = (int) $this->config->lastcache; @@ -97,13 +68,70 @@ public function getRoot() { return elgg_normalize_url("/cache/{$lastcache}/{$viewtype}/"); } + + /** + * Register a view as cacheable + * + * @param string $view the view name + * + * @return void + */ + public function registerCacheableView(string $view): void { + $this->simplecache_views[$view] = true; + } + + /** + * Is the view cacheable + * + * @param string $view the view name + * + * @return bool + */ + public function isCacheableView(string $view): bool { + if (isset($this->simplecache_views[$view])) { + return true; + } + + // build list of viewtypes to check + $current_viewtype = $this->views->getViewtype(); + $viewtypes = [$current_viewtype]; + + if ($this->views->doesViewtypeFallback($current_viewtype) && $current_viewtype != 'default') { + $viewtypes[] = 'default'; + } + + // If a static view file is found in any viewtype, it's considered cacheable + foreach ($viewtypes as $viewtype) { + $file = $this->views->findViewFile($view, $viewtype); + + if ($file && pathinfo($file, PATHINFO_EXTENSION) !== 'php') { + $this->simplecache_views[$view] = true; + + return true; + } + } + + // Assume not-cacheable by default + return false; + } + + /** + * Returns the cacheable views + * + * @return array + * + * @internal + */ + public function getCacheableViews(): array { + return $this->simplecache_views; + } /** * Is simple cache enabled * * @return bool */ - public function isEnabled() { + public function isEnabled(): bool { return (bool) $this->config->simplecache_enabled; } @@ -113,7 +141,7 @@ public function isEnabled() { * @return void * @see elgg_register_simplecache_view() */ - public function enable() { + public function enable(): void { $this->config->save('simplecache_enabled', 1); } @@ -123,7 +151,7 @@ public function enable() { * @return void * @see elgg_register_simplecache_view() */ - public function disable() { + public function disable(): void { if (!$this->isEnabled()) { return; } @@ -136,20 +164,19 @@ public function disable() { * * @return string */ - protected function getPath() { + protected function getPath(): string { return (string) $this->config->assetroot; } /** * Deletes all cached views in the simplecache * - * @return bool + * @return void + * * @since 3.3 */ - public function clear() { + public function clear(): void { elgg_delete_directory($this->getPath(), true); - - return true; } /** @@ -157,7 +184,7 @@ public function clear() { * * @return void */ - public function purge() { + public function purge(): void { $lastcache = (int) $this->config->lastcache; if (!is_dir($this->getPath())) { diff --git a/engine/classes/Elgg/Cache/SystemCache.php b/engine/classes/Elgg/Cache/SystemCache.php index 8ec5c7c2243..c161e2d1e12 100644 --- a/engine/classes/Elgg/Cache/SystemCache.php +++ b/engine/classes/Elgg/Cache/SystemCache.php @@ -15,20 +15,14 @@ class SystemCache { use Cacheable; - /** - * @var Config - */ - protected $config; - /** * Constructor * * @param BaseCache $cache Elgg disk cache * @param Config $config Elgg config */ - public function __construct(BaseCache $cache, Config $config) { + public function __construct(BaseCache $cache, protected Config $config) { $this->cache = $cache; - $this->config = $config; } /** @@ -119,20 +113,4 @@ public function disable() { $this->config->save('system_cache_enabled', 0); $this->reset(); } - - /** - * Initializes the system cache - * - * @return void - */ - public function init() { - if (!$this->isEnabled()) { - return; - } - - // cache system data if enabled and not loaded - if (!$this->config->system_cache_loaded) { - _elgg_services()->views->cacheConfiguration(_elgg_services()->serverCache); - } - } } diff --git a/engine/classes/Elgg/Cache/ViewCacher.php b/engine/classes/Elgg/Cache/ViewCacher.php index 546c6d3c2cd..e1d2a995785 100644 --- a/engine/classes/Elgg/Cache/ViewCacher.php +++ b/engine/classes/Elgg/Cache/ViewCacher.php @@ -11,25 +11,13 @@ */ class ViewCacher { - /** - * @var ViewsService - */ - private $views; - - /** - * @var Config - */ - private $config; - /** * Constructor * * @param ViewsService $views Views * @param Config $config Config */ - public function __construct(ViewsService $views, Config $config) { - $this->views = $views; - $this->config = $config; + public function __construct(protected ViewsService $views, protected Config $config) { } /** @@ -38,12 +26,12 @@ public function __construct(ViewsService $views, Config $config) { * @return void */ public function registerCoreViews() { - if ($this->config->system_cache_loaded) { + if ($this->views->isViewLocationsLoadedFromCache()) { return; } // Core view files in /views - $this->views->registerPluginViews(Paths::elgg()); + $this->views->registerViewsFromPath(Paths::elgg()); // Core view definitions in /engine/views.php $file = Paths::elgg() . 'engine/views.php'; @@ -54,7 +42,7 @@ public function registerCoreViews() { $spec = Includer::includeFile($file); if (is_array($spec)) { // check for uploaded fontawesome font - if (elgg_get_config('font_awesome_zip')) { + if ($this->config->font_awesome_zip) { $spec['default']['font-awesome/'] = elgg_get_data_path() . 'fontawesome/webfont/'; } diff --git a/engine/classes/Elgg/ClassLoader.php b/engine/classes/Elgg/ClassLoader.php index 0c85c6aa914..03edc12ca91 100644 --- a/engine/classes/Elgg/ClassLoader.php +++ b/engine/classes/Elgg/ClassLoader.php @@ -47,16 +47,11 @@ */ class ClassLoader { - protected $namespaces = []; + protected array $namespaces = []; - protected $prefixes = []; + protected array $prefixes = []; - protected $fallbacks = []; - - /** - * @var Config - */ - protected $config; + protected array $fallbacks = []; /** * @var \Elgg\ClassMap Map of classes to files @@ -66,16 +61,15 @@ class ClassLoader { /** * @var array of checked but not found files */ - protected $missing = []; + protected array $missing = []; /** * Constructor * * @param \Elgg\Config $config Site config */ - public function __construct(Config $config) { + public function __construct(protected Config $config) { $this->map = new \Elgg\ClassMap(); - $this->config = $config; $this->register(); } diff --git a/engine/classes/Elgg/Cli.php b/engine/classes/Elgg/Cli.php index 47afaf76d8e..b74e350efd6 100644 --- a/engine/classes/Elgg/Cli.php +++ b/engine/classes/Elgg/Cli.php @@ -22,21 +22,6 @@ class Cli { */ protected $console; - /** - * @var EventsService - */ - protected $events; - - /** - * @var InputInterface - */ - protected $input; - - /** - * @var OutputInterface - */ - protected $output; - /** * Constructor * @@ -45,18 +30,14 @@ class Cli { * @param OutputInterface $output Console output */ public function __construct( - EventsService $events, - InputInterface $input, - OutputInterface $output + protected EventsService $events, + protected InputInterface $input, + protected OutputInterface $output ) { - $console = new \Elgg\Cli\Application('Elgg', elgg_get_release()); $console->setup($input, $output); $this->console = $console; - $this->events = $events; - $this->input = $input; - $this->output = $output; } /** @@ -64,7 +45,7 @@ public function __construct( * * @return void */ - protected function bootstrap() { + protected function bootstrap(): void { $commands = array_merge($this->getCoreCommands(), $this->getPluginCommands()); $commands = $this->events->triggerResults('commands', 'cli', [], $commands); @@ -78,7 +59,7 @@ protected function bootstrap() { * * @return array */ - protected function getCoreCommands() { + protected function getCoreCommands(): array { $conf = \Elgg\Project\Paths::elgg() . 'engine/cli_commands.php'; return \Elgg\Includer::includeFile($conf); } @@ -88,7 +69,7 @@ protected function getCoreCommands() { * * @return array */ - protected function getPluginCommands() { + protected function getPluginCommands(): array { $return = []; $plugins = elgg_get_plugins('active'); @@ -112,7 +93,7 @@ protected function getPluginCommands() { * * @return void */ - public function add($command) { + public function add(string $command): void { if (!class_exists($command)) { return; } @@ -150,7 +131,7 @@ public function add($command) { * * @return void */ - public function run(bool $bootstrap = true) { + public function run(bool $bootstrap = true): void { if ($bootstrap) { $this->bootstrap(); } @@ -163,7 +144,7 @@ public function run(bool $bootstrap = true) { * * @return InputInterface */ - public function getInput() { + public function getInput(): InputInterface { return $this->input; } @@ -172,7 +153,7 @@ public function getInput() { * * @return OutputInterface */ - public function getOutput() { + public function getOutput(): OutputInterface { return $this->output; } } diff --git a/engine/classes/Elgg/Cli/CronCommand.php b/engine/classes/Elgg/Cli/CronCommand.php index a3ce999336b..f5dfbdfb10a 100644 --- a/engine/classes/Elgg/Cli/CronCommand.php +++ b/engine/classes/Elgg/Cli/CronCommand.php @@ -2,6 +2,7 @@ namespace Elgg\Cli; +use Elgg\Exceptions\CronException; use Symfony\Component\Console\Input\InputOption; /** @@ -42,14 +43,18 @@ protected function command() { } $time = new \DateTime($time); - _elgg_services()->cron->setCurrentTime($time); - $jobs = _elgg_services()->cron->run($intervals, $this->option('force')); - - if (!$this->option('quiet')) { - foreach ($jobs as $job) { - $this->write($job->getOutput()); + + try { + $jobs = _elgg_services()->cron->run($intervals, $this->option('force')); + if (!$this->option('quiet')) { + foreach ($jobs as $job) { + $this->write($job->getOutput()); + } } + } catch (CronException $e) { + $this->error($e->getMessage()); + return self::FAILURE; } return self::SUCCESS; diff --git a/engine/classes/Elgg/Cli/DatabaseSeedCommand.php b/engine/classes/Elgg/Cli/DatabaseSeedCommand.php index 717f53cefc9..2f258f7fadb 100644 --- a/engine/classes/Elgg/Cli/DatabaseSeedCommand.php +++ b/engine/classes/Elgg/Cli/DatabaseSeedCommand.php @@ -61,14 +61,17 @@ protected function command() { } _elgg_services()->set('mailer', new \Laminas\Mail\Transport\InMemory()); + _elgg_services()->events->registerHandler('enqueue', 'notification', '\Elgg\Values::getFalse', 99999); $options = [ - 'limit' => (int) $this->option('limit') ?: 20, + 'limit' => $this->option('limit'), 'image_folder' => $this->option('image_folder'), 'type' => $this->option('type'), 'create_since' => $this->option('create_since'), 'create_until' => $this->option('create_until'), 'create' => (bool) $this->argument('create'), + 'interactive' => !(bool) $this->option('no-interaction'), + 'cli_command' => $this, ]; try { diff --git a/engine/classes/Elgg/Cli/ErrorFormatter.php b/engine/classes/Elgg/Cli/ErrorFormatter.php index eea2626fb2a..6451c430d91 100644 --- a/engine/classes/Elgg/Cli/ErrorFormatter.php +++ b/engine/classes/Elgg/Cli/ErrorFormatter.php @@ -3,7 +3,8 @@ namespace Elgg\Cli; use Elgg\Logger\ElggLogFormatter; -use Monolog\Logger; +use Monolog\Level; +use Monolog\LogRecord; use Symfony\Component\Console\Helper\FormatterHelper; /** @@ -16,20 +17,20 @@ class ErrorFormatter extends ElggLogFormatter { /** * {@inheritdoc} */ - public function format(array $record): string { + public function format(LogRecord $record): string { $message = parent::format($record); $formatter = new FormatterHelper(); - switch ($record['level']) { - case Logger::EMERGENCY: - case Logger::CRITICAL: - case Logger::ALERT: - case Logger::ERROR: + switch ($record->level->value) { + case Level::Emergency: + case Level::Critical: + case Level::Alert: + case Level::Error: $style = 'error'; break; - case Logger::WARNING: + case Level::Warning: $style = 'comment'; break; diff --git a/engine/classes/Elgg/Cli/ErrorHandler.php b/engine/classes/Elgg/Cli/ErrorHandler.php index cc69b30c529..fefa4904523 100644 --- a/engine/classes/Elgg/Cli/ErrorHandler.php +++ b/engine/classes/Elgg/Cli/ErrorHandler.php @@ -4,6 +4,8 @@ use Elgg\Logger; use Monolog\Handler\AbstractProcessingHandler; +use Monolog\Level; +use Monolog\LogRecord; use Symfony\Component\Console\Output\NullOutput; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\StreamOutput; @@ -18,10 +20,10 @@ class ErrorHandler extends AbstractProcessingHandler { const VERBOSITY_LEVEL_MAP = [ OutputInterface::VERBOSITY_QUIET => Logger::OFF, - OutputInterface::VERBOSITY_NORMAL => Logger::WARNING, - OutputInterface::VERBOSITY_VERBOSE => Logger::NOTICE, - OutputInterface::VERBOSITY_VERY_VERBOSE => Logger::INFO, - OutputInterface::VERBOSITY_DEBUG => Logger::DEBUG, + OutputInterface::VERBOSITY_NORMAL => Level::Warning, + OutputInterface::VERBOSITY_VERBOSE => Level::Notice, + OutputInterface::VERBOSITY_VERY_VERBOSE => Level::Info, + OutputInterface::VERBOSITY_DEBUG => Level::Debug, ]; /** @@ -59,21 +61,21 @@ public function __construct( /** * {@inheritdoc} */ - public function write(array $record): void { - $stream = $record['level'] >= Logger::ERROR ? $this->stderr : $this->stdout; + public function write(LogRecord $record): void { + $stream = $record->level->value >= Level::Error ? $this->stderr : $this->stdout; - $stream->write($record['formatted'], true); + $stream->write($record->formatted, true); if ($stream instanceof StreamOutput) { $dumper = new CliDumper($stream->getStream()); $cloner = new VarCloner(); - if (!empty($record['context'])) { - $dumper->dump($cloner->cloneVar($record['context'])); + if (!empty($record->context)) { + $dumper->dump($cloner->cloneVar($record->context)); } - if (!empty($record['extra'])) { - $dumper->dump($cloner->cloneVar($record['extra'])); + if (!empty($record->extra)) { + $dumper->dump($cloner->cloneVar($record->extra)); } } } diff --git a/engine/classes/Elgg/Cli/InstallCommand.php b/engine/classes/Elgg/Cli/InstallCommand.php index f65ec469ea5..a6966185203 100644 --- a/engine/classes/Elgg/Cli/InstallCommand.php +++ b/engine/classes/Elgg/Cli/InstallCommand.php @@ -2,7 +2,6 @@ namespace Elgg\Cli; -use ElggInstaller; use Elgg\Exceptions\Configuration\InstallationException; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; @@ -71,8 +70,8 @@ protected function execute(InputInterface $input, OutputInterface $output) { } try { - $installer = new ElggInstaller(); - $htaccess = !is_file(\Elgg\Application::projectDir()->getPath('.htaccess')); + $installer = new \ElggInstaller(); + $htaccess = !is_file(\Elgg\Project\Paths::project() . '.htaccess'); $installer->batchInstall($params, $htaccess); } catch (InstallationException $ex) { $this->dumpRegisters(); diff --git a/engine/classes/Elgg/Cli/Progress.php b/engine/classes/Elgg/Cli/Progress.php index 28de068e2b4..6084dceb8ee 100644 --- a/engine/classes/Elgg/Cli/Progress.php +++ b/engine/classes/Elgg/Cli/Progress.php @@ -10,18 +10,12 @@ */ class Progress { - /** - * @var OutputInterface - */ - protected $output; - /** * Constructor * * @param OutputInterface $output Output */ - public function __construct(OutputInterface $output) { - $this->output = $output; + public function __construct(protected OutputInterface $output) { } /** diff --git a/engine/classes/Elgg/Cli/ResponseTransport.php b/engine/classes/Elgg/Cli/ResponseTransport.php index 2f02a56c0ed..c7b2c2df111 100644 --- a/engine/classes/Elgg/Cli/ResponseTransport.php +++ b/engine/classes/Elgg/Cli/ResponseTransport.php @@ -9,15 +9,12 @@ */ class ResponseTransport implements \Elgg\Http\ResponseTransport { - private $command; - /** * ResponseTransport constructor. * * @param Command $command Cli command */ - public function __construct(Command $command) { - $this->command = $command; + public function __construct(protected Command $command) { } /** diff --git a/engine/classes/Elgg/Cli/UpgradeCommand.php b/engine/classes/Elgg/Cli/UpgradeCommand.php index 94d57265313..a299c8b3ac3 100644 --- a/engine/classes/Elgg/Cli/UpgradeCommand.php +++ b/engine/classes/Elgg/Cli/UpgradeCommand.php @@ -66,7 +66,7 @@ protected function execute(InputInterface $input, OutputInterface $output) { $upgrades = _elgg_services()->upgrades->getPendingUpgrades(false); $job = _elgg_services()->upgrades->run($upgrades); - $job->done( + $job->then( function () { $this->notice(elgg_echo('cli:upgrade:system:upgraded')); }, @@ -100,7 +100,7 @@ function ($errors) use (&$return) { $upgrades = _elgg_services()->upgrades->getPendingUpgrades(true); $job = _elgg_services()->upgrades->run($upgrades); - $job->done( + $job->then( function () { $this->notice(elgg_echo('cli:upgrade:async:upgraded')); }, diff --git a/engine/classes/Elgg/Comments/Preloader.php b/engine/classes/Elgg/Comments/Preloader.php index 7c7ad4119d8..e959a5519b5 100644 --- a/engine/classes/Elgg/Comments/Preloader.php +++ b/engine/classes/Elgg/Comments/Preloader.php @@ -10,18 +10,12 @@ */ class Preloader { - /** - * @var \Elgg\Comments\DataService - */ - protected $data; - /** * Create a preloader * * @param \Elgg\Comments\DataService $data a dataservice */ - public function __construct(DataService $data) { - $this->data = $data; + public function __construct(protected DataService $data) { } /** diff --git a/engine/classes/Elgg/Composer/PostInstall.php b/engine/classes/Elgg/Composer/PostInstall.php index ee16e6fd0cf..336830fdc71 100644 --- a/engine/classes/Elgg/Composer/PostInstall.php +++ b/engine/classes/Elgg/Composer/PostInstall.php @@ -3,7 +3,7 @@ namespace Elgg\Composer; use Composer\Script\Event; -use Elgg\Filesystem\Directory\Local; +use Elgg\Project\Paths; /** * A composer command handler to run after composer install @@ -17,7 +17,7 @@ class PostInstall { * * @return void */ - public static function execute(Event $event) { + public static function execute(Event $event): void { self::copyFromElggToRoot('install/config/htaccess.dist', '.htaccess'); self::copyFromElggToRoot('index.php', 'index.php'); self::copyFromElggToRoot('install.php', 'install.php'); @@ -25,10 +25,12 @@ public static function execute(Event $event) { self::createProjectModFolder(); - $managed_plugins = \Elgg\Database\Plugins::BUNDLED_PLUGINS; - - foreach ($managed_plugins as $plugin) { - self::symlinkPluginFromRootToElgg($plugin); + if (stripos(PHP_OS, 'win') !== 0) { + // symlink the mods from Elgg /mod to the project /mod + $managed_plugins = \Elgg\Database\Plugins::BUNDLED_PLUGINS; + foreach ($managed_plugins as $plugin) { + self::symlinkPluginFromRootToElgg($plugin); + } } } @@ -41,9 +43,9 @@ public static function execute(Event $event) { * * @return boolean Whether the copy succeeded. */ - protected static function copyFromElggToRoot($elggPath, $rootPath, $overwrite = false) { - $from = Local::elggRoot()->getPath($elggPath); - $to = Local::projectRoot()->getPath($rootPath); + protected static function copyFromElggToRoot(string $elggPath, string $rootPath, bool $overwrite = false): bool { + $from = Paths::elgg() . $elggPath; + $to = Paths::project() . $rootPath; if (!$overwrite && file_exists($to)) { return false; @@ -60,8 +62,8 @@ protected static function copyFromElggToRoot($elggPath, $rootPath, $overwrite = * @since 4.2 */ protected static function createProjectModFolder(): bool { - $project_mod = Local::projectRoot()->getPath('mod'); - $elgg_mod = Local::elggRoot()->getPath('mod'); + $project_mod = Paths::project() . 'mod'; + $elgg_mod = Paths::elgg() . 'mod'; if ($project_mod === $elgg_mod) { // Elgg is the main project, no need to create the /mod folder @@ -84,9 +86,9 @@ protected static function createProjectModFolder(): bool { * * @return bool Whether the symlink succeeded. */ - protected static function symlinkPluginFromRootToElgg($plugin) { - $link = Local::projectRoot()->getPath("mod/{$plugin}"); - $target = Local::elggRoot()->getPath("mod/{$plugin}"); + protected static function symlinkPluginFromRootToElgg(string $plugin): bool { + $link = Paths::project() . "mod/{$plugin}"; + $target = Paths::elgg() . "mod/{$plugin}"; return is_dir($target) && !file_exists($link) && symlink($target, $link); } diff --git a/engine/classes/Elgg/Config.php b/engine/classes/Elgg/Config.php index 38ed07ad458..90585fc0113 100644 --- a/engine/classes/Elgg/Config.php +++ b/engine/classes/Elgg/Config.php @@ -95,6 +95,15 @@ * @property bool $remove_branding Is Elgg branding disabled * @property int $remove_unvalidated_users_days The number of days after which unvalidated users will be removed * @property bool $require_admin_validation + * @property string $security_txt_acknowledgments Security.txt link to acknowledgments + * @property string $security_txt_canonical Security.txt canonical url + * @property string $security_txt_contact Security.txt contact information (mailto or https) + * @property string $security_txt_csaf Security.txt link to CSAF provider + * @property string $security_txt_encryption Security.txt link to encryption key for communication + * @property int $security_txt_expires Security.txt expiration date + * @property string $security_txt_hiring Security.txt link to hiring page + * @property string $security_txt_language Security.txt preferred communication language + * @property string $security_txt_policy Security.txt link to security reporting policy * @property bool $security_disable_password_autocomplete * @property bool $security_email_require_password * @property bool $security_notify_admins @@ -112,9 +121,10 @@ * @property string[] $site_featured_menu_names * @property bool $subresource_integrity_enabled Should subresources (js/css) get integrity information * @property bool $system_cache_enabled Is the system cache enabled? - * @property bool $system_cache_loaded * @property bool $testing_mode Is the current application running (PHPUnit) tests * @property string $time_format Preferred PHP time format + * @property bool $trash_enabled Is the trash feature enabled + * @property int $trash_retention Number of days before trashed content is removed from the database * @property bool $user_joined_river Do we need to create a river event when a user joins the site * @property string $view Default viewtype (usually not set) * @property bool $walled_garden Is current site in walled garden mode? @@ -227,6 +237,8 @@ class Config { 'subresource_integrity_enabled' => false, 'system_cache_enabled' => false, 'testing_mode' => false, + 'trash_enabled' => false, + 'trash_retention' => 30, 'user_joined_river' => false, 'webp_enabled' => true, 'who_can_change_language' => 'everyone', @@ -379,7 +391,7 @@ public static function resolvePath(string $settings_path = ''): string { $settings_path = Paths::settingsFile(Paths::SETTINGS_PHP); } - return \Elgg\Project\Paths::sanitize($settings_path, false); + return Paths::sanitize($settings_path, false); } /** diff --git a/engine/classes/Elgg/Controllers/SecurityTxt.php b/engine/classes/Elgg/Controllers/SecurityTxt.php new file mode 100644 index 00000000000..07d321c675b --- /dev/null +++ b/engine/classes/Elgg/Controllers/SecurityTxt.php @@ -0,0 +1,61 @@ +format(DATE_ATOM), + ]; + + $fields = [ + 'encryption' => 'Encryption', + 'acknowledgments' => 'Acknowledgments', + 'language' => 'Preferred-Languages', + 'canonical' => 'Canonical', + 'policy' => 'Policy', + 'hiring' => 'Hiring', + 'csaf' => 'CSAF', + ]; + foreach ($fields as $name => $output) { + $value = elgg_get_config("security_txt_{$name}"); + if (empty($value)) { + continue; + } + + $lines[] = "{$output}: {$value}"; + } + + $response = elgg_ok_response(implode(PHP_EOL, $lines)); + $response->setHeaders([ + 'Content-Type' => 'text/plain; charset=utf-8', + ]); + + return $response; + } +} diff --git a/engine/classes/Elgg/Cron.php b/engine/classes/Elgg/Cron.php index 2f0defb3e13..8f46a4d5ea8 100644 --- a/engine/classes/Elgg/Cron.php +++ b/engine/classes/Elgg/Cron.php @@ -3,6 +3,8 @@ namespace Elgg; use Elgg\Exceptions\CronException; +use Elgg\I18n\DateTime; +use Elgg\I18n\Translator; use Elgg\Traits\Loggable; use Elgg\Traits\TimeUsing; use GO\Job; @@ -18,10 +20,9 @@ class Cron { use Loggable; use TimeUsing; - /** - * @var array - */ - protected $default_intervals = [ + protected const LOG_FILES_TO_KEEP = 5; + + protected array $default_intervals = [ 'minute' => '* * * * *', 'fiveminute' => '*/5 * * * *', 'fifteenmin' => '*/15 * * * *', @@ -33,31 +34,25 @@ class Cron { 'yearly' => '0 0 1 1 *', ]; - /** - * @var EventsService - */ - protected $events; - /** * Constructor * - * @param EventsService $events Events service + * @param EventsService $events Events service + * @param Translator $translator Translator service */ - public function __construct(EventsService $events) { - $this->events = $events; + public function __construct(protected EventsService $events, protected Translator $translator) { } /** * Executes handlers for periods that have elapsed since last cron * - * @param array $intervals Interval names to run - * @param bool $force Force cron jobs to run even they are not yet due + * @param null|array $intervals Interval names to run (default: all cron intervals) + * @param bool $force Force cron jobs to run even they are not yet due * * @return Job[] * @throws CronException */ - public function run(array $intervals = null, $force = false) { - + public function run(array $intervals = null, bool $force = false): array { if (!isset($intervals)) { $intervals = array_keys($this->default_intervals); } @@ -69,21 +64,27 @@ public function run(array $intervals = null, $force = false) { foreach ($intervals as $interval) { if (!array_key_exists($interval, $allowed_intervals)) { - throw new CronException("$interval is not a recognized cron interval"); + throw new CronException("{$interval} is not a recognized cron interval. Please use one of the following: " . implode(', ', array_keys($allowed_intervals))); } $cron_interval = $force ? $allowed_intervals['minute'] : $allowed_intervals[$interval]; - + $filename = $this->getLogFilename($interval, $time); + + $cron_logger = \Elgg\Logger\Cron::factory([ + 'interval' => $interval, + 'filename' => $filename, + ]); + $scheduler - ->call(function () use ($interval, $time) { - return $this->execute($interval, $time); + ->call(function () use ($interval, $time, $cron_logger, $filename) { + return $this->execute($interval, $cron_logger, $filename, $time); }) ->at($cron_interval) - ->before(function () use ($interval, $time) { - $this->before($interval, $time); + ->before(function () use ($interval, $time, $cron_logger) { + $this->before($interval, $cron_logger, $time); }) - ->then(function ($output) use ($interval) { - $this->after($output, $interval); + ->then(function ($output) use ($interval, $cron_logger) { + $this->after($output, $interval, $cron_logger); }); } @@ -93,134 +94,180 @@ public function run(array $intervals = null, $force = false) { /** * Execute commands before cron interval is run * - * @param string $interval Interval name - * @param \DateTime $time Time of the cron initialization + * @param string $interval Interval name + * @param \Elgg\Logger\Cron $cron_logger Cron logger + * @param null|\DateTime $time Time of the cron initialization (default: current service time) * * @return void */ - protected function before($interval, \DateTime $time = null) { - + protected function before(string $interval, \Elgg\Logger\Cron $cron_logger, \DateTime $time = null): void { if (!isset($time)) { $time = $this->getCurrentTime(); } - $this->events->triggerBefore('cron', $interval, $time); + try { + $this->events->triggerBefore('cron', $interval, $time); + } catch (\Throwable $t) { + $this->getLogger()->error($t); + } // give every period at least 'max_execution_time' (PHP ini setting) set_time_limit((int) ini_get('max_execution_time')); - - $now = new \DateTime(); - - $msg = elgg_echo('admin:cron:started', [$interval, $time->format(DATE_RFC2822)]) . PHP_EOL; - $msg .= elgg_echo('admin:cron:started:actual', [$interval, $now->format(DATE_RFC2822)]) . PHP_EOL; - - $this->cronLog('output', $interval, $msg); + + $now = new DateTime(); + + $cron_logger->notice($this->translator->translate('admin:cron:started', [$interval, $time->format(DATE_RFC2822)])); + $cron_logger->notice($this->translator->translate('admin:cron:started:actual', [$interval, $now->format(DATE_RFC2822)])); } /** * Execute handlers attached to a specific cron interval * - * @param string $interval Cron interval to execute - * @param \DateTime $time Time of cron initialization + * @param string $interval Cron interval to execute + * @param \Elgg\Logger\Cron $cron_logger Cron logger + * @param string $filename Filename of the cron log + * @param null|\DateTime $time Time of cron initialization (default: current service time) * * @return string */ - protected function execute($interval, \DateTime $time = null) { - + protected function execute(string $interval, \Elgg\Logger\Cron $cron_logger, string $filename, \DateTime $time = null): string { if (!isset($time)) { $time = $this->getCurrentTime(); } + + try { + $begin_callback = function (array $params) use ($cron_logger) { + $readable_callable = (string) elgg_extract('readable_callable', $params); + + $cron_logger->notice("Starting {$readable_callable}"); + }; + + $end_callback = function (array $params) use ($cron_logger) { + $readable_callable = (string) elgg_extract('readable_callable', $params); + + $cron_logger->notice("Finished {$readable_callable}"); + }; + + $this->events->trigger('cron', $interval, [ + 'time' => $time->getTimestamp(), + 'dt' => $time, + 'logger' => $cron_logger, + ], [ + EventsService::OPTION_BEGIN_CALLBACK => $begin_callback, + EventsService::OPTION_END_CALLBACK => $end_callback, + ]); + } catch (\Throwable $t) { + $this->getLogger()->error($t); + } - $now = new \DateTime(); - - $output = []; - - $output[] = elgg_echo('admin:cron:started', [$interval, $time->format(DATE_RFC2822)]); - $output[] = elgg_echo('admin:cron:started:actual', [$interval, $now->format(DATE_RFC2822)]); - - ob_start(); - - $old_stdout = $this->events->triggerResults('cron', $interval, [ - 'time' => $time->getTimestamp(), - 'dt' => $time, - ], ''); - - $output[] = ob_get_clean(); - $output[] = $old_stdout; - - $now = new \DateTime(); - - $output[] = elgg_echo('admin:cron:complete', [$interval, $now->format(DATE_RFC2822)]); + $now = new DateTime(); - return implode(PHP_EOL, array_filter($output)); + $complete = $this->translator->translate('admin:cron:complete', [$interval, $now->format(DATE_RFC2822)]); + $cron_logger->notice($complete); + + if (file_exists($filename) && is_readable($filename)) { + return file_get_contents($filename); + } + + return ''; } /** * Printers handler result * - * @param string $output Output string - * @param string $interval Interval name + * @param string $output Output string + * @param string $interval Interval name + * @param \Elgg\Logger\Cron $cron_logger Cron logger * * @return void */ - protected function after($output, $interval) { - - $time = new \DateTime(); - - $this->cronLog('output', $interval, $output); - $this->cronLog('completion', $interval, $time->getTimestamp()); - + protected function after(string $output, string $interval, \Elgg\Logger\Cron $cron_logger): void { $this->getLogger()->info($output); - - $this->events->triggerAfter('cron', $interval, $time); + + try { + $this->events->triggerAfter('cron', $interval, new \DateTime()); + } catch (\Throwable $t) { + $this->getLogger()->error($t); + } + + $cron_logger->close(); + $this->rotateLogs($interval); + $this->logCompletion($interval); } - + /** - * Log the results of a cron interval + * Get the log files for a given cron interval * - * @param string $setting 'output'|'completion' - * @param string $interval Interval name - * @param string $msg Logged message + * The results are sorted so the newest log is the first in the array * - * @return void + * @param string $interval cron interval + * @param bool $filenames_only only return the filenames (default: false) + * + * @return array */ - protected function cronLog($setting, $interval, $msg = '') { - $suffix = $setting ?: 'output'; - + public function getLogs(string $interval, bool $filenames_only = false): array { $fh = new \ElggFile(); $fh->owner_guid = elgg_get_site_entity()->guid; - $fh->setFilename("{$interval}-{$suffix}.log"); + $fh->setFilename("cron/{$interval}/dummy.log"); - $fh->open('write'); - $fh->write($msg); - $fh->close(); + $dir = pathinfo($fh->getFilenameOnFilestore(), PATHINFO_DIRNAME); + if (!is_dir($dir) || !is_readable($dir)) { + return []; + } + + $dh = new \DirectoryIterator($dir); + $files = []; + /* @var $file \DirectoryIterator */ + foreach ($dh as $file) { + if ($file->isDot() || !$file->isFile()) { + continue; + } + + if ($filenames_only) { + $files[] = $file->getFilename(); + } else { + $files[$file->getFilename()] = file_get_contents($file->getPathname()); + } + } + + if ($filenames_only) { + natcasesort($files); + } else { + uksort($files, 'strnatcasecmp'); + } + + return array_reverse($files); } /** - * Get the log contents of a cron interval + * Get the time of the last completion of a cron interval * - * @param string $setting 'output'|'completion' - * @param string $interval Interval name + * @param string $interval cron interval * - * @return string + * @return null|DateTime */ - public function getLog($setting, $interval) { - $suffix = $setting ?: 'output'; - + public function getLastCompletion(string $interval): ?DateTime { $fh = new \ElggFile(); $fh->owner_guid = elgg_get_site_entity()->guid; - $fh->setFilename("{$interval}-{$suffix}.log"); + $fh->setFilename("cron/{$interval}.complete"); if (!$fh->exists()) { - return ''; + return null; } - $contents = $fh->grabFile(); - if (!is_string($contents)) { - $contents = ''; + $date = $fh->grabFile(); + if (empty($date)) { + // how?? + return null; } - return $contents; + try { + return Values::normalizeTime($date); + } catch (\Elgg\Exceptions\ExceptionInterface $e) { + $this->getLogger()->warning($e); + } + + return null; } /** @@ -231,7 +278,7 @@ public function getLog($setting, $interval) { * @return array * @since 3.2 */ - public function getConfiguredIntervals(bool $only_names = false) { + public function getConfiguredIntervals(bool $only_names = false): array { $result = $this->events->triggerResults('cron:intervals', 'system', [], $this->default_intervals); if (!is_array($result)) { $this->getLogger()->warning("The event 'cron:intervals', 'system' should return an array, " . gettype($result) . ' given'); @@ -245,4 +292,78 @@ public function getConfiguredIntervals(bool $only_names = false) { return $result; } + + /** + * Get a filename to log in + * + * @param string $interval cron interval to log + * @param \DateTime|null $time start time of the cron + * + * @return string + */ + protected function getLogFilename(string $interval, \DateTime $time = null): string { + if (!isset($time)) { + $time = $this->getCurrentTime(); + } + + $date = $time->format(\DateTimeInterface::ATOM); + $date = str_replace('+', 'p', $date); + $date = preg_replace('/[^a-zA-Z0-9_-]+/', '-', $date); + + $fh = new \ElggFile(); + $fh->owner_guid = elgg_get_site_entity()->guid; + $fh->setFilename("cron/{$interval}/{$date}.log"); + + return $fh->getFilenameOnFilestore(); + } + + /** + * Rotate the log files + * + * @param string $interval cron interval + * + * @return void + */ + protected function rotateLogs(string $interval): void { + $files = $this->getLogs($interval, true); + if (count($files) <= self::LOG_FILES_TO_KEEP) { + return; + } + + $fh = new \ElggFile(); + $fh->owner_guid = elgg_get_site_entity()->guid; + + while (count($files) > self::LOG_FILES_TO_KEEP) { + $filename = array_pop($files); + + $fh->setFilename("cron/{$interval}/{$filename}"); + $fh->delete(); + } + } + + /** + * Log the completion time of a cron interval + * + * @param string $interval cron interval + * + * @return void + */ + protected function logCompletion(string $interval): void { + $fh = new \ElggFile(); + $fh->owner_guid = elgg_get_site_entity()->guid; + $fh->setFilename("cron/{$interval}.complete"); + + try { + if ($fh->open('write') === false) { + return; + } + } catch (\Elgg\Exceptions\ExceptionInterface $e) { + $this->getLogger()->warning($e); + return; + } + + $now = new DateTime(); + $fh->write($now->format(\DateTimeInterface::ATOM)); + $fh->close(); + } } diff --git a/engine/classes/Elgg/Database.php b/engine/classes/Elgg/Database.php index 7ea8416a0b8..d1f0de1a7e5 100644 --- a/engine/classes/Elgg/Database.php +++ b/engine/classes/Elgg/Database.php @@ -3,12 +3,13 @@ namespace Elgg; use Doctrine\DBAL\Connection; +use Doctrine\DBAL\Driver\Exception\NoIdentityValue; use Doctrine\DBAL\DriverManager; -use Doctrine\DBAL\Driver\ServerInfoAwareConnection; +use Doctrine\DBAL\Exception\DriverException; use Doctrine\DBAL\Result; -use Doctrine\DBAL\Query\QueryBuilder; use Elgg\Cache\QueryCache; use Elgg\Database\DbConfig; +use Elgg\Database\QueryBuilder; use Elgg\Exceptions\DatabaseException; use Elgg\Exceptions\RuntimeException; use Elgg\Traits\Debug\Profilable; @@ -38,19 +39,12 @@ class Database { /** * @var Connection[] */ - private $connections = []; + private array $connections = []; /** * @var int $query_count The number of queries made */ - private $query_count = 0; - - /** - * Query cache for select queries. - * - * @var \Elgg\Cache\QueryCache $query_cache The cache - */ - protected $query_cache; + private int $query_count = 0; /** * Queries are saved as an array with the DELAYED_* constants as keys. @@ -64,18 +58,17 @@ class Database { /** * @var \Elgg\Database\DbConfig $config Database configuration */ - private $config; + private $db_config; /** * Constructor * - * @param DbConfig $config DB configuration + * @param DbConfig $db_config DB configuration * @param QueryCache $query_cache Query Cache + * @param Config $config Elgg config */ - public function __construct(DbConfig $config, QueryCache $query_cache) { - $this->query_cache = $query_cache; - - $this->resetConnections($config); + public function __construct(DbConfig $db_config, protected QueryCache $query_cache, protected Config $config) { + $this->resetConnections($db_config); } /** @@ -88,7 +81,7 @@ public function __construct(DbConfig $config, QueryCache $query_cache) { public function resetConnections(DbConfig $config) { $this->closeConnections(); - $this->config = $config; + $this->db_config = $config; $this->table_prefix = $config->getTablePrefix(); $this->query_cache->enable(); $this->query_cache->clear(); @@ -138,7 +131,7 @@ public function getConnection(string $type): Connection { * @return void */ public function setupConnections(): void { - if ($this->config->isDatabaseSplit()) { + if ($this->db_config->isDatabaseSplit()) { $this->connect('read'); $this->connect('write'); } else { @@ -157,7 +150,7 @@ public function setupConnections(): void { * @throws DatabaseException */ public function connect(string $type = 'readwrite'): void { - $conf = $this->config->getConnectionConfig($type); + $conf = $this->db_config->getConnectionConfig($type); $params = [ 'dbname' => $conf['database'], @@ -243,7 +236,16 @@ public function insertData(QueryBuilder $query): int { $this->query_cache->clear(); $this->executeQuery($query); - return (int) $query->getConnection()->lastInsertId(); + + try { + return (int) $query->getConnection()->lastInsertId(); + } catch (DriverException $e) { + if ($e->getPrevious() instanceof NoIdentityValue) { + return 0; + } + + throw $e; + } } /** @@ -256,7 +258,7 @@ public function insertData(QueryBuilder $query): int { * * @return bool|int */ - public function updateData(QueryBuilder $query, bool $get_num_rows = false) { + public function updateData(QueryBuilder $query, bool $get_num_rows = false): bool|int { $params = $query->getParameters(); $sql = $query->getSQL(); @@ -269,7 +271,7 @@ public function updateData(QueryBuilder $query, bool $get_num_rows = false) { return true; } - return ($result instanceof Result) ? $result->rowCount() : $result; + return ($result instanceof Result) ? (int) $result->rowCount() : $result; } /** @@ -290,7 +292,7 @@ public function deleteData(QueryBuilder $query): int { $this->query_cache->clear(); $result = $this->executeQuery($query); - return ($result instanceof Result) ? $result->rowCount() : $result; + return ($result instanceof Result) ? (int) $result->rowCount() : $result; } /** @@ -465,6 +467,24 @@ public function trackQuery(QueryBuilder $query, callable $callback) { * @return void */ public function registerDelayedQuery(QueryBuilder $query, $callback = null): void { + if (Application::isCli() && !$this->config->testing_mode) { + // during CLI execute delayed queries immediately (unless in testing mode, during PHPUnit) + // this should prevent OOM during long-running jobs + // @see Database::executeDelayedQueries() + try { + $stmt = $this->executeQuery($query); + + if (is_callable($callback)) { + call_user_func($callback, $stmt); + } + } catch (\Throwable $t) { + // Suppress all exceptions to not allow the application to crash + $this->getLogger()->error($t); + } + + return; + } + $this->delayed_queries[] = [ self::DELAYED_QUERY => $query, self::DELAYED_HANDLER => $callback, @@ -489,9 +509,9 @@ public function executeDelayedQueries(): void { if (is_callable($handler)) { call_user_func($handler, $stmt); } - } catch (\Exception $e) { + } catch (\Throwable $t) { // Suppress all exceptions since page already sent to requestor - $this->getLogger()->error($e); + $this->getLogger()->error($t); } } @@ -538,20 +558,7 @@ public function getQueryCount(): int { * @return string Empty if version cannot be determined */ public function getServerVersion(string $type = DbConfig::READ_WRITE): string { - $driver = $this->getConnection($type)->getWrappedConnection(); - if ($driver instanceof ServerInfoAwareConnection) { - $version = $driver->getServerVersion(); - - if ($this->isMariaDB($type)) { - if (str_starts_with($version, '5.5.5-')) { - $version = substr($version, 6); - } - } - - return $version; - } - - return ''; + return $this->getConnection($type)->getServerVersion(); } /** @@ -562,14 +569,20 @@ public function getServerVersion(string $type = DbConfig::READ_WRITE): string { * @return bool if MariaDB is detected */ public function isMariaDB(string $type = DbConfig::READ_WRITE): bool { - $driver = $this->getConnection($type)->getWrappedConnection(); - if ($driver instanceof ServerInfoAwareConnection) { - $version = $driver->getServerVersion(); - - return stristr($version, 'mariadb') !== false; - } - - return false; + return $this->getConnection($type)->getDatabasePlatform() instanceof \Doctrine\DBAL\Platforms\MariaDBPlatform; + } + + /** + * Is the database MySQL + * + * @param string $type Connection type (Config constants, e.g. Config::READ_WRITE) + * + * @return bool if MySQL is detected + * + * @since 6.0 + */ + public function isMySQL(string $type = DbConfig::READ_WRITE): bool { + return $this->getConnection($type)->getDatabasePlatform() instanceof \Doctrine\DBAL\Platforms\MySQLPlatform; } /** diff --git a/engine/classes/Elgg/Database/AccessCollections.php b/engine/classes/Elgg/Database/AccessCollections.php index b86ae903403..a4666b788a1 100644 --- a/engine/classes/Elgg/Database/AccessCollections.php +++ b/engine/classes/Elgg/Database/AccessCollections.php @@ -27,12 +27,12 @@ class AccessCollections { /** * @var string name of the access collections database table */ - const TABLE_NAME = 'access_collections'; + public const TABLE_NAME = 'access_collections'; /** * @var string name of the access collection membership database table */ - const MEMBERSHIP_TABLE_NAME = 'access_collection_membership'; + public const MEMBERSHIP_TABLE_NAME = 'access_collection_membership'; protected Config $config; @@ -665,9 +665,9 @@ public function getMembers(int $collection_id, array $options = []) { */ public function getCollectionsByMember(int $member_guid): array { $select = Select::fromTable(self::TABLE_NAME, 'ac'); - $select->join('ac', self::MEMBERSHIP_TABLE_NAME, 'acm', $select->compare('ac.id', '=', 'acm.access_collection_id')); + $select->join($select->getTableAlias(), self::MEMBERSHIP_TABLE_NAME, 'acm', $select->compare("{$select->getTableAlias()}.id", '=', 'acm.access_collection_id')); - $select->select('ac.*') + $select->select("{$select->getTableAlias()}.*") ->where($select->compare('acm.user_guid', '=', $member_guid, ELGG_VALUE_GUID)) ->orderBy('name', 'ASC'); diff --git a/engine/classes/Elgg/Database/Annotations.php b/engine/classes/Elgg/Database/Annotations.php index 29dd2b94d6b..84db811a917 100644 --- a/engine/classes/Elgg/Database/Annotations.php +++ b/engine/classes/Elgg/Database/Annotations.php @@ -23,9 +23,9 @@ class Annotations extends Repository { * {@inheritdoc} */ public function count() { - $qb = Select::fromTable('annotations', 'n_table'); + $qb = Select::fromTable(AnnotationsTable::TABLE_NAME, AnnotationsTable::DEFAULT_JOIN_ALIAS); - $count_expr = $this->options->distinct ? 'DISTINCT n_table.id' : '*'; + $count_expr = $this->options->distinct ? "DISTINCT {$qb->getTableAlias()}.id" : '*'; $qb->select("COUNT({$count_expr}) AS total"); $qb = $this->buildQuery($qb); @@ -58,7 +58,7 @@ public function calculate($function, $property, $property_type = null) { $property_type = 'annotation'; } - $qb = Select::fromTable('annotations', 'n_table'); + $qb = Select::fromTable(AnnotationsTable::TABLE_NAME, AnnotationsTable::DEFAULT_JOIN_ALIAS); switch ($property_type) { case 'attribute': @@ -66,21 +66,21 @@ public function calculate($function, $property, $property_type = null) { throw new DomainException("'{$property}' is not a valid attribute"); } - $alias = $qb->joinEntitiesTable('n_table', 'entity_guid', 'inner', 'e'); + $alias = $qb->joinEntitiesTable($qb->getTableAlias(), 'entity_guid', 'inner', EntityTable::DEFAULT_JOIN_ALIAS); $qb->select("{$function}({$alias}.{$property}) AS calculation"); break; case 'annotation': - $alias = 'n_table'; + $alias = AnnotationsTable::DEFAULT_JOIN_ALIAS; if (!empty($this->options->annotation_name_value_pairs) && $this->options->annotation_name_value_pairs[0]->names != $property) { - $alias = $qb->joinAnnotationTable('n_table', 'entity_guid', $property); + $alias = $qb->joinAnnotationTable($qb->getTableAlias(), 'entity_guid', $property); } - $qb->select("{$function}($alias.value) AS calculation"); + $qb->select("{$function}({$alias}.value) AS calculation"); break; case 'metadata': - $alias = $qb->joinMetadataTable('n_table', 'entity_guid', $property); + $alias = $qb->joinMetadataTable($qb->getTableAlias(), 'entity_guid', $property); $qb->select("{$function}({$alias}.value) AS calculation"); break; } @@ -102,20 +102,20 @@ public function calculate($function, $property, $property_type = null) { * @return \ElggAnnotation[] */ public function get($limit = null, $offset = null, $callback = null) { - $qb = Select::fromTable('annotations', 'n_table'); + $qb = Select::fromTable(AnnotationsTable::TABLE_NAME, AnnotationsTable::DEFAULT_JOIN_ALIAS); - $distinct = $this->options->distinct ? 'DISTINCT' : ''; - $qb->select("{$distinct} n_table.*"); + $distinct = $this->options->distinct ? 'DISTINCT ' : ''; + $qb->select("{$distinct}{$qb->getTableAlias()}.*"); - $this->expandInto($qb, 'n_table'); + $this->expandInto($qb, $qb->getTableAlias()); $qb = $this->buildQuery($qb); - // Keeping things backwards compatible + // add default ordering $original_order = elgg_extract('order_by', $this->options->__original_options); - if (empty($original_order) && $original_order !== false) { - $qb->addOrderBy('n_table.time_created', 'asc'); - $qb->addOrderBy('n_table.id', 'asc'); + if (empty($this->options->order_by) && $original_order !== false) { + $qb->addOrderBy("{$qb->getTableAlias()}.time_created", 'asc'); + $qb->addOrderBy("{$qb->getTableAlias()}.id", 'asc'); } if ($limit > 0) { @@ -141,7 +141,7 @@ public function get($limit = null, $offset = null, $callback = null) { /** * Execute the query resolving calculation, count and/or batch options * - * @return array|\ElggData[]|\ElggAnnotation[]|false|int + * @return array|\ElggData[]|\ElggAnnotation[]|int|\ElggBatch * @throws LogicException */ public function execute() { @@ -183,11 +183,11 @@ protected function buildQuery(QueryBuilder $qb) { $ands = []; foreach ($this->options->joins as $join) { - $join->prepare($qb, 'n_table'); + $join->prepare($qb, $qb->getTableAlias()); } foreach ($this->options->wheres as $where) { - $ands[] = $where->prepare($qb, 'n_table'); + $ands[] = $where->prepare($qb, $qb->getTableAlias()); } $ands[] = $this->buildPairedAnnotationClause($qb, $this->options->annotation_name_value_pairs, $this->options->annotation_name_value_pairs_operator); @@ -214,7 +214,7 @@ protected function buildQuery(QueryBuilder $qb) { * @return \Closure|CompositeExpression|mixed|null|string */ protected function buildEntityWhereClause(QueryBuilder $qb) { - $joined_alias = $qb->joinEntitiesTable('n_table', 'entity_guid', 'inner', 'e'); + $joined_alias = $qb->joinEntitiesTable($qb->getTableAlias(), 'entity_guid', 'inner', EntityTable::DEFAULT_JOIN_ALIAS); return EntityWhereClause::factory($this->options)->prepare($qb, $joined_alias); } @@ -237,7 +237,7 @@ protected function buildPairedAnnotationClause(QueryBuilder $qb, $clauses, $bool } foreach ($clauses as $clause) { - $parts[] = $clause->prepare($qb, 'n_table'); + $parts[] = $clause->prepare($qb, $qb->getTableAlias()); } return $qb->merge($parts, $boolean); @@ -257,10 +257,10 @@ protected function buildPairedMetadataClause(QueryBuilder $qb, $clauses, $boolea $parts = []; foreach ($clauses as $clause) { - if (strtoupper($boolean) === 'OR' || count($clauses) > 1) { - $joined_alias = $qb->joinMetadataTable('n_table', 'entity_guid'); + if (strtoupper($boolean) === 'OR' || count($clauses) === 1) { + $joined_alias = $qb->joinMetadataTable($qb->getTableAlias(), 'entity_guid', null, 'inner', MetadataTable::DEFAULT_JOIN_ALIAS); } else { - $joined_alias = $qb->joinMetadataTable('n_table', 'entity_guid', $clause->names); + $joined_alias = $qb->joinMetadataTable($qb->getTableAlias(), 'entity_guid', $clause->names); } $parts[] = $clause->prepare($qb, $joined_alias); @@ -284,10 +284,10 @@ protected function buildPairedRelationshipClause(QueryBuilder $qb, $clauses, $bo foreach ($clauses as $clause) { $join_on = $clause->join_on == 'guid' ? 'entity_guid' : $clause->join_on; - if (strtoupper($boolean) == 'OR' || count($clauses) > 1) { - $joined_alias = $qb->joinRelationshipTable('n_table', $join_on, null, $clause->inverse); + if (strtoupper($boolean) === 'OR' || count($clauses) === 1) { + $joined_alias = $qb->joinRelationshipTable($qb->getTableAlias(), $join_on, null, $clause->inverse, 'inner', RelationshipsTable::DEFAULT_JOIN_ALIAS); } else { - $joined_alias = $qb->joinRelationshipTable('n_table', $join_on, $clause->names, $clause->inverse); + $joined_alias = $qb->joinRelationshipTable($qb->getTableAlias(), $join_on, $clause->names, $clause->inverse); } $parts[] = $clause->prepare($qb, $joined_alias); diff --git a/engine/classes/Elgg/Database/AnnotationsTable.php b/engine/classes/Elgg/Database/AnnotationsTable.php index 7c0d19901d8..cf18fda8427 100644 --- a/engine/classes/Elgg/Database/AnnotationsTable.php +++ b/engine/classes/Elgg/Database/AnnotationsTable.php @@ -15,10 +15,10 @@ class AnnotationsTable { use TimeUsing; - - protected Database $db; - - protected EventsService $events; + + public const TABLE_NAME = 'annotations'; + + public const DEFAULT_JOIN_ALIAS = 'a_table'; /** * Constructor @@ -26,9 +26,7 @@ class AnnotationsTable { * @param Database $db Database * @param EventsService $events Events */ - public function __construct(Database $db, EventsService $events) { - $this->db = $db; - $this->events = $events; + public function __construct(protected Database $db, protected EventsService $events) { } /** @@ -39,7 +37,7 @@ public function __construct(Database $db, EventsService $events) { * @return \ElggAnnotation|null */ public function get(int $id): ?\ElggAnnotation { - $qb = Select::fromTable('annotations'); + $qb = Select::fromTable(self::TABLE_NAME); $qb->select('*'); $where = new AnnotationWhereClause(); @@ -66,7 +64,7 @@ public function delete(\ElggAnnotation $annotation): bool { return false; } - $qb = Delete::fromTable('annotations'); + $qb = Delete::fromTable(self::TABLE_NAME); $qb->where($qb->compare('id', '=', $annotation->id, ELGG_VALUE_INTEGER)); $deleted = $this->db->deleteData($qb); @@ -112,7 +110,7 @@ public function create(\ElggAnnotation $annotation, \ElggEntity $entity): int|bo $time_created = $this->getCurrentTime()->getTimestamp(); - $qb = Insert::intoTable('annotations'); + $qb = Insert::intoTable(self::TABLE_NAME); $qb->values([ 'entity_guid' => $qb->param($annotation->entity_guid, ELGG_VALUE_INTEGER), 'name' => $qb->param($annotation->name, ELGG_VALUE_STRING), @@ -164,7 +162,7 @@ public function update(\ElggAnnotation $annotation): bool { return false; } - $qb = Update::table('annotations'); + $qb = Update::table(self::TABLE_NAME); $qb->set('name', $qb->param($annotation->name, ELGG_VALUE_STRING)) ->set('value', $qb->param($annotation->value, $annotation->value_type === 'integer' ? ELGG_VALUE_INTEGER : ELGG_VALUE_STRING)) ->set('value_type', $qb->param($annotation->value_type, ELGG_VALUE_STRING)) @@ -184,78 +182,6 @@ public function update(\ElggAnnotation $annotation): bool { return $result; } - /** - * Disable the annotation. - * - * @param \ElggAnnotation $annotation Annotation - * - * @return bool - * @since 1.8 - */ - public function disable(\ElggAnnotation $annotation): bool { - if ($annotation->enabled === 'no') { - return true; - } - - if (!$annotation->canEdit()) { - return false; - } - - if (!_elgg_services()->events->trigger('disable', $annotation->getType(), $annotation)) { - return false; - } - - if ($annotation->id) { - $qb = Update::table('annotations'); - $qb->set('enabled', $qb->param('no', ELGG_VALUE_STRING)) - ->where($qb->compare('id', '=', $annotation->id, ELGG_VALUE_INTEGER)); - - if (!$this->db->updateData($qb)) { - return false; - } - } - - $annotation->enabled = 'no'; - - return true; - } - - /** - * Enable the annotation - * - * @param \ElggAnnotation $annotation Annotation - * - * @return bool - * @since 1.8 - */ - public function enable(\ElggAnnotation $annotation): bool { - if ($annotation->enabled == 'yes') { - return true; - } - - if (!$annotation->canEdit()) { - return false; - } - - if (!$this->events->trigger('enable', $annotation->getType(), $annotation)) { - return false; - } - - if ($annotation->id) { - $qb = Update::table('annotations'); - $qb->set('enabled', $qb->param('yes', ELGG_VALUE_STRING)) - ->where($qb->compare('id', '=', $annotation->id, ELGG_VALUE_INTEGER)); - - if (!$this->db->updateData($qb)) { - return false; - } - } - - $annotation->enabled = 'yes'; - - return true; - } - /** * Returns annotations. Accepts all {@link elgg_get_entities()} options * @@ -311,77 +237,6 @@ public function deleteAll(array $options): bool { return $success === $count; } - - /** - * Disables annotations based on $options. - * - * @warning Unlike elgg_get_annotations() this will not accept an empty options array! - * - * @param array $options An options array. {@link elgg_get_annotations()} - * @return bool true on success, false on failure - */ - public function disableAll(array $options): bool { - if (!$this->isValidOptionsForBatchOperation($options)) { - return false; - } - - // if we can see hidden (disabled) we need to use the offset - // otherwise we risk an infinite loop if there are more than 50 - $inc_offset = _elgg_services()->session_manager->getDisabledEntityVisibility(); - - $options['batch'] = true; - $options['batch_size'] = 50; - $options['batch_inc_offset'] = $inc_offset; - - $annotations = Annotations::find($options); - $count = $annotations->count(); - - if (!$count) { - return true; - } - - $success = 0; - foreach ($annotations as $annotation) { - if ($annotation->disable()) { - $success++; - } - } - - return $success === $count; - } - - /** - * Enables annotations based on $options. - * - * @warning Unlike elgg_get_annotations() this will not accept an empty options array! - * - * @param array $options An options array. {@link elgg_get_annotations()} - * @return bool true on success, false on failure - */ - public function enableAll(array $options): bool { - if (!$this->isValidOptionsForBatchOperation($options)) { - return false; - } - - $options['batch'] = true; - $options['batch_size'] = 50; - - $annotations = Annotations::find($options); - $count = $annotations->count(); - - if (!$count) { - return true; - } - - $success = 0; - foreach ($annotations as $annotation) { - if ($annotation->enable()) { - $success++; - } - } - - return $success === $count; - } /** * Checks if there are some constraints on the options array for potentially dangerous operations @@ -422,7 +277,7 @@ public function exists(int $entity_guid, string $name, int $owner_guid): bool { return false; } - $qb = Select::fromTable('annotations'); + $qb = Select::fromTable(self::TABLE_NAME); $qb->select('id'); $qb->where($qb->compare('owner_guid', '=', $owner_guid, ELGG_VALUE_INTEGER)) ->andWhere($qb->compare('entity_guid', '=', $entity_guid, ELGG_VALUE_INTEGER)) diff --git a/engine/classes/Elgg/Database/ApiUsersTable.php b/engine/classes/Elgg/Database/ApiUsersTable.php index a5565127c6c..5a1c1eae4d1 100644 --- a/engine/classes/Elgg/Database/ApiUsersTable.php +++ b/engine/classes/Elgg/Database/ApiUsersTable.php @@ -16,11 +16,7 @@ class ApiUsersTable { /** * @var string name of the api users database table */ - const TABLE_NAME = 'api_users'; - - protected Database $database; - - protected Crypto $crypto; + public const TABLE_NAME = 'api_users'; /** * Create a new table handler @@ -28,9 +24,7 @@ class ApiUsersTable { * @param Database $database the Elgg database handler * @param Crypto $crypto crypto handler */ - public function __construct(Database $database, Crypto $crypto) { - $this->database = $database; - $this->crypto = $crypto; + public function __construct(protected Database $database, protected Crypto $crypto) { } /** diff --git a/engine/classes/Elgg/Database/Clauses/AccessWhereClause.php b/engine/classes/Elgg/Database/Clauses/AccessWhereClause.php index dee90d04652..1b1b8e65955 100644 --- a/engine/classes/Elgg/Database/Clauses/AccessWhereClause.php +++ b/engine/classes/Elgg/Database/Clauses/AccessWhereClause.php @@ -9,40 +9,23 @@ */ class AccessWhereClause extends WhereClause { - /** - * @var string - */ - public $access_column = 'access_id'; + public string $access_column = 'access_id'; - /** - * @var string - */ - public $owner_guid_column = 'owner_guid'; + public string $owner_guid_column = 'owner_guid'; - /** - * @var string - */ - public $guid_column = 'guid'; + public string $guid_column = 'guid'; - /** - * @var string - */ - public $enabled_column = 'enabled'; + public string $enabled_column = 'enabled'; - /** - * @var bool - */ - public $ignore_access; + public string $deleted_column = 'deleted'; - /** - * @var bool - */ - public $use_enabled_clause; + public ?bool $ignore_access = null; - /** - * @var int - */ - public $viewer_guid; + public ?bool $use_enabled_clause = null; + + public ?bool $use_deleted_clause = null; + + public ?int $viewer_guid = null; /** * {@inheritdoc} @@ -64,6 +47,10 @@ public function prepare(QueryBuilder $qb, $table_alias = null) { $this->use_enabled_clause = !_elgg_services()->session_manager->getDisabledEntityVisibility(); } + if (!isset($this->use_deleted_clause)) { + $this->use_deleted_clause = !_elgg_services()->session_manager->getDeletedEntityVisibility(); + } + $ors = []; $ands = []; @@ -84,6 +71,10 @@ public function prepare(QueryBuilder $qb, $table_alias = null) { $ands[] = $qb->compare($alias($this->enabled_column), '=', 'yes', ELGG_VALUE_STRING); } + if ($this->use_deleted_clause) { + $ands[] = $qb->compare($alias($this->deleted_column), '=', 'no', ELGG_VALUE_STRING); + } + $params = [ 'table_alias' => $table_alias, 'user_guid' => $this->viewer_guid, @@ -93,6 +84,8 @@ public function prepare(QueryBuilder $qb, $table_alias = null) { 'owner_guid_column' => $this->owner_guid_column, 'guid_column' => $this->guid_column, 'enabled_column' => $this->enabled_column, + 'deleted_column' => $this->deleted_column, + 'use_deleted_clause' => $this->use_deleted_clause, 'query_builder' => $qb, ]; diff --git a/engine/classes/Elgg/Database/Clauses/AnnotationWhereClause.php b/engine/classes/Elgg/Database/Clauses/AnnotationWhereClause.php index 6d44eebc50f..6afee6f4e44 100644 --- a/engine/classes/Elgg/Database/Clauses/AnnotationWhereClause.php +++ b/engine/classes/Elgg/Database/Clauses/AnnotationWhereClause.php @@ -25,11 +25,6 @@ class AnnotationWhereClause extends WhereClause { */ public $owner_guids; - /** - * @var string - */ - public $enabled; - /** * @var int|int[] */ @@ -40,25 +35,16 @@ class AnnotationWhereClause extends WhereClause { */ public $names; - /** - * @var string - */ - public $comparison = '='; + public string $comparison = '='; /** * @var string|string[] */ public $values; - /** - * @var string - */ - public $value_type = ELGG_VALUE_STRING; + public string $value_type = ELGG_VALUE_STRING; - /** - * @var bool - */ - public $case_sensitive = true; + public bool $case_sensitive = true; /** * @var int|string|\DateTime @@ -70,30 +56,13 @@ class AnnotationWhereClause extends WhereClause { */ public $created_before; - /** - * @var string - */ - public $sort_by_direction; - - /** - * @var string - */ - public $sort_by_calculation; + public ?string $sort_by_direction = null; - /** - * @var bool - */ - public $ignore_access; + public ?string $sort_by_calculation = null; - /** - * @var bool - */ - public $use_enabled_clause; + public ?bool $ignore_access = null; - /** - * @var int - */ - public $viewer_guid; + public ?int $viewer_guid = null; /** * {@inheritdoc} @@ -108,8 +77,9 @@ public function prepare(QueryBuilder $qb, $table_alias = null) { $wheres[] = parent::prepare($qb, $table_alias); $access = new AccessWhereClause(); - $access->use_enabled_clause = $this->use_enabled_clause; $access->ignore_access = $this->ignore_access; + $access->use_deleted_clause = false; + $access->use_enabled_clause = false; $access->viewer_guid = $this->viewer_guid; $access->guid_column = 'entity_guid'; $wheres[] = $access->prepare($qb, $table_alias); @@ -119,7 +89,6 @@ public function prepare(QueryBuilder $qb, $table_alias = null) { $wheres[] = $qb->compare($alias('value'), $this->comparison, $this->values, $this->value_type, $this->case_sensitive); $wheres[] = $qb->compare($alias('entity_guid'), '=', $this->entity_guids, ELGG_VALUE_GUID); $wheres[] = $qb->compare($alias('owner_guid'), '=', $this->owner_guids, ELGG_VALUE_GUID); - $wheres[] = $qb->compare($alias('enabled'), '=', $this->enabled, ELGG_VALUE_STRING); $wheres[] = $qb->compare($alias('access_id'), '=', $this->access_ids, ELGG_VALUE_ID); $wheres[] = $qb->between($alias('time_created'), $this->created_after, $this->created_before, ELGG_VALUE_TIMESTAMP); diff --git a/engine/classes/Elgg/Database/Clauses/ComparisonClause.php b/engine/classes/Elgg/Database/Clauses/ComparisonClause.php index ee179b76918..4ae02a777ef 100644 --- a/engine/classes/Elgg/Database/Clauses/ComparisonClause.php +++ b/engine/classes/Elgg/Database/Clauses/ComparisonClause.php @@ -11,31 +11,6 @@ */ class ComparisonClause extends Clause { - /** - * @var string - */ - public $x; - - /** - * @var string - */ - public $comparison; - - /** - * @var mixed|null - */ - public $y; - - /** - * @var null|string - */ - public $type; - - /** - * @var bool|null - */ - public $case_sensitive; - /** * Constructor * @@ -45,12 +20,13 @@ class ComparisonClause extends Clause { * @param string $type Value type for sanitization/casting * @param bool $case_sensitive Use case sensitive comparison for strings */ - public function __construct($x, $comparison, $y = null, $type = null, $case_sensitive = null) { - $this->x = $x; - $this->comparison = $comparison; - $this->y = $y; - $this->type = $type; - $this->case_sensitive = $case_sensitive; + public function __construct( + public string $x, + public string $comparison, + public mixed $y = null, + public ?string $type = null, + public ?bool $case_sensitive = null + ) { } /** @@ -66,13 +42,13 @@ public function prepare(QueryBuilder $qb, $table_alias = null) { $compare_with = function ($func, $boolean = 'OR') use ($x, $y, $type, $case_sensitive, $qb) { if (!isset($y)) { - return; + return null; } $y = is_array($y) ? $y : [$y]; $parts = []; foreach ($y as $val) { - $val = $qb->param($val, $type); + $val = isset($type) ? $qb->param($val, $type) : $val; if ($case_sensitive && $type === ELGG_VALUE_STRING) { $val = "BINARY {$val}"; } @@ -113,7 +89,7 @@ public function prepare(QueryBuilder $qb, $table_alias = null) { } if (is_array($y) || $comparison === 'not in') { - if (!empty($y)) { + if (!Values::isEmpty($y)) { $param = isset($type) ? $qb->param($y, $type) : $y; $match_expr = $qb->expr()->notIn($x, $param); } diff --git a/engine/classes/Elgg/Database/Clauses/EntitySortByClause.php b/engine/classes/Elgg/Database/Clauses/EntitySortByClause.php index b7f69471265..4faa090269c 100644 --- a/engine/classes/Elgg/Database/Clauses/EntitySortByClause.php +++ b/engine/classes/Elgg/Database/Clauses/EntitySortByClause.php @@ -2,11 +2,15 @@ namespace Elgg\Database\Clauses; +use Elgg\Database\AnnotationsTable; +use Elgg\Database\EntityTable; +use Elgg\Database\MetadataTable; use Elgg\Database\QueryBuilder; +use Elgg\Database\RelationshipsTable; use Elgg\Exceptions\DomainException; /** - * Extends QueryBuilder with clauses necesary to sort entity lists by entity properties + * Extends QueryBuilder with clauses necessary to sort entity lists by entity properties */ class EntitySortByClause extends OrderByClause { @@ -59,11 +63,11 @@ public function prepare(QueryBuilder $qb, $table_alias = null) { // default assumes the main table is 'entities' $from_column = 'guid'; switch ($qb->getTableName()) { - case QueryBuilder::TABLE_ANNOTATIONS: - case QueryBuilder::TABLE_METADATA: + case AnnotationsTable::TABLE_NAME: + case MetadataTable::TABLE_NAME: $from_column = 'entity_guid'; break; - case QueryBuilder::TABLE_RELATIONSHIPS: + case RelationshipsTable::TABLE_NAME: $from_column = 'guid_one'; if ((bool) $this->inverse_relationship) { $from_column = 'guid_two'; @@ -82,7 +86,7 @@ public function prepare(QueryBuilder $qb, $table_alias = null) { throw new DomainException("'{$this->property}' is not a valid entity attribute"); } - if ($qb->getTableName() !== QueryBuilder::TABLE_ENTITIES) { + if ($qb->getTableName() !== EntityTable::TABLE_NAME) { $e_alias = $qb->joinEntitiesTable($table_alias, $from_column, $this->join_type); } else { $e_alias = $table_alias; @@ -97,7 +101,7 @@ public function prepare(QueryBuilder $qb, $table_alias = null) { break; case 'relationship': - if ($qb->getTableName() !== QueryBuilder::TABLE_RELATIONSHIPS) { + if ($qb->getTableName() !== RelationshipsTable::TABLE_NAME) { $er_alias = $qb->joinRelationshipTable($table_alias, $from_column, $this->property, $this->inverse_relationship, $this->join_type); if (!empty($this->relationship_guid)) { $guid_column = $this->inverse_relationship ? 'guid_two' : 'guid_one'; @@ -122,6 +126,6 @@ public function prepare(QueryBuilder $qb, $table_alias = null) { $this->expr = $column; - return parent::prepare($qb, $table_alias); + parent::prepare($qb, $table_alias); } } diff --git a/engine/classes/Elgg/Database/Clauses/EntityWhereClause.php b/engine/classes/Elgg/Database/Clauses/EntityWhereClause.php index de9b8c91e0e..7d566837b3f 100644 --- a/engine/classes/Elgg/Database/Clauses/EntityWhereClause.php +++ b/engine/classes/Elgg/Database/Clauses/EntityWhereClause.php @@ -70,6 +70,11 @@ class EntityWhereClause extends WhereClause { */ public $enabled; + /** + * @var string + */ + public $deleted; + /** * @var bool */ @@ -80,6 +85,11 @@ class EntityWhereClause extends WhereClause { */ public $use_enabled_clause; + /** + * @var bool + */ + public $use_deleted_clause; + /** * @var int */ @@ -99,6 +109,7 @@ public function prepare(QueryBuilder $qb, $table_alias = '') { $access = new AccessWhereClause(); $access->use_enabled_clause = $this->use_enabled_clause; + $access->use_deleted_clause = $this->use_deleted_clause; $access->ignore_access = $this->ignore_access; $access->viewer_guid = $this->viewer_guid; $wheres[] = $access->prepare($qb, $table_alias); @@ -114,6 +125,7 @@ public function prepare(QueryBuilder $qb, $table_alias = '') { $wheres[] = $qb->between($alias('time_updated'), $this->updated_after, $this->updated_before, ELGG_VALUE_TIMESTAMP); $wheres[] = $qb->between($alias('last_action'), $this->last_action_after, $this->last_action_before, ELGG_VALUE_TIMESTAMP); $wheres[] = $qb->compare($alias('enabled'), '=', $this->enabled, ELGG_VALUE_STRING); + $wheres[] = $qb->compare($alias('deleted'), '=', $this->deleted, ELGG_VALUE_STRING); $wheres[] = $qb->compare($alias('access_id'), '=', $this->access_ids, ELGG_VALUE_ID); return $qb->merge($wheres); diff --git a/engine/classes/Elgg/Database/Clauses/GroupByClause.php b/engine/classes/Elgg/Database/Clauses/GroupByClause.php index 01048e38aa6..d60f5a68a99 100644 --- a/engine/classes/Elgg/Database/Clauses/GroupByClause.php +++ b/engine/classes/Elgg/Database/Clauses/GroupByClause.php @@ -2,7 +2,6 @@ namespace Elgg\Database\Clauses; -use Closure; use Doctrine\DBAL\Query\Expression\CompositeExpression; use Elgg\Database\QueryBuilder; @@ -12,14 +11,14 @@ class GroupByClause extends Clause { /** - * @var Closure|CompositeExpression|string + * @var \Closure|CompositeExpression|string */ public $expr; /** * Constructor * - * @param CompositeExpression|Closure|string $expr Expression + * @param CompositeExpression|\Closure|string $expr Expression */ public function __construct($expr) { $this->expr = $expr; diff --git a/engine/classes/Elgg/Database/Clauses/HavingClause.php b/engine/classes/Elgg/Database/Clauses/HavingClause.php index d9ac6a51491..a5443aba034 100644 --- a/engine/classes/Elgg/Database/Clauses/HavingClause.php +++ b/engine/classes/Elgg/Database/Clauses/HavingClause.php @@ -2,7 +2,6 @@ namespace Elgg\Database\Clauses; -use Closure; use Doctrine\DBAL\Query\Expression\CompositeExpression; use Elgg\Database\QueryBuilder; @@ -12,14 +11,14 @@ class HavingClause extends Clause { /** - * @var Closure|CompositeExpression|string + * @var \Closure|CompositeExpression|string */ public $expr; /** * Constructor * - * @param CompositeExpression|Closure|string $expr Expression + * @param CompositeExpression|\Closure|string $expr Expression */ public function __construct($expr) { $this->expr = $expr; diff --git a/engine/classes/Elgg/Database/Clauses/JoinClause.php b/engine/classes/Elgg/Database/Clauses/JoinClause.php index 00fdc22a48a..ec6d32eccb0 100644 --- a/engine/classes/Elgg/Database/Clauses/JoinClause.php +++ b/engine/classes/Elgg/Database/Clauses/JoinClause.php @@ -2,7 +2,6 @@ namespace Elgg\Database\Clauses; -use Closure; use Doctrine\DBAL\Query\Expression\CompositeExpression; use Elgg\Database\QueryBuilder; @@ -22,7 +21,7 @@ class JoinClause extends Clause { public $joined_alias; /** - * @var CompositeExpression|Closure|string + * @var CompositeExpression|\Closure|string */ public $condition; @@ -34,10 +33,10 @@ class JoinClause extends Clause { /** * Constructor * - * @param string $joined_table Table to join - * @param string $joined_alias Alias of the joined table - * @param CompositeExpression|Closure|string $condition On expression - * @param string $join_type Join type INNER|LEFT|RIGHT + * @param string $joined_table Table to join + * @param string $joined_alias Alias of the joined table + * @param CompositeExpression|\Closure|string $condition On expression + * @param string $join_type Join type INNER|LEFT|RIGHT */ public function __construct($joined_table, $joined_alias = null, $condition = null, $join_type = 'inner') { $this->joined_table = $joined_table; diff --git a/engine/classes/Elgg/Database/Clauses/OrderByClause.php b/engine/classes/Elgg/Database/Clauses/OrderByClause.php index c78191db7c8..1f61589c799 100644 --- a/engine/classes/Elgg/Database/Clauses/OrderByClause.php +++ b/engine/classes/Elgg/Database/Clauses/OrderByClause.php @@ -2,7 +2,6 @@ namespace Elgg\Database\Clauses; -use Closure; use Doctrine\DBAL\Query\Expression\CompositeExpression; use Elgg\Database\QueryBuilder; @@ -12,7 +11,7 @@ class OrderByClause extends Clause { /** - * @var Closure|CompositeExpression|null|string + * @var \Closure|CompositeExpression|null|string */ public $expr; @@ -24,8 +23,8 @@ class OrderByClause extends Clause { /** * Constructor * - * @param CompositeExpression|Closure|string $expr Expression - * @param string $direction Direction + * @param CompositeExpression|\Closure|string $expr Expression + * @param string $direction Direction */ public function __construct($expr = null, $direction = null) { $this->expr = $expr; diff --git a/engine/classes/Elgg/Database/Clauses/RiverWhereClause.php b/engine/classes/Elgg/Database/Clauses/RiverWhereClause.php index dca78102c15..11ecd977c05 100644 --- a/engine/classes/Elgg/Database/Clauses/RiverWhereClause.php +++ b/engine/classes/Elgg/Database/Clauses/RiverWhereClause.php @@ -2,10 +2,7 @@ namespace Elgg\Database\Clauses; -use DateTime; use Elgg\Database\QueryBuilder; -use ElggAnnotation; -use ElggEntity; /** * Builds queries for matching river items against their properties @@ -33,32 +30,32 @@ class RiverWhereClause extends WhereClause { public $views; /** - * @var int[]|ElggEntity[] + * @var int[]|\ElggEntity[] */ public $subject_guids; /** - * @var int[]|ElggEntity[] + * @var int[]|\ElggEntity[] */ public $object_guids; /** - * @var int[]|ElggEntity[] + * @var int[]|\ElggEntity[] */ public $target_guids; /** - * @var int[]|ElggAnnotation[] + * @var int[]|\ElggAnnotation[] */ public $annotation_ids; /** - * @var int|string|DateTime + * @var int|string|\DateTime */ public $created_after; /** - * @var int|string|DateTime + * @var int|string|\DateTime */ public $created_before; diff --git a/engine/classes/Elgg/Database/Clauses/SelectClause.php b/engine/classes/Elgg/Database/Clauses/SelectClause.php index fee6e601857..8ca417d7a5e 100644 --- a/engine/classes/Elgg/Database/Clauses/SelectClause.php +++ b/engine/classes/Elgg/Database/Clauses/SelectClause.php @@ -2,7 +2,6 @@ namespace Elgg\Database\Clauses; -use Closure; use Doctrine\DBAL\Query\Expression\CompositeExpression; use Elgg\Database\QueryBuilder; @@ -12,14 +11,14 @@ class SelectClause extends Clause { /** - * @var Closure|CompositeExpression|string + * @var \Closure|CompositeExpression|string */ public $expr; /** * Constructor * - * @param CompositeExpression|Closure|string $expr Expression + * @param CompositeExpression|\Closure|string $expr Expression */ public function __construct($expr) { $this->expr = $expr; diff --git a/engine/classes/Elgg/Database/Clauses/WhereClause.php b/engine/classes/Elgg/Database/Clauses/WhereClause.php index 0d0d7a4f3ec..7208ec4aa8d 100644 --- a/engine/classes/Elgg/Database/Clauses/WhereClause.php +++ b/engine/classes/Elgg/Database/Clauses/WhereClause.php @@ -2,7 +2,6 @@ namespace Elgg\Database\Clauses; -use Closure; use Doctrine\DBAL\Query\Expression\CompositeExpression; use Elgg\Database\QueryBuilder; @@ -12,14 +11,14 @@ class WhereClause extends Clause { /** - * @var Closure|CompositeExpression|null|string + * @var \Closure|CompositeExpression|null|string */ public $expr; /** * Constructor * - * @param CompositeExpression|Closure|string $expr Expression + * @param CompositeExpression|\Closure|string $expr Expression */ public function __construct($expr = null) { $this->expr = $expr; diff --git a/engine/classes/Elgg/Database/ConfigTable.php b/engine/classes/Elgg/Database/ConfigTable.php index c747ef2a583..9e495e043d6 100644 --- a/engine/classes/Elgg/Database/ConfigTable.php +++ b/engine/classes/Elgg/Database/ConfigTable.php @@ -20,7 +20,7 @@ class ConfigTable { /** * @var string name of the config database table */ - const TABLE_NAME = 'config'; + public const TABLE_NAME = 'config'; protected Database $db; diff --git a/engine/classes/Elgg/Database/DelayedEmailQueueTable.php b/engine/classes/Elgg/Database/DelayedEmailQueueTable.php index 4c7ae762c4b..c2f52ee8e16 100644 --- a/engine/classes/Elgg/Database/DelayedEmailQueueTable.php +++ b/engine/classes/Elgg/Database/DelayedEmailQueueTable.php @@ -19,17 +19,14 @@ class DelayedEmailQueueTable { /** * @var string name of the database table */ - const TABLE_NAME = 'delayed_email_queue'; - - protected Database $db; + public const TABLE_NAME = 'delayed_email_queue'; /** * Create new service * * @param Database $db the database service */ - public function __construct(Database $db) { - $this->db = $db; + public function __construct(protected Database $db) { } /** @@ -50,7 +47,7 @@ public function queueEmail(int $recipient_guid, string $delivery_interval, $item 'timestamp' => $insert->param($this->getCurrentTime()->getTimestamp(), ELGG_VALUE_TIMESTAMP), ]); - return $this->db->insertData($insert) !== false; + return $this->db->insertData($insert) !== 0; } /** @@ -71,39 +68,52 @@ public function getRow(int $id): ?DatabaseRecord { /** * Get all the rows in the queue for a given recipient * - * @param int $recipient_guid the recipient - * @param string $delivery_interval the interval for the recipient - * @param int $timestamp (optional) all queue items before time (default: now) + * @param int $recipient_guid the recipient + * @param string $delivery_interval the interval for the recipient + * @param null|int $timestamp (optional) all queue items before time (default: now) + * @param int $max_results (optional) maximum number of rows to return * * @return DatabaseRecord[] database rows */ - public function getRecipientRows(int $recipient_guid, string $delivery_interval, int $timestamp = null): array { + public function getRecipientRows(int $recipient_guid, string $delivery_interval, int $timestamp = null, int $max_results = 0): array { $select = Select::fromTable(self::TABLE_NAME); $select->select('*') ->where($select->compare('recipient_guid', '=', $recipient_guid, ELGG_VALUE_GUID)) ->andWhere($select->compare('delivery_interval', '=', $delivery_interval, ELGG_VALUE_STRING)) - ->andWhere($select->compare('timestamp', '<', $timestamp ?? $this->getCurrentTime()->getTimestamp(), ELGG_VALUE_TIMESTAMP)); + ->andWhere($select->compare('timestamp', '<', $timestamp ?? $this->getCurrentTime()->getTimestamp(), ELGG_VALUE_TIMESTAMP)) + ->orderBy('timestamp', 'ASC') + ->addOrderBy('id', 'ASC'); + + if ($max_results > 0) { + $select->setMaxResults($max_results); + } return $this->db->getData($select, [$this, 'rowToRecord']); } /** - * Get the queued items from the database for a given interval + * Fetch the GUID of the next recipient to process * - * @param string $delivery_interval the delivery interval to get - * @param int $timestamp (optional) all queue items before time (default: now) + * @param string $delivery_interval the delivery interval to get + * @param null|int $timestamp (optional) based on queue items before time (default: now) * - * @return DatabaseRecord[] + * @return null|int */ - public function getIntervalRows(string $delivery_interval, int $timestamp = null): array { + public function getNextRecipientGUID(string $delivery_interval, int $timestamp = null): ?int { $select = Select::fromTable(self::TABLE_NAME); - $select->select('*') + $select->select('recipient_guid') ->where($select->compare('delivery_interval', '=', $delivery_interval, ELGG_VALUE_STRING)) ->andWhere($select->compare('timestamp', '<', $timestamp ?? $this->getCurrentTime()->getTimestamp())) - ->orderBy('recipient_guid', 'ASC') - ->addOrderBy('timestamp', 'ASC'); + ->orderBy('timestamp', 'ASC') + ->addOrderBy('id', 'ASC') + ->setMaxResults(1); - return $this->db->getData($select, [$this, 'rowToRecord']); + $row = $this->db->getDataRow($select); + if (empty($row)) { + return null; + } + + return (int) $row->recipient_guid; } /** @@ -123,17 +133,24 @@ public function deleteRow(int $id): int { /** * Delete all the queue items from the database for the given recipient and interval * - * @param int $recipient_guid the recipient - * @param string $delivery_interval the interval for the recipient - * @param int $timestamp (optional) all queue items before time (default: now) + * @param int $recipient_guid the recipient + * @param string $delivery_interval the interval for the recipient + * @param null|int $timestamp (optional) all queue items before time (default: now) + * @param int $max_id (optional) the max row ID to remove (this includes the given row ID) * * @return int number of deleted rows */ - public function deleteRecipientRows(int $recipient_guid, string $delivery_interval, int $timestamp = null): int { + public function deleteRecipientRows(int $recipient_guid, string $delivery_interval, int $timestamp = null, int $max_id = 0): int { $delete = Delete::fromTable(self::TABLE_NAME); $delete->where($delete->compare('recipient_guid', '=', $recipient_guid, ELGG_VALUE_GUID)) ->andWhere($delete->compare('delivery_interval', '=', $delivery_interval, ELGG_VALUE_STRING)) - ->andWhere($delete->compare('timestamp', '<', $timestamp ?? $this->getCurrentTime()->getTimestamp(), ELGG_VALUE_INTEGER)); + ->andWhere($delete->compare('timestamp', '<', $timestamp ?? $this->getCurrentTime()->getTimestamp(), ELGG_VALUE_INTEGER)) + ->orderBy('timestamp', 'ASC') + ->addOrderBy('id', 'ASC'); + + if ($max_id > 0) { + $delete->andWhere($delete->compare('id', '<=', $max_id, ELGG_VALUE_ID)); + } return $this->db->deleteData($delete); } @@ -169,7 +186,7 @@ public function updateRecipientInterval(int $recipient_guid, string $delivery_in } /** - * Convert a database row to a managable object + * Convert a database row to a manageable object * * @param \stdClass $row the database record * diff --git a/engine/classes/Elgg/Database/Delete.php b/engine/classes/Elgg/Database/Delete.php index 88355ac551a..3d88efa2f0f 100644 --- a/engine/classes/Elgg/Database/Delete.php +++ b/engine/classes/Elgg/Database/Delete.php @@ -6,14 +6,18 @@ * Query builder for updating data in the database */ class Delete extends QueryBuilder { - + /** - * {@inheritdoc} + * Returns a QueryBuilder for deleting data from a given table + * + * @param string $table table name + * + * @return static */ - public static function fromTable($table, $alias = null) { + public static function fromTable(string $table): static { $connection = _elgg_services()->db->getConnection('write'); $qb = new static($connection); - $qb->delete($table, $alias); + $qb->delete($table); return $qb; } diff --git a/engine/classes/Elgg/Database/Entities.php b/engine/classes/Elgg/Database/Entities.php index ade15ce04b8..cabc2d39997 100644 --- a/engine/classes/Elgg/Database/Entities.php +++ b/engine/classes/Elgg/Database/Entities.php @@ -8,17 +8,12 @@ use Elgg\Database\Clauses\MetadataWhereClause; use Elgg\Database\Clauses\RelationshipWhereClause; use Elgg\Exceptions\DomainException; -use Elgg\Exceptions\InvalidArgumentException; use Elgg\Exceptions\LogicException; /** * Entities repository contains methods for fetching entities from database or performing * calculations on entity properties. * - * @todo Resolve table alias collissions when querying for both annotationa and metadata name value pairs - * Currently, n_table is expected across core and plugins, we need to refactor that code - * and remove n_table joins here - * * @internal */ class Entities extends Repository { @@ -27,9 +22,9 @@ class Entities extends Repository { * {@inheritdoc} */ public function count() { - $qb = Select::fromTable('entities', 'e'); + $qb = Select::fromTable(EntityTable::TABLE_NAME, EntityTable::DEFAULT_JOIN_ALIAS); - $count_expr = $this->options->distinct ? 'DISTINCT e.guid' : '*'; + $count_expr = $this->options->distinct ? "DISTINCT {$qb->getTableAlias()}.guid" : '*'; $qb->select("COUNT({$count_expr}) AS total"); $qb = $this->buildQuery($qb); @@ -66,7 +61,7 @@ public function calculate($function, $property, $property_type = null) { } } - $qb = Select::fromTable('entities', 'e'); + $qb = Select::fromTable(EntityTable::TABLE_NAME, EntityTable::DEFAULT_JOIN_ALIAS); switch ($property_type) { case 'attribute': @@ -74,16 +69,16 @@ public function calculate($function, $property, $property_type = null) { throw new DomainException("'{$property}' is not a valid attribute"); } - $qb->addSelect("{$function}(e.{$property}) AS calculation"); + $qb->addSelect("{$function}({$qb->getTableAlias()}.{$property}) AS calculation"); break; case 'metadata': - $alias = $qb->joinMetadataTable('e', 'guid', $property, 'inner', 'n_table'); + $alias = $qb->joinMetadataTable($qb->getTableAlias(), 'guid', $property, 'inner', MetadataTable::DEFAULT_JOIN_ALIAS); $qb->addSelect("{$function}({$alias}.value) AS calculation"); break; case 'annotation': - $alias = $qb->joinAnnotationTable('e', 'guid', $property, 'inner', 'n_table'); + $alias = $qb->joinAnnotationTable($qb->getTableAlias(), 'guid', $property, 'inner', AnnotationsTable::DEFAULT_JOIN_ALIAS); $qb->addSelect("{$function}({$alias}.value) AS calculation"); break; } @@ -106,21 +101,21 @@ public function calculate($function, $property, $property_type = null) { * @return \ElggEntity[] */ public function get($limit = null, $offset = null, $callback = null) { - $qb = Select::fromTable('entities', 'e'); + $qb = Select::fromTable(EntityTable::TABLE_NAME, EntityTable::DEFAULT_JOIN_ALIAS); - $distinct = $this->options->distinct ? 'DISTINCT' : ''; - $qb->select("{$distinct} e.*"); + $distinct = $this->options->distinct ? 'DISTINCT ' : ''; + $qb->select("{$distinct}{$qb->getTableAlias()}.*"); - $this->expandInto($qb, 'e'); + $this->expandInto($qb, $qb->getTableAlias()); $qb = $this->buildQuery($qb); - // Keeping things backwards compatible + // add default ordering $original_order = elgg_extract('order_by', $this->options->__original_options); - if (empty($original_order) && $original_order !== false) { - $qb->addOrderBy('e.time_created', 'desc'); + if (empty($this->options->order_by) && $original_order !== false) { + $qb->addOrderBy("{$qb->getTableAlias()}.time_created", 'desc'); // also add order by guid, to rely less on internals of MySQL fallback ordering - $qb->addOrderBy('e.guid', 'desc'); + $qb->addOrderBy("{$qb->getTableAlias()}.guid", 'desc'); } if ($limit > 0) { @@ -152,11 +147,11 @@ public function get($limit = null, $offset = null, $callback = null) { * @return array An array months as YYYYMM */ public function getDates(): array { - $qb = Select::fromTable('entities', 'e'); + $qb = Select::fromTable(EntityTable::TABLE_NAME, EntityTable::DEFAULT_JOIN_ALIAS); - $qb->select('DISTINCT EXTRACT(YEAR_MONTH FROM FROM_UNIXTIME(e.time_created)) AS yearmonth'); + $qb->select("DISTINCT EXTRACT(YEAR_MONTH FROM FROM_UNIXTIME({$qb->getTableAlias()}.time_created)) AS yearmonth"); - $this->expandInto($qb, 'e'); + $this->expandInto($qb, $qb->getTableAlias()); $qb = $this->buildQuery($qb); @@ -179,7 +174,7 @@ public function getDates(): array { /** * Execute the query resolving calculation, count and/or batch options * - * @return array|\ElggData[]|\ElggEntity[]|false|int + * @return array|\ElggData[]|\ElggEntity[]|int|\ElggBatch * @throws LogicException */ public function execute() { @@ -221,11 +216,11 @@ protected function buildQuery(QueryBuilder $qb) { $ands = []; foreach ($this->options->joins as $join) { - $join->prepare($qb, 'e'); + $join->prepare($qb, $qb->getTableAlias()); } foreach ($this->options->wheres as $where) { - $ands[] = $where->prepare($qb, 'e'); + $ands[] = $where->prepare($qb, $qb->getTableAlias()); } $ands[] = $this->buildEntityClause($qb); @@ -252,7 +247,7 @@ protected function buildQuery(QueryBuilder $qb) { * @return \Closure|CompositeExpression|mixed|null|string */ protected function buildEntityClause(QueryBuilder $qb) { - return EntityWhereClause::factory($this->options)->prepare($qb, 'e'); + return EntityWhereClause::factory($this->options)->prepare($qb, $qb->getTableAlias()); } /** @@ -271,9 +266,9 @@ protected function buildPairedMetadataClause(QueryBuilder $qb, $clauses, $boolea foreach ($clauses as $clause) { if ($clause instanceof MetadataWhereClause) { if (strtoupper($boolean) === 'OR' || count($clauses) === 1) { - $joined_alias = $qb->joinMetadataTable('e', 'guid', null, 'inner', 'n_table'); + $joined_alias = $qb->joinMetadataTable($qb->getTableAlias(), 'guid', null, 'inner', MetadataTable::DEFAULT_JOIN_ALIAS); } else { - $joined_alias = $qb->joinMetadataTable('e', 'guid', $clause->names); + $joined_alias = $qb->joinMetadataTable($qb->getTableAlias(), 'guid', $clause->names); } $parts[] = $clause->prepare($qb, $joined_alias); @@ -298,9 +293,9 @@ protected function buildPairedAnnotationClause(QueryBuilder $qb, $clauses, $bool foreach ($clauses as $clause) { if (strtoupper($boolean) === 'OR' || count($clauses) === 1) { - $joined_alias = $qb->joinAnnotationTable('e', 'guid', null, 'inner', 'n_table'); + $joined_alias = $qb->joinAnnotationTable($qb->getTableAlias(), 'guid', null, 'inner', AnnotationsTable::DEFAULT_JOIN_ALIAS); } else { - $joined_alias = $qb->joinAnnotationTable('e', 'guid', $clause->names); + $joined_alias = $qb->joinAnnotationTable($qb->getTableAlias(), 'guid', $clause->names); } $parts[] = $clause->prepare($qb, $joined_alias); @@ -322,10 +317,10 @@ protected function buildPairedRelationshipClause(QueryBuilder $qb, $clauses, $bo $parts = []; foreach ($clauses as $clause) { - if (strtoupper($boolean) == 'OR' || count($clauses) === 1) { - $joined_alias = $qb->joinRelationshipTable('e', $clause->join_on, null, $clause->inverse, 'inner', 'r'); + if (strtoupper($boolean) === 'OR' || count($clauses) === 1) { + $joined_alias = $qb->joinRelationshipTable($qb->getTableAlias(), $clause->join_on, null, $clause->inverse, 'inner', RelationshipsTable::DEFAULT_JOIN_ALIAS); } else { - $joined_alias = $qb->joinRelationshipTable('e', $clause->join_on, $clause->names, $clause->inverse); + $joined_alias = $qb->joinRelationshipTable($qb->getTableAlias(), $clause->join_on, $clause->names, $clause->inverse); } $parts[] = $clause->prepare($qb, $joined_alias); diff --git a/engine/classes/Elgg/Database/EntityTable.php b/engine/classes/Elgg/Database/EntityTable.php index a90fcffe3bb..bb8ca3fbead 100644 --- a/engine/classes/Elgg/Database/EntityTable.php +++ b/engine/classes/Elgg/Database/EntityTable.php @@ -7,7 +7,6 @@ use Elgg\Config; use Elgg\Database; use Elgg\Database\Clauses\EntityWhereClause; -use Elgg\EntityPreloader; use Elgg\EventsService; use Elgg\Exceptions\ClassException; use Elgg\Exceptions\Database\UserFetchFailureException; @@ -31,7 +30,9 @@ class EntityTable { /** * @var string name of the entities database table */ - const TABLE_NAME = 'entities'; + public const TABLE_NAME = 'entities'; + + public const DEFAULT_JOIN_ALIAS = 'e'; protected Config $config; @@ -39,8 +40,6 @@ class EntityTable { protected EntityCache $entity_cache; - protected EntityPreloader $entity_preloader; - protected MetadataCache $metadata_cache; protected EventsService $events; @@ -51,6 +50,8 @@ class EntityTable { protected array $deleted_guids = []; + protected array $trashed_guids = []; + protected array $entity_classes = []; /** @@ -135,8 +136,8 @@ public function getRow(int $guid, int $user_guid = null): ?\stdClass { $where->guids = $guid; $where->viewer_guid = $user_guid; - $select = Select::fromTable(self::TABLE_NAME, 'e'); - $select->select('e.*'); + $select = Select::fromTable(self::TABLE_NAME, self::DEFAULT_JOIN_ALIAS); + $select->select("{$select->getTableAlias()}.*"); $select->addClause($where); return $this->db->getDataRow($select) ?: null; @@ -234,34 +235,6 @@ public function rowToElggStar(\stdClass $row): ?\ElggEntity { return $entity; } - /** - * Get an entity from the in-memory or memcache caches - * - * @param int $guid GUID - * - * @return \ElggEntity|null - */ - public function getFromCache(int $guid): ?\ElggEntity { - $entity = $this->entity_cache->load($guid); - if ($entity) { - return $entity; - } - - $entity = _elgg_services()->sessionCache->entities->load($guid); - if (!$entity instanceof \ElggEntity) { - return null; - } - - // Validate accessibility if from cache - if (!elgg_get_ignore_access() && !$entity->hasAccess()) { - return null; - } - - $entity->cache(false); - - return $entity; - } - /** * Invalidate cache for entity * @@ -270,7 +243,7 @@ public function getFromCache(int $guid): ?\ElggEntity { * @return void */ public function invalidateCache(int $guid): void { - elgg_call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES, function() use ($guid) { + elgg_call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES | ELGG_SHOW_DELETED_ENTITIES, function() use ($guid) { $entity = $this->get($guid); if ($entity instanceof \ElggEntity) { $entity->invalidateCache(); @@ -292,7 +265,7 @@ public function invalidateCache(int $guid): void { * @return \ElggEntity|null The correct Elgg or custom object based upon entity type and subtype */ public function get(int $guid, string $type = null, string $subtype = null): ?\ElggEntity { - $entity = $this->getFromCache($guid); + $entity = $this->entity_cache->load($guid); if ($entity instanceof \ElggEntity && (!isset($type) || $entity->type === $type) && (!isset($subtype) || $entity->subtype === $subtype) @@ -338,7 +311,7 @@ public function get(int $guid, string $type = null, string $subtype = null): ?\E * @return bool */ public function exists(int $guid): bool { - return elgg_call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES, function() use ($guid) { + return elgg_call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES | ELGG_SHOW_DELETED_ENTITIES, function() use ($guid) { // need to ignore access and show hidden entities to check existence return !empty($this->getRow($guid)); }); @@ -386,6 +359,28 @@ public function fetch(QueryBuilder $query, array $options = []): array { return $results; } + /** + * Update the time_deleted column in the entities table for $entity. + * + * @param \ElggEntity $entity Entity to update + * @param int $deleted Timestamp when the entity was deleted + * + * @return int + */ + public function updateTimeDeleted(\ElggEntity $entity, int $deleted = null): int { + if ($deleted === null) { + $deleted = $this->getCurrentTime()->getTimestamp(); + } + + $update = Update::table(self::TABLE_NAME); + $update->set('time_deleted', $update->param($deleted, ELGG_VALUE_TIMESTAMP)) + ->where($update->compare('guid', '=', $entity->guid, ELGG_VALUE_GUID)); + + $this->db->updateData($update); + + return (int) $deleted; + } + /** * Update the last_action column in the entities table for $entity. * @@ -424,7 +419,7 @@ public function getUserForPermissionsCheck(int $guid = null): ?\ElggUser { return $this->session_manager->getLoggedInUser(); } - $user = elgg_call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES, function() use ($guid) { + $user = elgg_call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES | ELGG_SHOW_DELETED_ENTITIES, function() use ($guid) { // need to ignore access and show hidden entities for potential hidden/disabled users return $this->get($guid, 'user'); }); @@ -440,6 +435,22 @@ public function getUserForPermissionsCheck(int $guid = null): ?\ElggUser { return $user; } + /** + * Restore entity + * + * @param \ElggEntity $entity Entity to restore + * + * @return bool + */ + public function restore(\ElggEntity $entity): bool { + $qb = Update::table(self::TABLE_NAME); + $qb->set('deleted', $qb->param('no', ELGG_VALUE_STRING)) + ->set('time_deleted', $qb->param(0, ELGG_VALUE_TIMESTAMP)) + ->where($qb->compare('guid', '=', $entity->guid, ELGG_VALUE_GUID)); + + return $this->db->updateData($qb); + } + /** * Enables entity * @@ -479,39 +490,95 @@ public function disable(\ElggEntity $entity): bool { * @return bool */ public function delete(\ElggEntity $entity, bool $recursive = true): bool { - $guid = $entity->guid; - if (!$guid) { + if (!$entity->guid) { return false; } - - if (!$this->events->triggerBefore('delete', $entity->type, $entity)) { + + set_time_limit(0); + + return $this->events->triggerSequence('delete', $entity->type, $entity, function(\ElggEntity $entity) use ($recursive) { + if ($entity instanceof \ElggUser) { + // ban to prevent using the site during delete + $entity->ban(); + } + + // we're going to delete this entity, log the guid to prevent deadloops + $this->deleted_guids[] = $entity->guid; + + if ($recursive) { + $this->deleteRelatedEntities($entity); + } + + $this->deleteEntityProperties($entity); + + $qb = Delete::fromTable(self::TABLE_NAME); + $qb->where($qb->compare('guid', '=', $entity->guid, ELGG_VALUE_GUID)); + + return (bool) $this->db->deleteData($qb); + }); + } + + /** + * Trash an entity (not quite delete but close) + * + * @param \ElggEntity $entity Entity + * @param bool $recursive Trash all owned and contained entities + * + * @return bool + */ + public function trash(\ElggEntity $entity, bool $recursive = true): bool { + if (!$entity->guid) { return false; } - $this->events->trigger('delete', $entity->type, $entity); - - if ($entity instanceof \ElggUser) { - // ban to prevent using the site during delete - $entity->ban(); + if (!$this->config->trash_enabled) { + return $this->delete($entity, $recursive); } - - // we're going to delete this entity, log the guid to prevent deadloops - $this->deleted_guids[] = $entity->guid; - if ($recursive) { - $this->deleteRelatedEntities($entity); + if ($entity->isDeleted()) { + // already trashed + return true; } - - $this->deleteEntityProperties($entity); - - $qb = Delete::fromTable(self::TABLE_NAME); - $qb->where($qb->compare('guid', '=', $guid, ELGG_VALUE_GUID)); - - $this->db->deleteData($qb); - - $this->events->triggerAfter('delete', $entity->type, $entity); - - return true; + + return $this->events->triggerSequence('trash', $entity->type, $entity, function(\ElggEntity $entity) use ($recursive) { + $unban_after = false; + if ($entity instanceof \ElggUser && !$entity->isBanned()) { + // temporarily ban to prevent using the site during disable + $entity->ban(); + $unban_after = true; + } + + $this->trashed_guids[] = $entity->guid; + + if ($recursive) { + set_time_limit(0); + + $this->trashRelatedEntities($entity); + } + + $deleter_guid = elgg_get_logged_in_user_guid(); + if (!empty($deleter_guid)) { + $entity->addRelationship($deleter_guid, 'delete_by'); + } + + $qb = Update::table(self::TABLE_NAME); + $qb->set('deleted', $qb->param('yes', ELGG_VALUE_STRING)) + ->where($qb->compare('guid', '=', $entity->guid, ELGG_VALUE_GUID)); + + $trashed = $this->db->updateData($qb); + + $entity->updateTimeDeleted(); + + if ($unban_after) { + $entity->unban(); + } + + if ($trashed) { + $entity->invalidateCache(); + } + + return $trashed; + }); } /** @@ -523,7 +590,7 @@ public function delete(\ElggEntity $entity, bool $recursive = true): bool { */ protected function deleteRelatedEntities(\ElggEntity $entity): void { // Temporarily overriding access controls - elgg_call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES, function() use ($entity) { + elgg_call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES | ELGG_SHOW_DELETED_ENTITIES, function() use ($entity) { /* @var $batch \ElggBatch */ $batch = elgg_get_entities([ 'wheres' => function (QueryBuilder $qb, $main_alias) use ($entity) { @@ -550,9 +617,54 @@ protected function deleteRelatedEntities(\ElggEntity $entity): void { continue; } - if (!$this->delete($e, true)) { + if (!$e->delete(true, true)) { + $batch->reportFailure(); + } + } + }); + } + + /** + * Trash entities owned or contained by the entity being trashed + * + * @param \ElggEntity $entity Entity + * + * @return void + */ + protected function trashRelatedEntities(\ElggEntity $entity): void { + // Temporarily overriding access controls + elgg_call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES | ELGG_SHOW_DELETED_ENTITIES, function() use ($entity) { + /* @var $batch \ElggBatch */ + $batch = elgg_get_entities([ + 'wheres' => function (QueryBuilder $qb, $main_alias) use ($entity) { + $ors = $qb->merge([ + $qb->compare("{$main_alias}.owner_guid", '=', $entity->guid, ELGG_VALUE_GUID), + $qb->compare("{$main_alias}.container_guid", '=', $entity->guid, ELGG_VALUE_GUID), + ], 'OR'); + + return $qb->merge([ + $ors, + $qb->compare("{$main_alias}.guid", 'neq', $entity->guid, ELGG_VALUE_GUID), + ]); + }, + 'limit' => false, + 'batch' => true, + 'batch_inc_offset' => false, + ]); + + /* @var $e \ElggEntity */ + foreach ($batch as $e) { + if (in_array($e->guid, $this->trashed_guids)) { + // prevent deadloops, doing this here in case of large deletes which could cause query length issues + $batch->reportFailure(); + continue; + } + + if (!$e->delete(true, false)) { $batch->reportFailure(); } + + $e->addRelationship($entity->guid, 'deleted_with'); } }); } @@ -566,7 +678,7 @@ protected function deleteRelatedEntities(\ElggEntity $entity): void { */ protected function deleteEntityProperties(\ElggEntity $entity): void { // Temporarily overriding access controls and disable system_log to save performance - elgg_call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES | ELGG_DISABLE_SYSTEM_LOG, function() use ($entity) { + elgg_call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES | ELGG_SHOW_DELETED_ENTITIES | ELGG_DISABLE_SYSTEM_LOG, function() use ($entity) { $entity->removeAllRelatedRiverItems(); $entity->deleteOwnedAccessCollections(); $entity->deleteAccessCollectionMemberships(); diff --git a/engine/classes/Elgg/Database/HMACCacheTable.php b/engine/classes/Elgg/Database/HMACCacheTable.php index e1f61b67cb0..7ed6ad3a696 100644 --- a/engine/classes/Elgg/Database/HMACCacheTable.php +++ b/engine/classes/Elgg/Database/HMACCacheTable.php @@ -19,9 +19,7 @@ class HMACCacheTable { /** * @var string name of the hmac cache database table */ - const TABLE_NAME = 'hmac_cache'; - - protected Database $database; + public const TABLE_NAME = 'hmac_cache'; /** * @var int HMAC lifetime is 25 hours (this should be related to the time drift allowed in header validation) @@ -32,11 +30,8 @@ class HMACCacheTable { * Create a new table handler * * @param Database $database the Elgg database handler - * - * @return void */ - public function __construct(Database $database) { - $this->database = $database; + public function __construct(protected Database $database) { } /** diff --git a/engine/classes/Elgg/Database/Insert.php b/engine/classes/Elgg/Database/Insert.php index a96a7859b54..e7a47a03248 100644 --- a/engine/classes/Elgg/Database/Insert.php +++ b/engine/classes/Elgg/Database/Insert.php @@ -6,11 +6,15 @@ * Query builder for inserting data into the database */ class Insert extends QueryBuilder { - + /** - * {@inheritdoc} + * Returns a QueryBuilder for inserting data in a given table + * + * @param string $table table name + * + * @return static */ - public static function intoTable($table) { + public static function intoTable(string $table): static { $connection = _elgg_services()->db->getConnection('write'); $qb = new static($connection); $qb->insert($table); diff --git a/engine/classes/Elgg/Database/Metadata.php b/engine/classes/Elgg/Database/Metadata.php index 08dac230c07..a8eae0a0098 100644 --- a/engine/classes/Elgg/Database/Metadata.php +++ b/engine/classes/Elgg/Database/Metadata.php @@ -23,9 +23,9 @@ class Metadata extends Repository { * {@inheritdoc} */ public function count() { - $qb = Select::fromTable('metadata', 'n_table'); + $qb = Select::fromTable(MetadataTable::TABLE_NAME, MetadataTable::DEFAULT_JOIN_ALIAS); - $count_expr = $this->options->distinct ? 'DISTINCT n_table.id' : '*'; + $count_expr = $this->options->distinct ? "DISTINCT {$qb->getTableAlias()}.id" : '*'; $qb->select("COUNT({$count_expr}) AS total"); $qb = $this->buildQuery($qb); @@ -58,7 +58,7 @@ public function calculate($function, $property, $property_type = null) { $property_type = 'metadata'; } - $qb = Select::fromTable('metadata', 'n_table'); + $qb = Select::fromTable(MetadataTable::TABLE_NAME, MetadataTable::DEFAULT_JOIN_ALIAS); switch ($property_type) { case 'attribute': @@ -66,24 +66,21 @@ public function calculate($function, $property, $property_type = null) { throw new DomainException("'{$property}' is not a valid attribute"); } - /** - * @todo When no entity constraints are present, do we need to ensure that entity access clause is added? - */ - $alias = $qb->joinEntitiesTable('n_table', 'entity_guid', 'inner', 'e'); + $alias = $qb->joinEntitiesTable($qb->getTableAlias(), 'entity_guid', 'inner', 'e'); $qb->addSelect("{$function}({$alias}.{$property}) AS calculation"); break; case 'metadata': - $alias = 'n_table'; + $alias = MetadataTable::DEFAULT_JOIN_ALIAS; if (!empty($this->options->metadata_name_value_pairs) && $this->options->metadata_name_value_pairs[0]->names != $property) { - $alias = $qb->joinMetadataTable('n_table', 'entity_guid', $property); + $alias = $qb->joinMetadataTable($qb->getTableAlias(), 'entity_guid', $property); } - $qb->addSelect("{$function}($alias.value) AS calculation"); + $qb->addSelect("{$function}({$alias}.value) AS calculation"); break; case 'annotation': - $alias = $qb->joinAnnotationTable('n_table', 'entity_guid', $property); + $alias = $qb->joinAnnotationTable($qb->getTableAlias(), 'entity_guid', $property, 'inner', AnnotationsTable::DEFAULT_JOIN_ALIAS); $qb->addSelect("{$function}({$alias}.value) AS calculation"); break; } @@ -105,20 +102,20 @@ public function calculate($function, $property, $property_type = null) { * @return \ElggMetadata[] */ public function get($limit = null, $offset = null, $callback = null) { - $qb = Select::fromTable('metadata', 'n_table'); + $qb = Select::fromTable(MetadataTable::TABLE_NAME, MetadataTable::DEFAULT_JOIN_ALIAS); - $distinct = $this->options->distinct ? 'DISTINCT' : ''; - $qb->select("{$distinct} n_table.*"); + $distinct = $this->options->distinct ? 'DISTINCT ' : ''; + $qb->select("{$distinct}{$qb->getTableAlias()}.*"); - $this->expandInto($qb, 'n_table'); + $this->expandInto($qb, $qb->getTableAlias()); $qb = $this->buildQuery($qb); - // Keeping things backwards compatible + // add default ordering $original_order = elgg_extract('order_by', $this->options->__original_options); - if (empty($original_order) && $original_order !== false) { - $qb->addOrderBy('n_table.time_created', 'asc'); - $qb->addOrderBy('n_table.id', 'asc'); + if (empty($this->options->order_by) && $original_order !== false) { + $qb->addOrderBy("{$qb->getTableAlias()}.time_created", 'asc'); + $qb->addOrderBy("{$qb->getTableAlias()}.id", 'asc'); } if ($limit > 0) { @@ -139,7 +136,7 @@ public function get($limit = null, $offset = null, $callback = null) { /** * Execute the query resolving calculation, count and/or batch options * - * @return array|\ElggData[]|\ElggMetadata[]|false|int + * @return array|\ElggData[]|\ElggMetadata[]|int|\ElggBatch * @throws LogicException */ public function execute() { @@ -181,11 +178,11 @@ protected function buildQuery(QueryBuilder $qb) { $ands = []; foreach ($this->options->joins as $join) { - $join->prepare($qb, 'n_table'); + $join->prepare($qb, $qb->getTableAlias()); } foreach ($this->options->wheres as $where) { - $ands[] = $where->prepare($qb, 'n_table'); + $ands[] = $where->prepare($qb, $qb->getTableAlias()); } $ands[] = $this->buildPairedMetadataClause($qb, $this->options->metadata_name_value_pairs, $this->options->metadata_name_value_pairs_operator); @@ -214,7 +211,7 @@ protected function buildQuery(QueryBuilder $qb) { protected function buildEntityWhereClause(QueryBuilder $qb) { // Even if all of these properties are empty, we want to add this clause regardless, // to ensure that entity access clauses are appended to the query - $joined_alias = $qb->joinEntitiesTable('n_table', 'entity_guid', 'inner', 'e'); + $joined_alias = $qb->joinEntitiesTable($qb->getTableAlias(), 'entity_guid', 'inner', EntityTable::DEFAULT_JOIN_ALIAS); return EntityWhereClause::factory($this->options)->prepare($qb, $joined_alias); } @@ -232,7 +229,7 @@ protected function buildPairedMetadataClause(QueryBuilder $qb, $clauses, $boolea $parts = []; foreach ($clauses as $clause) { - $parts[] = $clause->prepare($qb, 'n_table'); + $parts[] = $clause->prepare($qb, $qb->getTableAlias()); } return $qb->merge($parts, $boolean); @@ -252,10 +249,10 @@ protected function buildPairedAnnotationClause(QueryBuilder $qb, $clauses, $bool $parts = []; foreach ($clauses as $clause) { - if (strtoupper($boolean) === 'OR' || count($clauses) > 1) { - $joined_alias = $qb->joinAnnotationTable('n_table', 'entity_guid'); + if (strtoupper($boolean) === 'OR' || count($clauses) === 1) { + $joined_alias = $qb->joinAnnotationTable($qb->getTableAlias(), 'entity_guid', null, 'inner', AnnotationsTable::DEFAULT_JOIN_ALIAS); } else { - $joined_alias = $qb->joinAnnotationTable('n_table', 'entity_guid', $clause->names); + $joined_alias = $qb->joinAnnotationTable($qb->getTableAlias(), 'entity_guid', $clause->names); } $parts[] = $clause->prepare($qb, $joined_alias); @@ -280,10 +277,10 @@ protected function buildPairedRelationshipClause(QueryBuilder $qb, $clauses, $bo $parts = []; foreach ($clauses as $clause) { - if (strtoupper($boolean) == 'OR' || count($clauses) > 1) { - $joined_alias = $qb->joinRelationshipTable('n_table', 'entity_guid', null, $clause->inverse); + if (strtoupper($boolean) === 'OR' || count($clauses) === 1) { + $joined_alias = $qb->joinRelationshipTable($qb->getTableAlias(), 'entity_guid', null, $clause->inverse, 'inner', RelationshipsTable::DEFAULT_JOIN_ALIAS); } else { - $joined_alias = $qb->joinRelationshipTable('n_table', 'entity_guid', $clause->names, $clause->inverse); + $joined_alias = $qb->joinRelationshipTable($qb->getTableAlias(), 'entity_guid', $clause->names, $clause->inverse); } $parts[] = $clause->prepare($qb, $joined_alias); diff --git a/engine/classes/Elgg/Database/MetadataTable.php b/engine/classes/Elgg/Database/MetadataTable.php index cc47a5b1c3a..53cf7759a0d 100644 --- a/engine/classes/Elgg/Database/MetadataTable.php +++ b/engine/classes/Elgg/Database/MetadataTable.php @@ -20,7 +20,11 @@ class MetadataTable { use TimeUsing; - const MYSQL_TEXT_BYTE_LIMIT = 65535; + protected const MYSQL_TEXT_BYTE_LIMIT = 65535; + + public const TABLE_NAME = 'metadata'; + + public const DEFAULT_JOIN_ALIAS = 'n_table'; protected MetadataCache $metadata_cache; @@ -143,7 +147,7 @@ function(QueryBuilder $qb, $main_alias) { * @return \ElggMetadata|null */ public function get(int $id): ?\ElggMetadata { - $qb = Select::fromTable('metadata'); + $qb = Select::fromTable(self::TABLE_NAME); $qb->select('*'); $where = new MetadataWhereClause(); @@ -170,7 +174,7 @@ public function delete(\ElggMetadata $metadata): bool { return false; } - $qb = Delete::fromTable('metadata'); + $qb = Delete::fromTable(self::TABLE_NAME); $qb->where($qb->compare('id', '=', $metadata->id, ELGG_VALUE_INTEGER)); $deleted = $this->db->deleteData($qb); @@ -245,7 +249,7 @@ public function create(\ElggMetadata $metadata, bool $allow_multiple = false): i $time_created = $this->getCurrentTime()->getTimestamp(); - $qb = Insert::intoTable('metadata'); + $qb = Insert::intoTable(self::TABLE_NAME); $qb->values([ 'name' => $qb->param($metadata->name, ELGG_VALUE_STRING), 'entity_guid' => $qb->param($metadata->entity_guid, ELGG_VALUE_INTEGER), @@ -297,7 +301,7 @@ public function update(\ElggMetadata $metadata): bool { elgg_log("Metadata '{$metadata->name}' is above the MySQL TEXT size limit and may be truncated.", 'WARNING'); } - $qb = Update::table('metadata'); + $qb = Update::table(self::TABLE_NAME); $qb->set('name', $qb->param($metadata->name, ELGG_VALUE_STRING)) ->set('value', $qb->param($metadata->value, $metadata->value_type === 'integer' ? ELGG_VALUE_INTEGER : ELGG_VALUE_STRING)) ->set('value_type', $qb->param($metadata->value_type, ELGG_VALUE_STRING)) @@ -347,7 +351,7 @@ public function getAll(array $options = []) { * @internal */ public function getRowsForGuids(array $guids): array { - $qb = Select::fromTable('metadata'); + $qb = Select::fromTable(self::TABLE_NAME); $qb->select('*') ->where($qb->compare('entity_guid', 'IN', $guids, ELGG_VALUE_GUID)) ->orderBy('entity_guid', 'asc') @@ -433,7 +437,7 @@ protected function getIDsByName(int $entity_guid, string $name) { if ($this->metadata_cache->isLoaded($entity_guid)) { $ids = $this->metadata_cache->getSingleId($entity_guid, $name); } else { - $qb = Select::fromTable('metadata'); + $qb = Select::fromTable(self::TABLE_NAME); $qb->select('id') ->where($qb->compare('entity_guid', '=', $entity_guid, ELGG_VALUE_INTEGER)) ->andWhere($qb->compare('name', '=', $name, ELGG_VALUE_STRING)); diff --git a/engine/classes/Elgg/Database/Mutex.php b/engine/classes/Elgg/Database/Mutex.php index 71fc0883c2d..4f385d0f78f 100644 --- a/engine/classes/Elgg/Database/Mutex.php +++ b/engine/classes/Elgg/Database/Mutex.php @@ -19,15 +19,12 @@ class Mutex { use Loggable; - protected Database $db; - /** * Constructor * * @param Database $db Database */ - public function __construct(Database $db) { - $this->db = $db; + public function __construct(protected Database $db) { } /** diff --git a/engine/classes/Elgg/Database/Plugins.php b/engine/classes/Elgg/Database/Plugins.php index f1e1c7efd20..ec4ce56a80a 100644 --- a/engine/classes/Elgg/Database/Plugins.php +++ b/engine/classes/Elgg/Database/Plugins.php @@ -7,14 +7,13 @@ use Elgg\Context; use Elgg\Database; use Elgg\EventsService; -use Elgg\Exceptions\InvalidArgumentException; use Elgg\Exceptions\PluginException; use Elgg\Http\Request; use Elgg\I18n\Translator; +use Elgg\Invoker; use Elgg\Project\Paths; use Elgg\SessionManagerService; use Elgg\SystemMessagesService; -use Elgg\Traits\Cacheable; use Elgg\Traits\Debug\Profilable; use Elgg\Traits\Loggable; use Elgg\ViewsService; @@ -29,7 +28,6 @@ class Plugins { use Profilable; - use Cacheable; use Loggable; const BUNDLED_PLUGINS = [ @@ -60,6 +58,7 @@ class Plugins { 'site_notifications', 'system_log', 'tagcloud', + 'theme_sandbox', 'thewire', 'uservalidationbyemail', 'web_services', @@ -69,27 +68,13 @@ class Plugins { * @var \ElggPlugin[] */ protected ?array $boot_plugins; - - protected Database $db; - - protected SessionManagerService $session_manager; - - protected EventsService $events; - - protected Translator $translator; - - protected ViewsService $views; - - protected Config $config; - - protected SystemMessagesService $system_messages; - + protected Context $context; /** * Constructor * - * @param BaseCache $cache Cache for referencing plugins by ID + * @param BaseCache $cache Plugins cache * @param Database $db Database * @param SessionManagerService $session_manager Session * @param EventsService $events Events @@ -97,28 +82,21 @@ class Plugins { * @param ViewsService $views Views service * @param Config $config Config * @param SystemMessagesService $system_messages System messages + * @param Invoker $invoker Invoker * @param Request $request Context */ public function __construct( - BaseCache $cache, - Database $db, - SessionManagerService $session_manager, - EventsService $events, - Translator $translator, - ViewsService $views, - Config $config, - SystemMessagesService $system_messages, + protected BaseCache $cache, + protected Database $db, + protected SessionManagerService $session_manager, + protected EventsService $events, + protected Translator $translator, + protected ViewsService $views, + protected Config $config, + protected SystemMessagesService $system_messages, + protected Invoker $invoker, Request $request ) { - $this->cache = $cache; - $this->db = $db; - $this->session_manager = $session_manager; - $this->events = $events; - $this->translator = $translator; - $this->views = $views; - $this->config = $config; - $this->system_messages = $system_messages; - $this->context = $request->getContextStack(); } @@ -128,12 +106,7 @@ public function __construct( * @return string */ public function getPath(): string { - $path = $this->config->plugins_path; - if (!$path) { - $path = Paths::project() . 'mod/'; - } - - return $path; + return $this->config->plugins_path ?: Paths::project() . 'mod/'; } /** @@ -145,6 +118,7 @@ public function getPath(): string { * @return void */ public function setBootPlugins(array $plugins = null, bool $order_plugins = true): void { + $this->cache->clear(); if (!is_array($plugins)) { unset($this->boot_plugins); return; @@ -170,27 +144,14 @@ public function setBootPlugins(array $plugins = null, bool $order_plugins = true $plugin->registerLanguages(); $this->boot_plugins[$plugin_id] = $plugin; + + // make sure the plugin is in the entity and plugin cache + $plugin->cache(); + + // can't use ElggEntity::cache() as it conflict with metadata preloading $this->cache->save($plugin_id, $plugin); } } - - /** - * Clear plugin caches - * - * @return void - */ - public function clear(): void { - $this->cache->clear(); - } - - /** - * Invalidate plugin cache - * - * @return void - */ - public function invalidate(): void { - $this->cache->invalidate(); - } /** * Returns a list of plugin directory names from a base directory. @@ -236,150 +197,105 @@ public function getDirsInDir(string $dir = null): array { * @return bool */ public function generateEntities(): bool { - $mod_dir = $this->getPath(); - // ignore access in case this is called with no admin logged in - needed for creating plugins perhaps? - $old_ia = $this->session_manager->setIgnoreAccess(true); - // show hidden entities so that we can enable them if appropriate - $old_access = $this->session_manager->setDisabledEntityVisibility(true); - - $known_plugins = $this->find('all'); - if (empty($known_plugins)) { - $known_plugins = []; - } - - // keeps track if reindexing is needed - $reindex = false; - - // map paths to indexes - $id_map = []; - $latest_priority = -1; - foreach ($known_plugins as $i => $plugin) { - // if the ID is wrong, delete the plugin because we can never load it. - $id = $plugin->getID(); - if (!$id) { - $plugin->delete(); - unset($known_plugins[$i]); - continue; - } + return $this->invoker->call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES, function() { + $mod_dir = $this->getPath(); - $id_map[$plugin->getID()] = $i; - $plugin->cache(); + $known_plugins = $this->find('all'); - // disabled plugins should have no priority, so no need to check if the priority is incorrect - if (!$plugin->isEnabled()) { - continue; + // keeps track if reindexing is needed + $reindex = false; + + // map paths to indexes + $id_map = []; + $latest_priority = 0; + foreach ($known_plugins as $i => $plugin) { + // if the ID is wrong, delete the plugin because we can never load it. + $id = $plugin->getID() . $plugin->guid; + if (!$id) { + $plugin->delete(); + unset($known_plugins[$i]); + continue; + } + + $id_map[$plugin->getID()] = $i; + + // disabled plugins should have no priority, so no need to check if the priority is incorrect + if (!$plugin->isEnabled()) { + continue; + } + + $current_priority = $plugin->getPriority(); + if (($current_priority - $latest_priority) > 1) { + $reindex = true; + } + + $latest_priority = $current_priority; } - $current_priority = $plugin->getPriority(); - if (($current_priority - $latest_priority) > 1) { - $reindex = true; + $physical_plugins = $this->getDirsInDir($mod_dir); + if (empty($physical_plugins)) { + return false; } - $latest_priority = $current_priority; - } - - $physical_plugins = $this->getDirsInDir($mod_dir); - if (empty($physical_plugins)) { - $this->session_manager->setIgnoreAccess($old_ia); - $this->session_manager->setDisabledEntityVisibility($old_access); - - return false; - } - - // check real plugins against known ones - foreach ($physical_plugins as $plugin_id) { - // is this already in the db? - if (array_key_exists($plugin_id, $id_map)) { - $index = $id_map[$plugin_id]; - $plugin = $known_plugins[$index]; - // was this plugin deleted and its entity disabled? + // check real plugins against known ones + foreach ($physical_plugins as $plugin_id) { + // is this already in the db? + if (array_key_exists($plugin_id, $id_map)) { + $index = $id_map[$plugin_id]; + $plugin = $known_plugins[$index]; + // was this plugin deleted and its entity disabled? + if (!$plugin->isEnabled()) { + $plugin->enable(); + try { + $plugin->deactivate(); + } catch (PluginException $e) { + // do nothing + } + + $plugin->setPriority('new'); + } + + // remove from the list of plugins to disable + unset($known_plugins[$index]); + } else { + // create new plugin + // priority is forced to last in save() if not set. + \ElggPlugin::fromId($plugin_id); + } + } + + // everything remaining in $known_plugins needs to be disabled + // because they are entities, but their dirs were removed. + // don't delete the entities because they hold settings. + foreach ($known_plugins as $plugin) { if (!$plugin->isEnabled()) { - $plugin->enable(); + continue; + } + + $reindex = true; + + if ($plugin->isActive()) { try { $plugin->deactivate(); } catch (PluginException $e) { // do nothing } - - $plugin->setPriority('new'); } - - // remove from the list of plugins to disable - unset($known_plugins[$index]); - } else { - // create new plugin - // priority is forced to last in save() if not set. - $plugin = \ElggPlugin::fromId($plugin_id); - $plugin->cache(); - } - } - - // everything remaining in $known_plugins needs to be disabled - // because they are entities, but their dirs were removed. - // don't delete the entities because they hold settings. - foreach ($known_plugins as $plugin) { - if (!$plugin->isEnabled()) { - continue; + + // remove the priority. + $plugin->deleteMetadata(\ElggPlugin::PRIORITY_SETTING_NAME); + + $plugin->disable(); } - $reindex = true; - - if ($plugin->isActive()) { - try { - $plugin->deactivate(); - } catch (PluginException $e) { - // do nothing - } + if ($reindex) { + $this->reindexPriorities(); } - // remove the priority. - $plugin->deleteMetadata(\ElggPlugin::PRIORITY_SETTING_NAME); - - $plugin->disable(); - } - - if ($reindex) { - $this->reindexPriorities(); - } - - $this->session_manager->setIgnoreAccess($old_ia); - $this->session_manager->setDisabledEntityVisibility($old_access); - - return true; - } - - /** - * Cache a reference to this plugin by its ID - * - * @param \ElggPlugin $plugin the plugin to cache - * - * @return void - */ - public function cache(\ElggPlugin $plugin): void { - if (!$plugin->getID()) { - return; - } - - $this->cache->save($plugin->getID(), $plugin); - } - - /** - * Remove plugin from cache - * - * @param string $plugin_id Plugin ID - * - * @return void - */ - public function invalidateCache($plugin_id): void { - try { - $this->cache->delete($plugin_id); - } catch (InvalidArgumentException $ex) { - // A plugin must have been deactivated due to missing folder - // without proper cleanup - elgg_invalidate_caches(); - } + return true; + }); } /** @@ -393,12 +309,12 @@ public function get(string $plugin_id): ?\ElggPlugin { if (empty($plugin_id)) { return null; } - + $plugin = $this->cache->load($plugin_id); if ($plugin instanceof \ElggPlugin) { return $plugin; } - + $plugins = elgg_get_entities([ 'type' => 'object', 'subtype' => 'plugin', @@ -409,14 +325,16 @@ public function get(string $plugin_id): ?\ElggPlugin { 'limit' => 1, 'distinct' => false, ]); - + if (empty($plugins)) { return null; } - - $plugins[0]->cache(); - - return $plugins[0]; + + $plugin = $plugins[0]; + + $this->cache->save($plugin_id, $plugin); + + return $plugin; } /** @@ -440,12 +358,12 @@ public function exists(string $id): bool { * @return int */ public function getMaxPriority(): int { - $qb = Select::fromTable('entities', 'e'); + $qb = Select::fromTable(EntityTable::TABLE_NAME, EntityTable::DEFAULT_JOIN_ALIAS); $qb->select('MAX(CAST(md.value AS unsigned)) as max') - ->join('e', 'metadata', 'md', 'e.guid = md.entity_guid') + ->join($qb->getTableAlias(), MetadataTable::TABLE_NAME, 'md', "{$qb->getTableAlias()}.guid = md.entity_guid") ->where($qb->compare('md.name', '=', \ElggPlugin::PRIORITY_SETTING_NAME, ELGG_VALUE_STRING)) - ->andWhere($qb->compare('e.type', '=', 'object', ELGG_VALUE_STRING)) - ->andWhere($qb->compare('e.subtype', '=', 'plugin', ELGG_VALUE_STRING)); + ->andWhere($qb->compare("{$qb->getTableAlias()}.type", '=', 'object', ELGG_VALUE_STRING)) + ->andWhere($qb->compare("{$qb->getTableAlias()}.subtype", '=', 'plugin', ELGG_VALUE_STRING)); $data = $this->db->getDataRow($qb); if (empty($data)) { @@ -725,7 +643,7 @@ public function find(string $status = 'active'): array { // shorten callstack $volatile_data_name = 'select:value'; - $options['select'] = ['n_table.value']; + $options['select'] = [MetadataTable::DEFAULT_JOIN_ALIAS . '.value']; $options['metadata_names'] = [ \ElggPlugin::PRIORITY_SETTING_NAME, ]; @@ -747,10 +665,10 @@ public function find(string $status = 'active'): array { break; } - $old_ia = $this->session_manager->setIgnoreAccess(true); - $plugins = elgg_get_entities($options) ?: []; - $this->session_manager->setIgnoreAccess($old_ia); - + $plugins = $this->invoker->call(ELGG_IGNORE_ACCESS, function () use ($options) { + return elgg_get_entities($options) ?: []; + }); + $result = $this->orderPluginsByPriority($plugins, $volatile_data_name); if ($status === 'active' && !isset($this->boot_plugins)) { @@ -758,6 +676,11 @@ public function find(string $status = 'active'): array { $this->setBootPlugins($result, false); } + foreach ($plugins as $plugin) { + // can't use ElggEntity::cache() as it conflict with metadata preloading + $this->cache->save($plugin->getID(), $plugin); + } + return $result; } @@ -807,7 +730,7 @@ protected function orderPluginsByPriority(array $plugins = [], string $volatile_ public function setPriorities(array $order): bool { $name = \ElggPlugin::PRIORITY_SETTING_NAME; - $plugins = $this->find('any'); + $plugins = $this->find('all'); if (empty($plugins)) { return false; } @@ -890,7 +813,7 @@ public function setPriority(\ElggPlugin $plugin, int $priority): int|false { return false; } - $qb = Update::table('metadata'); + $qb = Update::table(MetadataTable::TABLE_NAME); $qb->where($qb->compare('name', '=', $name, ELGG_VALUE_STRING)) ->andWhere($qb->compare('entity_guid', '!=', $plugin->guid, ELGG_VALUE_INTEGER)); diff --git a/engine/classes/Elgg/Database/QueryBuilder.php b/engine/classes/Elgg/Database/QueryBuilder.php index 8f5b7570ad1..267ff6856d8 100644 --- a/engine/classes/Elgg/Database/QueryBuilder.php +++ b/engine/classes/Elgg/Database/QueryBuilder.php @@ -2,6 +2,7 @@ namespace Elgg\Database; +use Doctrine\DBAL\ArrayParameterType; use Doctrine\DBAL\Connection; use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\Query\Expression\CompositeExpression; @@ -26,28 +27,44 @@ abstract class QueryBuilder extends DbalQueryBuilder { 'min', 'sum', ]; - const TABLE_ANNOTATIONS = 'annotations'; - const TABLE_ENTITIES = 'entities'; - const TABLE_METADATA = 'metadata'; - const TABLE_RELATIONSHIPS = 'entity_relationships'; protected array $joins = []; protected int $join_index = 0; - protected ?string $table_name; + protected ?string $table_name = null; - protected ?string $table_alias; + protected ?string $table_alias = null; + + /** + * Initializes a new QueryBuilder. + * + * @param Connection $backup_connection Connection used for this query + */ + public function __construct(protected readonly Connection $backup_connection) { + parent::__construct($backup_connection); + } + + /** + * Returns the connection. Need to do it this way because DBAL Query Builder does not expose the connection in 4.x + * + * @return Connection + * + * @since 6.0 + */ + public function getConnection(): Connection { + return $this->backup_connection; + } /** - * Creates a new SelectQueryBuilder for join/where subqueries using the DB connection of the primary QueryBuilder + * Creates a new SelectQueryBuilder for join/where sub queries using the DB connection of the primary QueryBuilder * - * @param string $table Main table name - * @param string $alias Select alias + * @param string $table Main table name + * @param string|null $alias Select alias * * @return Select */ - public function subquery($table, $alias = null) { + public function subquery(string $table, string $alias = null): Select { $qb = new Select($this->getConnection()); $qb->from($table, $alias); @@ -57,12 +74,12 @@ public function subquery($table, $alias = null) { /** * Apply clause to this instance * - * @param Clause $clause Clause - * @param string $alias Table alias + * @param Clause $clause Clause + * @param string|null $alias Table alias * * @return static */ - public function addClause(Clause $clause, $alias = null) { + public function addClause(Clause $clause, string $alias = null): static { if (!isset($alias)) { $alias = $this->getTableAlias(); } @@ -82,7 +99,7 @@ public function addClause(Clause $clause, $alias = null) { * * @return string */ - public function prefix($table) { + public function prefix(string $table): string { $prefix = _elgg_services()->db->prefix; if ($prefix === '') { return $table; @@ -100,15 +117,16 @@ public function prefix($table) { * * @return string */ - public function getTableName() { - return $this->table_name; + public function getTableName(): string { + return (string) $this->table_name; } /** * Returns the alias of the primary table - * @return string + * + * @return null|string */ - public function getTableAlias() { + public function getTableAlias(): ?string { return $this->table_alias; } @@ -116,13 +134,13 @@ public function getTableAlias() { * Sets a new parameter assigning it a unique parameter key/name if none provided * Returns the name of the new parameter * - * @param mixed $value Parameter value - * @param string $type Parameter type - * @param string $key Parameter key/index + * @param mixed $value Parameter value + * @param string $type Parameter type + * @param string|null $key Parameter key/index * * @return string */ - public function param($value, $type = null, $key = null) { + public function param($value, string $type = ELGG_VALUE_STRING, string $key = null): string { if (!$key) { $parameters = $this->getParameters(); $key = ':qb' . (count($parameters) + 1); @@ -165,9 +183,9 @@ public function param($value, $type = null, $key = null) { $value = array_shift($value); } else { if ($type === ParameterType::INTEGER) { - $type = Connection::PARAM_INT_ARRAY; + $type = ArrayParameterType::INTEGER; } elseif ($type === ParameterType::STRING) { - $type = Connection::PARAM_STR_ARRAY; + $type = ArrayParameterType::STRING; } } } @@ -181,7 +199,6 @@ public function param($value, $type = null, $key = null) { * @param bool $track_query should the query be tracked by timers and loggers */ public function execute(bool $track_query = true) { - if (!$track_query) { if ($this instanceof Select) { return parent::executeQuery(); @@ -204,11 +221,11 @@ public function execute(bool $track_query = true) { * * @internal Use create() method on the extending class */ - public function from($from, $alias = null) { - $this->table_name = $from; + public function from(string $table, ?string $alias = null): self { + $this->table_name = $table; $this->table_alias = $alias; - return parent::from($this->prefix($from), $alias); + return parent::from($this->prefix($table), $alias); } /** @@ -216,10 +233,10 @@ public function from($from, $alias = null) { * * @internal Use create() method on the extending class */ - public function insert($insert = null) { - $this->table_name = $insert; + public function insert(string $table): self { + $this->table_name = $table; - return parent::insert($this->prefix($insert)); + return parent::insert($this->prefix($table)); } /** @@ -227,11 +244,10 @@ public function insert($insert = null) { * * @internal Use create() method on the extending class */ - public function update($update = null, $alias = null) { - $this->table_name = $update; - $this->table_alias = $alias; + public function update(string $table): self { + $this->table_name = $table; - return parent::update($this->prefix($update), $alias); + return parent::update($this->prefix($table)); } /** @@ -239,39 +255,38 @@ public function update($update = null, $alias = null) { * * @internal Use create() method on the extending class */ - public function delete($delete = null, $alias = null) { - $this->table_name = $delete; - $this->table_alias = $alias; + public function delete(string $table): self { + $this->table_name = $table; - return parent::delete($this->prefix($delete), $alias); + return parent::delete($this->prefix($table)); } /** * {@inheritdoc} */ - public function join($fromAlias, $join, $alias, $condition = null) { + public function join(string $fromAlias, string $join, string $alias, ?string $condition = null): self { return parent::join($fromAlias, $this->prefix($join), $alias, $condition); } /** * {@inheritdoc} */ - public function innerJoin($fromAlias, $join, $alias, $condition = null) { + public function innerJoin(string $fromAlias, string $join, string $alias, ?string $condition = null): self { return parent::innerJoin($fromAlias, $this->prefix($join), $alias, $condition); } /** * {@inheritdoc} */ - public function leftJoin($fromAlias, $join, $alias, $condition = null) { + public function leftJoin(string $fromAlias, string $join, string $alias, ?string $condition = null): self { return parent::leftJoin($fromAlias, $this->prefix($join), $alias, $condition); } /** * {@inheritdoc} */ - public function rightJoin($fromAlias, $join, $alias, $condition = null) { - return parent::rightJoin($fromAlias, $this->prefix($join), $alias, $condition); // TODO: Change the autogenerated stub + public function rightJoin(string $fromAlias, string $join, string $alias, ?string $condition = null): self { + return parent::rightJoin($fromAlias, $this->prefix($join), $alias, $condition); } /** @@ -280,11 +295,11 @@ public function rightJoin($fromAlias, $join, $alias, $condition = null) { * @param mixed $parts Composite expression(s) or string(s) * @param string $boolean AND|OR * - * @return CompositeExpression|string + * @return CompositeExpression|string|null */ public function merge($parts = null, $boolean = 'AND') { if (empty($parts)) { - return; + return null; } $parts = (array) $parts; @@ -301,7 +316,7 @@ public function merge($parts = null, $boolean = 'AND') { return true; }); if (empty($parts)) { - return; + return null; } if (count($parts) === 1) { @@ -313,9 +328,9 @@ public function merge($parts = null, $boolean = 'AND') { $parts = array_values($parts); if (strtoupper($boolean) === 'OR') { return call_user_func_array([$this->expr(), 'or'], $parts); - } else { - return call_user_func_array([$this->expr(), 'and'], $parts); } + + return call_user_func_array([$this->expr(), 'and'], $parts); } /** @@ -334,7 +349,7 @@ public function merge($parts = null, $boolean = 'AND') { * * @return CompositeExpression|null|string */ - public function compare($x, $comparison, $y = null, $type = null, $case_sensitive = null) { + public function compare(string $x, string $comparison, $y = null, string $type = null, bool $case_sensitive = null) { return (new ComparisonClause($x, $comparison, $y, $type, $case_sensitive))->prepare($this); } @@ -348,7 +363,7 @@ public function compare($x, $comparison, $y = null, $type = null, $case_sensitiv * * @return CompositeExpression|null|string */ - public function between($x, $lower = null, $upper = null, $type = null) { + public function between(string $x, $lower = null, $upper = null, string $type = null) { $wheres = []; if ($lower) { $wheres[] = $this->compare($x, '>=', $lower, $type); @@ -363,9 +378,10 @@ public function between($x, $lower = null, $upper = null, $type = null) { /** * Get an index of the next available join alias + * * @return string */ - public function getNextJoinAlias() { + public function getNextJoinAlias(): string { $this->join_index++; return "qbt{$this->join_index}"; @@ -374,25 +390,25 @@ public function getNextJoinAlias() { /** * Join entity table from alias and return joined table alias * - * @param string $from_alias Main table alias - * @param string $from_column Guid column name in the main table - * @param string $join_type JOIN type - * @param string $joined_alias Joined table alias + * @param string $from_alias Main table alias + * @param string $from_column Guid column name in the main table + * @param string|null $join_type JOIN type + * @param string|null $joined_alias Joined table alias * * @return string */ - public function joinEntitiesTable($from_alias = '', $from_column = 'guid', $join_type = 'inner', $joined_alias = null) { + public function joinEntitiesTable(string $from_alias = '', string $from_column = 'guid', ?string $join_type = 'inner', string $joined_alias = null): string { if (in_array($joined_alias, $this->joins)) { return $joined_alias; } if ($from_alias) { - $from_column = "$from_alias.$from_column"; + $from_column = "{$from_alias}.{$from_column}"; } $hash = sha1(serialize([ $join_type, - self::TABLE_ENTITIES, + EntityTable::TABLE_NAME, $from_column, ])); @@ -401,10 +417,10 @@ public function joinEntitiesTable($from_alias = '', $from_column = 'guid', $join } $condition = function (QueryBuilder $qb, $joined_alias) use ($from_column) { - return $qb->compare("$joined_alias.guid", '=', $from_column); + return $qb->compare("{$joined_alias}.guid", '=', $from_column); }; - $clause = new JoinClause(self::TABLE_ENTITIES, $joined_alias, $condition, $join_type); + $clause = new JoinClause(EntityTable::TABLE_NAME, $joined_alias, $condition, $join_type); $joined_alias = $clause->prepare($this, $from_alias); $this->joins[$hash] = $joined_alias; @@ -418,23 +434,23 @@ public function joinEntitiesTable($from_alias = '', $from_column = 'guid', $join * @param string $from_alias Alias of the main table * @param string $from_column Guid column name in the main table * @param string|string[] $name Metadata name(s) - * @param string $join_type JOIN type - * @param string $joined_alias Joined table alias + * @param string|null $join_type JOIN type + * @param string|null $joined_alias Joined table alias * * @return string */ - public function joinMetadataTable($from_alias = '', $from_column = 'guid', $name = null, $join_type = 'inner', $joined_alias = null) { + public function joinMetadataTable(string $from_alias = '', string $from_column = 'guid', $name = null, ?string $join_type = 'inner', string $joined_alias = null): string { if (in_array($joined_alias, $this->joins)) { return $joined_alias; } if ($from_alias) { - $from_column = "$from_alias.$from_column"; + $from_column = "{$from_alias}.{$from_column}"; } $hash = sha1(serialize([ $join_type, - self::TABLE_METADATA, + MetadataTable::TABLE_NAME, $from_column, (array) $name, ])); @@ -445,12 +461,12 @@ public function joinMetadataTable($from_alias = '', $from_column = 'guid', $name $condition = function (QueryBuilder $qb, $joined_alias) use ($from_column, $name) { return $qb->merge([ - $qb->compare("$joined_alias.entity_guid", '=', $from_column), - $qb->compare("$joined_alias.name", '=', $name, ELGG_VALUE_STRING), + $qb->compare("{$joined_alias}.entity_guid", '=', $from_column), + $qb->compare("{$joined_alias}.name", '=', $name, ELGG_VALUE_STRING), ]); }; - $clause = new JoinClause(self::TABLE_METADATA, $joined_alias, $condition, $join_type); + $clause = new JoinClause(MetadataTable::TABLE_NAME, $joined_alias, $condition, $join_type); $joined_alias = $clause->prepare($this, $from_alias); @@ -465,23 +481,23 @@ public function joinMetadataTable($from_alias = '', $from_column = 'guid', $name * @param string $from_alias Main table alias * @param string $from_column Guid column name in the main table * @param string|string[] $name Annotation name - * @param string $join_type JOIN type - * @param string $joined_alias Joined table alias + * @param string|null $join_type JOIN type + * @param string|null $joined_alias Joined table alias * * @return string */ - public function joinAnnotationTable($from_alias = '', $from_column = 'guid', $name = null, $join_type = 'inner', $joined_alias = null) { + public function joinAnnotationTable(string $from_alias = '', string $from_column = 'guid', $name = null, ?string $join_type = 'inner', string $joined_alias = null): string { if (in_array($joined_alias, $this->joins)) { return $joined_alias; } if ($from_alias) { - $from_column = "$from_alias.$from_column"; + $from_column = "{$from_alias}.{$from_column}"; } $hash = sha1(serialize([ $join_type, - self::TABLE_ANNOTATIONS, + AnnotationsTable::TABLE_NAME, $from_column, (array) $name, ])); @@ -492,12 +508,12 @@ public function joinAnnotationTable($from_alias = '', $from_column = 'guid', $na $condition = function (QueryBuilder $qb, $joined_alias) use ($from_column, $name) { return $qb->merge([ - $qb->compare("$joined_alias.entity_guid", '=', $from_column), - $qb->compare("$joined_alias.name", '=', $name, ELGG_VALUE_STRING), + $qb->compare("{$joined_alias}.entity_guid", '=', $from_column), + $qb->compare("{$joined_alias}.name", '=', $name, ELGG_VALUE_STRING), ]); }; - $clause = new JoinClause(self::TABLE_ANNOTATIONS, $joined_alias, $condition, $join_type); + $clause = new JoinClause(AnnotationsTable::TABLE_NAME, $joined_alias, $condition, $join_type); $joined_alias = $clause->prepare($this, $from_alias); @@ -509,27 +525,27 @@ public function joinAnnotationTable($from_alias = '', $from_column = 'guid', $na /** * Join relationship table from alias and return joined table alias * - * @param string $from_alias Main table alias - * @param string $from_column Guid column name in the main table - * @param string $name Relationship name - * @param bool $inverse Join on guid_two column - * @param string $join_type JOIN type - * @param string $joined_alias Joined table alias + * @param string $from_alias Main table alias + * @param string $from_column Guid column name in the main table + * @param string $name Relationship name + * @param bool $inverse Join on guid_two column + * @param string|null $join_type JOIN type + * @param string|null $joined_alias Joined table alias * * @return string */ - public function joinRelationshipTable($from_alias = '', $from_column = 'guid', $name = null, $inverse = false, $join_type = 'inner', $joined_alias = null) { + public function joinRelationshipTable(string $from_alias = '', string $from_column = 'guid', $name = null, bool $inverse = false, ?string $join_type = 'inner', string $joined_alias = null): string { if (in_array($joined_alias, $this->joins)) { return $joined_alias; } if ($from_alias) { - $from_column = "$from_alias.$from_column"; + $from_column = "{$from_alias}.{$from_column}"; } $hash = sha1(serialize([ $join_type, - self::TABLE_RELATIONSHIPS, + RelationshipsTable::TABLE_NAME, $from_column, $inverse, (array) $name, @@ -551,7 +567,7 @@ public function joinRelationshipTable($from_alias = '', $from_column = 'guid', $ return $qb->merge($parts); }; - $clause = new JoinClause(self::TABLE_RELATIONSHIPS, $joined_alias, $condition, $join_type); + $clause = new JoinClause(RelationshipsTable::TABLE_NAME, $joined_alias, $condition, $join_type); $joined_alias = $clause->prepare($this, $from_alias); diff --git a/engine/classes/Elgg/Database/Relationships.php b/engine/classes/Elgg/Database/Relationships.php index e21bf4b6e0d..a50f36d9d1b 100644 --- a/engine/classes/Elgg/Database/Relationships.php +++ b/engine/classes/Elgg/Database/Relationships.php @@ -39,7 +39,7 @@ public function calculate($function, $property, $property_type = null) { $join_column = $this->getJoinColumn(); - $select = Select::fromTable('entity_relationships', 'er'); + $select = Select::fromTable(RelationshipsTable::TABLE_NAME, 'er'); switch ($property_type) { case 'attribute': @@ -47,21 +47,21 @@ public function calculate($function, $property, $property_type = null) { throw new DomainException("'{$property}' is not a valid attribute"); } - $alias = $select->joinEntitiesTable('er', $join_column, 'inner', 'e'); + $alias = $select->joinEntitiesTable($select->getTableAlias(), $join_column, 'inner', 'e'); $select->select("{$function}({$alias}.{$property}) AS calculation"); break; case 'annotation': - $alias = 'n_table'; + $alias = AnnotationsTable::DEFAULT_JOIN_ALIAS; if (!empty($this->options->annotation_name_value_pairs) && $this->options->annotation_name_value_pairs[0]->names != $property) { - $alias = $select->joinAnnotationTable('er', $join_column, $property); + $alias = $select->joinAnnotationTable($select->getTableAlias(), $join_column, $property); } - $select->select("{$function}($alias.value) AS calculation"); + $select->select("{$function}({$alias}.value) AS calculation"); break; case 'metadata': - $alias = $select->joinMetadataTable('er', $join_column, $property); + $alias = $select->joinMetadataTable($select->getTableAlias(), $join_column, $property); $select->select("{$function}({$alias}.value) AS calculation"); break; } @@ -77,9 +77,9 @@ public function calculate($function, $property, $property_type = null) { * {@inheritDoc} */ public function count() { - $select = Select::fromTable('entity_relationships', 'er'); + $select = Select::fromTable(RelationshipsTable::TABLE_NAME, 'er'); - $count_expr = $this->options->distinct ? 'DISTINCT er.id' : '*'; + $count_expr = $this->options->distinct ? "DISTINCT {$select->getTableAlias()}.id" : '*'; $select->select("COUNT({$count_expr}) AS total"); $select = $this->buildQuery($select); @@ -127,20 +127,20 @@ public function execute() { * {@inheritDoc} */ public function get($limit = null, $offset = null, $callback = null) { - $select = Select::fromTable('entity_relationships', 'er'); + $select = Select::fromTable(RelationshipsTable::TABLE_NAME, 'er'); - $distinct = $this->options->distinct ? 'DISTINCT' : ''; - $select->select("$distinct er.*"); + $distinct = $this->options->distinct ? 'DISTINCT ' : ''; + $select->select("{$distinct}{$select->getTableAlias()}.*"); - $this->expandInto($select, 'er'); + $this->expandInto($select, $select->getTableAlias()); $select = $this->buildQuery($select); - // Keeping things backwards compatible + // add default ordering $original_order = elgg_extract('order_by', $this->options->__original_options); - if (empty($original_order) && $original_order !== false) { - $select->addOrderBy('er.time_created', 'desc'); - $select->addOrderBy('er.id', 'desc'); + if (empty($this->options->order_by) && $original_order !== false) { + $select->addOrderBy("{$select->getTableAlias()}.time_created", 'desc'); + $select->addOrderBy("{$select->getTableAlias()}.id", 'desc'); } if ($limit > 0) { @@ -181,11 +181,11 @@ protected function buildQuery(QueryBuilder $qb) { $ands = []; foreach ($this->options->joins as $join) { - $join->prepare($qb, 'er'); + $join->prepare($qb, $qb->getTableAlias()); } foreach ($this->options->wheres as $where) { - $ands[] = $where->prepare($qb, 'er'); + $ands[] = $where->prepare($qb, $qb->getTableAlias()); } $ands[] = $this->buildEntityClause($qb); @@ -211,7 +211,7 @@ protected function buildQuery(QueryBuilder $qb) { * @return \Closure|CompositeExpression|mixed|null|string */ protected function buildEntityClause(QueryBuilder $qb) { - $joined_alias = $qb->joinEntitiesTable('er', $this->getJoinColumn(), 'inner', 'e'); + $joined_alias = $qb->joinEntitiesTable($qb->getTableAlias(), $this->getJoinColumn(), 'inner', 'e'); return EntityWhereClause::factory($this->options)->prepare($qb, $joined_alias); } @@ -233,9 +233,9 @@ protected function buildPairedMetadataClause(QueryBuilder $qb, $clauses, $boolea foreach ($clauses as $clause) { if ($clause instanceof MetadataWhereClause) { if (strtoupper($boolean) === 'OR' || count($clauses) === 1) { - $joined_alias = $qb->joinMetadataTable('er', $join_column, null, 'inner', 'md'); + $joined_alias = $qb->joinMetadataTable($qb->getTableAlias(), $join_column, null, 'inner', 'md'); } else { - $joined_alias = $qb->joinMetadataTable('er', $join_column, $clause->names); + $joined_alias = $qb->joinMetadataTable($qb->getTableAlias(), $join_column, $clause->names); } $parts[] = $clause->prepare($qb, $joined_alias); @@ -262,9 +262,9 @@ protected function buildPairedAnnotationClause(QueryBuilder $qb, $clauses, $bool foreach ($clauses as $clause) { if (strtoupper($boolean) === 'OR' || count($clauses) === 1) { - $joined_alias = $qb->joinAnnotationTable('er', $join_column, null, 'inner', 'an'); + $joined_alias = $qb->joinAnnotationTable($qb->getTableAlias(), $join_column, null, 'inner', AnnotationsTable::DEFAULT_JOIN_ALIAS); } else { - $joined_alias = $qb->joinAnnotationTable('er', $join_column, $clause->names); + $joined_alias = $qb->joinAnnotationTable($qb->getTableAlias(), $join_column, $clause->names); } $parts[] = $clause->prepare($qb, $joined_alias); @@ -286,7 +286,7 @@ protected function buildPairedRelationshipClause(QueryBuilder $qb, $clauses, $bo $parts = []; foreach ($clauses as $clause) { - $parts[] = $clause->prepare($qb, 'er'); + $parts[] = $clause->prepare($qb, $qb->getTableAlias()); } return $qb->merge($parts, $boolean); diff --git a/engine/classes/Elgg/Database/RelationshipsTable.php b/engine/classes/Elgg/Database/RelationshipsTable.php index 67ced24138c..4c9d0f858ac 100644 --- a/engine/classes/Elgg/Database/RelationshipsTable.php +++ b/engine/classes/Elgg/Database/RelationshipsTable.php @@ -25,15 +25,11 @@ class RelationshipsTable { /** * @var integer The max length of the relationship column data */ - const RELATIONSHIP_COLUMN_LENGTH = 255; + public const RELATIONSHIP_COLUMN_LENGTH = 255; - protected Database $db; - - protected EntityTable $entities; - - protected MetadataTable $metadata; - - protected EventsService $events; + public const TABLE_NAME = 'entity_relationships'; + + public const DEFAULT_JOIN_ALIAS = 'r'; /** * Constructor @@ -43,11 +39,12 @@ class RelationshipsTable { * @param MetadataTable $metadata Metadata table * @param EventsService $events Events service */ - public function __construct(Database $db, EntityTable $entities, MetadataTable $metadata, EventsService $events) { - $this->db = $db; - $this->entities = $entities; - $this->metadata = $metadata; - $this->events = $events; + public function __construct( + protected Database $db, + protected EntityTable $entities, + protected MetadataTable $metadata, + protected EventsService $events + ) { } /** @@ -58,7 +55,7 @@ public function __construct(Database $db, EntityTable $entities, MetadataTable $ * @return \ElggRelationship|null */ public function get(int $id): ?\ElggRelationship { - $select = Select::fromTable('entity_relationships'); + $select = Select::fromTable(self::TABLE_NAME); $select->select('*') ->where($select->compare('id', '=', $id, ELGG_VALUE_ID)); @@ -83,7 +80,7 @@ public function delete(int $id, bool $call_event = true): bool { return false; } - $delete = Delete::fromTable('entity_relationships'); + $delete = Delete::fromTable(self::TABLE_NAME); $delete->where($delete->compare('id', '=', $id, ELGG_VALUE_ID)); return (bool) $this->db->deleteData($delete); @@ -120,7 +117,7 @@ public function add(int $guid_one, string $relationship, int $guid_two, bool $re return false; } - $insert = Insert::intoTable('entity_relationships'); + $insert = Insert::intoTable(self::TABLE_NAME); $insert->values([ 'guid_one' => $insert->param($guid_one, ELGG_VALUE_GUID), 'relationship' => $insert->param($relationship, ELGG_VALUE_STRING), @@ -166,7 +163,7 @@ public function add(int $guid_one, string $relationship, int $guid_two, bool $re * @return \ElggRelationship|false Depending on success */ public function check(int $guid_one, string $relationship, int $guid_two) { - $select = Select::fromTable('entity_relationships'); + $select = Select::fromTable(self::TABLE_NAME); $select->select('*') ->where($select->compare('guid_one', '=', $guid_one, ELGG_VALUE_GUID)) ->andWhere($select->compare('relationship', '=', $relationship, ELGG_VALUE_STRING)) @@ -231,7 +228,7 @@ public function removeAll(int $guid, string $relationship = '', bool $inverse_re * @return true */ protected function removeAllWithoutEvents(int $guid, string $relationship = '', bool $inverse_relationship = false, string $type = ''): bool { - $delete = Delete::fromTable('entity_relationships'); + $delete = Delete::fromTable(self::TABLE_NAME); if ($inverse_relationship) { $delete->where($delete->compare('guid_two', '=', $guid, ELGG_VALUE_GUID)); @@ -244,7 +241,7 @@ protected function removeAllWithoutEvents(int $guid, string $relationship = '', } if (!empty($type)) { - $entity_sub = $delete->subquery('entities'); + $entity_sub = $delete->subquery(EntityTable::TABLE_NAME); $entity_sub->select('guid') ->where($delete->compare('type', '=', $type, ELGG_VALUE_STRING)); @@ -274,7 +271,7 @@ protected function removeAllWithoutEvents(int $guid, string $relationship = '', * @return true */ protected function removeAllWithEvents(int $guid, string $relationship = '', bool $inverse_relationship = false, string $type = ''): bool { - $select = Select::fromTable('entity_relationships'); + $select = Select::fromTable(self::TABLE_NAME); $select->select('*'); if ($inverse_relationship) { @@ -288,9 +285,9 @@ protected function removeAllWithEvents(int $guid, string $relationship = '', boo } if (!empty($type)) { - $entity_sub = $select->subquery('entities'); + $entity_sub = $select->subquery(EntityTable::TABLE_NAME); $entity_sub->select('guid') - ->where($select->compare('type', '=', $type, ELGG_VALUE_STRING)); + ->where($select->compare('type', '=', $type, ELGG_VALUE_STRING)); if (!$inverse_relationship) { $select->andWhere($select->compare('guid_two', 'in', $entity_sub->getSQL())); @@ -319,7 +316,7 @@ protected function removeAllWithEvents(int $guid, string $relationship = '', boo continue; } - $delete = Delete::fromTable('entity_relationships'); + $delete = Delete::fromTable(self::TABLE_NAME); $delete->where($delete->compare('id', 'in', $chunk)); $this->db->deleteData($delete); @@ -338,8 +335,8 @@ protected function removeAllWithEvents(int $guid, string $relationship = '', boo * @return \ElggEntity[]|int|boolean If count, int. If not count, array. false on errors. */ public function getEntitiesFromCount(array $options = []) { - $options['selects'][] = new SelectClause('COUNT(e.guid) AS total'); - $options['group_by'][] = new GroupByClause('r.guid_two'); + $options['selects'][] = new SelectClause('COUNT(' . EntityTable::DEFAULT_JOIN_ALIAS . '.guid) AS total'); + $options['group_by'][] = new GroupByClause(self::DEFAULT_JOIN_ALIAS . '.guid_two'); $options['order_by'][] = new OrderByClause('total', 'desc'); return Entities::find($options); diff --git a/engine/classes/Elgg/Database/Repository.php b/engine/classes/Elgg/Database/Repository.php index 06a9f1e838d..c1bc5d8245c 100644 --- a/engine/classes/Elgg/Database/Repository.php +++ b/engine/classes/Elgg/Database/Repository.php @@ -108,11 +108,7 @@ abstract public function get($limit = null, $offset = null, $callback = null); * @return \ElggData[]|int|mixed */ public static function find(array $options = []) { - try { - return static::with($options)->execute(); - } catch (DataFormatException $e) { - return elgg_extract('count', $options) ? 0 : false; - } + return static::with($options)->execute(); } /** @@ -185,18 +181,18 @@ public function select($expression) { * @param string $joined_table Name of the table (with or without dbprefix) * @param string $joined_alias Alias of the joined table * If not set, the alias will be assigned automatically - * @param string $x Base column, e.g. 'n_table.entity_guid' + * @param string $join_column Base column, e.g. 'n_table.entity_guid' * This value is NOT a query parameter and will not be sanitized * @param string $comparison Comparison operator, e.g. '=', 'not like' etc - * @param mixed $y Comparison value(s) + * @param mixed $values Comparison value(s) * @param string $type Type of the comparison value(s), e.g. ELGG_VALUE_STRING, ELGG_VALUE_INT - * @param bool $case_sensitive Use case senstivie comparison for string values + * @param bool $case_sensitive Use case sensitive comparison for string values * * @return static */ - public function join($joined_table, $joined_alias = null, $x = null, $comparison = null, $y = null, $type = null, $case_sensitive = null) { - $join = new JoinClause($joined_table, $joined_alias, function (QueryBuilder $qb, $joined_alias) use ($x, $comparison, $y, $type, $case_sensitive) { - return $qb->compare("$joined_alias.$x", $comparison, $y, $type, $case_sensitive); + public function join($joined_table, $joined_alias = null, $join_column = null, $comparison = null, $values = null, $type = null, $case_sensitive = null) { + $join = new JoinClause($joined_table, $joined_alias, function (QueryBuilder $qb, $joined_alias) use ($join_column, $comparison, $values, $type, $case_sensitive) { + return $qb->compare("{$joined_alias}.{$join_column}", $comparison, $values, $type, $case_sensitive); }); $this->options->join($join); diff --git a/engine/classes/Elgg/Database/River.php b/engine/classes/Elgg/Database/River.php index b0b76f3267d..2fab93552cf 100644 --- a/engine/classes/Elgg/Database/River.php +++ b/engine/classes/Elgg/Database/River.php @@ -73,9 +73,9 @@ public static function find(array $options = []) { * {@inheritdoc} */ public function count() { - $qb = Select::fromTable('river', 'rv'); + $qb = Select::fromTable(RiverTable::TABLE_NAME, RiverTable::DEFAULT_JOIN_ALIAS); - $count_expr = $this->options->distinct ? 'DISTINCT rv.id' : '*'; + $count_expr = $this->options->distinct ? "DISTINCT {$qb->getTableAlias()}.id" : '*'; $qb->select("COUNT({$count_expr}) AS total"); $qb = $this->buildQuery($qb); @@ -100,9 +100,9 @@ public function calculate($function, $property, $property_type = 'annotation') { throw new DomainException("'{$function}' is not a valid numeric function"); } - $qb = Select::fromTable('river', 'rv'); + $qb = Select::fromTable(RiverTable::TABLE_NAME, RiverTable::DEFAULT_JOIN_ALIAS); - $alias = 'n_table'; + $alias = AnnotationsTable::DEFAULT_JOIN_ALIAS; if (!empty($this->options->annotation_name_value_pairs) && $this->options->annotation_name_value_pairs[0]->names != $property) { $alias = $qb->getNextJoinAlias(); @@ -111,8 +111,8 @@ public function calculate($function, $property, $property_type = 'annotation') { $qb->addClause($annotation, $alias); } - $qb->join('rv', 'annotations', $alias, "rv.annotation_id = {$alias}.id"); - $qb->select("{$function}(n_table.value) AS calculation"); + $qb->joinAnnotationTable($qb->getTableAlias(), 'annotation_id', null, 'inner', $alias); + $qb->select("{$function}({$alias}.value) AS calculation"); $qb = $this->buildQuery($qb); @@ -131,19 +131,19 @@ public function calculate($function, $property, $property_type = 'annotation') { * @return \ElggEntity[] */ public function get($limit = null, $offset = null, $callback = null) { - $qb = Select::fromTable('river', 'rv'); + $qb = Select::fromTable(RiverTable::TABLE_NAME, RiverTable::DEFAULT_JOIN_ALIAS); - $distinct = $this->options->distinct ? 'DISTINCT' : ''; - $qb->select("{$distinct} rv.*"); + $distinct = $this->options->distinct ? 'DISTINCT ' : ''; + $qb->select("{$distinct}{$qb->getTableAlias()}.*"); - $this->expandInto($qb, 'rv'); + $this->expandInto($qb, $qb->getTableAlias()); $qb = $this->buildQuery($qb); - // Keeping things backwards compatible + // add default ordering $original_order = elgg_extract('order_by', $this->options->__original_options); - if (empty($original_order) && $original_order !== false) { - $qb->addOrderBy('rv.posted', 'desc'); + if (empty($this->options->order_by) && $original_order !== false) { + $qb->addOrderBy("{$qb->getTableAlias()}.posted", 'desc'); } if ($limit > 0) { @@ -178,7 +178,7 @@ public function get($limit = null, $offset = null, $callback = null) { /** * Execute the query resolving calculation, count and/or batch options * - * @return array|\ElggData[]|\ElggEntity[]|false|int + * @return array|\ElggData[]|\ElggEntity[]|int|\ElggBatch * @throws LogicException */ public function execute() { @@ -211,11 +211,11 @@ protected function buildQuery(QueryBuilder $qb) { $ands = []; foreach ($this->options->joins as $join) { - $join->prepare($qb, 'rv'); + $join->prepare($qb, $qb->getTableAlias()); } foreach ($this->options->wheres as $where) { - $ands[] = $where->prepare($qb, 'rv'); + $ands[] = $where->prepare($qb, $qb->getTableAlias()); } $ands[] = $this->buildRiverClause($qb); @@ -251,7 +251,7 @@ protected function buildRiverClause(QueryBuilder $qb) { $where->created_before = $this->options->created_before; $where->annotation_ids = $this->options->river_annotation_ids; - return $where->prepare($qb, 'rv'); + return $where->prepare($qb, $qb->getTableAlias()); } /** @@ -268,14 +268,14 @@ public function buildEntityClauses($qb) { $ands = []; if (!empty($this->options->subject_guids) || $use_access_clause) { - $qb->joinEntitiesTable('rv', 'subject_guid', 'inner', 'se'); + $qb->joinEntitiesTable($qb->getTableAlias(), 'subject_guid', 'inner', 'se'); $subject = new EntityWhereClause(); $subject->guids = $this->options->subject_guids; $ands[] = $subject->prepare($qb, 'se'); } if (!empty($this->options->object_guids) || $use_access_clause || !empty($this->options->type_subtype_pairs)) { - $qb->joinEntitiesTable('rv', 'object_guid', 'inner', 'oe'); + $qb->joinEntitiesTable($qb->getTableAlias(), 'object_guid', 'inner', 'oe'); $object = new EntityWhereClause(); $object->guids = $this->options->object_guids; $object->type_subtype_pairs = $this->options->type_subtype_pairs; @@ -284,7 +284,7 @@ public function buildEntityClauses($qb) { if (!empty($this->options->target_guids) || $use_access_clause) { $target_ors = []; - $qb->joinEntitiesTable('rv', 'target_guid', 'left', 'te'); + $qb->joinEntitiesTable($qb->getTableAlias(), 'target_guid', 'left', 'te'); $target = new EntityWhereClause(); $target->guids = $this->options->target_guids; $target_ors[] = $target->prepare($qb, 'te'); @@ -311,23 +311,9 @@ protected function buildPairedAnnotationClause(QueryBuilder $qb, $clauses, $bool foreach ($clauses as $clause) { if (strtoupper($boolean) === 'OR' || count($clauses) === 1) { - $joined_alias = 'n_table'; + $joined_alias = $qb->joinAnnotationTable($qb->getTableAlias(), 'annotation_id'); } else { - $joined_alias = $qb->getNextJoinAlias(); - } - - $joins = $qb->getQueryPart('join'); - $is_joined = false; - if (!empty($joins['rv'])) { - foreach ($joins['rv'] as $join) { - if ($join['joinAlias'] === $joined_alias) { - $is_joined = true; - } - } - } - - if (!$is_joined) { - $qb->join('rv', 'annotations', $joined_alias, "$joined_alias.id = rv.annotation_id"); + $joined_alias = $qb->joinAnnotationTable($qb->getTableAlias(), 'annotation_id', $clause->names); } $parts[] = $clause->prepare($qb, $joined_alias); @@ -350,10 +336,10 @@ protected function buildPairedRelationshipClause(QueryBuilder $qb, $clauses, $bo foreach ($clauses as $clause) { $join_on = $clause->join_on === 'guid' ? 'subject_guid' : $clause->join_on; - if (strtoupper($boolean) == 'OR' || count($clauses) === 1) { - $joined_alias = $qb->joinRelationshipTable('rv', $join_on, null, $clause->inverse, 'inner', 'r'); + if (strtoupper($boolean) === 'OR' || count($clauses) === 1) { + $joined_alias = $qb->joinRelationshipTable($qb->getTableAlias(), $join_on, null, $clause->inverse, 'inner', RelationshipsTable::DEFAULT_JOIN_ALIAS); } else { - $joined_alias = $qb->joinRelationshipTable('rv', $join_on, $clause->names, $clause->inverse); + $joined_alias = $qb->joinRelationshipTable($qb->getTableAlias(), $join_on, $clause->names, $clause->inverse); } $parts[] = $clause->prepare($qb, $joined_alias); diff --git a/engine/classes/Elgg/Database/RiverTable.php b/engine/classes/Elgg/Database/RiverTable.php index 2d9d94bae35..d639d3c450a 100644 --- a/engine/classes/Elgg/Database/RiverTable.php +++ b/engine/classes/Elgg/Database/RiverTable.php @@ -20,17 +20,9 @@ class RiverTable { /** * @var string name of the river database table */ - const TABLE_NAME = 'river'; + public const TABLE_NAME = 'river'; - protected AnnotationsTable $annotationsTable; - - protected Database $db; - - protected EntityTable $entityTable; - - protected EventsService $events; - - protected ViewsService $views; + public const DEFAULT_JOIN_ALIAS = 'rv'; /** * Create the river table service @@ -41,12 +33,13 @@ class RiverTable { * @param EventsService $events events service * @param ViewsService $views views service */ - public function __construct(Database $db, AnnotationsTable $annotationsTable, EntityTable $entityTable, EventsService $events, ViewsService $views) { - $this->annotationsTable = $annotationsTable; - $this->db = $db; - $this->entityTable = $entityTable; - $this->events = $events; - $this->views = $views; + public function __construct( + protected Database $db, + protected AnnotationsTable $annotationsTable, + protected EntityTable $entityTable, + protected EventsService $events, + protected ViewsService $views + ) { } /** diff --git a/engine/classes/Elgg/Database/Seeder.php b/engine/classes/Elgg/Database/Seeder.php index 4163acfecb3..9fe289f10e8 100644 --- a/engine/classes/Elgg/Database/Seeder.php +++ b/engine/classes/Elgg/Database/Seeder.php @@ -2,9 +2,11 @@ namespace Elgg\Database; +use Elgg\Cli\Command; use Elgg\Cli\Progress; use Elgg\Database\Seeds\Seed; use Elgg\EventsService; +use Elgg\I18n\Translator; use Elgg\Invoker; /** @@ -21,22 +23,27 @@ class Seeder { protected Progress $progress; protected Invoker $invoker; + + protected Translator $translator; /** * Seeder constructor. * - * @param EventsService $events Events service - * @param Progress $progress Progress helper - * @param Invoker $invoker Invoker service + * @param EventsService $events Events service + * @param Progress $progress Progress helper + * @param Invoker $invoker Invoker service + * @param Translator $translator Translator */ public function __construct( EventsService $events, Progress $progress, - Invoker $invoker + Invoker $invoker, + Translator $translator ) { $this->events = $events; $this->progress = $progress; $this->invoker = $invoker; + $this->translator = $translator; } /** @@ -53,19 +60,19 @@ public function __construct( * @return void */ public function seed(array $options = []): void { - $this->invoker->call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES | ELGG_DISABLE_SYSTEM_LOG, function() use ($options) { + $this->invoker->call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES | ELGG_SHOW_DELETED_ENTITIES | ELGG_DISABLE_SYSTEM_LOG, function() use ($options) { $defaults = [ - 'limit' => max(elgg_get_config('default_limit'), 20), + 'limit' => null, 'image_folder' => elgg_get_config('seeder_local_image_folder'), 'type' => '', 'create' => false, 'create_since' => 'now', 'create_until' => 'now', + 'interactive' => true, + 'cli_command' => null, ]; $options = array_merge($defaults, $options); - $seeds = $this->getSeederClasses(); - // set global configuration if ($options['image_folder'] !== $defaults['image_folder']) { elgg_set_config('seeder_local_image_folder', $options['image_folder']); @@ -73,16 +80,38 @@ public function seed(array $options = []): void { unset($options['image_folder']); + // fetch CLI command + $cli_command = $options['cli_command']; + unset($options['cli_command']); + + // interactive mode + $interactive = $options['interactive'] && empty($options['type']); + unset($options['interactive']); + + $seeds = $this->getSeederClasses(); foreach ($seeds as $seed) { + $seed_options = $options; + // check for type limitation - if (!empty($options['type']) && $options['type'] !== $seed::getType()) { + if (!empty($seed_options['type']) && $seed_options['type'] !== $seed::getType()) { continue; } + // check the seed limit + $seed_options['limit'] = $seed_options['limit'] ?? $seed::getDefaultLimit(); + if ($interactive && $cli_command instanceof Command) { + $seed_options['limit'] = (int) $cli_command->ask($this->translator->translate('cli:database:seed:ask:limit', [$seed::getType()]), $seed_options['limit'], false, false); + } + + if ($seed_options['limit'] < 1) { + // skip seeding + continue; + } + /* @var $seeder Seed */ - $seeder = new $seed($options); + $seeder = new $seed($seed_options); - $progress_bar = $this->progress->start($seed, $options['limit']); + $progress_bar = $this->progress->start($seed, $seed_options['limit']); $seeder->setProgressBar($progress_bar); @@ -102,7 +131,7 @@ public function seed(array $options = []): void { * @return void */ public function unseed(array $options = []): void { - $this->invoker->call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES | ELGG_DISABLE_SYSTEM_LOG, function() use ($options) { + $this->invoker->call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES | ELGG_SHOW_DELETED_ENTITIES | ELGG_DISABLE_SYSTEM_LOG, function() use ($options) { $defaults = [ 'type' => '', ]; diff --git a/engine/classes/Elgg/Database/Seeds/Groups.php b/engine/classes/Elgg/Database/Seeds/Groups.php index 7925def35c9..eaa99887a47 100644 --- a/engine/classes/Elgg/Database/Seeds/Groups.php +++ b/engine/classes/Elgg/Database/Seeds/Groups.php @@ -2,6 +2,8 @@ namespace Elgg\Database\Seeds; +use Elgg\Exceptions\Seeding\MaxAttemptsException; + /** * Seed users * @@ -34,7 +36,7 @@ public function seed() { } while ($this->getCount() < $this->limit) { - if ($this->create) { + try { $group = $this->createGroup([ 'access_id' => $this->getRandomGroupVisibility(), 'content_access_mode' => $this->getRandomGroupContentAccessMode(), @@ -43,11 +45,8 @@ public function seed() { 'profile_fields' => $profile_fields, 'group_tool_options' => _elgg_services()->group_tools->all(), ]); - } else { - $group = $this->getRandomGroup($exclude); - } - - if (!$group) { + } catch (MaxAttemptsException $e) { + // unable to create a group with the given options continue; } @@ -107,7 +106,6 @@ public function seed() { * {@inheritdoc} */ public function unseed() { - /* @var $groups \ElggBatch */ $groups = elgg_get_entities([ 'type' => 'group', @@ -119,10 +117,12 @@ public function unseed() { /* @var $group \ElggGroup */ foreach ($groups as $group) { - if ($group->delete()) { + if ($group->delete(true, true)) { $this->log("Deleted group {$group->guid}"); } else { $this->log("Failed to delete group {$group->guid}"); + $groups->reportFailure(); + continue; } $this->advance(); diff --git a/engine/classes/Elgg/Database/Seeds/Seed.php b/engine/classes/Elgg/Database/Seeds/Seed.php index f01c68e87df..af875f82cc6 100644 --- a/engine/classes/Elgg/Database/Seeds/Seed.php +++ b/engine/classes/Elgg/Database/Seeds/Seed.php @@ -21,17 +21,17 @@ abstract class Seed implements Seedable { /** * @var int Max number of items to be created by the seed */ - protected $limit = 20; + protected int $limit; /** * @var bool Create new entities */ - protected $create = false; + protected bool $create = false; /** * @var int Number of seeded entities */ - protected $seeded_counter = 0; + protected int $seeded_counter = 0; /** * Seed constructor. @@ -46,6 +46,8 @@ public function __construct(array $options = []) { $limit = (int) elgg_extract('limit', $options); if ($limit > 0) { $this->limit = $limit; + } else { + $this->limit = static::getDefaultLimit(); } $this->create = (bool) elgg_extract('create', $options, $this->create); @@ -98,6 +100,15 @@ public function advance(int $step = 1): void { $this->progressAdvance($step); } + + /** + * Get the default number of content to seed + * + * @return int + */ + public static function getDefaultLimit(): int { + return max(elgg_get_config('default_limit'), 20); + } /** * Populate database diff --git a/engine/classes/Elgg/Database/Seeds/Users.php b/engine/classes/Elgg/Database/Seeds/Users.php index 72730589ae6..a853301ea59 100644 --- a/engine/classes/Elgg/Database/Seeds/Users.php +++ b/engine/classes/Elgg/Database/Seeds/Users.php @@ -2,7 +2,9 @@ namespace Elgg\Database\Seeds; +use Elgg\Database\RiverTable; use Elgg\Database\Update; +use Elgg\Exceptions\Seeding\MaxAttemptsException; /** * Seed users @@ -36,15 +38,12 @@ public function seed() { } while ($this->getCount() < $this->limit) { - if ($this->create) { + try { $user = $this->createUser([], [ 'profile_fields' => $profile_fields, ]); - } else { - $user = $this->getRandomUser($exclude); - } - - if (!$user) { + } catch (MaxAttemptsException $e) { + // unable to create a user with the given options continue; } @@ -94,7 +93,7 @@ public function seed() { ]); /* @var $item \ElggRiverItem */ foreach ($river as $item) { - $update = Update::table('river'); + $update = Update::table(RiverTable::TABLE_NAME); $update->set('posted', $update->param($this->getRandomCreationTimestamp(), ELGG_VALUE_TIMESTAMP)) ->where($update->compare('id', '=', $item->id, ELGG_VALUE_ID)); @@ -113,7 +112,6 @@ public function seed() { * {@inheritdoc} */ public function unseed() { - /* @var $users \ElggBatch */ $users = elgg_get_entities([ 'type' => 'user', @@ -125,10 +123,12 @@ public function unseed() { /* @var $user \ElggUser */ foreach ($users as $user) { - if ($user->delete()) { + if ($user->delete(true, true)) { $this->log("Deleted user {$user->guid}"); } else { $this->log("Failed to delete user {$user->guid}"); + $users->reportFailure(); + continue; } $this->advance(); diff --git a/engine/classes/Elgg/Database/Select.php b/engine/classes/Elgg/Database/Select.php index 84f51b5f6ae..dd8e6326f6d 100644 --- a/engine/classes/Elgg/Database/Select.php +++ b/engine/classes/Elgg/Database/Select.php @@ -6,11 +6,16 @@ * Query builder for fetching data from the database */ class Select extends QueryBuilder { - + /** - * {@inheritdoc} + * Returns a QueryBuilder for selecting data from a given table + * + * @param string $table table name + * @param string|null $alias table alias + * + * @return static */ - public static function fromTable($table, $alias = null) { + public static function fromTable(string $table, string $alias = null): static { $connection = _elgg_services()->db->getConnection('read'); $qb = new static($connection); diff --git a/engine/classes/Elgg/Database/SessionHandler.php b/engine/classes/Elgg/Database/SessionHandler.php index 55ba3a3cf7b..abf74285f8d 100644 --- a/engine/classes/Elgg/Database/SessionHandler.php +++ b/engine/classes/Elgg/Database/SessionHandler.php @@ -17,17 +17,14 @@ class SessionHandler implements \SessionHandlerInterface { /** * @var string name of the users sessions database table */ - const TABLE_NAME = 'users_sessions'; - - protected Database $db; + public const TABLE_NAME = 'users_sessions'; /** * Constructor * * @param Database $db The database */ - public function __construct(Database $db) { - $this->db = $db; + public function __construct(protected Database $db) { } /** diff --git a/engine/classes/Elgg/Database/Update.php b/engine/classes/Elgg/Database/Update.php index cfa55261377..576c70ed1b4 100644 --- a/engine/classes/Elgg/Database/Update.php +++ b/engine/classes/Elgg/Database/Update.php @@ -6,14 +6,18 @@ * Query builder for updating data in the database */ class Update extends QueryBuilder { - + /** - * {@inheritdoc} + * Returns a QueryBuilder for updating data in a given table + * + * @param string $table table name + * + * @return static */ - public static function table($table, $alias = null) { + public static function table(string $table): static { $connection = _elgg_services()->db->getConnection('write'); $qb = new static($connection); - $qb->update($table, $alias); + $qb->update($table); return $qb; } diff --git a/engine/classes/Elgg/Database/UsersApiSessionsTable.php b/engine/classes/Elgg/Database/UsersApiSessionsTable.php index eb6e0d4f1d1..92f8ac121ff 100644 --- a/engine/classes/Elgg/Database/UsersApiSessionsTable.php +++ b/engine/classes/Elgg/Database/UsersApiSessionsTable.php @@ -19,11 +19,7 @@ class UsersApiSessionsTable { /** * @var string name of the users api sessions database table */ - const TABLE_NAME = 'users_apisessions'; - - protected Database $database; - - protected Crypto $crypto; + public const TABLE_NAME = 'users_apisessions'; /** * Create a new table handler @@ -31,9 +27,7 @@ class UsersApiSessionsTable { * @param Database $database the Elgg database handler * @param Crypto $crypto crypto handler */ - public function __construct(Database $database, Crypto $crypto) { - $this->database = $database; - $this->crypto = $crypto; + public function __construct(protected Database $database, protected Crypto $crypto) { } /** diff --git a/engine/classes/Elgg/Database/UsersRememberMeCookiesTable.php b/engine/classes/Elgg/Database/UsersRememberMeCookiesTable.php index ac84bdbfdc5..5e29350a614 100644 --- a/engine/classes/Elgg/Database/UsersRememberMeCookiesTable.php +++ b/engine/classes/Elgg/Database/UsersRememberMeCookiesTable.php @@ -18,17 +18,14 @@ class UsersRememberMeCookiesTable { /** * @var string name of the persistent cookies database table */ - const TABLE_NAME = 'users_remember_me_cookies'; + public const TABLE_NAME = 'users_remember_me_cookies'; - protected Database $database; - /** * Create a new service * * @param Database $database the database service */ - public function __construct(Database $database) { - $this->database = $database; + public function __construct(protected Database $database) { } /** diff --git a/engine/classes/Elgg/Di/DiContainer.php b/engine/classes/Elgg/Di/DiContainer.php index cf03d1cf3e7..5711ace1e90 100644 --- a/engine/classes/Elgg/Di/DiContainer.php +++ b/engine/classes/Elgg/Di/DiContainer.php @@ -52,7 +52,7 @@ public function __set($name, $value) { /** * {@inheritdoc} */ - public function set(string $name, $value) { + public function set(string $name, mixed $value): void { parent::set($name, $value); if (is_object($value)) { @@ -86,13 +86,11 @@ public function reset(string $name): void { /** * Create a DI Container * - * @param array $options additional options - * * @return self */ - public static function factory(array $options = []) { + public static function factory() { $dic_builder = new ContainerBuilder(static::class); - $dic_builder->useAnnotations(false); + $dic_builder->useAttributes(false); foreach (static::getDefinitionSources() as $location) { $dic_builder->addDefinitions($location); diff --git a/engine/classes/Elgg/Di/InternalContainer.php b/engine/classes/Elgg/Di/InternalContainer.php index 0adc88404ac..859d3dc7f4b 100644 --- a/engine/classes/Elgg/Di/InternalContainer.php +++ b/engine/classes/Elgg/Di/InternalContainer.php @@ -21,7 +21,6 @@ * @property-read \Elgg\Users\Accounts $accounts * @property-read \Elgg\Database\AdminNotices $adminNotices * @property-read \Elgg\Ajax\Service $ajax - * @property-read \Elgg\Amd\Config $amdConfig * @property-read \Elgg\Database\AnnotationsTable $annotationsTable * @property-read \Elgg\Database\ApiUsersTable $apiUsersTable * @property-read \Elgg\AuthenticationService $authentication @@ -51,6 +50,7 @@ * @property-read \Elgg\EntityCapabilitiesService $entity_capabilities * @property-read \Elgg\EntityPreloader $entityPreloader * @property-read \Elgg\Database\EntityTable $entityTable + * @property-read \Elgg\Javascript\ESMService $esm * @property-read \Elgg\EventsService $events * @property-read \Elgg\Assets\ExternalFiles $externalFiles * @property-read \Elgg\Forms\FieldsService $fields @@ -177,7 +177,7 @@ public function initConfig(Config $config): Config { * {@inheritDoc} */ public static function factory(array $options = []) { - $container = parent::factory($options); + $container = parent::factory(); if (isset($options['config'])) { $config = $options['config']; diff --git a/engine/classes/Elgg/Email/DelayedEmailService.php b/engine/classes/Elgg/Email/DelayedEmailService.php index 913a5b2bb58..275b897daa7 100644 --- a/engine/classes/Elgg/Email/DelayedEmailService.php +++ b/engine/classes/Elgg/Email/DelayedEmailService.php @@ -23,31 +23,8 @@ class DelayedEmailService { use Loggable; - /** - * @var DelayedEmailQueueTable - */ - protected $queue_table; - - /** - * @var EmailService - */ - protected $email; - - /** - * @var ViewsService - */ - protected $views; - - /** - * @var Translator - */ - protected $translator; - - /** - * @var Invoker - */ - protected $invoker; - + protected const NOTIFICATIONS_BATCH_SIZE = 500; + /** * Create a new service * @@ -57,12 +34,13 @@ class DelayedEmailService { * @param Translator $translator translator service * @param Invoker $invoker invoker serivce */ - public function __construct(DelayedEmailQueueTable $queue_table, EmailService $email, ViewsService $views, Translator $translator, Invoker $invoker) { - $this->queue_table = $queue_table; - $this->email = $email; - $this->views = $views; - $this->translator = $translator; - $this->invoker = $invoker; + public function __construct( + protected DelayedEmailQueueTable $queue_table, + protected EmailService $email, + protected ViewsService $views, + protected Translator $translator, + protected Invoker $invoker + ) { } /** @@ -100,46 +78,47 @@ public function processQueuedNotifications(string $delivery_interval, int $times return ($this->invoker->call(ELGG_IGNORE_ACCESS, function() use ($delivery_interval, $timestamp) { $count = 0; - $last_recipient_guid = null; - $notifications = []; // process one recipient - $processRecipient = function($row = null) use (&$last_recipient_guid, &$notifications, $delivery_interval, $timestamp) { + $processRecipient = function(int $recipient_guid, array $notifications, int $max_id) use ($delivery_interval, $timestamp) { try { - $this->processRecipientNotifications($last_recipient_guid, $notifications, $delivery_interval); + $this->processRecipientNotifications($recipient_guid, $notifications, $delivery_interval); } catch (\Throwable $t) { $this->getLogger()->error($t); } // cleanup the queue for this recipient - $this->queue_table->deleteRecipientRows($last_recipient_guid, $delivery_interval, $timestamp); - - // start collecting data for the new recipient - $last_recipient_guid = $row ? $row->recipient_guid : null; - $notifications = []; + return $this->queue_table->deleteRecipientRows($recipient_guid, $delivery_interval, $timestamp, $max_id); }; - $rows = $this->queue_table->getIntervalRows($delivery_interval, $timestamp); - foreach ($rows as $row) { - $count++; - - if (!isset($last_recipient_guid)) { - $last_recipient_guid = $row->recipient_guid; - } elseif ($last_recipient_guid !== $row->recipient_guid) { - // process one recipient - $processRecipient($row); - } - - $notfication = $row->getNotification(); - if (!$notfication instanceof Notification) { - continue; + // get the next recipient to process + $recipient_guid = $this->queue_table->getNextRecipientGUID($delivery_interval, $timestamp); + while ($recipient_guid > 0) { + // get a notification batch to process for this recipient + $rows = $this->queue_table->getRecipientRows($recipient_guid, $delivery_interval, $timestamp, self::NOTIFICATIONS_BATCH_SIZE); + while (!empty($rows)) { + $notifications = []; + $max_id = 0; + foreach ($rows as $row) { + $max_id = max($max_id, $row->id); + + $notification = $row->getNotification(); + if (!$notification instanceof Notification) { + continue; + } + + $notifications[] = $notification; + } + + // send all notifications in this batch + $count += $processRecipient($recipient_guid, $notifications, $max_id); + + // get next batch + $rows = $this->queue_table->getRecipientRows($recipient_guid, $delivery_interval, $timestamp, static::NOTIFICATIONS_BATCH_SIZE); } - $notifications[] = $notfication; - } - - if (isset($last_recipient_guid)) { - $processRecipient(); + // get next recipient to process + $recipient_guid = $this->queue_table->getNextRecipientGUID($delivery_interval, $timestamp); } return $count; diff --git a/engine/classes/Elgg/EmailService.php b/engine/classes/Elgg/EmailService.php index 0d2f26aee46..ab1cf831e07 100644 --- a/engine/classes/Elgg/EmailService.php +++ b/engine/classes/Elgg/EmailService.php @@ -28,41 +28,6 @@ class EmailService { use Loggable; - /** - * @var Config - */ - protected $config; - - /** - * @var EventsService - */ - protected $events; - - /** - * @var TransportInterface - */ - protected $mailer; - - /** - * @var HtmlFormatter - */ - protected $html_formatter; - - /** - * @var ImageFetcherService - */ - protected $image_fetcher; - - /** - * @var ViewsService - */ - protected $views; - - /** - * @var CssCompiler - */ - protected $css_compiler; - /** * Constructor * @@ -75,21 +40,14 @@ class EmailService { * @param CssCompiler $css_compiler Css compiler */ public function __construct( - Config $config, - EventsService $events, - TransportInterface $mailer, - HtmlFormatter $html_formatter, - ViewsService $views, - ImageFetcherService $image_fetcher, - CssCompiler $css_compiler - ) { - $this->config = $config; - $this->events = $events; - $this->mailer = $mailer; - $this->html_formatter = $html_formatter; - $this->views = $views; - $this->image_fetcher = $image_fetcher; - $this->css_compiler = $css_compiler; + protected Config $config, + protected EventsService $events, + protected TransportInterface $mailer, + protected HtmlFormatter $html_formatter, + protected ViewsService $views, + protected ImageFetcherService $image_fetcher, + protected CssCompiler $css_compiler + ) { } /** @@ -100,7 +58,7 @@ public function __construct( * @return bool * @throws RuntimeException */ - public function send(Email $email) { + public function send(Email $email): bool { $email = $this->events->triggerResults('prepare', 'system:email', [], $email); if (!$email instanceof Email) { $msg = "'prepare','system:email' event handlers should return an instance of " . Email::class; @@ -123,8 +81,7 @@ public function send(Email $email) { * @return bool * @throws RuntimeException */ - public function transport(Email $email) { - + public function transport(Email $email): bool { if ($this->events->triggerResults('transport', 'system:email', ['email' => $email], false)) { return true; } diff --git a/engine/classes/Elgg/Entity/CropIcon.php b/engine/classes/Elgg/Entity/CropIcon.php index 74afb1fdc6d..73881ff9f7d 100644 --- a/engine/classes/Elgg/Entity/CropIcon.php +++ b/engine/classes/Elgg/Entity/CropIcon.php @@ -71,30 +71,7 @@ protected function prepareUpload(int $entity_guid, string $input_name, string $i return; } - $current = []; - if ($icon_type === 'icon') { - $current = [ - 'x1' => $entity->x1, - 'y1' => $entity->y1, - 'x2' => $entity->x2, - 'y2' => $entity->y2, - ]; - } elseif (isset($entity->{"{$icon_type}_coords"})) { - $current = unserialize($entity->{"{$icon_type}_coords"}); - - if (!is_array($current)) { - $current = []; - } - } - - // cast to ints - array_walk($current, function(&$value) { - $value = (int) $value; - }); - // remove invalid values - $current = array_filter($current, function($value) { - return $value >= 0; - }); + $current = $entity->getIconCoordinates($icon_type); $input_cropping_coords = [ 'x1' => (int) get_input("{$input_name}_x1", get_input('x1')), diff --git a/engine/classes/Elgg/Entity/RemoveDeletedEntitiesHandler.php b/engine/classes/Elgg/Entity/RemoveDeletedEntitiesHandler.php new file mode 100644 index 00000000000..1735cd65451 --- /dev/null +++ b/engine/classes/Elgg/Entity/RemoveDeletedEntitiesHandler.php @@ -0,0 +1,72 @@ + false, + 'batch' => true, + 'batch_inc_offset' => false, + 'wheres' => [ + function(QueryBuilder $qb, $main_alias) { + // only deleted items + return $qb->compare("{$main_alias}.deleted", '=', 'yes', ELGG_VALUE_STRING); + }, + function(QueryBuilder $qb, $main_alias) use ($retention) { + // past the retention period + return $qb->compare("{$main_alias}.time_deleted", '<', \Elgg\Values::normalizeTimestamp("-{$retention} days"), ELGG_VALUE_TIMESTAMP); + }, + function(QueryBuilder $qb, $main_alias) { + // get only the root deleted items (not the related/sub items) + // the related items will be deleted with the root item + $sub = $qb->subquery(RelationshipsTable::TABLE_NAME); + $sub->select('guid_one') + ->where($qb->compare('relationship', '=', 'deleted_with')); + + return $qb->compare("{$main_alias}.guid", 'not in', $sub->getSQL()); + } + ], + 'sort_by' => [ + 'property' => 'time_deleted', + 'direction' => 'ASC', + ], + ]); + + $starttime = microtime(true); + + /* @var $entity \ElggEntity */ + foreach ($entities as $entity) { + if ((microtime(true) - $starttime) > 300) { + // limit the cleanup to 5 minutes + break; + } + + if (!$entity->delete(true, true)) { + $entities->reportFailure(); + } + } + }); + } +} diff --git a/engine/classes/Elgg/EntityIcon.php b/engine/classes/Elgg/EntityIcon.php deleted file mode 100644 index 4c383b70bb0..00000000000 --- a/engine/classes/Elgg/EntityIcon.php +++ /dev/null @@ -1,85 +0,0 @@ - the size of the icon (default: medium) - * string 'type' => the icon type (default: icon) - * @return string - */ - public function getIconURL(array $params): string; - - /** - * Returns the timestamp of when the icon was changed. - * - * @param string $size The size of the icon - * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' - * - * @return int|null A unix timestamp of when the icon was last changed, or null if not set. - */ - public function getIconLastChange(string $size, string $type = 'icon'): ?int; - - /** - * Returns if the entity has an icon of the passed type. - * - * @param string $size The size of the icon - * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' - * @return bool - */ - public function hasIcon(string $size, string $type = 'icon'): bool; -} diff --git a/engine/classes/Elgg/EntityIconService.php b/engine/classes/Elgg/EntityIconService.php index 6b28557fe1a..b82835adc6c 100644 --- a/engine/classes/Elgg/EntityIconService.php +++ b/engine/classes/Elgg/EntityIconService.php @@ -22,41 +22,6 @@ class EntityIconService { use Loggable; use TimeUsing; - /** - * @var Config - */ - private $config; - - /** - * @var EventsService - */ - private $events; - - /** - * @var EntityTable - */ - private $entities; - - /** - * @var UploadService - */ - private $uploads; - - /** - * @var ImageService - */ - private $images; - - /** - * @var MimeTypeService - */ - protected $mimetype; - - /** - * @var HttpRequest - */ - protected $request; - /** * Constructor * @@ -69,21 +34,14 @@ class EntityIconService { * @param Request $request Http Request service */ public function __construct( - Config $config, - EventsService $events, - EntityTable $entities, - UploadService $uploads, - ImageService $images, - MimeTypeService $mimetype, - HttpRequest $request + protected Config $config, + protected EventsService $events, + protected EntityTable $entities, + protected UploadService $uploads, + protected ImageService $images, + protected MimeTypeService $mimetype, + protected HttpRequest $request ) { - $this->config = $config; - $this->events = $events; - $this->entities = $entities; - $this->uploads = $uploads; - $this->images = $images; - $this->mimetype = $mimetype; - $this->request = $request; } /** @@ -96,7 +54,7 @@ public function __construct( * * @return bool */ - public function saveIconFromUploadedFile(\ElggEntity $entity, $input_name, $type = 'icon', array $coords = []) { + public function saveIconFromUploadedFile(\ElggEntity $entity, string $input_name, string $type = 'icon', array $coords = []): bool { $input = $this->uploads->getFile($input_name); if (empty($input)) { return false; @@ -138,7 +96,7 @@ public function saveIconFromUploadedFile(\ElggEntity $entity, $input_name, $type * @return bool * @throws InvalidArgumentException */ - public function saveIconFromLocalFile(\ElggEntity $entity, $filename, $type = 'icon', array $coords = []) { + public function saveIconFromLocalFile(\ElggEntity $entity, string $filename, string $type = 'icon', array $coords = []): bool { if (!file_exists($filename) || !is_readable($filename)) { throw new InvalidArgumentException(__METHOD__ . " expects a readable local file. {$filename} is not readable"); } @@ -171,7 +129,7 @@ public function saveIconFromLocalFile(\ElggEntity $entity, $filename, $type = 'i * @return bool * @throws InvalidArgumentException */ - public function saveIconFromElggFile(\ElggEntity $entity, \ElggFile $file, $type = 'icon', array $coords = []) { + public function saveIconFromElggFile(\ElggEntity $entity, \ElggFile $file, string $type = 'icon', array $coords = []): bool { if (!$file->exists()) { throw new InvalidArgumentException(__METHOD__ . ' expects an instance of ElggFile with an existing file on filestore'); } @@ -203,9 +161,7 @@ public function saveIconFromElggFile(\ElggEntity $entity, \ElggFile $file, $type * * @return bool */ - public function saveIcon(\ElggEntity $entity, \ElggFile $file, $type = 'icon', array $coords = []) { - - $type = (string) $type; + public function saveIcon(\ElggEntity $entity, \ElggFile $file, string $type = 'icon', array $coords = []): bool { if (!strlen($type)) { $this->getLogger()->error('Icon type passed to ' . __METHOD__ . ' can not be empty'); return false; @@ -223,6 +179,8 @@ public function saveIcon(\ElggEntity $entity, \ElggFile $file, $type = 'icon', a return false; } + $entity->lockIconThumbnailGeneration($type); + $this->prepareIcon($file->getFilenameOnFilestore()); $x1 = (int) elgg_extract('x1', $coords); @@ -269,23 +227,13 @@ public function saveIcon(\ElggEntity $entity, \ElggFile $file, $type = 'icon', a } } - if ($type == 'icon') { - $entity->icontime = time(); - if ($x1 || $y1 || $x2 || $y2) { - $entity->x1 = $x1; - $entity->y1 = $y1; - $entity->x2 = $x2; - $entity->y2 = $y2; - } - } else { - if ($x1 || $y1 || $x2 || $y2) { - $entity->{"{$type}_coords"} = serialize([ - 'x1' => $x1, - 'y1' => $y1, - 'x2' => $x2, - 'y2' => $y2, - ]); - } + // first invalidate entity metadata cache, because of a high risk of racing condition to save the coordinates + // the racing condition occurs with 2 (or more) icon save calls and the time between clearing + // the coordinates in deleteIcon() and the new save here + $entity->invalidateCache(); + + if ($x1 || $y1 || $x2 || $y2) { + $entity->saveIconCoordinates($coords, $type); } $this->events->triggerResults("entity:{$type}:saved", $entity->getType(), [ @@ -296,6 +244,8 @@ public function saveIcon(\ElggEntity $entity, \ElggFile $file, $type = 'icon', a 'y2' => $y2, ]); + $entity->unlockIconThumbnailGeneration($type); + return true; } @@ -306,8 +256,7 @@ public function saveIcon(\ElggEntity $entity, \ElggFile $file, $type = 'icon', a * * @return void */ - protected function prepareIcon($filename) { - + protected function prepareIcon(string $filename): void { // fix orientation $temp_file = new \ElggTempFile(); $temp_file->setFilename(uniqid() . basename($filename)); @@ -334,8 +283,7 @@ protected function prepareIcon($filename) { * * @return bool */ - protected function generateIcon(\ElggEntity $entity, \ElggFile $file, $type = 'icon', $coords = [], $icon_size = '') { - + protected function generateIcon(\ElggEntity $entity, \ElggFile $file, string $type = 'icon', array $coords = [], string $icon_size = ''): bool { if (!$file->exists()) { $this->getLogger()->error('Trying to generate an icon from a non-existing file'); return false; @@ -395,6 +343,12 @@ protected function generateIcon(\ElggEntity $entity, \ElggFile $file, $type = 'i if (!_elgg_services()->imageService->resize($source, $destination, $resize_params)) { $this->getLogger()->error("Failed to create {$size} icon from {$file->getFilenameOnFilestore()} with coords [{$x1}, {$y1}],[{$x2}, {$y2}]"); + + if ($size !== 'master') { + // remove 0 byte icon in order to retry the resize on the next request + $icon->delete(); + } + return false; } } @@ -417,8 +371,7 @@ protected function generateIcon(\ElggEntity $entity, \ElggFile $file, $type = 'i * * @throws UnexpectedValueException */ - public function getIcon(\ElggEntity $entity, $size, $type = 'icon', $generate = true) { - + public function getIcon(\ElggEntity $entity, string $size, string $type = 'icon', bool $generate = true): \ElggIcon { $size = elgg_strtolower($size); $params = [ @@ -453,23 +406,17 @@ public function getIcon(\ElggEntity $entity, $size, $type = 'icon', $generate = return $icon; } + if ($entity->isIconThumbnailGenerationLocked($type)) { + return $icon; + } + // try to generate icon based on master size $master_icon = $this->getIcon($entity, 'master', $type, false); if (!$master_icon->exists()) { return $icon; } - if ($type === 'icon') { - $coords = [ - 'x1' => $entity->x1, - 'y1' => $entity->y1, - 'x2' => $entity->x2, - 'y2' => $entity->y2, - ]; - } else { - $coords = $entity->{"{$type}_coords"}; - $coords = empty($coords) ? [] : unserialize($coords); - } + $coords = $entity->getIconCoordinates($type); $this->generateIcon($entity, $master_icon, $type, $coords, $size); @@ -485,9 +432,10 @@ public function getIcon(\ElggEntity $entity, $size, $type = 'icon', $generate = * * @return bool */ - public function deleteIcon(\ElggEntity $entity, $type = 'icon', $retain_master = false) { + public function deleteIcon(\ElggEntity $entity, string $type = 'icon', bool $retain_master = false): bool { $delete = $this->events->triggerResults("entity:{$type}:delete", $entity->getType(), [ 'entity' => $entity, + 'retain_master' => $retain_master, // just removing thumbs or everything? ], true); if ($delete === false) { @@ -531,15 +479,7 @@ public function deleteIcon(\ElggEntity $entity, $type = 'icon', $retain_master = } } - if ($type == 'icon') { - unset($entity->icontime); - unset($entity->x1); - unset($entity->y1); - unset($entity->x2); - unset($entity->y2); - } else { - unset($entity->{"{$type}_coords"}); - } + $entity->removeIconCoordinates($type); return $result; } @@ -597,7 +537,7 @@ public function getIconURL(\ElggEntity $entity, string|array $params = []): stri * * @return string */ - public function getFallbackIconUrl(\ElggEntity $entity, array $params = []) { + public function getFallbackIconUrl(\ElggEntity $entity, array $params = []): string { $type = elgg_extract('type', $params, 'icon', false); $size = elgg_extract('size', $params, 'medium', false); @@ -621,6 +561,8 @@ public function getFallbackIconUrl(\ElggEntity $entity, array $params = []) { if (elgg_view_exists("{$type}/default/{$size}.png", 'default')) { return elgg_get_simplecache_url("{$type}/default/{$size}.png"); } + + return ''; } /** @@ -632,11 +574,13 @@ public function getFallbackIconUrl(\ElggEntity $entity, array $params = []) { * * @return int|null A unix timestamp of when the icon was last changed, or null if not set. */ - public function getIconLastChange(\ElggEntity $entity, $size, $type = 'icon') { + public function getIconLastChange(\ElggEntity $entity, string $size, string $type = 'icon'): ?int { $icon = $this->getIcon($entity, $size, $type); if ($icon->exists()) { return $icon->getModifiedTime(); } + + return null; } /** @@ -648,7 +592,7 @@ public function getIconLastChange(\ElggEntity $entity, $size, $type = 'icon') { * * @return bool */ - public function hasIcon(\ElggEntity $entity, $size, $type = 'icon') { + public function hasIcon(\ElggEntity $entity, string $size, string $type = 'icon'): bool { $icon = $this->getIcon($entity, $size, $type); return $icon->exists() && $icon->getSize() > 0; } @@ -709,10 +653,9 @@ public function getSizes(string $entity_type = null, string $entity_subtype = nu * * @param string $input_name the file input name which is the prefix for the cropping coordinates * - * @return false|array + * @return null|array */ - protected function detectCroppingCoordinates(string $input_name) { - + protected function detectCroppingCoordinates(string $input_name): ?array { $auto_coords = [ 'x1' => get_input("{$input_name}_x1", get_input('x1')), // x1 is BC fallback 'x2' => get_input("{$input_name}_x2", get_input('x2')), // x2 is BC fallback @@ -725,7 +668,7 @@ protected function detectCroppingCoordinates(string $input_name) { }); if (count($auto_coords) !== 4) { - return false; + return null; } // make ints @@ -735,7 +678,7 @@ protected function detectCroppingCoordinates(string $input_name) { // make sure coords make sense x2 > x1 && y2 > y1 if ($auto_coords['x2'] <= $auto_coords['x1'] || $auto_coords['y2'] <= $auto_coords['y1']) { - return false; + return null; } return $auto_coords; diff --git a/engine/classes/Elgg/EntityPreloader.php b/engine/classes/Elgg/EntityPreloader.php index 4ffba4b1fe5..f35d7fb0f5b 100644 --- a/engine/classes/Elgg/EntityPreloader.php +++ b/engine/classes/Elgg/EntityPreloader.php @@ -2,9 +2,8 @@ namespace Elgg; -use Elgg\Database\EntityTable; -use Elgg\Database\Entities; use Elgg\Cache\EntityCache; +use Elgg\Database\Entities; /** * Preload entities based on properties of fetched objects @@ -12,7 +11,9 @@ * @internal */ class EntityPreloader { - + + const MAX_PRELOAD = 256; + /** * @var callable * @internal DO NOT USE. For unit test mocking @@ -28,11 +29,11 @@ class EntityPreloader { /** * Constructor * - * @param EntityTable $entity_table Entity service + * @param EntityCache $entity_cache Entity cache */ - public function __construct(EntityTable $entity_table) { - $this->_callable_cache_checker = function ($guid) use ($entity_table) { - return $entity_table->getFromCache($guid); + public function __construct(EntityCache $entity_cache) { + $this->_callable_cache_checker = function ($guid) use ($entity_cache) { + return $entity_cache->load($guid); }; $this->_callable_entity_loader = function ($options) { return Entities::find($options); @@ -56,7 +57,7 @@ public function preload($objects, array $guid_properties) { if (count($guids) > 1) { call_user_func($this->_callable_entity_loader, [ 'guids' => $guids, - 'limit' => EntityCache::MAX_SIZE, + 'limit' => self::MAX_PRELOAD, 'order_by' => false, ]); } diff --git a/engine/classes/Elgg/Event.php b/engine/classes/Elgg/Event.php index 262e37cc8ac..b82c7fbb80a 100644 --- a/engine/classes/Elgg/Event.php +++ b/engine/classes/Elgg/Event.php @@ -10,31 +10,6 @@ */ class Event { - /** - * @var PublicContainer - */ - protected $dic; - - /** - * @var string - */ - protected $name; - - /** - * @var string - */ - protected $type; - - /** - * @var mixed - */ - protected $value; - - /** - * @var mixed - */ - protected $params; - /** * Constructor * @@ -44,12 +19,13 @@ class Event { * @param mixed $value Event value * @param mixed $params Event params */ - public function __construct(PublicContainer $dic, string $name, string $type, $value = null, $params = []) { - $this->dic = $dic; - $this->name = $name; - $this->type = $type; - $this->value = $value; - $this->params = $params; + public function __construct( + protected PublicContainer $dic, + protected string $name, + protected string $type, + protected $value = null, + protected $params = [] + ) { } /** diff --git a/engine/classes/Elgg/EventsService.php b/engine/classes/Elgg/EventsService.php index 5c3a5c9d26a..cf09fbe4f59 100644 --- a/engine/classes/Elgg/EventsService.php +++ b/engine/classes/Elgg/EventsService.php @@ -22,34 +22,26 @@ class EventsService { const REG_KEY_HANDLER = 2; const OPTION_STOPPABLE = 'stoppable'; + const OPTION_USE_TIMER = 'use_timer'; + const OPTION_TIMER_KEYS = 'timer_keys'; + const OPTION_BEGIN_CALLBACK = 'begin_callback'; + const OPTION_END_CALLBACK = 'end_callback'; - /** - * @var HandlersService - */ - protected $handlers; - - /** - * @var int - */ - protected $next_index = 0; + protected int $next_index = 0; /** * @var array [name][type][] = registration */ - protected $registrations = []; + protected array $registrations = []; - /** - * @var array - */ - protected $backups = []; + protected array $backups = []; /** * Constructor * * @param HandlersService $handlers Handlers */ - public function __construct(HandlersService $handlers) { - $this->handlers = $handlers; + public function __construct(protected HandlersService $handlers) { } /** @@ -70,7 +62,13 @@ public function trigger(string $name, string $type, $object = null, array $optio $options = array_merge([ self::OPTION_STOPPABLE => true, ], $options); - + + // allow for the profiling of system events (when enabled) + if ($this->hasTimer() && $type === 'system' && $name !== 'shutdown') { + $options[self::OPTION_USE_TIMER] = true; + $options[self::OPTION_TIMER_KEYS] = ["[{$name},{$type}]"]; + } + // get registered handlers $handlers = $this->getOrderedHandlers($name, $type); @@ -79,26 +77,17 @@ public function trigger(string $name, string $type, $object = null, array $optio // creating objects for every triggering is expensive. /* @var $event Event|string */ $event = 'event'; + $event_args = [ + $name, + $type, + null, + [ + 'object' => $object, + '_elgg_sequence_id' => elgg_extract('_elgg_sequence_id', $options), + ], + ]; foreach ($handlers as $handler) { - $handler_description = false; - if ($this->hasTimer() && $type === 'system' && $name !== 'shutdown') { - $handler_description = $this->handlers->describeCallable($handler) . '()'; - $this->beginTimer(["[{$name},{$type}]", $handler_description]); - } - - list($success, $return, $event) = $this->handlers->call($handler, $event, [ - $name, - $type, - null, - [ - 'object' => $object, - '_elgg_sequence_id' => elgg_extract('_elgg_sequence_id', $options), - ], - ]); - - if ($handler_description) { - $this->endTimer(["[{$name},{$type}]", $handler_description]); - } + list($success, $return, $event) = $this->callHandler($handler, $event, $event_args, $options); if (!$success) { continue; @@ -115,23 +104,26 @@ public function trigger(string $name, string $type, $object = null, array $optio /** * Triggers a event that is allowed to return a mixed result * - * @param string $name The name of the event - * @param string $type The type of the event - * @param mixed $params Supplied params for the event - * @param mixed $value The value of the event, this can be altered by registered callbacks + * @param string $name The name of the event + * @param string $type The type of the event + * @param mixed $params Supplied params for the event + * @param mixed $value The value of the event, this can be altered by registered callbacks + * @param array $options (internal) options for triggering the event * * @return mixed * * @see elgg_trigger_event_results() */ - public function triggerResults(string $name, string $type, array $params = [], $value = null) { + public function triggerResults(string $name, string $type, array $params = [], $value = null, array $options = []) { // This starts as a string, but if a handler type-hints an object we convert it on-demand inside // \Elgg\HandlersService::call and keep it alive during all handler calls. We do this because // creating objects for every triggering is expensive. /* @var $event Event|string */ $event = 'event'; foreach ($this->getOrderedHandlers($name, $type) as $handler) { - list($success, $return, $event) = $this->handlers->call($handler, $event, [$name, $type, $value, $params]); + $event_args = [$name, $type, $value, $params]; + + list($success, $return, $event) = $this->callHandler($handler, $event, $event_args, $options); if (!$success) { continue; @@ -194,7 +186,7 @@ public function triggerAfter(string $name, string $type, $object = null, array $ } /** - * Trigger an sequence of :before, , and :after handlers. + * Trigger a sequence of :before, , and :after handlers. * Allows :before to terminate the sequence by returning false from a handler * Allows running a callable on successful before :after is triggered * Returns the result of the callable or bool @@ -224,7 +216,9 @@ public function triggerSequence(string $name, string $type, $object = null, call $result = call_user_func($callable, $object); } - $this->triggerAfter($name, $type, $object, $options); + if ($result !== false) { + $this->triggerAfter($name, $type, $object, $options); + } return $result; } @@ -253,7 +247,7 @@ public function triggerResultsSequence(string $name, string $type, array $params return false; } - $result = $this->triggerResults($name, $type, $params, $value); + $result = $this->triggerResults($name, $type, $params, $value, $options); if ($result === false) { return false; } @@ -262,7 +256,9 @@ public function triggerResultsSequence(string $name, string $type, array $params $result = call_user_func($callable, $params); } - $this->triggerAfter($name, $type, $params, $options); + if ($result !== false) { + $this->triggerAfter($name, $type, $params, $options); + } return $result; } @@ -275,16 +271,17 @@ public function triggerResultsSequence(string $name, string $type, array $params * @param mixed $object The object involved in the event * @param string $message The deprecation message * @param string $version Human-readable *release* version: 1.9, 1.10, ... + * @param array $options (internal) options for triggering the event * * @return bool * * @see elgg_trigger_deprecated_event() */ - public function triggerDeprecated(string $name, string $type, $object = null, string $message = '', string $version = ''): bool { + public function triggerDeprecated(string $name, string $type, $object = null, string $message = '', string $version = '', array $options = []): bool { $message = "The '{$name}', '{$type}' event is deprecated. {$message}"; $this->checkDeprecation($name, $type, $message, $version); - return $this->trigger($name, $type, $object); + return $this->trigger($name, $type, $object, $options); } /** @@ -296,16 +293,17 @@ public function triggerDeprecated(string $name, string $type, $object = null, st * @param mixed $returnvalue The return value * @param string $message The deprecation message * @param string $version Human-readable *release* version: 1.9, 1.10, ... + * @param array $options (internal) options for triggering the event * * @return mixed * * @see elgg_trigger_deprecated_event_results() */ - public function triggerDeprecatedResults(string $name, string $type, array $params = [], $returnvalue = null, string $message = '', string $version = '') { + public function triggerDeprecatedResults(string $name, string $type, array $params = [], $returnvalue = null, string $message = '', string $version = '', array $options = []) { $message = "The '{$name}', '{$type}' event is deprecated. {$message}"; $this->checkDeprecation($name, $type, $message, $version); - return $this->triggerResults($name, $type, $params, $returnvalue); + return $this->triggerResults($name, $type, $params, $returnvalue, $options); } /** @@ -326,14 +324,9 @@ public function registerHandler(string $name, string $type, $callback, int $prio return false; } - if (($name == 'view' || $name == 'view_vars') && $type !== 'all') { - $type = ViewsService::canonicalizeViewName($type); - } - - $services = _elgg_services(); if (in_array($this->getLogger()->getLevel(false), [LogLevel::WARNING, LogLevel::NOTICE, LogLevel::INFO, LogLevel::DEBUG])) { - if (!$services->handlers->isCallable($callback)) { - $this->getLogger()->warning('Handler: ' . $services->handlers->describeCallable($callback) . ' is not callable'); + if (!$this->handlers->isCallable($callback)) { + $this->getLogger()->warning('Handler: ' . $this->handlers->describeCallable($callback) . ' is not callable'); } } @@ -358,10 +351,6 @@ public function registerHandler(string $name, string $type, $callback, int $prio * @return void */ public function unregisterHandler(string $name, string $type, $callback): void { - if (($name === 'view' || $name === 'view_vars') && $type !== 'all') { - $type = ViewsService::canonicalizeViewName($type); - } - if (empty($this->registrations[$name][$type])) { return; } @@ -567,4 +556,55 @@ protected function checkDeprecation(string $name, string $type, string $message, $this->logDeprecatedMessage($message, $version); } + + /** + * @param callable $callable Callable + * @param mixed $event Event object + * @param array $args Event arguments + * @param array $options (internal) options for triggering the event + * + * @return array [success, result, object] + */ + protected function callHandler($callable, $event, array $args, array $options = []): array { + // call a function before the actual callable + $begin_callback = elgg_extract(self::OPTION_BEGIN_CALLBACK, $options); + if (is_callable($begin_callback)) { + call_user_func($begin_callback, [ + 'callable' => $callable, + 'readable_callable' => $this->handlers->describeCallable($callable), + 'event' => $event, + 'arguments' => $args, + ]); + } + + // time the callable function + $use_timer = (bool) elgg_extract(self::OPTION_USE_TIMER, $options, false); + $timer_keys = (array) elgg_extract(self::OPTION_TIMER_KEYS, $options, []); + if ($use_timer) { + $timer_keys[] = $this->handlers->describeCallable($callable); + $this->beginTimer($timer_keys); + } + + // execute the callable function + $results = $this->handlers->call($callable, $event, $args); + + // end the timer + if ($use_timer) { + $this->endTimer($timer_keys); + } + + // call a function after the actual callable + $end_callback = elgg_extract(self::OPTION_END_CALLBACK, $options); + if (is_callable($end_callback)) { + call_user_func($end_callback, [ + 'callable' => $callable, + 'readable_callable' => $this->handlers->describeCallable($callable), + 'event' => $event, + 'arguments' => $args, + 'results' => $results, + ]); + } + + return $results; + } } diff --git a/engine/classes/Elgg/Export/Data.php b/engine/classes/Elgg/Export/Data.php index 33194cb52af..ff5bd048479 100644 --- a/engine/classes/Elgg/Export/Data.php +++ b/engine/classes/Elgg/Export/Data.php @@ -2,25 +2,26 @@ namespace Elgg\Export; -use ArrayObject; -use DateTime; +use Elgg\I18n\DateTime; +use Elgg\Values; /** * Exported representation of an ElggData instance * * @property string $time_created */ -abstract class Data extends ArrayObject { +abstract class Data extends \ArrayObject { /** * {@inheritdoc} */ - public function __construct($input = [], int $flags = ArrayObject::ARRAY_AS_PROPS, string $iterator_class = 'ArrayIterator') { + public function __construct($input = [], int $flags = \ArrayObject::ARRAY_AS_PROPS, string $iterator_class = \ArrayIterator::class) { parent::__construct($input, $flags, $iterator_class); } /** * Get time created + * * @return DateTime|null */ public function getTimeCreated() { @@ -28,6 +29,6 @@ public function getTimeCreated() { return null; } - return new DateTime($this->time_created); + return Values::normalizeTime($this->time_created); } } diff --git a/engine/classes/Elgg/Export/Entity.php b/engine/classes/Elgg/Export/Entity.php index 92c53062630..a72a1be28a5 100644 --- a/engine/classes/Elgg/Export/Entity.php +++ b/engine/classes/Elgg/Export/Entity.php @@ -2,7 +2,8 @@ namespace Elgg\Export; -use DateTime; +use Elgg\I18n\DateTime; +use Elgg\Values; /** * Entity export representation @@ -15,12 +16,12 @@ * @property string $time_updated * @property string $url * @property int $read_access - * */ class Entity extends Data { /** - * Get updated tme + * Get updated time + * * @return DateTime|null */ public function getTimeUpdated() { @@ -28,6 +29,6 @@ public function getTimeUpdated() { return null; } - return new DateTime($this->time_created); + return Values::normalizeTime($this->time_created); } } diff --git a/engine/classes/Elgg/FileService/File.php b/engine/classes/Elgg/FileService/File.php index 00649ab0cf2..31a36836a86 100644 --- a/engine/classes/Elgg/FileService/File.php +++ b/engine/classes/Elgg/FileService/File.php @@ -3,6 +3,7 @@ namespace Elgg\FileService; use Elgg\Exceptions\DomainException; +use Elgg\Project\Paths; use Elgg\Security\Base64Url; /** @@ -105,8 +106,8 @@ public function getURL(): ?string { } $relative_path = ''; - $root_prefix = _elgg_services()->config->dataroot; - $path = $this->file->getFilenameOnFilestore(); + $root_prefix = Paths::sanitize(_elgg_services()->config->dataroot); + $path = Paths::sanitize($this->file->getFilenameOnFilestore(), false); if (str_starts_with($path, $root_prefix)) { $relative_path = substr($path, strlen($root_prefix)); } diff --git a/engine/classes/Elgg/Filesystem/Directory.php b/engine/classes/Elgg/Filesystem/Directory.php deleted file mode 100644 index 19ef29c30a8..00000000000 --- a/engine/classes/Elgg/Filesystem/Directory.php +++ /dev/null @@ -1,120 +0,0 @@ - - * - * @throws InvalidArgumentException - */ - public function getFiles($path = '', $recursive = true); - - /** - * List the directories in the given directory path. - * - * @param string $path The subdirectory path within this directory - * @param bool $recursive Find directories recursively - * - * @return \Elgg\Structs\Collection\InMemory - * - * @throws InvalidArgumentException - */ - public function getDirectories($path = '', $recursive = true); - - /** - * Get the absolute path to the given directory-relative path. - * - * @param string $path A file/directory path within this directory. - * - * @return string - * - * @throws InvalidArgumentException - */ - public function getPath($path = ''); - - /** - * Do a PHP include of the file and return the result. - * - * NB: This only really works with local filesystems amirite? - * - * @param string $path Filesystem-relative path for the file to include. - * - * @return mixed - * - * @throws InvalidArgumentException - */ - public function includeFile($path); - - /** - * Whether this directory has an existing file at the given location. - * - * @param string $path The relative path within this directory - * - * @return boolean - * - * @throws InvalidArgumentException - */ - public function isFile($path); - - /** - * Write a file, overwriting the contents if necessary. - * - * @param string $path The path to the file. - * @param string $content The literal text content of the file. - * - * @return void - * - * @throws InvalidArgumentException - */ - public function putContents($path, $content); -} diff --git a/engine/classes/Elgg/Filesystem/Directory/Fly.php b/engine/classes/Elgg/Filesystem/Directory/Fly.php deleted file mode 100644 index 22cad786e16..00000000000 --- a/engine/classes/Elgg/Filesystem/Directory/Fly.php +++ /dev/null @@ -1,210 +0,0 @@ -fs = $filesystem; - $this->local_path = rtrim(strtr($local_path, '\\', '/'), '/\\'); - $this->chroot = $this->normalize($chroot); - } - - /** - * {@inheritDoc} - */ - public function chroot($path) { - return new self($this->fs, $this->local_path, $path); - } - - /** - * Whether this filesystem has an existing directory at the given path. - * - * @param string $path The path to the directory, relative to this filesystem. - * - * @return boolean - */ - private function isDirectory($path) { - $path = $this->getInternalPath($path); - return !empty($this->fs->listContents($path)->toArray()); - } - - /** - * {@inheritDoc} - */ - public function isFile($path) { - return $this->fs->fileExists($this->getInternalPath($path)); - } - - /** - * {@inheritDoc} - */ - public function getContents($path) { - return (string) $this->fs->read($this->getInternalPath($path)); - } - - /** - * {@inheritDoc} - * - * @throws RuntimeException - */ - public function getFile($path) { - if ($this->isDirectory($path)) { - throw new RuntimeException("There is already a directory at that location: {$path}"); - } - - return new File($this, $path); - } - - /** - * {@inheritDoc} - */ - public function getFiles($path = '', $recursive = true) { - return $this->getEntries($path, $recursive, ['file']); - } - - /** - * {@inheritDoc} - */ - public function getDirectories($path = '', $recursive = true) { - return $this->getEntries($path, $recursive, ['dir']); - } - - /** - * List the files and directories in the given directory path. - * - * @param string $path The subdirectory path within this directory - * @param bool $recursive Find files and directories recursively - * @param string[] $types Entry types to return ('file' and/or 'dir') - * - * @return Collection - */ - protected function getEntries($path = '', $recursive = true, $types = ['file', 'dir']) { - $contents = $this->fs->listContents($this->getInternalPath($path), $recursive)->toArray(); - if (empty($contents)) { - $contents = []; - } - - $contents = array_filter($contents, function ($metadata) use ($types) { - return in_array($metadata['type'], $types); - }); - - return Collection\InMemory::fromArray(array_map(function ($metadata) { - if ($metadata['type'] === 'file') { - return new File($this, $metadata['path']); - } - - return new self($this->fs, $this->local_path, $metadata['path']); - }, $contents)); - } - - /** - * {@inheritDoc} - */ - public function getPath($path = '') { - $path = $this->normalize($this->getInternalPath($path)); - return "{$this->local_path}/$path"; - } - - /** - * Get a path suitable for passing to the underlying filesystem. - * - * @param string $path The path relative to this directory. - * - * @return string - */ - private function getInternalPath($path) { - $path = strtr($path, '\\', '//'); - return $this->normalize("{$this->chroot}/$path"); - } - - /** - * {@inheritDoc} - */ - public function includeFile($path) { - return include $this->getPath($path); - } - - /** - * {@inheritDoc} - */ - public function putContents($path, $content) { - $this->fs->write($this->getInternalPath($path), $content); - } - - /** - * Shorthand for generating a new local filesystem. - * - * @param string $path absolute path to directory on local filesystem. - * - * @return Directory - */ - public static function createLocal($path) { - $fs = new Filesystem(new LocalAdapter($path)); - return new self($fs, $path); - } - - /** - * Shorthand for generating a new in-memory-only filesystem. - * - * @return Directory - */ - public static function createInMemory() { - $fs = new Filesystem(new InMemoryFilesystemAdapter()); - return new self($fs); - } - - /** - * Get a standardized form of the given path to work with internally. - * - * @param string $path A relative path within this filesystem - * - * @return string - * @throws InvalidArgumentException - */ - private function normalize($path) { - $test_path = "/{$path}/"; - if (str_contains($test_path, '/./') || str_contains($test_path, '/../')) { - throw new InvalidArgumentException('Paths cannot contain "." or ".."'); - } - - return trim(strtr($path, '\\', '/'), '/'); - } -} diff --git a/engine/classes/Elgg/Filesystem/Directory/InMemory.php b/engine/classes/Elgg/Filesystem/Directory/InMemory.php deleted file mode 100644 index bc892e391cb..00000000000 --- a/engine/classes/Elgg/Filesystem/Directory/InMemory.php +++ /dev/null @@ -1,32 +0,0 @@ - 'contents'] - * - * @return Directory - */ - public static function fromArray(array $files) /*: Directory*/ { - $dir = Fly::createInMemory(); - - foreach ($files as $file => $content) { - $dir->putContents($file, $content); - } - - return $dir; - } -} diff --git a/engine/classes/Elgg/Filesystem/Directory/Local.php b/engine/classes/Elgg/Filesystem/Directory/Local.php deleted file mode 100644 index e38345472f2..00000000000 --- a/engine/classes/Elgg/Filesystem/Directory/Local.php +++ /dev/null @@ -1,62 +0,0 @@ -directory = $directory; - $this->path = $path; - } - - /** - * @return boolean Whether this file exists. - */ - public function exists() { - return $this->directory->isFile($this->path); - } - - /** - * @return string The file's basename. - */ - public function getBasename() { - return pathinfo($this->path, PATHINFO_BASENAME); - } - - /** - * Get the text content of this file. Empty string if it doesn't exist. - * - * @return string - */ - public function getContents() { - return $this->directory->getContents($this->path); - } - - /** - * Put content into this file. - * - * @param string $content File content - * @return void - */ - public function putContents($content) { - $this->directory->putContents($this->path, $content); - } - - /** - * @return string The file's extension. - */ - public function getExtension() { - return pathinfo($this->path, PATHINFO_EXTENSION); - } - - /** - * @return string The full path to this file. - */ - public function getPath() { - return $this->directory->getPath($this->path); - } - - /** - * Do a PHP include of the file and return the result. - * - * @return mixed - */ - public function includeFile() { - return $this->directory->includeFile($this->path); - } - - /** - * {@inheritDoc} - */ - public function __toString() { - return $this->path; - } -} diff --git a/engine/classes/Elgg/Filesystem/MimeTypeDetector.php b/engine/classes/Elgg/Filesystem/MimeTypeDetector.php index 055b20f3113..dc256a9dde5 100644 --- a/engine/classes/Elgg/Filesystem/MimeTypeDetector.php +++ b/engine/classes/Elgg/Filesystem/MimeTypeDetector.php @@ -32,7 +32,8 @@ class MimeTypeDetector { 'html' => 'text/html', 'php' => 'text/html', 'css' => 'text/css', - 'js' => 'application/javascript', + 'js' => 'text/javascript', + 'mjs' => 'text/javascript', 'json' => 'application/json', 'xml' => 'application/xml', 'swf' => 'application/x-shockwave-flash', @@ -178,6 +179,11 @@ public function fixDetectionErrors($type, $extension) { if ($type === 'application/vnd.ms-office' && $extension === 'ppt') { return 'application/vnd.ms-powerpoint'; } + + // bad css/js detection + if ($type === 'text/plain' && in_array($extension, ['css', 'js', 'mjs'])) { + return $this->extensions[$extension]; + } // try extension detection as a fallback for octet-stream if ($type === 'application/octet-stream' && $this->use_extension && isset($this->extensions[$extension])) { diff --git a/engine/classes/Elgg/Filesystem/MimeTypeService.php b/engine/classes/Elgg/Filesystem/MimeTypeService.php index 624cdfa6f3f..018cbcba247 100644 --- a/engine/classes/Elgg/Filesystem/MimeTypeService.php +++ b/engine/classes/Elgg/Filesystem/MimeTypeService.php @@ -12,15 +12,12 @@ */ class MimeTypeService { - protected $events; - /** * Constructor * * @param EventsService $events Events service */ - public function __construct(EventsService $events) { - $this->events = $events; + public function __construct(protected EventsService $events) { } /** diff --git a/engine/classes/Elgg/Forms/FieldsService.php b/engine/classes/Elgg/Forms/FieldsService.php index ab393a587fd..8e6f4b640e9 100644 --- a/engine/classes/Elgg/Forms/FieldsService.php +++ b/engine/classes/Elgg/Forms/FieldsService.php @@ -15,20 +15,7 @@ class FieldsService { use Loggable; - /** - * @var array - */ - protected $fields = []; - - /** - * @var EventsService - */ - protected $events; - - /** - * @var Translator - */ - protected $translator; + protected array $fields = []; /** * Constructor @@ -36,9 +23,7 @@ class FieldsService { * @param EventsService $events events service * @param Translator $translator translator service */ - public function __construct(EventsService $events, Translator $translator) { - $this->events = $events; - $this->translator = $translator; + public function __construct(protected EventsService $events, protected Translator $translator) { } /** diff --git a/engine/classes/Elgg/Forms/PrepareSecurityTxt.php b/engine/classes/Elgg/Forms/PrepareSecurityTxt.php new file mode 100644 index 00000000000..8d658ca9f33 --- /dev/null +++ b/engine/classes/Elgg/Forms/PrepareSecurityTxt.php @@ -0,0 +1,39 @@ +getValue(); + + $fields = [ + 'contact', + 'expires', + 'encryption', + 'acknowledgments', + 'language', + 'canonical', + 'policy', + 'hiring', + 'csaf', + ]; + foreach ($fields as $field) { + $body_vars[$field] = elgg_extract($field, $body_vars, elgg_get_config("security_txt_{$field}")); + } + + return $body_vars; + } +} diff --git a/engine/classes/Elgg/Forms/StickyForms.php b/engine/classes/Elgg/Forms/StickyForms.php index 8fbd65b0149..47775453c16 100644 --- a/engine/classes/Elgg/Forms/StickyForms.php +++ b/engine/classes/Elgg/Forms/StickyForms.php @@ -9,19 +9,13 @@ * @internal */ class StickyForms { - - /** - * @var \ElggSession - */ - protected $session; - + /** * Constructor * * @param \ElggSession $session Session for storage */ - public function __construct(\ElggSession $session) { - $this->session = $session; + public function __construct(protected \ElggSession $session) { } /** diff --git a/engine/classes/Elgg/FormsService.php b/engine/classes/Elgg/FormsService.php index c2cd325b765..c03d118ed9a 100644 --- a/engine/classes/Elgg/FormsService.php +++ b/engine/classes/Elgg/FormsService.php @@ -3,6 +3,7 @@ namespace Elgg; use Elgg\Exceptions\LogicException; +use Elgg\Javascript\ESMService; use Elgg\Traits\Loggable; /** @@ -15,35 +16,22 @@ class FormsService { use Loggable; - /** - * @var EventsService - */ - protected $events; - - /** - * @var ViewsService - */ - protected $views; + protected bool $rendering = false; - /** - * @var bool - */ - protected $rendering; - - /** - * @var string - */ - protected $footer = ''; + protected string $footer = ''; /** * Constructor * * @param ViewsService $views Views service * @param EventsService $events Events service + * @param ESMService $esm ESM service */ - public function __construct(ViewsService $views, EventsService $events) { - $this->views = $views; - $this->events = $events; + public function __construct( + protected ViewsService $views, + protected EventsService $events, + protected ESMService $esm + ) { } /** @@ -104,6 +92,7 @@ public function render(string $action, array $form_vars = [], array $body_vars = } if (elgg_extract('ajax', $form_vars)) { + $this->esm->import('input/form-ajax'); $form_vars['class'][] = 'elgg-js-ajax-form'; unset($form_vars['ajax']); } @@ -125,6 +114,14 @@ public function render(string $action, array $form_vars = [], array $body_vars = $body = $this->views->renderView("forms/{$action}", $body_vars); if (!empty($body)) { + // wrap form body + $body = $this->views->renderView('elements/forms/body', [ + 'body' => $body, + 'action_name' => $action, + 'body_vars' => $body_vars, + 'form_vars' => $form_vars, + ]); + // Grab the footer if one was set during form rendering $body .= $this->views->renderView('elements/forms/footer', [ 'footer' => $this->getFooter(), diff --git a/engine/classes/Elgg/Gatekeeper.php b/engine/classes/Elgg/Gatekeeper.php index bc77209eaa9..23040aebc3e 100644 --- a/engine/classes/Elgg/Gatekeeper.php +++ b/engine/classes/Elgg/Gatekeeper.php @@ -23,36 +23,6 @@ */ class Gatekeeper { - /** - * @var SessionManagerService - */ - protected $session_manager; - - /** - * @var \Elgg\Http\Request - */ - protected $request; - - /** - * @var RedirectService - */ - protected $redirects; - - /** - * @var EntityTable - */ - protected $entities; - - /** - * @var AccessCollections - */ - protected $access; - - /** - * @var Translator - */ - protected $translator; - /** * Constructor * @@ -64,27 +34,22 @@ class Gatekeeper { * @param Translator $translator Translator */ public function __construct( - SessionManagerService $session_manager, - HttpRequest $request, - RedirectService $redirects, - EntityTable $entities, - AccessCollections $access, - Translator $translator + protected SessionManagerService $session_manager, + protected HttpRequest $request, + protected RedirectService $redirects, + protected EntityTable $entities, + protected AccessCollections $access, + protected Translator $translator ) { - $this->session_manager = $session_manager; - $this->request = $request; - $this->redirects = $redirects; - $this->entities = $entities; - $this->access = $access; - $this->translator = $translator; } /** * Require a user to be authenticated to with code execution + * * @return void * @throws LoggedInGatekeeperException */ - public function assertAuthenticatedUser() { + public function assertAuthenticatedUser(): void { if ($this->session_manager->isLoggedIn()) { return; } @@ -96,10 +61,11 @@ public function assertAuthenticatedUser() { /** * Require a user to be not authenticated (logged out) to with code execution + * * @return void * @throws LoggedOutGatekeeperException */ - public function assertUnauthenticatedUser() { + public function assertUnauthenticatedUser(): void { if (!$this->session_manager->isLoggedIn()) { return; } @@ -112,11 +78,12 @@ public function assertUnauthenticatedUser() { /** * Require an admin user to be authenticated to proceed with code execution + * * @return void * @throws GatekeeperException * @throws AdminGatekeeperException */ - public function assertAuthenticatedAdmin() { + public function assertAuthenticatedAdmin(): void { $this->assertAuthenticatedUser(); $user = $this->session_manager->getLoggedInUser(); @@ -307,7 +274,7 @@ public function assertAccessibleGroup(\ElggGroup $group, \ElggUser $user = null) * @return void * @throws AjaxGatekeeperException */ - public function assertXmlHttpRequest() { + public function assertXmlHttpRequest(): void { if ($this->request->isXmlHttpRequest()) { return; } diff --git a/engine/classes/Elgg/Groups/Tool.php b/engine/classes/Elgg/Groups/Tool.php index cacd7608979..731fe8dab5a 100644 --- a/engine/classes/Elgg/Groups/Tool.php +++ b/engine/classes/Elgg/Groups/Tool.php @@ -14,15 +14,7 @@ */ class Tool implements CollectionItemInterface { - /** - * @var string - */ - public $name; - - /** - * @var array - */ - protected $options; + protected array $options; /** * Constructor @@ -30,9 +22,7 @@ class Tool implements CollectionItemInterface { * @param string $name Tool name * @param array $options Tool options */ - public function __construct($name, array $options = []) { - $this->name = $name; - + public function __construct(public string $name, array $options = []) { $defaults = [ 'label' => null, 'default_on' => true, @@ -83,7 +73,7 @@ public function getPriority() { * * @return string */ - public function getLabel() { + public function getLabel(): string { $label = elgg_extract('label', $this->options); if (isset($label)) { return $label; @@ -108,9 +98,10 @@ public function getDescription(): ?string { /** * Is the tool enabled by default? + * * @return bool */ - public function isEnabledByDefault() { + public function isEnabledByDefault(): bool { $default_on = elgg_extract('default_on', $this->options, true); if ($default_on === true || $default_on === 'yes') { @@ -122,9 +113,10 @@ public function isEnabledByDefault() { /** * Get metadata name for DB storage + * * @return string */ - public function mapMetadataName() { + public function mapMetadataName(): string { return "{$this->name}_enable"; } @@ -136,7 +128,7 @@ public function mapMetadataName() { * * @return string */ - public function mapMetadataValue($value = null) { + public function mapMetadataValue($value = null): string { if (!isset($value)) { $value = $this->default_on; } diff --git a/engine/classes/Elgg/Groups/Tools.php b/engine/classes/Elgg/Groups/Tools.php index 814583bea90..034cefde92a 100644 --- a/engine/classes/Elgg/Groups/Tools.php +++ b/engine/classes/Elgg/Groups/Tools.php @@ -17,19 +17,13 @@ class Tools { */ protected $tools; - /** - * @var EventsService - */ - protected $events; - /** * Constructor * * @param EventsService $events Events */ - public function __construct(EventsService $events) { + public function __construct(protected EventsService $events) { $this->tools = new Collection([], Tool::class); - $this->events = $events; } /** diff --git a/engine/classes/Elgg/Http/Input.php b/engine/classes/Elgg/Http/Input.php index b331b0d0998..106f618cfa8 100644 --- a/engine/classes/Elgg/Http/Input.php +++ b/engine/classes/Elgg/Http/Input.php @@ -10,18 +10,12 @@ */ class Input { - /** - * @var Request - */ - protected $request; - /** * Constructor * * @param Request $request Http Request object */ - public function __construct(Request $request) { - $this->request = $request; + public function __construct(protected Request $request) { } /** diff --git a/engine/classes/Elgg/Http/RedirectResponse.php b/engine/classes/Elgg/Http/RedirectResponse.php index f146892f5a2..714a89b6ca2 100644 --- a/engine/classes/Elgg/Http/RedirectResponse.php +++ b/engine/classes/Elgg/Http/RedirectResponse.php @@ -10,12 +10,15 @@ class RedirectResponse extends Response { /** * Constructor * - * @param string $forward_url Forward url - * @param int $status_code HTTP status code + * @param string $forward_url Forward url + * @param int $status_code HTTP status code + * @param bool $secure_forward_url If true the forward url will be validated to be an on-site url * * @see elgg_redirect_response() */ - public function __construct(string $forward_url = REFERRER, int $status_code = ELGG_HTTP_FOUND) { + public function __construct(string $forward_url = REFERRER, int $status_code = ELGG_HTTP_FOUND, bool $secure_forward_url = true) { + $this->secure_forward_url = $secure_forward_url; + $this->setForwardURL($forward_url); $this->setStatusCode($status_code); } diff --git a/engine/classes/Elgg/Http/Request.php b/engine/classes/Elgg/Http/Request.php index b6a66e57bc4..a1283fea29e 100644 --- a/engine/classes/Elgg/Http/Request.php +++ b/engine/classes/Elgg/Http/Request.php @@ -76,7 +76,7 @@ public function __construct( * * @return void */ - public function initializeTrustedProxyConfiguration(Config $config) { + public function initializeTrustedProxyConfiguration(Config $config): void { $trusted_proxies = $config->http_request_trusted_proxy_ips; if (empty($trusted_proxies)) { return; @@ -132,7 +132,7 @@ public function setRoute(Route $route) { * * @return Route|null */ - public function getRoute() { + public function getRoute(): ?Route { return $this->route; } @@ -215,7 +215,7 @@ public function getParams(bool $filter_result = true): array { * * @return string */ - public function getCurrentURL() { + public function getCurrentURL(): string { $url = parse_url(elgg_get_site_url()); $page = $url['scheme'] . '://' . $url['host']; @@ -238,7 +238,7 @@ public function getCurrentURL() { * * @return string[] */ - public function getUrlSegments(bool $raw = false) { + public function getUrlSegments(bool $raw = false): array { $path = trim($this->getElggPath(), '/'); if (!$raw) { $path = htmlspecialchars($path, ENT_QUOTES, 'UTF-8'); @@ -258,7 +258,7 @@ public function getUrlSegments(bool $raw = false) { * * @return Request */ - public function setUrlSegments(array $segments) { + public function setUrlSegments(array $segments): Request { $base_path = trim($this->getBasePath(), '/'); $server = $this->server->all(); $server['REQUEST_URI'] = "$base_path/" . implode('/', $segments); @@ -273,7 +273,7 @@ public function setUrlSegments(array $segments) { * * @return string */ - public function getFirstUrlSegment() { + public function getFirstUrlSegment(): string { $segments = $this->getUrlSegments(); if (!empty($segments)) { return array_shift($segments); @@ -287,7 +287,7 @@ public function getFirstUrlSegment() { * * @return string */ - public function getElggPath() { + public function getElggPath(): string { if (PHP_SAPI === 'cli-server') { $path = $this->getRequestUri(); } else { @@ -300,7 +300,7 @@ public function getElggPath() { /** * {@inheritdoc} */ - public function getClientIp() { + public function getClientIp(): ?string { $ip = parent::getClientIp(); if ($ip == $this->server->get('REMOTE_ADDR')) { @@ -319,7 +319,7 @@ public function getClientIp() { /** * {@inheritdoc} */ - public function isXmlHttpRequest() { + public function isXmlHttpRequest(): bool { return (strtolower($this->headers->get('X-Requested-With') ?: '') === 'xmlhttprequest' || $this->query->get('X-Requested-With') === 'XMLHttpRequest' || $this->request->get('X-Requested-With') === 'XMLHttpRequest'); @@ -348,7 +348,7 @@ public function sniffElggUrl() { * * @return bool */ - public function isRewriteCheck() { + public function isRewriteCheck(): bool { if ($this->getPathInfo() !== ('/' . self::REWRITE_TEST_TOKEN)) { return false; } @@ -375,7 +375,7 @@ public function isAction(): bool { * * @return bool */ - public function isCliServer() { + public function isCliServer(): bool { return PHP_SAPI === 'cli-server'; } @@ -386,7 +386,7 @@ public function isCliServer() { * * @return bool */ - public function isCliServable($root) { + public function isCliServable(string $root): bool { $file = rtrim($root, '\\/') . $this->getElggPath(); if (!is_file($file)) { return false; @@ -394,7 +394,7 @@ public function isCliServable($root) { // http://php.net/manual/en/features.commandline.webserver.php $extensions = '.3gp, .apk, .avi, .bmp, .css, .csv, .doc, .docx, .flac, .gif, .gz, .gzip, .htm, .html, .ics,'; - $extensions .= ' .jpe, .jpeg, .jpg, .js, .kml, .kmz, .m4a, .mov, .mp3, .mp4, .mpeg, .mpg, .odp, .ods, .odt,'; + $extensions .= ' .jpe, .jpeg, .jpg, .js, .kml, .kmz, .m4a, .mjs, .mov, .mp3, .mp4, .mpeg, .mpg, .odp, .ods, .odt,'; $extensions .= ' .oga, .ogg, .ogv, .pdf, .pdf, .png, .pps, .pptx, .qt, .svg, .swf, .tar, .text, .tif, .txt,'; $extensions .= ' .wav, .webm, .wmv, .xls, .xlsx, .xml, .xsl, .xsd, and .zip'; @@ -461,7 +461,7 @@ public function getFile(string $input_name, bool $check_for_validity = true): ?U * @return void * @throws BadRequestException */ - public function validate() { + public function validate(): void { $this->validateRequestHostHeader(); $this->validateRequestBodyTruncated(); } @@ -475,7 +475,7 @@ public function validate() { * @throws BadRequestException * @since 3.3.25 */ - protected function validateRequestHostHeader() { + protected function validateRequestHostHeader(): void { $config = _elgg_services()->config; if (empty($config->wwwroot)) { return; diff --git a/engine/classes/Elgg/Http/Response.php b/engine/classes/Elgg/Http/Response.php index 9e7f042c9fd..1f28bcc9aad 100644 --- a/engine/classes/Elgg/Http/Response.php +++ b/engine/classes/Elgg/Http/Response.php @@ -13,30 +13,17 @@ */ abstract class Response implements ResponseBuilder { - /** - * @var string - */ protected $content; - /** - * @var int - */ - protected $status_code; + protected int $status_code; - /** - * @var string - */ - protected $forward_url; + protected ?string $forward_url = null; - /** - * @var array - */ - protected $headers; + protected array $headers = []; - /** - * @var \Exception - */ - protected $exception; + protected ?\Exception $exception = null; + + protected bool $secure_forward_url = true; /** * {@inheritdoc} @@ -58,7 +45,7 @@ public function getContent() { } /** - * {@inheritDoc} + * {@inheritdoc} */ public function setException(\Exception $e) { $this->exception = $e; @@ -66,7 +53,7 @@ public function setException(\Exception $e) { } /** - * {@inheritDoc} + * {@inheritdoc} */ public function getException() { return $this->exception; @@ -103,7 +90,16 @@ public function setForwardURL(string $forward_url = REFERRER) { * {@inheritdoc} */ public function getForwardURL(): ?string { - return $this->forward_url; + if (!isset($this->forward_url)) { + return null; + } + + $forward_url = $this->forward_url; + if ($forward_url === REFERRER || !$this->secure_forward_url) { + return $forward_url; + } + + return elgg_normalize_site_url($forward_url) !== null ? $forward_url : ''; } /** @@ -118,7 +114,7 @@ public function setHeaders(array $headers = []) { * {@inheritdoc} */ public function getHeaders() { - return (array) $this->headers; + return $this->headers; } /** diff --git a/engine/classes/Elgg/Http/ResponseFactory.php b/engine/classes/Elgg/Http/ResponseFactory.php index 045da16bc99..f14c716030d 100644 --- a/engine/classes/Elgg/Http/ResponseFactory.php +++ b/engine/classes/Elgg/Http/ResponseFactory.php @@ -21,12 +21,6 @@ class ResponseFactory { use Loggable; - - protected Request $request; - - protected AjaxService $ajax; - - protected EventsService $events; protected ResponseTransport $transport; @@ -41,11 +35,11 @@ class ResponseFactory { * @param AjaxService $ajax AJAX service * @param EventsService $events Events service */ - public function __construct(Request $request, AjaxService $ajax, EventsService $events) { - $this->request = $request; - $this->ajax = $ajax; - $this->events = $events; - + public function __construct( + protected Request $request, + protected AjaxService $ajax, + protected EventsService $events + ) { $this->transport = \Elgg\Application::getResponseTransport(); $this->headers = new ResponseHeaderBag(); } @@ -254,7 +248,7 @@ public function respond(ResponseBuilder $response) { $is_xhr = $this->request->isXmlHttpRequest(); - $is_action = str_starts_with($response_type, 'action:'); + $is_action = $this->isAction(); if ($is_action && $response->getForwardURL() === null) { // actions must always set a redirect url @@ -265,10 +259,10 @@ public function respond(ResponseBuilder $response) { $response->setForwardURL((string) $this->request->headers->get('Referer')); } - if ($response->getForwardURL() !== null && !$is_xhr) { + if ($response->getForwardURL() !== null && !$is_xhr && !$response->isRedirection()) { // non-xhr requests should issue a forward if redirect url is set // unless it's an error, in which case we serve an error page - if ($this->isAction() || (!$response->isClientError() && !$response->isServerError())) { + if ($is_action || (!$response->isClientError() && !$response->isServerError())) { $response->setStatusCode(ELGG_HTTP_FOUND); } } diff --git a/engine/classes/Elgg/Http/WebAppManifestResource.php b/engine/classes/Elgg/Http/WebAppManifestResource.php index ea59c15e755..d42d52dd1a4 100644 --- a/engine/classes/Elgg/Http/WebAppManifestResource.php +++ b/engine/classes/Elgg/Http/WebAppManifestResource.php @@ -13,17 +13,13 @@ * @internal */ class WebAppManifestResource { - - /** @var \ElggSite */ - private $site; - + /** * Constructor * * @param \ElggSite $site The site serving this manifest. */ - public function __construct(\ElggSite $site) { - $this->site = $site; + public function __construct(protected \ElggSite $site) { } /** @@ -31,7 +27,7 @@ public function __construct(\ElggSite $site) { * * @return array */ - public function get() { + public function get(): array { return [ 'display' => 'standalone', 'name' => $this->site->getDisplayName(), diff --git a/engine/classes/Elgg/I18n/DateTime.php b/engine/classes/Elgg/I18n/DateTime.php index 8bc2809fb8a..25d8c11f8fd 100644 --- a/engine/classes/Elgg/I18n/DateTime.php +++ b/engine/classes/Elgg/I18n/DateTime.php @@ -5,7 +5,7 @@ use DateTime as PHPDateTime; /** - * Extension of the DateTime class to support formating a date using the locale + * Extension of the DateTime class to support formatting a date using the locale * * @since 3.0 */ @@ -24,11 +24,7 @@ public function formatLocale(string $format, string $language = null) { $language = _elgg_services()->translator->getCurrentLanguage(); } - if (extension_loaded('intl')) { - $result = $this->formatIntl($format, $language); - } else { - $result = $this->formatStrftime($format, $language); - } + $result = $this->formatIntl($format, $language); if ($result === false) { elgg_log("Unable to generate locale representation for format: '{$format}', using non-locale version", 'INFO'); @@ -37,81 +33,6 @@ public function formatLocale(string $format, string $language = null) { return $result; } - - /** - * Convert a date format to a strftime format - * - * Timezone conversion is done for unix. Windows users must exchange %z and %Z. - * - * Unsupported date formats : n, t, L, B, u, e, I, P, Z, c, r - * Unsupported strftime formats : %U, %W, %C, %g, %r, %R, %T, %X, %c, %D, %F, %x - * - * @param string $dateFormat a date format - * - * @return false|string - * @see https://secure.php.net/manual/en/function.strftime.php#96424 - */ - protected function dateFormatToStrftime(string $dateFormat) { - if (preg_match('/(? '%d', 'D' => '%a', 'j' => '%e', 'l' => '%A', 'N' => '%u', 'w' => '%w', 'z' => '%j', - // Week - no date eq : %U, %W - 'W' => '%V', - // Month - no strf eq : n, t - 'F' => '%B', 'm' => '%m', 'M' => '%b', - // Year - no strf eq : L; no date eq : %C, %g - 'o' => '%G', 'Y' => '%Y', 'y' => '%y', - // Time - no strf eq : B, G, u; no date eq : %r, %R, %T, %X - 'a' => '%P', 'A' => '%p', 'g' => '%l', 'h' => '%I', 'H' => '%H', 'i' => '%M', 's' => '%S', - // Timezone - no strf eq : e, I, P, Z - 'O' => '%z', 'T' => '%Z', - // Full Date / Time - no strf eq : c, r; no date eq : %c, %D, %F, %x - 'U' => '%s', - // less supported replacements - // Day - 'S' => '', - // Time - 'G' => '%k', - ]; - - return strtr((string) $dateFormat, $caracs); - } - - /** - * Try to format to a locale using strftime() - * - * @param string $format output format, supports date() formatting - * @param string $language the output language - * - * @return string|false - * @since 4.1 - */ - protected function formatStrftime(string $format, string $language) { - // convert date() format to strftime() format - $correct_format = $this->dateFormatToStrftime($format); - if ($correct_format === false) { - return false; - } - - if (version_compare(PHP_VERSION, '8.1.0', '>=')) { - elgg_log('In order to get rid of the deprecated warnings about strftime() enable the "intl" PHP module', 'WARNING'); - } - - // switch locale - $current_locale = _elgg_services()->locale->setLocaleFromLanguageKey(LC_TIME, $language); - - $result = strftime($correct_format, $this->getTimestamp()); - - // restore locale - _elgg_services()->locale->setLocale(LC_TIME, $current_locale); - - return $result; - } /** * Convert a date format to a ICU format diff --git a/engine/classes/Elgg/I18n/Locale.php b/engine/classes/Elgg/I18n/Locale.php index 508abb001b9..fe57fa563e0 100644 --- a/engine/classes/Elgg/I18n/Locale.php +++ b/engine/classes/Elgg/I18n/Locale.php @@ -11,17 +11,13 @@ * @internal */ final class Locale { - - /** @var string */ - private $locale; - + /** * Use Locale::parse to construct * * @param string $locale A string representation of the locale */ - private function __construct($locale) { - $this->locale = $locale; + private function __construct(private string $locale) { } /** @@ -40,9 +36,9 @@ public function __toString() { * * @throws InvalidLocaleException */ - public static function parse($locale) { + public static function parse(string $locale): Locale { if (!preg_match('~^[a-z0-9_]{2,20}$~', $locale)) { - throw new InvalidLocaleException("Unrecognized locale: $locale"); + throw new InvalidLocaleException("Unrecognized locale: {$locale}"); } return new Locale($locale); diff --git a/engine/classes/Elgg/I18n/LocaleService.php b/engine/classes/Elgg/I18n/LocaleService.php index c08539a740f..d03d1f4b23d 100644 --- a/engine/classes/Elgg/I18n/LocaleService.php +++ b/engine/classes/Elgg/I18n/LocaleService.php @@ -12,24 +12,14 @@ */ class LocaleService { - /** - * @var Config - */ - protected $config; - - /** - * @var array - */ - protected $locale; + protected array $locale; /** * Create new service * * @param Config $config Elgg config */ - public function __construct(Config $config) { - $this->config = $config; - + public function __construct(protected Config $config) { $this->initializeElggLocale(); } diff --git a/engine/classes/Elgg/I18n/ReleaseCleaner.php b/engine/classes/Elgg/I18n/ReleaseCleaner.php index 820f678f876..485e05ee09f 100644 --- a/engine/classes/Elgg/I18n/ReleaseCleaner.php +++ b/engine/classes/Elgg/I18n/ReleaseCleaner.php @@ -180,7 +180,14 @@ protected function cleanupEmptyTranslations(string $translation_file): void { // something was changed file_put_contents($translation_file, $contents); - $this->log[] = "Cleaned empty translations from {$translation_file}"; + $translations = Includer::includeFile($translation_file); + if (!empty($translations)) { + $this->log[] = "Cleaned empty translations from {$translation_file}"; + } else { + unlink($translation_file); + + $this->log[] = "Removed empty translation file {$translation_file}"; + } } } diff --git a/engine/classes/Elgg/I18n/Translator.php b/engine/classes/Elgg/I18n/Translator.php index 2e7a1ab5eeb..96bc6db16fb 100644 --- a/engine/classes/Elgg/I18n/Translator.php +++ b/engine/classes/Elgg/I18n/Translator.php @@ -17,10 +17,6 @@ class Translator { use Loggable; - protected Config $config; - - protected LocaleService $locale; - protected array $translations = []; protected string $defaultPath; @@ -53,10 +49,7 @@ class Translator { * @param Config $config Elgg config * @param LocaleService $locale locale service */ - public function __construct(Config $config, LocaleService $locale) { - $this->config = $config; - $this->locale = $locale; - + public function __construct(protected Config $config, protected LocaleService $locale) { $this->defaultPath = dirname(__DIR__, 4) . '/languages/'; $this->registerLanguagePath($this->defaultPath); diff --git a/engine/classes/Elgg/ImageService.php b/engine/classes/Elgg/ImageService.php index 28c078e2ed1..bb37c8974f8 100644 --- a/engine/classes/Elgg/ImageService.php +++ b/engine/classes/Elgg/ImageService.php @@ -30,23 +30,13 @@ class ImageService { */ protected $imagine; - /** - * @var Config - */ - protected $config; - - /** - * @var MimeTypeService - */ - protected $mimetype; - /** * Constructor * * @param Config $config Elgg config * @param MimeTypeService $mimetype MimeType service */ - public function __construct(Config $config, MimeTypeService $mimetype) { + public function __construct(protected Config $config, protected MimeTypeService $mimetype) { switch ($config->image_processor) { case 'imagick': @@ -61,9 +51,6 @@ public function __construct(Config $config, MimeTypeService $mimetype) { $this->imagine = new \Imagine\Gd\Imagine(); break; } - - $this->config = $config; - $this->mimetype = $mimetype; } /** @@ -118,7 +105,12 @@ public function resize(string $source, string $destination = null, array $params } $target_size = new Box($max_width, $max_height); - $thumbnail = $image->resize($target_size); + $image->resize($target_size); + + // create new canvas with a background (default: white) + $background_color = elgg_extract('background_color', $params, 'ffffff'); + $thumbnail = $this->imagine->create($image->getSize(), $image->palette()->color($background_color)); + $thumbnail->paste($image, new Point(0, 0)); if (pathinfo($destination, PATHINFO_EXTENSION) === 'webp') { $options = [ diff --git a/engine/classes/Elgg/Invoker.php b/engine/classes/Elgg/Invoker.php index 4a0ece854bd..66d27777ebf 100644 --- a/engine/classes/Elgg/Invoker.php +++ b/engine/classes/Elgg/Invoker.php @@ -9,25 +9,13 @@ */ class Invoker { - /** - * @var SessionManagerService - */ - protected $session_manager; - - /** - * @var PublicContainer - */ - protected $dic; - /** * Constructor * * @param SessionManagerService $session_manager Session * @param PublicContainer $dic DI container */ - public function __construct(SessionManagerService $session_manager, PublicContainer $dic) { - $this->session_manager = $session_manager; - $this->dic = $dic; + public function __construct(protected SessionManagerService $session_manager, protected PublicContainer $dic) { } /** @@ -39,26 +27,35 @@ public function __construct(SessionManagerService $session_manager, PublicContai * ELGG_ENFORCE_ACCESS * ELGG_SHOW_DISABLED_ENTITIES * ELGG_HIDE_DISABLED_ENTITIES + * ELGG_SHOW_DELETED_ENTITIES + * ELGG_HIDE_DELETED_ENTITIES * @param \Closure $closure Callable to call * * @return mixed - * @throws \Exception + * @throws \Throwable */ public function call(int $flags, \Closure $closure) { - $ia = $this->session_manager->getIgnoreAccess(); + $access = $this->session_manager->getIgnoreAccess(); if ($flags & ELGG_IGNORE_ACCESS) { $this->session_manager->setIgnoreAccess(true); - } else if ($flags & ELGG_ENFORCE_ACCESS) { + } elseif ($flags & ELGG_ENFORCE_ACCESS) { $this->session_manager->setIgnoreAccess(false); } - $ha = $this->session_manager->getDisabledEntityVisibility(); + $disabled = $this->session_manager->getDisabledEntityVisibility(); if ($flags & ELGG_SHOW_DISABLED_ENTITIES) { $this->session_manager->setDisabledEntityVisibility(true); - } else if ($flags & ELGG_HIDE_DISABLED_ENTITIES) { + } elseif ($flags & ELGG_HIDE_DISABLED_ENTITIES) { $this->session_manager->setDisabledEntityVisibility(false); } + + $deleted = $this->session_manager->getDeletedEntityVisibility(); + if ($flags & ELGG_SHOW_DELETED_ENTITIES) { + $this->session_manager->setDeletedEntityVisibility(true); + } elseif ($flags & ELGG_HIDE_DELETED_ENTITIES) { + $this->session_manager->setDeletedEntityVisibility(false); + } $system_log_enabled = null; $system_log_service = null; @@ -77,9 +74,10 @@ public function call(int $flags, \Closure $closure) { } } - $restore = function () use ($ia, $ha, $system_log_service, $system_log_enabled) { - $this->session_manager->setIgnoreAccess($ia); - $this->session_manager->setDisabledEntityVisibility($ha); + $restore = function () use ($access, $disabled, $deleted, $system_log_service, $system_log_enabled) { + $this->session_manager->setIgnoreAccess($access); + $this->session_manager->setDisabledEntityVisibility($disabled); + $this->session_manager->setDeletedEntityVisibility($deleted); if (isset($system_log_service)) { if ($system_log_enabled) { diff --git a/engine/classes/Elgg/Javascript/AddSRIConfig.php b/engine/classes/Elgg/Javascript/AddSRIConfig.php deleted file mode 100644 index cf3a1f3629f..00000000000 --- a/engine/classes/Elgg/Javascript/AddSRIConfig.php +++ /dev/null @@ -1,34 +0,0 @@ -getValue(); - - $data = _elgg_services()->serverCache->load('sri') ?? []; - - $return['sri'] = $data['js'] ?? []; - - return $return; - } -} diff --git a/engine/classes/Elgg/Javascript/ESMService.php b/engine/classes/Elgg/Javascript/ESMService.php new file mode 100644 index 00000000000..d48aae956e1 --- /dev/null +++ b/engine/classes/Elgg/Javascript/ESMService.php @@ -0,0 +1,83 @@ +views->getESModules(); + $imports = []; + if (!empty($modules)) { + foreach ($modules as $name) { + $short_name = str_replace('.mjs', '', $name); + $imports[$short_name] = $this->cache->getUrl($name); + } + } + + $imports = array_merge($imports, $this->runtime_modules); + + return ['imports' => $imports]; + } + + /** + * Registers a module to the import map + * + * @param string $name name of the module + * @param string $href location from where to download the module (usually a simplecache location) + * + * @return void + */ + public function register(string $name, string $href): void { + $this->runtime_modules[$name] = $href; + } + + /** + * Request a module to be loaded on the page + * + * @param string $name name of the module + * + * @return void + */ + public function import(string $name): void { + $this->imports[$name] = true; + } + + /** + * Returns all modules that requested to be loaded + * + * @return array + */ + public function getImports(): array { + return array_keys($this->imports); + } +} diff --git a/engine/classes/Elgg/Javascript/SetLightboxConfigHandler.php b/engine/classes/Elgg/Javascript/SetLightboxConfigHandler.php index 704c95fe700..438a6bfe62e 100644 --- a/engine/classes/Elgg/Javascript/SetLightboxConfigHandler.php +++ b/engine/classes/Elgg/Javascript/SetLightboxConfigHandler.php @@ -12,7 +12,7 @@ class SetLightboxConfigHandler { /** * Set lightbox config * - * @param \Elgg\Event $event 'elgg.data', 'site' + * @param \Elgg\Event $event 'elgg.data', 'page' * * @return array */ diff --git a/engine/classes/Elgg/Logger/BacktraceProcessor.php b/engine/classes/Elgg/Logger/BacktraceProcessor.php index 29255e7cfbe..bc3b2bd7530 100644 --- a/engine/classes/Elgg/Logger/BacktraceProcessor.php +++ b/engine/classes/Elgg/Logger/BacktraceProcessor.php @@ -3,6 +3,8 @@ namespace Elgg\Logger; use Elgg\Logger; +use Monolog\Level; +use Monolog\LogRecord; /** * Inject backtrace stack into the record @@ -19,21 +21,21 @@ class BacktraceProcessor { * @param int $level Logging level * @param int $backtrace_level Backtrance level (-1 for all) */ - public function __construct($level = Logger::WARNING, $backtrace_level = -1) { + public function __construct($level = Level::Warning, $backtrace_level = -1) { $this->level = Logger::toMonologLevel($level); $this->backtrace_level = $backtrace_level; } /** - * Process recrod + * Process record * - * @param array $record Record + * @param LogRecord $record Record * - * @return array + * @return LogRecord */ - public function __invoke(array $record) { + public function __invoke(LogRecord $record): LogRecord { // return if the level is not high enough - if ($record['level'] < $this->level) { + if ($record->level->isLowerThan($this->level)) { return $record; } diff --git a/engine/classes/Elgg/Logger/Cron.php b/engine/classes/Elgg/Logger/Cron.php new file mode 100644 index 00000000000..26498ed40f8 --- /dev/null +++ b/engine/classes/Elgg/Logger/Cron.php @@ -0,0 +1,65 @@ +cron; + if (empty($interval) || !in_array($interval, $cron->getConfiguredIntervals(true))) { + throw new InvalidArgumentException('Please specify a valid cron interval'); + } + + $filename = elgg_extract('filename', $params); + if (empty($filename)) { + throw new InvalidArgumentException('Please provide a log filename'); + } + + $logger = new static(self::CHANNEL); + + $handler = new StreamHandler($filename); + + $formatter = new ElggLogFormatter(); + $formatter->allowInlineLineBreaks(); + $formatter->ignoreEmptyContextAndExtra(); + + $handler->setFormatter($formatter); + + $handler->pushProcessor(new MemoryUsageProcessor()); + $handler->pushProcessor(new MemoryPeakUsageProcessor()); + $handler->pushProcessor(new ProcessIdProcessor()); + $handler->pushProcessor(new TagProcessor([$interval])); + $handler->pushProcessor(new PsrLogMessageProcessor()); + + $logger->pushHandler($handler); + + return $logger; + } +} diff --git a/engine/classes/Elgg/Logger/ElggLogFormatter.php b/engine/classes/Elgg/Logger/ElggLogFormatter.php index 88aa6f50376..e615934329b 100644 --- a/engine/classes/Elgg/Logger/ElggLogFormatter.php +++ b/engine/classes/Elgg/Logger/ElggLogFormatter.php @@ -4,6 +4,7 @@ use Elgg\Exceptions\DatabaseException; use Monolog\Formatter\LineFormatter; +use Monolog\LogRecord; /** * Custom log formatter @@ -13,30 +14,27 @@ class ElggLogFormatter extends LineFormatter { /** * {@inheritdoc} */ - public function format(array $record): string { - - $context = elgg_extract('context', $record, []); + public function format(LogRecord $record): string { + $context = $record->context; $exception = elgg_extract('exception', $context); - if ($exception instanceof \Throwable) { - $timestamp = isset($exception->timestamp) ? (int) $exception->timestamp : time(); - - $dt = new \DateTime(); - $dt->setTimestamp($timestamp); - $record['datetime'] = $dt; - - $eol = PHP_EOL; - $message = "Exception at time {$timestamp}:{$eol}{$exception->getMessage()}{$eol}"; - $record['message'] = preg_replace('~\R~u', $eol, $message); - - if ($exception instanceof DatabaseException) { - $record['context']['sql'] = $exception->getQuery(); - $record['context']['params'] = $exception->getParameters(); - } - - unset($record['context']['exception']); + if (!$exception instanceof \Throwable) { + return parent::format($record); + } + + $dt = new \DateTimeImmutable(); + + $eol = PHP_EOL; + $message = "Exception at time {$dt->getTimestamp()}:{$eol}{$exception->getMessage()}{$eol}"; + $record_message = preg_replace('~\R~u', $eol, $message); + + if ($exception instanceof DatabaseException) { + $context['sql'] = $exception->getQuery(); + $context['params'] = $exception->getParameters(); } + + unset($context['exception']); - return parent::format($record); + return parent::format(new LogRecord($dt, $record->channel, $record->level, $record_message, $context, $record->extra, $record->formatted)); } } diff --git a/engine/classes/Elgg/Menu/Menu.php b/engine/classes/Elgg/Menu/Menu.php index e2f0359a80a..73c91118d58 100644 --- a/engine/classes/Elgg/Menu/Menu.php +++ b/engine/classes/Elgg/Menu/Menu.php @@ -9,11 +9,6 @@ */ class Menu { - /** - * @var array - */ - private $params; - /** * Constructor * @@ -21,8 +16,7 @@ class Menu { * "name" menu name * "menu" array of sections (each an array of items) */ - public function __construct(array $params) { - $this->params = $params; + public function __construct(protected array $params) { } /** diff --git a/engine/classes/Elgg/Menu/MenuSection.php b/engine/classes/Elgg/Menu/MenuSection.php index 946bc02f3e6..c32dd80f799 100644 --- a/engine/classes/Elgg/Menu/MenuSection.php +++ b/engine/classes/Elgg/Menu/MenuSection.php @@ -3,14 +3,11 @@ namespace Elgg\Menu; use Elgg\Collections\CollectionItemInterface; -use ElggMenuItem; /** * Menu section */ -class MenuSection - extends MenuItems - implements CollectionItemInterface { +class MenuSection extends MenuItems implements CollectionItemInterface { /** * @var string @@ -35,6 +32,7 @@ public function setId($id) { /** * Get unique item identifier within a collection + * * @return string|int */ public function getID() { @@ -54,6 +52,7 @@ public function setPriority($priority) { /** * Get priority (weight) of the item within a collection + * * @return int */ public function getPriority() { @@ -65,7 +64,7 @@ public function getPriority() { * * @param string $item_name Menu item name * - * @return ElggMenuItem|null + * @return \ElggMenuItem|null */ public function getItem($item_name) { return $this->get($item_name); @@ -73,7 +72,8 @@ public function getItem($item_name) { /** * Get menu items - * @return ElggMenuItem[] + * + * @return \ElggMenuItem[] */ public function getItems() { return $this->all(); diff --git a/engine/classes/Elgg/Menu/PreparedMenu.php b/engine/classes/Elgg/Menu/PreparedMenu.php index 7b215eab87e..0eed309bd68 100644 --- a/engine/classes/Elgg/Menu/PreparedMenu.php +++ b/engine/classes/Elgg/Menu/PreparedMenu.php @@ -3,7 +3,6 @@ namespace Elgg\Menu; use Elgg\Collections\Collection; -use ElggMenuItem; /** * Represents a menu that has been broken down into sections, @@ -27,7 +26,7 @@ public function getSection($id) { * * @param string $section_id Section ID * - * @return ElggMenuItem[] + * @return \ElggMenuItem[] */ public function getItems($section_id) { if ($this->has($section_id)) { diff --git a/engine/classes/Elgg/Menu/Service.php b/engine/classes/Elgg/Menu/Service.php index 4466d2bcb2f..a3495a630d8 100644 --- a/engine/classes/Elgg/Menu/Service.php +++ b/engine/classes/Elgg/Menu/Service.php @@ -10,16 +10,6 @@ */ class Service { - /** - * @var EventsService - */ - protected $events; - - /** - * @var Config - */ - protected $config; - /** * @var \ElggMenuItem[] */ @@ -31,9 +21,7 @@ class Service { * @param EventsService $events Events * @param Config $config Elgg config */ - public function __construct(EventsService $events, Config $config) { - $this->events = $events; - $this->config = $config; + public function __construct(protected EventsService $events, protected Config $config) { } /** @@ -229,6 +217,7 @@ protected function prepareDropdownMenu(PreparedMenu $menu, array $params): Prepa 'icon' => 'ellipsis-v', 'href' => false, 'text' => '', + 'title' => elgg_echo('more'), 'child_menu' => [ 'display' => 'dropdown', 'data-position' => json_encode([ diff --git a/engine/classes/Elgg/Menu/UnpreparedMenu.php b/engine/classes/Elgg/Menu/UnpreparedMenu.php index dbb04f030d0..a564285ff52 100644 --- a/engine/classes/Elgg/Menu/UnpreparedMenu.php +++ b/engine/classes/Elgg/Menu/UnpreparedMenu.php @@ -3,7 +3,6 @@ namespace Elgg\Menu; use Elgg\Exceptions\InvalidArgumentException; -use ElggMenuItem; /** * Linear set of menu items collected from configuration and the "register" event. @@ -25,9 +24,9 @@ class UnpreparedMenu { /** * Constructor * - * @param array $params Parameters to be passed to the "prepare" event and views. - * Must include value for "name". - * @param ElggMenuItem[]|MenuItems $items Menu items + * @param array $params Parameters to be passed to the "prepare" event and views. + * Must include value for "name". + * @param \ElggMenuItem[]|MenuItems $items Menu items */ public function __construct(array $params, $items) { $this->params = $params; diff --git a/engine/classes/Elgg/Menus/AdminHeader.php b/engine/classes/Elgg/Menus/AdminHeader.php index a5b253dfb44..76087290d4a 100644 --- a/engine/classes/Elgg/Menus/AdminHeader.php +++ b/engine/classes/Elgg/Menus/AdminHeader.php @@ -107,7 +107,7 @@ public static function registerMaintenance(\Elgg\Event $event) { * @return void|MenuItems */ public static function registerAdminAdminister(\Elgg\Event $event) { - if (!elgg_in_context('admin') || !elgg_is_admin_logged_in()) { + if (!elgg_is_admin_logged_in()) { return; } @@ -118,6 +118,7 @@ public static function registerAdminAdminister(\Elgg\Event $event) { 'name' => 'administer', 'text' => elgg_echo('menu:page:header:administer'), 'href' => false, + 'priority' => 10, ]); $return[] = \ElggMenuItem::factory([ @@ -151,16 +152,7 @@ public static function registerAdminAdminister(\Elgg\Event $event) { 'priority' => 600, 'parent_name' => 'administer', ]); - - $return[] = \ElggMenuItem::factory([ - 'name' => 'administer_utilities', - 'text' => elgg_echo('admin:administer_utilities'), - 'href' => false, - 'priority' => 50, - 'parent_name' => 'administer', - 'show_with_empty_children' => false, - ]); - + return $return; } @@ -172,7 +164,7 @@ public static function registerAdminAdminister(\Elgg\Event $event) { * @return PreparedMenu|null */ public static function prepareAdminAdministerUsersChildren(\Elgg\Event $event): ?PreparedMenu { - if (!elgg_in_context('admin') || !elgg_is_admin_logged_in()) { + if (!elgg_is_admin_logged_in()) { return null; } @@ -231,7 +223,7 @@ public static function prepareAdminAdministerUsersChildren(\Elgg\Event $event): * @return void|MenuItems */ public static function registerAdminConfigure(\Elgg\Event $event) { - if (!elgg_in_context('admin') || !elgg_is_admin_logged_in()) { + if (!elgg_is_admin_logged_in()) { return; } @@ -242,6 +234,7 @@ public static function registerAdminConfigure(\Elgg\Event $event) { 'name' => 'configure', 'text' => elgg_echo('menu:page:header:configure'), 'href' => false, + 'priority' => 20, ]); $return[] = \ElggMenuItem::factory([ @@ -260,6 +253,14 @@ public static function registerAdminConfigure(\Elgg\Event $event) { 'parent_name' => 'configure', ]); + $return[] = \ElggMenuItem::factory([ + 'name' => 'settings:theme', + 'text' => elgg_echo('admin:theme'), + 'href' => 'admin/theme', + 'priority' => 25, + 'parent_name' => 'configure', + ]); + $return[] = \ElggMenuItem::factory([ 'name' => 'security', 'text' => elgg_echo('admin:security'), @@ -268,31 +269,52 @@ public static function registerAdminConfigure(\Elgg\Event $event) { 'parent_name' => 'configure', ]); - // Utilities - $return[] = \ElggMenuItem::factory([ - 'name' => 'configure_utilities', - 'text' => elgg_echo('admin:configure_utilities'), - 'href' => false, - 'priority' => 600, - 'parent_name' => 'configure', - ]); $return[] = \ElggMenuItem::factory([ 'name' => 'configure_utilities:maintenance', 'text' => elgg_echo('admin:configure_utilities:maintenance'), 'href' => 'admin/configure_utilities/maintenance', - 'parent_name' => 'configure_utilities', - ]); - $return[] = \ElggMenuItem::factory([ - 'name' => 'configure_utilities:menu_items', - 'text' => elgg_echo('admin:configure_utilities:menu_items'), - 'href' => 'admin/configure_utilities/menu_items', - 'parent_name' => 'configure_utilities', + 'priority' => 40, + 'parent_name' => 'configure', ]); + $return[] = \ElggMenuItem::factory([ 'name' => 'configure_utilities:robots', 'text' => elgg_echo('admin:configure_utilities:robots'), 'href' => 'admin/configure_utilities/robots', - 'parent_name' => 'configure_utilities', + 'priority' => 50, + 'parent_name' => 'configure', + ]); + + return $return; + } + + /** + * Add the utilities section to the admin page menu + * + * @param \Elgg\Event $event 'register', 'menu:admin_header' + * + * @return void|MenuItems + */ + public static function registerAdminUtilities(\Elgg\Event $event) { + if (!elgg_is_admin_logged_in()) { + return; + } + + /* @var $return MenuItems */ + $return = $event->getValue(); + + $return[] = \ElggMenuItem::factory([ + 'name' => 'utilities', + 'text' => elgg_echo('menu:page:header:utilities'), + 'href' => false, + 'priority' => 30, + ]); + + $return[] = \ElggMenuItem::factory([ + 'name' => 'configure_utilities:menu_items', + 'text' => elgg_echo('admin:configure_utilities:menu_items'), + 'href' => 'admin/configure_utilities/menu_items', + 'parent_name' => 'utilities', ]); return $return; @@ -306,7 +328,7 @@ public static function registerAdminConfigure(\Elgg\Event $event) { * @return void|MenuItems */ public static function registerAdminDefaultWidgets(\Elgg\Event $event) { - if (!elgg_in_context('admin') || !elgg_is_admin_logged_in()) { + if (!elgg_is_admin_logged_in()) { return; } @@ -321,7 +343,7 @@ public static function registerAdminDefaultWidgets(\Elgg\Event $event) { 'name' => 'default_widgets', 'text' => elgg_echo('admin:configure_utilities:default_widgets'), 'href' => 'admin/configure_utilities/default_widgets', - 'parent_name' => 'configure_utilities', + 'parent_name' => 'utilities', ]); return $return; @@ -335,7 +357,7 @@ public static function registerAdminDefaultWidgets(\Elgg\Event $event) { * @return void|MenuItems */ public static function registerAdminInformation(\Elgg\Event $event) { - if (!elgg_in_context('admin') || !elgg_is_admin_logged_in()) { + if (!elgg_is_admin_logged_in()) { return; } @@ -346,6 +368,7 @@ public static function registerAdminInformation(\Elgg\Event $event) { 'name' => 'information', 'text' => elgg_echo('menu:page:header:information'), 'href' => false, + 'priority' => 40, ]); $return[] = \ElggMenuItem::factory([ diff --git a/engine/classes/Elgg/Menus/Breadcrumbs.php b/engine/classes/Elgg/Menus/Breadcrumbs.php index e6b9fbac0c3..52507fa8c94 100644 --- a/engine/classes/Elgg/Menus/Breadcrumbs.php +++ b/engine/classes/Elgg/Menus/Breadcrumbs.php @@ -17,9 +17,9 @@ class Breadcrumbs { * * @param \Elgg\Event $event 'prepare', 'menu:breadcrumbs' * - * @return void|PreparedMenu + * @return void */ - public static function cleanupBreadcrumbs(\Elgg\Event $event) { + public static function cleanupBreadcrumbs(\Elgg\Event $event): void { /* @var $breadcrumbs PreparedMenu */ $breadcrumbs = $event->getValue(); @@ -36,7 +36,46 @@ public static function cleanupBreadcrumbs(\Elgg\Event $event) { // remove last crumb if it has no link if (empty($last->getHref())) { + elgg_log("Having a breadcrumb at the end of the list without a link makes no sense. Please update your code for the '{$last->getText()}[{$last->getID()}]' breadcrumb.", 'NOTICE'); $breadcrumbs->getSection('default')->remove($last->getID()); + } elseif (!$last->getChildren() && elgg_http_url_is_identical(elgg_get_current_url(), $last->getHref())) { + elgg_log("Having a breadcrumb at the end of the list which links to the current page makes no sense. Please update your code for the '{$last->getText()}[{$last->getID()}]' breadcrumb.", 'NOTICE'); + $breadcrumbs->getSection('default')->remove($last->getID()); + } + } + + /** + * Adds a home item + * + * @param \Elgg\Event $event 'prepare', 'menu:breadcrumbs' + * + * @return null|PreparedMenu + */ + public static function addHomeItem(\Elgg\Event $event): ?PreparedMenu { + /* @var $return PreparedMenu */ + $return = $event->getValue(); + + /* @var $items \ElggMenuItem[] */ + $items = $return->getItems('default'); + if (empty($items)) { + return null; + } + + $href = elgg_get_site_url(); + if (elgg_in_context('admin')) { + $href = elgg_generate_url('admin'); } + + array_unshift($items, \ElggMenuItem::factory([ + 'name' => 'home', + 'icon' => 'home', + 'text' => false, + 'title' => elgg_get_site_entity()->getDisplayName(), + 'href' => $href, + ])); + + $return->getSection('default')->fill($items); + + return $return; } } diff --git a/engine/classes/Elgg/Menus/Entity.php b/engine/classes/Elgg/Menus/Entity.php index 4b75dba4cd0..39451c6a29a 100644 --- a/engine/classes/Elgg/Menus/Entity.php +++ b/engine/classes/Elgg/Menus/Entity.php @@ -27,14 +27,23 @@ public static function registerEdit(\Elgg\Event $event) { return; } - $edit_url = elgg_generate_entity_url($entity, 'edit'); + /* @var $return MenuItems */ + $return = $event->getValue(); - if (empty($edit_url) || !$entity->canEdit()) { + if ($return->get('edit')) { + // a menu item for editing already exists return; } - /* @var $return MenuItems */ - $return = $event->getValue(); + if (!$entity->canEdit()) { + // checking this before generating the url to prevent notices from deprecated routes + return; + } + + $edit_url = elgg_generate_entity_url($entity, 'edit'); + if (empty($edit_url)) { + return; + } $return[] = \ElggMenuItem::factory([ 'name' => 'edit', @@ -51,7 +60,7 @@ public static function registerEdit(\Elgg\Event $event) { /** * Register the delete menu item * - * @param \Elgg\Event $event 'register', 'menu:entity' + * @param \Elgg\Event $event 'register', 'menu:entity|menu:entity:trash' * * @return void|MenuItems */ @@ -64,11 +73,7 @@ public static function registerDelete(\Elgg\Event $event) { return; } - $delete_url = elgg_generate_action_url('entity/delete', [ - 'guid' => $entity->guid, - ]); - - if (empty($delete_url) || !$entity->canDelete()) { + if (!$entity->canDelete()) { return; } @@ -80,7 +85,9 @@ public static function registerDelete(\Elgg\Event $event) { 'icon' => 'delete', 'text' => elgg_echo('delete'), 'title' => elgg_echo('delete:this'), - 'href' => $delete_url, + 'href' => elgg_generate_action_url('entity/delete', [ + 'guid' => $entity->guid, + ]), 'confirm' => elgg_echo('deleteconfirm'), 'priority' => 950, ]); @@ -88,6 +95,80 @@ public static function registerDelete(\Elgg\Event $event) { return $return; } + /** + * Register the trash menu item + * + * @param \Elgg\Event $event 'register', 'menu:entity' + * + * @return null|MenuItems + */ + public static function registerTrash(\Elgg\Event $event): ?MenuItems { + if (!elgg_get_config('trash_enabled')) { + return null; + } + + $entity = $event->getEntityParam(); + if (!$entity instanceof \ElggEntity || $entity instanceof \ElggUser || $entity instanceof \ElggPlugin || $entity instanceof \ElggUpgrade) { + // users mostly use the hover menu for their actions + // plugins can't be removed + // upgrades deleting has no point, they'll be rediscovered again + return null; + } + + if ($entity->isDeleted() || !$entity->canDelete() || !$entity->hasCapability('restorable')) { + return null; + } + + /* @var $return MenuItems */ + $return = $event->getValue(); + + // replace the delete menu item with the trash action + $return->remove('delete'); + + $return[] = \ElggMenuItem::factory([ + 'name' => 'trash', + 'icon' => 'trash-alt', + 'text' => elgg_echo('trash'), + 'title' => elgg_echo('trash:this'), + 'href' => elgg_generate_action_url('entity/trash', [ + 'guid' => $entity->guid, + ]), + 'confirm' => elgg_echo('trashconfirm'), + 'priority' => 950, + ]); + + return $return; + } + + /** + * Registers menu items for the entity menu of a comment + * + * @param \Elgg\Event $event 'register', 'menu:entity:object:comment' + * + * @return void|MenuItems + */ + public static function registerComment(\Elgg\Event $event) { + $entity = $event->getEntityParam(); + if (!$entity instanceof \ElggComment || !$entity->canEdit()) { + return; + } + + /* @var $return MenuItems */ + $return = $event->getValue(); + + $return[] = \ElggMenuItem::factory([ + 'name' => 'edit', + 'icon' => 'edit', + 'text' => elgg_echo('edit'), + 'title' => elgg_echo('edit:this'), + 'href' => false, + 'priority' => 900, + 'data-comment-guid' => $entity->guid, + ]); + + return $return; + } + /** * Registers menu items for the entity menu of a plugin * @@ -205,7 +286,7 @@ public static function registerUpgrade(\Elgg\Event $event) { 'text' => elgg_echo('admin:upgrades:menu:run_single'), 'href' => false, 'deps' => [ - 'core/js/upgrader', + 'admin/upgrades', ], 'data-guid' => $entity->guid, 'priority' => 600, diff --git a/engine/classes/Elgg/Menus/EntityTrash.php b/engine/classes/Elgg/Menus/EntityTrash.php new file mode 100644 index 00000000000..25cde7a00c6 --- /dev/null +++ b/engine/classes/Elgg/Menus/EntityTrash.php @@ -0,0 +1,56 @@ +getEntityParam(); + if (!$entity->canEdit() || !$entity->hasCapability('restorable')) { + return null; + } + + /* @var $return MenuItems */ + $return = $event->getValue(); + + $container = $entity->getContainerEntity(); + if ($container instanceof \ElggEntity && !$container->isDeleted()) { + $return[] = \ElggMenuItem::factory([ + 'name' => 'restore', + 'icon' => 'trash-restore-alt', + 'text' => elgg_echo('restore:this'), + 'href' => elgg_generate_action_url('entity/restore', [ + 'guid' => $entity->guid, + ]), + 'confirm' => elgg_echo('restoreconfirm'), + 'priority' => 900, + ]); + } else { + $return[] = \ElggMenuItem::factory([ + 'name' => 'restore_and_move', + 'icon' => 'trash-restore-alt', + 'text' => elgg_echo('restore:this:move'), + 'title' => elgg_echo('restore:this'), + 'href' => elgg_http_add_url_query_elements('ajax/form/entity/chooserestoredestination', [ + 'entity_guid' => $entity->guid, + ]), + 'link_class' => 'elgg-lightbox', + 'priority' => 800, + ]); + } + + return $return; + } +} diff --git a/engine/classes/Elgg/Menus/Page.php b/engine/classes/Elgg/Menus/Page.php index e7666d2dc18..fc9fa5923cd 100644 --- a/engine/classes/Elgg/Menus/Page.php +++ b/engine/classes/Elgg/Menus/Page.php @@ -120,6 +120,17 @@ public static function registerUserSettings(\Elgg\Event $event) { 'section' => 'configure', ]); + if (elgg_get_config('trash_enabled')) { + $return[] = \ElggMenuItem::factory([ + 'name' => '1_trash', + 'text' => elgg_echo('trash:menu:page'), + 'href' => elgg_generate_url('trash:owner', [ + 'username' => $user->username, + ]), + 'section' => 'configure', + ]); + } + return $return; } @@ -173,45 +184,4 @@ public static function registerUserSettingsPlugins(\Elgg\Event $event) { return $return; } - - /** - * Moves menu items registered to the page to the admin header - * - * @param \Elgg\Event $event 'register', 'menu:page' - * - * @return void - * - * @since 5.0 - */ - public static function moveOldAdminSectionsToAdminHeader(\Elgg\Event $event) { - if (!elgg_in_context('admin') || !elgg_is_admin_logged_in()) { - return; - } - - /* @var $return MenuItems */ - $return = $event->getValue(); - - $remove_items = []; - foreach ($return as $menu_item) { - $section_name = $menu_item->getSection(); - if (!in_array($section_name, ['configure', 'administer', 'information'])) { - continue; - } - - $menu_item->setSection('default'); - if (empty($menu_item->getParentName())) { - $menu_item->setParentName($section_name); - } - - elgg_register_menu_item('admin_header', $menu_item); - $remove_items[] = $menu_item->getID(); - - elgg_deprecated_notice("The menu item [{$menu_item->getID()}] is using an old section of the admin page menu. These sections have been moved to the 'admin_header' menu. Please update your menu item configuration.", '5.0'); - } - - foreach ($remove_items as $id) { - // need to remove separately because removing during a foreach has issues - $return->remove($id); - } - } } diff --git a/engine/classes/Elgg/Menus/Social.php b/engine/classes/Elgg/Menus/Social.php index a1feb857ac8..ac25ce5b31b 100644 --- a/engine/classes/Elgg/Menus/Social.php +++ b/engine/classes/Elgg/Menus/Social.php @@ -28,6 +28,10 @@ public static function registerComments(\Elgg\Event $event) { if (!$entity->hasCapability('commentable')) { return; } + + if ($entity->isDeleted()) { + return; + } /* @var $return MenuItems */ $return = $event->getValue(); diff --git a/engine/classes/Elgg/Menus/Title.php b/engine/classes/Elgg/Menus/Title.php index dddda2a7bb8..1f27d7d2aca 100644 --- a/engine/classes/Elgg/Menus/Title.php +++ b/engine/classes/Elgg/Menus/Title.php @@ -99,6 +99,7 @@ public static function registerEntityToTitle(\Elgg\Event $event) { 'icon' => 'ellipsis-v', 'href' => false, 'text' => '', + 'title' => elgg_echo('more'), 'child_menu' => [ 'display' => 'dropdown', 'data-position' => json_encode([ diff --git a/engine/classes/Elgg/Menus/Widget.php b/engine/classes/Elgg/Menus/Widget.php index dd4a7b44106..218f987dfd3 100644 --- a/engine/classes/Elgg/Menus/Widget.php +++ b/engine/classes/Elgg/Menus/Widget.php @@ -36,8 +36,17 @@ public static function registerEdit(\Elgg\Event $event) { 'name' => 'settings', 'text' => elgg_view_icon('settings-alt'), 'title' => elgg_echo('widget:edit'), - 'href' => "#widget-edit-{$widget->guid}", - 'link_class' => ['elgg-widget-edit-button', 'elgg-toggle'], + 'href' => elgg_http_add_url_query_elements('ajax/view/object/widget/edit', [ + 'guid' => $widget->guid, + 'show_access' => $event->getParam('show_access', true), + ]), + 'data-colorbox-opts' => json_encode([ + 'width' => 750, + 'max-height' => '80%', + 'trapFocus' => false, + 'fixed' => true, + ]), + 'link_class' => ['elgg-widget-edit-button', 'elgg-lightbox'], 'priority' => 800, ]); diff --git a/engine/classes/Elgg/Notifications/CreateContentEventHandler.php b/engine/classes/Elgg/Notifications/CreateContentEventHandler.php index 275838d8510..9c1a78f24c1 100644 --- a/engine/classes/Elgg/Notifications/CreateContentEventHandler.php +++ b/engine/classes/Elgg/Notifications/CreateContentEventHandler.php @@ -28,6 +28,16 @@ public function __invoke(\Elgg\Event $event): void { return; } + if ($entity instanceof \ElggObject) { + $notification_events = _elgg_services()->notifications->getEvents(); + if (!isset($notification_events[$entity->getType()]) || !isset($notification_events[$entity->getType()][$entity->getSubtype()])) { + // no notification events registered for this entity type/subtype + // so there is no need to subscribe + // this also prevents the database from flooding with relationships that are never used (e.g. subscriptions to site notifications) + return; + } + } + $content_preferences = $owner->getNotificationSettings('content_create'); $enabled_methods = array_keys(array_filter($content_preferences)); diff --git a/engine/classes/Elgg/Notifications/SubscriptionsService.php b/engine/classes/Elgg/Notifications/SubscriptionsService.php index 1a0d1376d5f..8b5dd4d9842 100644 --- a/engine/classes/Elgg/Notifications/SubscriptionsService.php +++ b/engine/classes/Elgg/Notifications/SubscriptionsService.php @@ -28,21 +28,6 @@ class SubscriptionsService { * @var string Used when an entity no longer wishes to recieve notifications */ const MUTE_NOTIFICATIONS_RELATIONSHIP = 'mute_notifications'; - - /** - * @var Database - */ - protected $db; - - /** - * @var RelationshipsTable - */ - protected $relationshipsTable; - - /** - * @var EventsService - */ - protected $events; /** * Constructor @@ -51,10 +36,11 @@ class SubscriptionsService { * @param RelationshipsTable $relationshipsTable Relationship database table * @param EventsService $events Events service */ - public function __construct(Database $db, RelationshipsTable $relationshipsTable, EventsService $events) { - $this->db = $db; - $this->relationshipsTable = $relationshipsTable; - $this->events = $events; + public function __construct( + protected Database $db, + protected RelationshipsTable $relationshipsTable, + protected EventsService $events + ) { } /** @@ -265,7 +251,7 @@ public function hasSubscriptions(int $user_guid, int $target_guid, array $method return false; } - $select = Select::fromTable('entity_relationships'); + $select = Select::fromTable(RelationshipsTable::TABLE_NAME); $select->select('count(*) as total') ->where($select->compare('guid_one', '=', $user_guid, ELGG_VALUE_GUID)) ->andWhere($select->compare('guid_two', '=', $target_guid, ELGG_VALUE_GUID)); @@ -330,7 +316,7 @@ public function removeSubscription(int $user_guid, string $method, int $target_g * @since 4.0 */ public function removeSubscriptions(int $user_guid, int $target_guid, array $methods = []): bool { - $delete = Delete::fromTable('entity_relationships'); + $delete = Delete::fromTable(RelationshipsTable::TABLE_NAME); $delete->where($delete->compare('guid_one', '=', $user_guid, ELGG_VALUE_GUID)) ->andWhere($delete->compare('guid_two', '=', $target_guid, ELGG_VALUE_GUID)); @@ -561,7 +547,7 @@ protected function filterMutedNotifications(array $subscriptions, NotificationEv } // get muted relations - $select = Select::fromTable('entity_relationships'); + $select = Select::fromTable(RelationshipsTable::TABLE_NAME); $select->select('guid_one') ->where($select->compare('relationship', '=', self::MUTE_NOTIFICATIONS_RELATIONSHIP, ELGG_VALUE_STRING)) ->andWhere($select->compare('guid_two', 'in', $guids_to_check, ELGG_VALUE_GUID)); @@ -653,7 +639,7 @@ protected function getSubscriptionRecords(array $container_guid, array $methods, return []; } - $select = Select::fromTable('entity_relationships'); + $select = Select::fromTable(RelationshipsTable::TABLE_NAME); $select->select('guid_one AS guid') ->addSelect("GROUP_CONCAT(relationship SEPARATOR ',') AS methods") ->where($select->compare('guid_two', 'in', $container_guid, ELGG_VALUE_GUID)) diff --git a/engine/classes/Elgg/Page/AddMetasHandler.php b/engine/classes/Elgg/Page/AddMetasHandler.php index 388f0ff76cd..7a0b0e970aa 100644 --- a/engine/classes/Elgg/Page/AddMetasHandler.php +++ b/engine/classes/Elgg/Page/AddMetasHandler.php @@ -35,7 +35,7 @@ public function __invoke(\Elgg\Event $event) { // https://developer.chrome.com/multidevice/android/installtohomescreen $head_params['metas']['viewport'] = [ 'name' => 'viewport', - 'content' => 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0', + 'content' => 'width=device-width, initial-scale=1.0, maximum-scale=5.0, user-scalable=1', ]; $head_params['metas']['mobile-web-app-capable'] = [ diff --git a/engine/classes/Elgg/PersistentLoginService.php b/engine/classes/Elgg/PersistentLoginService.php index cb248fb7a0a..834cfb270d5 100644 --- a/engine/classes/Elgg/PersistentLoginService.php +++ b/engine/classes/Elgg/PersistentLoginService.php @@ -18,30 +18,9 @@ class PersistentLoginService { use TimeUsing; - /** - * @var array - */ - protected $cookie_config; - - /** - * @var string - */ - protected $cookie_token; - - /** - * @var \ElggSession - */ - protected $session; + protected array $cookie_config; - /** - * @var \Elgg\Security\Crypto - */ - protected $crypto; - - /** - * @var UsersRememberMeCookiesTable - */ - protected $persistent_cookie_table; + protected string $cookie_token; /** * @var callable @@ -59,15 +38,12 @@ class PersistentLoginService { * @param \Elgg\Http\Request $request The request */ public function __construct( - UsersRememberMeCookiesTable $cookie_table, - \ElggSession $session, - \Elgg\Security\Crypto $crypto, - \Elgg\Config $config, - \Elgg\Http\Request $request) { - $this->persistent_cookie_table = $cookie_table; - $this->session = $session; - $this->crypto = $crypto; - + protected UsersRememberMeCookiesTable $cookie_table, + protected \ElggSession $session, + protected \Elgg\Security\Crypto $crypto, + \Elgg\Config $config, + \Elgg\Http\Request $request + ) { $global_cookies_config = $config->getCookieConfig(); $this->cookie_config = $global_cookies_config['remember_me']; @@ -85,7 +61,7 @@ public function makeLoginPersistent(\ElggUser $user): void { $token = $this->generateToken(); $hash = $this->hashToken($token); - $this->persistent_cookie_table->insertHash($user, $hash); + $this->cookie_table->insertHash($user, $hash); $this->setCookie($token); $this->setSessionToken($token); } @@ -98,7 +74,7 @@ public function makeLoginPersistent(\ElggUser $user): void { public function removePersistentLogin(): void { if ($this->cookie_token) { $client_hash = $this->hashToken($this->cookie_token); - $this->persistent_cookie_table->deleteHash($client_hash); + $this->cookie_table->deleteHash($client_hash); } $this->setCookie(''); @@ -114,7 +90,7 @@ public function removePersistentLogin(): void { * @return void */ public function handlePasswordChange(\ElggUser $subject, \ElggUser $modifier = null): void { - $this->persistent_cookie_table->deleteAllHashes($subject); + $this->cookie_table->deleteAllHashes($subject); if (!$modifier || ($modifier->guid !== $subject->guid) || !$this->cookie_token) { return; } @@ -162,7 +138,7 @@ public function getUserFromToken(string $token): ?\ElggUser { return null; } - $user_row = $this->persistent_cookie_table->getRowFromHash($hash); + $user_row = $this->cookie_table->getRowFromHash($hash); if (empty($user_row)) { return null; } @@ -185,7 +161,7 @@ public function updateTokenUsage(\ElggUser $user): ?bool { // update the database record // not interested in number of updated rows, as an update in the same second won't update the row - $this->persistent_cookie_table->updateHash($user, $this->hashToken($this->cookie_token)); + $this->cookie_table->updateHash($user, $this->hashToken($this->cookie_token)); // also update the cookie lifetime client-side $this->setCookie($this->cookie_token); @@ -211,7 +187,7 @@ public function removeExpiredTokens($time): bool { return false; } - return (bool) $this->persistent_cookie_table->deleteExpiredHashes($time->getTimestamp()); + return (bool) $this->cookie_table->deleteExpiredHashes($time->getTimestamp()); } /** diff --git a/engine/classes/Elgg/Plugin/Composer.php b/engine/classes/Elgg/Plugin/Composer.php index 7a37daeb78c..0926faf2486 100644 --- a/engine/classes/Elgg/Plugin/Composer.php +++ b/engine/classes/Elgg/Plugin/Composer.php @@ -16,11 +16,6 @@ */ class Composer { - /** - * @var \ElggPlugin - */ - protected $plugin; - /** * @var \Eloquent\Composer\Configuration\Element\Configuration */ @@ -33,9 +28,7 @@ class Composer { * * @throws ComposerException */ - public function __construct(\ElggPlugin $plugin) { - $this->plugin = $plugin; - + public function __construct(protected \ElggPlugin $plugin) { try { // need to suppress warning because of deprecated notices that get converted to warnings during phpunit $reader = @new \Eloquent\Composer\Configuration\ConfigurationReader; @@ -193,7 +186,14 @@ public function assertActivePluginConflicts() { * @return boolean */ public function checkConstraints($version, $constraints) { - return Semver::satisfies($version, $constraints); + try { + return Semver::satisfies($version, $constraints); + } catch (\UnexpectedValueException $e) { + // something is wrong with the version number + elgg_log($e, 'ERROR'); + } + + return false; } /** diff --git a/engine/classes/Elgg/PluginBootstrap.php b/engine/classes/Elgg/PluginBootstrap.php index bb8eb04c24c..61382c2f194 100644 --- a/engine/classes/Elgg/PluginBootstrap.php +++ b/engine/classes/Elgg/PluginBootstrap.php @@ -9,25 +9,13 @@ */ abstract class PluginBootstrap implements PluginBootstrapInterface { - /** - * @var \ElggPlugin - */ - protected $plugin; - - /** - * @var PublicContainer - */ - protected $dic; - /** * Constructor * * @param \ElggPlugin $plugin The plugin * @param PublicContainer $dic Public services */ - public function __construct(\ElggPlugin $plugin, PublicContainer $dic) { - $this->plugin = $plugin; - $this->dic = $dic; + public function __construct(protected \ElggPlugin $plugin, protected PublicContainer $dic) { } /** diff --git a/engine/classes/Elgg/PluginBootstrapInterface.php b/engine/classes/Elgg/PluginBootstrapInterface.php index 4f605041bee..ab833fbbecd 100644 --- a/engine/classes/Elgg/PluginBootstrapInterface.php +++ b/engine/classes/Elgg/PluginBootstrapInterface.php @@ -3,7 +3,6 @@ namespace Elgg; use Elgg\Di\PublicContainer; -use ElggPlugin; /** * Plugin bootstrap interface @@ -81,13 +80,15 @@ public function upgrade(); /** * Returns Elgg's public DI container + * * @return PublicContainer */ public function elgg(); /** * Returns plugin entity this bootstrap is related to - * @return ElggPlugin + * + * @return \ElggPlugin */ public function plugin(); } diff --git a/engine/classes/Elgg/Project/ChangelogWriter.php b/engine/classes/Elgg/Project/ChangelogWriter.php new file mode 100644 index 00000000000..57f724cd5e9 --- /dev/null +++ b/engine/classes/Elgg/Project/ChangelogWriter.php @@ -0,0 +1,490 @@ + 'Features', + 'performance' => 'Performance', + 'documentation' => 'Documentation', + 'fix' => 'Bug fixes', + 'deprecated' => 'Deprecations', + 'breaking' => 'Breaking Changes', + 'removed' => 'Removed', + ]; + + /** + * Constructor + * + * @param array $options writer options + */ + public function __construct(array $options = []) { + $defaults = [ + 'changelog' => Paths::elgg() . 'CHANGELOG.md', + 'version' => null, + 'notes' => '', + 'repository' => 'https://github.com/Elgg/Elgg/', + ]; + + $options = array_merge($defaults, $options); + if (empty($options['version'])) { + throw new InvalidArgumentException('Please provide a release version number'); + } + + if (!file_exists($options['changelog']) || !is_writable($options['changelog'])) { + throw new InvalidArgumentException("The changelog file doesn't exist or is not writable"); + } + + $this->options = $options; + } + + /** + * Write the changelog for the current release + * + * @return void + */ + public function __invoke(): void { + $tags = $this->getGitTags(); + + $sections = []; + + $sections[] = $this->formatHeader(); + $sections[] = $this->readNotes(); + + $contributors = $this->getGitContributors([ + 'exclude' => $tags, + ]); + $sections[] = $this->formatContributors($contributors); + + $commits = $this->getGitCommits([ + 'exclude' => $tags, + ]); + $sections[] = $this->formatCommits($commits); + + $sections = array_filter($sections); + $output = trim(implode(PHP_EOL . PHP_EOL, $sections)); + + $this->writeChangelog($output); + } + + /** + * Read anything in the changelog before the first '' and consider this release notes + * + * @return string + */ + protected function readNotes(): string { + $contents = file_get_contents($this->getOption('changelog')); + $first_anchor = strpos($contents, 'executeCommand($command); + if (!isset($commits)) { + return []; + } + + $results = []; + $result = [ + 'body' => '', + ]; + $index = 0; + $subject_pattern = '/^((Merge )|(Revert )|((\w*)\(([\w]+)\)\: ([^\n]*))$)/'; + foreach ($commits as $line) { + if ($line === '==END==') { + $result['body'] = trim($result['body'] ?: '', PHP_EOL); + + $results[] = $result; + $index = 0; + $result = [ + 'body' => '', + ]; + continue; + } + + switch ($index) { + case 0: // long hash + $result['hash'] = $line; + break; + + case 1: // short hash + $result['short_hash'] = $line; + break; + + case 2: // subject + $matches = []; + preg_match($subject_pattern, $line, $matches); + + $result['type'] = $matches[5] ?? 'skip'; + $result['component'] = $matches[6] ?? ''; + $result['subject'] = $matches[7] ?? ''; + break; + + default: // the rest of the commit body + if (empty($line)) { + break; + } + + $result['body'] .= $line . PHP_EOL; + break; + } + + $index++; + } + + $filtered = []; + $fixes_pattern = '/(closes|fixes)\s+#(\d+)/i'; + foreach ($results as $result) { + if ($result['type'] === 'skip') { + continue; + } + + // check if the commit contains a breaking change + if (str_contains(strtolower($result['body']), 'breaking change:')) { + $result['type'] = 'break'; + } + + // see if the commit fixed/closed issues + $matches = []; + preg_match_all($fixes_pattern, $result['body'], $matches); + if (!empty($matches) && !empty($matches[2])) { + $result['closes'] = array_map(function ($value) { + return (int) $value; + }, $matches[2]); + } + + $filtered[] = $result; + } + + return $filtered; + } + + /** + * Get the contributors + * + * @param array $options options + * + * @return array + */ + protected function getGitContributors(array $options = []): array { + $defaults = [ + 'exclude' => [], + 'to' => 'HEAD', + ]; + $options = array_merge($defaults, $options); + + $command = vsprintf('git shortlog -sne %s --no-merges %s', [ + $options['to'], + implode(' ', array_map(function ($value) { + if (str_contains(PHP_OS, 'WIN')) { + return "^^{$value}"; + } + + return "^{$value}"; + }, $options['exclude'])), + ]); + + $contributors = $this->executeCommand($command); + if (!isset($contributors)) { + return []; + } + + $contributor_pattern = '/\s+([0-9]+)\s+(.*)\s<(.*)>/'; + $result = []; + foreach ($contributors as $contributor) { + $matches = []; + preg_match($contributor_pattern, $contributor, $matches); + if (empty($matches)) { + continue; + } + + $result[] = [ + 'count' => (int) $matches[1], + 'name' => $matches[2], + 'email' => $matches[3], + ]; + } + + // sort the contributors with most contributed first + usort($result, function ($a, $b) { + return $b['count'] - $a['count']; + }); + + return $result; + } + + /** + * Format the different commits into sections + * + * @param array $commits all the commits + * + * @return string + */ + protected function formatCommits(array $commits): string { + if (empty($commits)) { + return ''; + } + + // group commits by type + $types = []; + foreach ($commits as $commit) { + $type = $commit['type']; + if (str_starts_with($type, 'feat')) { + $type = 'feature'; + } elseif (str_starts_with($type, 'fix')) { + $type = 'fix'; + } elseif (str_starts_with($type, 'perf')) { + $type = 'performance'; + } elseif (str_starts_with($type, 'doc')) { + $type = 'documentation'; + } elseif (str_starts_with($type, 'deprecate')) { + $type = 'deprecated'; + } elseif (str_starts_with($type, 'break')) { + $type = 'breaking'; + } elseif (str_starts_with($type, 'remove')) { + $type = 'removed'; + } else { + continue; + } + + if (!isset($types[$type])) { + $types[$type] = []; + } + + $component = $commit['component']; + if (!isset($types[$type][$component])) { + $types[$type][$component] = []; + } + + $subject = $commit['subject']; + $commit_link = $this->makeCommitLink($commit); + $closes = ''; + if (!empty($commit['closes'])) { + $closes .= 'closes '; + foreach ($commit['closes'] as $issue_id) { + $closes .= $this->makeIssueLink($issue_id) . ', '; + } + } + + $types[$type][$component][] = trim(vsprintf('%s %s %s', [ + $subject, + $commit_link, + $closes, + ]), ' ,'); + } + + if (empty($types)) { + return ''; + } + + // format the different types into sections + $sections = []; + foreach ($this->commit_types as $type => $label) { + if (!isset($types[$type])) { + continue; + } + + $section = "#### {$label}" . PHP_EOL . PHP_EOL; + + foreach ($types[$type] as $component => $commits) { + if (count($commits) === 1) { + $section .= "* **{$component}:** {$commits[0]}" . PHP_EOL; + } else { + $section .= "* **{$component}:**" . PHP_EOL; + + foreach ($commits as $commit) { + $section .= ' * ' . $commit . PHP_EOL; + } + } + } + + $sections[] = $section; + } + + return trim(implode(PHP_EOL . PHP_EOL, $sections)); + } + + /** + * Format the contributors into a section + * + * @param array $contributors contributors + * + * @return string + */ + protected function formatContributors(array $contributors): string { + if (empty($contributors)) { + return ''; + } + + $section = '#### Contributors' . PHP_EOL . PHP_EOL; + + foreach ($contributors as $contributor) { + $section .= "* {$contributor['name']} ({$contributor['count']})" . PHP_EOL; + } + + return trim($section); + } + + /** + * Format release header + * + * @return string + */ + protected function formatHeader(): string { + $version = $this->getOption('version', ''); + $parts = explode('.', $version); + $date = date('Y-m-d'); + + $section = '' . PHP_EOL; + if ($parts[2] === '0') { + // major version + $section .= "## {$version} ({$date})"; + } else { + // patch version + $section .= "### {$version} ({$date})"; + } + + return trim($section); + } + + /** + * Get a link to a GitHub commit + * + * @param array $commit commit information + * + * @return string + */ + protected function makeCommitLink(array $commit): string { + if (empty($commit)) { + return ''; + } + + return vsprintf('[%s](%s/commit/%s)', [ + $commit['short_hash'], + $this->getOption('repository'), + $commit['hash'], + ]); + } + + /** + * Generate a link to a GitHub issue + * + * @param int $issue_id the issue ID + * + * @return string + */ + protected function makeIssueLink(int $issue_id): string { + if (empty($issue_id)) { + return ''; + } + + return vsprintf('[#%s](%s/commit/%s)', [ + $issue_id, + $this->getOption('repository'), + $issue_id, + ]); + } + + /** + * Write the release notes to the changelog + * + * @param string $release_notes release notes + * + * @return void + */ + protected function writeChangelog(string $release_notes): void { + $contents = file_get_contents($this->getOption('changelog')); + $first_anchor = strpos($contents, 'serverSupportsRemoteRead = ($this->fetchUrl($url) === Request::REWRITE_TEST_OUTPUT); return $this->serverSupportsRemoteRead; } @@ -113,7 +111,7 @@ public function runRewriteTest($url) { * * @return boolean */ - public function runLocalhostAccessTest() { + public function runLocalhostAccessTest(): bool { return (bool) $this->fetchUrl(_elgg_services()->config->wwwroot); } @@ -124,7 +122,7 @@ public function runLocalhostAccessTest() { * * @return string Note that empty string may imply failure in fetching or empty response */ - private function fetchUrl($url) { + private function fetchUrl(string $url): string { $response = ''; if (ini_get('allow_url_fopen')) { @@ -157,13 +155,12 @@ private function fetchUrl($url) { * * @return bool */ - public function createHtaccess($url) { - $root = Local::projectRoot(); - $file = $root->getFile('.htaccess'); + public function createHtaccess(string $url): bool { + $htaccess = Paths::project() . '.htaccess'; - if ($file->exists()) { + if (file_exists($htaccess)) { // check that this is the Elgg .htaccess - $data = $file->getContents(); + $data = file_get_contents($htaccess); if (empty($data)) { // don't have permission to read the file $this->htaccessIssue = 'read_permission'; @@ -184,13 +181,13 @@ public function createHtaccess($url) { return true; } - if (!is_writable($root->getPath())) { + if (!is_writable(Paths::project())) { $this->htaccessIssue = 'write_permission'; return false; } // create the .htaccess file - $result = copy(Paths::elgg() . 'install/config/htaccess.dist', $file->getPath()); + $result = copy(Paths::elgg() . 'install/config/htaccess.dist', $htaccess); if (!$result) { $this->htaccessIssue = 'cannot_copy'; return false; @@ -201,10 +198,10 @@ public function createHtaccess($url) { //try to rewrite to guessed subdirectory $subdir = $this->guessSubdirectory($url); if (!empty($subdir)) { - $contents = $file->getContents(); + $contents = file_get_contents($htaccess); $contents = preg_replace("/#RewriteBase \/(\r?\n)/", "RewriteBase $subdir\$1", $contents); if ($contents) { - $file->putContents($contents); + file_put_contents($htaccess, $contents); } } } @@ -219,7 +216,7 @@ public function createHtaccess($url) { * * @return array */ - protected function returnStatus($url) { + protected function returnStatus(string $url): array { if ($this->rewriteTestPassed) { return [ 'severity' => 'success', diff --git a/engine/classes/Elgg/Router/UrlGenerator.php b/engine/classes/Elgg/Router/UrlGenerator.php index bf732d4f4e0..6a61c27d4c3 100644 --- a/engine/classes/Elgg/Router/UrlGenerator.php +++ b/engine/classes/Elgg/Router/UrlGenerator.php @@ -2,9 +2,22 @@ namespace Elgg\Router; +use Psr\Log\LoggerInterface; + /** * UrlGenerator Wrapper */ class UrlGenerator extends \Symfony\Component\Routing\Generator\UrlGenerator { + /** + * Create a new UrlGenerator + * + * @param RouteCollection $routes route collection + * @param RequestContext $context request context + * @param LoggerInterface $logger logger + * @param string $defaultLocale optional locale to generate urls for + */ + public function __construct(RouteCollection $routes, RequestContext $context, LoggerInterface $logger = null, string $defaultLocale = null) { + parent::__construct($routes, $context, $logger, $defaultLocale); + } } diff --git a/engine/classes/Elgg/Router/UrlMatcher.php b/engine/classes/Elgg/Router/UrlMatcher.php index ff57c3857a6..a20826b5bb4 100644 --- a/engine/classes/Elgg/Router/UrlMatcher.php +++ b/engine/classes/Elgg/Router/UrlMatcher.php @@ -7,4 +7,13 @@ */ class UrlMatcher extends \Symfony\Component\Routing\Matcher\UrlMatcher { + /** + * Create a new UrlMatcher + * + * @param RouteCollection $routes route collection + * @param RequestContext $context request context + */ + public function __construct(RouteCollection $routes, RequestContext $context) { + parent::__construct($routes, $context); + } } diff --git a/engine/classes/Elgg/Search/SearchService.php b/engine/classes/Elgg/Search/SearchService.php index 517363ffa22..e38ebcf2f93 100644 --- a/engine/classes/Elgg/Search/SearchService.php +++ b/engine/classes/Elgg/Search/SearchService.php @@ -21,21 +21,6 @@ */ class SearchService { - /** - * @var Config - */ - private $config; - - /** - * @var EventsService - */ - private $events; - - /** - * @var Database - */ - private $db; - use LegacyQueryOptionsAdapter; /** @@ -45,10 +30,11 @@ class SearchService { * @param \Elgg\EventsService $events Events service * @param Database $db Database */ - public function __construct(Config $config, EventsService $events, Database $db) { - $this->config = $config; - $this->events = $events; - $this->db = $db; + public function __construct( + protected Config $config, + protected EventsService $events, + protected Database $db + ) { } /** diff --git a/engine/classes/Elgg/Security/Hmac.php b/engine/classes/Elgg/Security/Hmac.php index 8a6886bd979..3f661e0d467 100644 --- a/engine/classes/Elgg/Security/Hmac.php +++ b/engine/classes/Elgg/Security/Hmac.php @@ -9,25 +9,12 @@ */ class Hmac { - /** - * @var string - */ - private $key; - /** * @var callable */ - private $comparator; + protected $comparator; - /** - * @var string - */ - private $data; - - /** - * @var string - */ - private $algo; + protected string $data; /** * Constructor @@ -39,8 +26,7 @@ class Hmac { * * @throws \Elgg\Exceptions\InvalidArgumentException */ - public function __construct($key, callable $comparator, $data, $algo = 'sha256') { - $this->key = $key; + public function __construct(protected string $key, callable $comparator, $data, protected string $algo = 'sha256') { $this->comparator = $comparator; if (!$data) { throw new InvalidArgumentException('$data cannot be empty'); @@ -51,7 +37,6 @@ public function __construct($key, callable $comparator, $data, $algo = 'sha256') } $this->data = $data; - $this->algo = $algo; } /** @@ -59,7 +44,7 @@ public function __construct($key, callable $comparator, $data, $algo = 'sha256') * * @return string */ - public function getToken() { + public function getToken(): string { $bytes = hash_hmac($this->algo, $this->data, $this->key, true); return Base64Url::encode($bytes); } @@ -68,9 +53,10 @@ public function getToken() { * Does the MAC match the given token? * * @param string $token HMAC token in Base64URL encoding + * * @return bool */ - public function matchesToken($token) { + public function matchesToken($token): bool { $expected_token = $this->getToken(); return call_user_func($this->comparator, $expected_token, $token); } diff --git a/engine/classes/Elgg/Security/HmacFactory.php b/engine/classes/Elgg/Security/HmacFactory.php index f5487c964da..06a5f9ffb5c 100644 --- a/engine/classes/Elgg/Security/HmacFactory.php +++ b/engine/classes/Elgg/Security/HmacFactory.php @@ -10,26 +10,14 @@ class HmacFactory { use TimeUsing; - - /** - * @var SiteSecret - */ - protected $site_secret; - - /** - * @var Crypto - */ - protected $crypto; /** * Constructor * - * @param SiteSecret $secret Site secret - * @param Crypto $crypto Elgg crypto service + * @param SiteSecret $site_secret Site secret + * @param Crypto $crypto Elgg crypto service */ - public function __construct(SiteSecret $secret, Crypto $crypto) { - $this->site_secret = $secret; - $this->crypto = $crypto; + public function __construct(protected SiteSecret $site_secret, protected Crypto $crypto) { } /** diff --git a/engine/classes/Elgg/Security/PasswordGeneratorService.php b/engine/classes/Elgg/Security/PasswordGeneratorService.php index 66cec4cc504..09d37c15f5a 100644 --- a/engine/classes/Elgg/Security/PasswordGeneratorService.php +++ b/engine/classes/Elgg/Security/PasswordGeneratorService.php @@ -20,21 +20,6 @@ * @internal */ class PasswordGeneratorService { - - /** - * @var Config - */ - protected $config; - - /** - * @var Translator - */ - protected $translator; - - /** - * @var EventsService - */ - protected $events; /** * Constructor @@ -43,10 +28,11 @@ class PasswordGeneratorService { * @param Translator $translator Translator * @param EventsService $events Events service */ - public function __construct(Config $config, Translator $translator, EventsService $events) { - $this->config = $config; - $this->translator = $translator; - $this->events = $events; + public function __construct( + protected Config $config, + protected Translator $translator, + protected EventsService $events + ) { } /** diff --git a/engine/classes/Elgg/Security/SiteSecret.php b/engine/classes/Elgg/Security/SiteSecret.php index be3d0291967..b310848dd52 100644 --- a/engine/classes/Elgg/Security/SiteSecret.php +++ b/engine/classes/Elgg/Security/SiteSecret.php @@ -25,20 +25,7 @@ class SiteSecret { const CONFIG_KEY = '__site_secret__'; - /** - * @var string - */ - private $key; - - /** - * @var Crypto - */ - protected $crypto; - - /** - * @var ConfigTable - */ - protected $table; + protected string $key; /** * Constructor @@ -46,10 +33,7 @@ class SiteSecret { * @param Crypto $crypto Crypto service * @param ConfigTable $table Config table */ - public function __construct(Crypto $crypto, ConfigTable $table) { - $this->crypto = $crypto; - $this->table = $table; - + public function __construct(protected Crypto $crypto, protected ConfigTable $table) { $key = $table->get(self::CONFIG_KEY); if (!$key) { throw new InstallationException('Site secret is not in the config table.'); diff --git a/engine/classes/Elgg/SessionManagerService.php b/engine/classes/Elgg/SessionManagerService.php index ec7952940c2..4df2d15d584 100644 --- a/engine/classes/Elgg/SessionManagerService.php +++ b/engine/classes/Elgg/SessionManagerService.php @@ -14,51 +14,14 @@ * @since 5.0 */ class SessionManagerService { - - /** - * @var EntityCache - */ - protected $entity_cache; - /** - * @var EventsService - */ - protected $events; + protected bool $ignore_access = false; - /** - * @var bool - */ - protected $ignore_access = false; + protected ?\ElggUser $logged_in_user = null; - /** - * @var \ElggUser|null - */ - protected $logged_in_user; - - /** - * @var PersistentLoginService - */ - protected $persistent_login; - - /** - * @var bool - */ - protected $show_disabled_entities = false; - - /** - * @var \ElggSession - */ - protected $session; - - /** - * @var SessionCache - */ - protected $session_cache; - - /** - * @var Translator - */ - protected $translator; + protected bool $show_disabled_entities = false; + + protected bool $show_deleted_entities = false; /** * Constructor @@ -71,19 +34,13 @@ class SessionManagerService { * @param EntityCache $entity_cache the entity cache */ public function __construct( - \ElggSession $session, - EventsService $events, - Translator $translator, - PersistentLoginService $persistent_login, - SessionCache $session_cache, - EntityCache $entity_cache - ) { - $this->session = $session; - $this->events = $events; - $this->translator = $translator; - $this->persistent_login = $persistent_login; - $this->session_cache = $session_cache; - $this->entity_cache = $entity_cache; + protected \ElggSession $session, + protected EventsService $events, + protected Translator $translator, + protected PersistentLoginService $persistent_login, + protected SessionCache $session_cache, + protected EntityCache $entity_cache + ) { } /** @@ -131,6 +88,31 @@ public function setDisabledEntityVisibility(bool $show = true): bool { return $prev; } + + /** + * Are deleted entities shown? + * + * @return bool + * @since 6.0 + */ + public function getDeletedEntityVisibility(): bool { + return $this->show_deleted_entities; + } + + /** + * Include deleted entities in queries + * + * @param bool $show Visibility status + * + * @return bool Previous setting + * @since 6.0 + */ + public function setDeletedEntityVisibility(bool $show = true): bool { + $prev = $this->show_deleted_entities; + $this->show_deleted_entities = $show; + + return $prev; + } /** * Set a user specific token in the session for the currently logged in user @@ -203,41 +185,47 @@ public function login(\ElggUser $user, bool $persistent = false): void { if ($user->isBanned()) { throw new LoginException($this->translator->translate('LoginException:BannedUser')); } - - // give plugins a chance to reject the login of this user (no user in session!) - if (!$this->events->triggerBefore('login', 'user', $user)) { - throw new LoginException($this->translator->translate('LoginException:Unknown')); - } + + // check before updating last login to determine first login + $first_login = empty($user->last_login); + + $this->events->triggerSequence('login', 'user', $user, function(\ElggUser $user) use ($persistent) { + if (!$user->isEnabled()) { + return false; + } + + $this->setLoggedInUser($user, true); + $this->setUserToken($user); + + // re-register at least the core language file for users with language other than site default + $this->translator->registerTranslations(\Elgg\Project\Paths::elgg() . 'languages/'); + + // if remember me checked, set cookie with token and store hash(token) for user + if ($persistent) { + $this->persistent_login->makeLoginPersistent($user); + } + + // User's privilege has been elevated, so change the session id (prevents session fixation) + $this->session->migrate(); + + $user->setLastLogin(); + + _elgg_services()->accounts->resetAuthenticationFailures($user); // can't inject DI service because of circular reference + + return true; + }); if (!$user->isEnabled()) { - // fallback if no plugin provided a reason + $this->removeLoggedInUser(); + throw new LoginException($this->translator->translate('LoginException:DisabledUser')); } - // #5933: set logged in user early so code in login event will be able to - // use elgg_get_logged_in_user_entity(). - $this->setLoggedInUser($user); - $this->setUserToken($user); - - // re-register at least the core language file for users with language other than site default - $this->translator->registerTranslations(\Elgg\Project\Paths::elgg() . 'languages/'); - - // if remember me checked, set cookie with token and store hash(token) for user - if ($persistent) { - $this->persistent_login->makeLoginPersistent($user); + if (!elgg_is_logged_in()) { + // login might be prevented without throwing a custom exception + throw new LoginException($this->translator->translate('LoginException:Unknown')); } - // User's privilege has been elevated, so change the session id (prevents session fixation) - $this->session->migrate(); - - // check before updating last login to determine first login - $first_login = empty($user->last_login); - - $user->setLastLogin(); - _elgg_services()->accounts->resetAuthenticationFailures($user); // can't inject DI service because of circular reference - - $this->events->triggerAfter('login', 'user', $user); - if ($first_login) { $this->events->trigger('login:first', 'user', $user); $user->first_login = time(); @@ -278,13 +266,23 @@ public function logout(): bool { /** * Sets the logged in user * - * @param \ElggUser $user The user who is logged in + * @param \ElggUser $user The user who is logged in + * @param bool|null $migrate Migrate the session (default: !\Elgg\Application::isCli()) + * * @return void * @since 1.9 */ - public function setLoggedInUser(\ElggUser $user): void { + public function setLoggedInUser(\ElggUser $user, bool $migrate = null): void { $current_user = $this->getLoggedInUser(); if ($current_user != $user) { + if (!isset($migrate)) { + $migrate = !\Elgg\Application::isCli(); + } + + if ($migrate) { + $this->session->migrate(true); + } + $this->session->set('guid', $user->guid); $this->logged_in_user = $user; $this->session_cache->clear(); diff --git a/engine/classes/Elgg/Structs/Collection.php b/engine/classes/Elgg/Structs/Collection.php index 57e2cd3844c..cef016686e1 100644 --- a/engine/classes/Elgg/Structs/Collection.php +++ b/engine/classes/Elgg/Structs/Collection.php @@ -2,9 +2,6 @@ namespace Elgg\Structs; -use Countable; -use Iterator; - /** * A read-only interface to a (possibly mutable) group of items. * @@ -28,7 +25,7 @@ * @since 1.10 * @internal */ -interface Collection extends Countable, Iterator { +interface Collection extends \Countable, \Iterator { /** * Returns a new collection only containing the elements which pass the filter. diff --git a/engine/classes/Elgg/Structs/Collection/InMemory.php b/engine/classes/Elgg/Structs/Collection/InMemory.php index d40363235bc..44bdc105e62 100644 --- a/engine/classes/Elgg/Structs/Collection/InMemory.php +++ b/engine/classes/Elgg/Structs/Collection/InMemory.php @@ -12,16 +12,12 @@ */ final class InMemory implements Collection { - /** @var array */ - private $items; - /** * Constructor * * @param array $items The set of items in the collection */ - private function __construct(array $items = []) { - $this->items = $items; + private function __construct(protected array $items = []) { } /** diff --git a/engine/classes/Elgg/SystemMessagesService.php b/engine/classes/Elgg/SystemMessagesService.php index d857ec34556..fe7ca6d5dd2 100644 --- a/engine/classes/Elgg/SystemMessagesService.php +++ b/engine/classes/Elgg/SystemMessagesService.php @@ -17,18 +17,12 @@ class SystemMessagesService { const ERROR = 'error'; const SESSION_KEY = '_elgg_msgs'; - /** - * @var \ElggSession - */ - protected $session; - /** * Constructor * * @param \ElggSession $session The Elgg session */ - public function __construct(\ElggSession $session) { - $this->session = $session; + public function __construct(protected \ElggSession $session) { } /** diff --git a/engine/classes/Elgg/Traits/Database/LegacyQueryOptionsAdapter.php b/engine/classes/Elgg/Traits/Database/LegacyQueryOptionsAdapter.php index 276ea8dd3a6..4b174371be5 100644 --- a/engine/classes/Elgg/Traits/Database/LegacyQueryOptionsAdapter.php +++ b/engine/classes/Elgg/Traits/Database/LegacyQueryOptionsAdapter.php @@ -31,7 +31,7 @@ trait LegacyQueryOptionsAdapter { * * @return array */ - public function normalizeOptions(array $options = []) { + public function normalizeOptions(array $options = []): array { if (!isset($options['__original_options'])) { $options['__original_options'] = $options; @@ -41,40 +41,28 @@ public function normalizeOptions(array $options = []) { $options = $this->normalizeGuidOptions($options); $options = $this->normalizeTimeOptions($options); - $options = $this->normalizeAccessOptions($options); - $options = $this->normalizeTypeSubtypeOptions($options); - $options = $this->normalizeRelationshipOptions($options); $options = $this->normalizeAnnotationOptions($options); $options = $this->normalizeMetadataOptions($options); $options = $this->normalizeMetadataSearchOptions($options); - - foreach (['selects', 'joins', 'wheres'] as $prop) { - if (empty($options[$prop])) { - $options[$prop] = []; - } - - if (!is_array($options[$prop])) { - if ($options[$prop]) { - $options[$prop] = [$options[$prop]]; - } - } - } - $options = $this->normalizeSelectClauses($options); $options = $this->normalizeWhereClauses($options); $options = $this->normalizeJoinClauses($options); + $options = $this->normalizeGroupByClauses($options); + $options = $this->normalizeHavingClauses($options); $options = $this->normalizeOrderByClauses($options); - return $this->normalizeGroupByClauses($options); + + return $options; } /** * Returns defaults array + * * @return array */ - protected function getDefaults() { + protected function getDefaults(): array { return [ 'types' => null, 'subtypes' => null, @@ -100,6 +88,7 @@ protected function getDefaults() { 'selects' => [], 'wheres' => [], 'joins' => [], + 'having' => null, 'group_by' => null, 'metadata_name_value_pairs' => null, @@ -152,8 +141,8 @@ protected function getDefaults() { * * @return array */ - protected function normalizeAccessOptions(array $options = []) { - return self::normalizePluralOptions($options, ['access_id']); + protected function normalizeAccessOptions(array $options = []): array { + return $this->normalizePluralOptions($options, ['access_id']); } /** @@ -164,14 +153,11 @@ protected function normalizeAccessOptions(array $options = []) { * @return array * @throws InvalidArgumentException */ - protected function normalizeTypeSubtypeOptions(array $options = []) { - - $singulars = [ + protected function normalizeTypeSubtypeOptions(array $options = []): array { + $options = $this->normalizePluralOptions($options, [ 'type', 'subtype', - ]; - - $options = self::normalizePluralOptions($options, $singulars); + ]); // can't use helper function with type_subtype_pair because // it's already an array...just need to merge it @@ -218,15 +204,13 @@ protected function normalizeTypeSubtypeOptions(array $options = []) { * * @return array */ - protected function normalizeMetadataOptions(array $options = []) { - $singulars = [ + protected function normalizeMetadataOptions(array $options = []): array { + $options = $this->normalizePluralOptions($options, [ 'metadata_id', 'metadata_name', 'metadata_value', 'metadata_name_value_pair', - ]; - - $options = self::normalizePluralOptions($options, $singulars); + ]); $options = $this->normalizePairedOptions('metadata', $options); @@ -309,12 +293,8 @@ protected function normalizeMetadataOptions(array $options = []) { * * @return array */ - protected function normalizeMetadataSearchOptions(array $options = []) { - $singulars = [ - 'search_name_value_pair', - ]; - - $options = self::normalizePluralOptions($options, $singulars); + protected function normalizeMetadataSearchOptions(array $options = []): array { + $options = $this->normalizePluralOptions($options, ['search_name_value_pair']); $options = $this->normalizePairedOptions('search', $options); @@ -376,15 +356,13 @@ protected function normalizeMetadataSearchOptions(array $options = []) { * * @return array */ - protected function normalizeAnnotationOptions(array $options = []) { - $singulars = [ + protected function normalizeAnnotationOptions(array $options = []): array { + $options = $this->normalizePluralOptions($options, [ 'annotation_id', 'annotation_name', 'annotation_value', 'annotation_name_value_pair', - ]; - - $options = self::normalizePluralOptions($options, $singulars); + ]); $options = $this->normalizePairedOptions('annotation', $options); @@ -454,7 +432,6 @@ protected function normalizeAnnotationOptions(array $options = []) { $clause->comparison = $pair['comparison']; $clause->value_type = $pair['type']; $clause->case_sensitive = $pair['case_sensitive']; - $clause->enabled = $pair['enabled']; $clause->access_ids = (array) $pair['access_ids']; $clause->sort_by_calculation = $pair['sort_by_calculation']; @@ -476,7 +453,7 @@ protected function normalizeAnnotationOptions(array $options = []) { * * @return array */ - protected function normalizePairedOptions($type = 'metadata', array $options = []) { + protected function normalizePairedOptions($type = 'metadata', array $options = []): array { if (!is_array($options["{$type}_name_value_pairs"])) { $options["{$type}_name_value_pairs"] = []; } @@ -498,6 +475,7 @@ protected function normalizePairedOptions($type = 'metadata', array $options = [ 'comparison' => elgg_extract('operand', $options["{$type}_name_value_pairs"], '='), 'case_sensitive' => elgg_extract('case_sensitive', $options["{$type}_name_value_pairs"], $case_sensitive_default) ]; + unset($options["{$type}_name_value_pairs"]['name']); unset($options["{$type}_name_value_pairs"]['value']); unset($options["{$type}_name_value_pairs"]['operand']); @@ -604,10 +582,7 @@ protected function normalizePairedOptions($type = 'metadata', array $options = [ * * @return array */ - protected function normalizeRelationshipOptions(array $options = []) { - - $pair = []; - + protected function normalizeRelationshipOptions(array $options = []): array { $defaults = [ 'relationship_ids' => null, 'relationship' => null, @@ -618,16 +593,17 @@ protected function normalizeRelationshipOptions(array $options = []) { 'relationship_created_before' => null, ]; + $simple_pair = []; foreach (array_keys($defaults) as $prop) { if (isset($options[$prop])) { - $pair[$prop] = $options[$prop]; + $simple_pair[$prop] = $options[$prop]; } unset($options[$prop]); } $options['relationship_pairs'] = (array) $options['relationship_pairs']; - $options['relationship_pairs'][] = $pair; + $options['relationship_pairs'][] = $simple_pair; foreach ($options['relationship_pairs'] as $index => $relationship_pair) { if ($relationship_pair instanceof WhereClause) { @@ -678,16 +654,13 @@ protected function normalizeRelationshipOptions(array $options = []) { * * @return array */ - protected function normalizeGuidOptions(array $options = []) { - - $singulars = [ + protected function normalizeGuidOptions(array $options = []): array { + $options = $this->normalizePluralOptions($options, [ 'guid', 'owner_guid', 'container_guid', 'annotation_owner_guid', - ]; - - $options = self::normalizePluralOptions($options, $singulars); + ]); $names = [ 'guids', @@ -723,8 +696,7 @@ protected function normalizeGuidOptions(array $options = []) { * * @return array */ - protected function normalizeTimeOptions(array $options = []) { - + protected function normalizeTimeOptions(array $options = []): array { $props = [ 'modified', 'created', @@ -765,7 +737,7 @@ protected function normalizeTimeOptions(array $options = []) { * * @return array */ - protected function removeKeyPrefix($prefix, array $array = []) { + protected function removeKeyPrefix(string $prefix, array $array = []): array { foreach ($array as $key => $value) { $new_key = $key; if (str_starts_with($key, $prefix)) { @@ -795,9 +767,18 @@ protected function removeKeyPrefix($prefix, array $array = []) { * * @return array */ - protected function normalizeSelectClauses(array $options = []) { - - $options = self::normalizePluralOptions($options, ['select']); + protected function normalizeSelectClauses(array $options = []): array { + $options = $this->normalizePluralOptions($options, ['select']); + + if (empty($options['selects'])) { + $options['selects'] = []; + + return $options; + } + + if (!is_array($options['selects'])) { + $options['selects'] = [$options['selects']]; + } foreach ($options['selects'] as $key => $clause) { if (empty($clause)) { @@ -822,10 +803,19 @@ protected function normalizeSelectClauses(array $options = []) { * * @return array */ - protected function normalizeWhereClauses(array $options = []) { - - $options = self::normalizePluralOptions($options, ['where']); + protected function normalizeWhereClauses(array $options = []): array { + $options = $this->normalizePluralOptions($options, ['where']); + if (empty($options['wheres'])) { + $options['wheres'] = []; + + return $options; + } + + if (!is_array($options['wheres'])) { + $options['wheres'] = [$options['wheres']]; + } + foreach ($options['wheres'] as $key => $clause) { if (empty($clause)) { unset($options['wheres'][$key]); @@ -849,9 +839,18 @@ protected function normalizeWhereClauses(array $options = []) { * * @return array */ - protected function normalizeJoinClauses(array $options = []) { - - $options = self::normalizePluralOptions($options, ['join']); + protected function normalizeJoinClauses(array $options = []): array { + $options = $this->normalizePluralOptions($options, ['join']); + + if (empty($options['joins'])) { + $options['joins'] = []; + + return $options; + } + + if (!is_array($options['joins'])) { + $options['joins'] = [$options['joins']]; + } foreach ($options['joins'] as $key => $join) { if (empty($join)) { @@ -891,18 +890,15 @@ protected function normalizeJoinClauses(array $options = []) { * * @return array */ - protected function normalizeOrderByClauses(array $options = []) { - - $order_by = $options['order_by']; + protected function normalizeOrderByClauses(array $options = []): array { + $orders = $options['order_by']; $options['order_by'] = []; - if (!empty($order_by)) { - if (is_string($order_by)) { - $orders = explode(',', $order_by); - } else if (is_array($order_by)) { - $orders = $order_by; - } else { - $orders = [$order_by]; + if (!empty($orders)) { + if (is_string($orders)) { + $orders = explode(',', $orders); + } elseif (!is_array($orders)) { + $orders = [$orders]; } foreach ($orders as $order) { @@ -926,7 +922,7 @@ protected function normalizeOrderByClauses(array $options = []) { $options['order_by'][] = new OrderByClause($column, $direction); } } - + $sort_by = $options['sort_by']; if (isset($sort_by['property'])) { // single array variant, convert to an array of sort_by specs @@ -950,36 +946,50 @@ protected function normalizeOrderByClauses(array $options = []) { } /** - * Normalize 'group_by' statements + * Normalize 'having' statements * * @param array $options Options * * @return array */ - protected function normalizeGroupByClauses(array $options = []) { - - if (!isset($options['having'])) { + protected function normalizeHavingClauses(array $options = []): array { + if (empty($options['having'])) { $options['having'] = []; - } else { - if (!is_array($options['having'])) { - $options['having'] = [$options['having']]; - } - - foreach ($options['having'] as $key => $expr) { - if ($expr instanceof HavingClause) { - continue; - } + + return $options; + } + + if (!is_array($options['having'])) { + $options['having'] = [$options['having']]; + } - $options['having'][$key] = new HavingClause($expr); + foreach ($options['having'] as $key => $expr) { + if ($expr instanceof HavingClause) { + continue; } + + $options['having'][$key] = new HavingClause($expr); } + return $options; + } + + /** + * Normalize 'group_by' statements + * + * @param array $options Options + * + * @return array + */ + protected function normalizeGroupByClauses(array $options = []): array { if (empty($options['group_by'])) { $options['group_by'] = []; + + return $options; } - if (is_string($options['group_by'])) { - $options['group_by'] = (array) trim($options['group_by']); + if (!is_array($options['group_by'])) { + $options['group_by'] = [$options['group_by']]; } foreach ($options['group_by'] as $key => $expr) { @@ -997,10 +1007,11 @@ protected function normalizeGroupByClauses(array $options = []) { * Normalizes metadata / annotation option names to their corresponding metastrings name. * * @param array $options An options array + * * @return array * @internal */ - public static function normalizeMetastringOptions(array $options = []) { + public static function normalizeMetastringOptions(array $options = []): array { // support either metastrings_type or metastring_type // because I've made this mistake many times and hunting it down is a pain... @@ -1051,7 +1062,7 @@ public static function normalizeMetastringOptions(array $options = []) { * @return array * @internal */ - public static function normalizePluralOptions($options, $singulars) { + public static function normalizePluralOptions(array $options, array $singulars): array { foreach ($singulars as $singular) { $plural = $singular . 's'; diff --git a/engine/classes/Elgg/Traits/Debug/Profilable.php b/engine/classes/Elgg/Traits/Debug/Profilable.php index 48153b797fd..509e3a2a62d 100644 --- a/engine/classes/Elgg/Traits/Debug/Profilable.php +++ b/engine/classes/Elgg/Traits/Debug/Profilable.php @@ -11,10 +11,7 @@ */ trait Profilable { - /** - * @var Timer|null - */ - private $timer; + private Timer $timer; /** * Set a timer that should collect begin/end times for events @@ -43,7 +40,7 @@ public function hasTimer(): bool { * @return void * @see \Elgg\Timer::begin() */ - public function beginTimer(array $keys): void { + protected function beginTimer(array $keys): void { if (!$this->hasTimer()) { return; } @@ -59,7 +56,7 @@ public function beginTimer(array $keys): void { * @return void * @see \Elgg\Timer::end() */ - public function endTimer(array $keys): void { + protected function endTimer(array $keys): void { if (!$this->hasTimer()) { return; } diff --git a/engine/classes/Elgg/Traits/Entity/Icons.php b/engine/classes/Elgg/Traits/Entity/Icons.php new file mode 100644 index 00000000000..b04a15750b2 --- /dev/null +++ b/engine/classes/Elgg/Traits/Entity/Icons.php @@ -0,0 +1,227 @@ +iconService->saveIconFromUploadedFile($this, $input_name, $type, $coords); + } + + /** + * Saves icons using a local file as the source. + * + * @param string $filename The full path to the local file + * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' + * @param array $coords An array of cropping coordinates x1, y1, x2, y2 + * + * @return bool + */ + public function saveIconFromLocalFile(string $filename, string $type = 'icon', array $coords = []): bool { + return _elgg_services()->iconService->saveIconFromLocalFile($this, $filename, $type, $coords); + } + + /** + * Saves icons using a file located in the data store as the source. + * + * @param string $file An ElggFile instance + * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' + * @param array $coords An array of cropping coordinates x1, y1, x2, y2 + * + * @return bool + */ + public function saveIconFromElggFile(\ElggFile $file, string $type = 'icon', array $coords = []): bool { + return _elgg_services()->iconService->saveIconFromElggFile($this, $file, $type, $coords); + } + + /** + * Returns entity icon as an ElggIcon object + * The icon file may or may not exist on filestore + * + * @param string $size Size of the icon + * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' + * + * @return \ElggIcon + */ + public function getIcon(string $size, string $type = 'icon'): \ElggIcon { + return _elgg_services()->iconService->getIcon($this, $size, $type); + } + + /** + * Removes all icon files and metadata for the passed type of icon. + * + * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' + * + * @return bool + */ + public function deleteIcon(string $type = 'icon'): bool { + return _elgg_services()->iconService->deleteIcon($this, $type); + } + + /** + * Returns the timestamp of when the icon was changed. + * + * @param string $size The size of the icon + * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' + * + * @return int|null A unix timestamp of when the icon was last changed, or null if not set. + */ + public function getIconLastChange(string $size, string $type = 'icon'): ?int { + return _elgg_services()->iconService->getIconLastChange($this, $size, $type); + } + + /** + * Returns if the entity has an icon of the passed type. + * + * @param string $size The size of the icon + * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' + * + * @return bool + */ + public function hasIcon(string $size, string $type = 'icon'): bool { + return _elgg_services()->iconService->hasIcon($this, $size, $type); + } + + /** + * Get the URL for this entity's icon + * + * Plugins can register for the 'entity:icon:url', '' event + * to customize the icon for an entity. + * + * @param mixed $params A string defining the size of the icon (e.g. tiny, small, medium, large) + * or an array of parameters including 'size' + * + * @return string The URL + * @since 1.8.0 + */ + public function getIconURL(string|array $params = []): string { + return _elgg_services()->iconService->getIconURL($this, $params); + } + + /** + * Save cropping coordinates for an icon type + * + * @param array $coords An array of cropping coordinates x1, y1, x2, y2 + * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' + * + * @return void + * @since 6.0 + */ + public function saveIconCoordinates(array $coords, string $type = 'icon'): void { + // remove noise from the coords array + $allowed_keys = ['x1', 'x2', 'y1', 'y2']; + $coords = array_filter($coords, function($value, $key) use ($allowed_keys) { + return in_array($key, $allowed_keys) && is_int($value); + }, ARRAY_FILTER_USE_BOTH); + + if (!isset($coords['x1']) || !isset($coords['x2']) || !isset($coords['y1']) || !isset($coords['y2'])) { + throw new InvalidArgumentException('Please provide correct coordinates [x1, x2, y1, y2]'); + } + + if ($coords['x1'] < 0 || $coords['x2'] < 0 || $coords['y1'] < 0 || $coords['y2'] < 0) { + throw new RangeException("Coordinates can't have negative numbers"); + } + + $this->{"{$type}_coords"} = serialize($coords); + } + + /** + * Get the cropping coordinates for an icon type + * + * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' + * + * @return null|array + * @since 6.0 + */ + public function getIconCoordinates(string $type = 'icon'): array { + if (!isset($this->{"{$type}_coords"})) { + return []; + } + + $coords = unserialize($this->{"{$type}_coords"}) ?: []; + + // cast to integers + array_walk($coords, function(&$value) { + $value = (int) $value; + }); + + // remove invalid values + return array_filter($coords, function($value) { + return $value >= 0; + }); + } + + /** + * Remove the cropping coordinates of an icon type + * + * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' + * + * @return void + * @since 6.0 + */ + public function removeIconCoordinates(string $type = 'icon'): void { + unset($this->{"{$type}_coords"}); + } + + /** + * Lock thumbnail generation during icon upload/resize + * + * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' + * + * @return void + * @since 6.0 + * @internal for use in the \Elgg\EntityIconService + */ + public function lockIconThumbnailGeneration(string $type = 'icon'): void { + $this->{"{$type}_thumbnail_locked"} = time(); + } + + /** + * Is thumbnail generation prevented + * + * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' + * @param int $ttl Time-to-live for the lock in seconds (in case of errors) + * + * @return bool + * @since 6.0 + * @internal for use in the \Elgg\EntityIconService + */ + public function isIconThumbnailGenerationLocked(string $type = 'icon', int $ttl = 30): bool { + if (!isset($this->{"{$type}_thumbnail_locked"})) { + return false; + } + + $locked = (int) $this->{"{$type}_thumbnail_locked"}; + return $locked > (time() - $ttl); + } + + /** + * Unlock thumbnail generation when upload/resize is complete + * + * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' + * + * @return void + * @since 6.0 + * @internal for use in the \Elgg\EntityIconService + */ + public function unlockIconThumbnailGeneration(string $type = 'icon'): void { + unset($this->{"{$type}_thumbnail_locked"}); + } +} diff --git a/engine/classes/Elgg/Traits/Entity/PluginSettings.php b/engine/classes/Elgg/Traits/Entity/PluginSettings.php index 0626500411a..edc6da5654f 100644 --- a/engine/classes/Elgg/Traits/Entity/PluginSettings.php +++ b/engine/classes/Elgg/Traits/Entity/PluginSettings.php @@ -28,7 +28,9 @@ public function setPluginSetting(string $plugin_id, string $name, $value): bool $name = $this->getNamespacedPluginSettingName($plugin_id, $name); - return $this->setMetadata($name, $value); + return elgg_call(ELGG_DISABLE_SYSTEM_LOG, function() use ($name, $value) { + return $this->setMetadata($name, $value); + }); } /** @@ -57,7 +59,9 @@ public function getPluginSetting(string $plugin_id, string $name, $default = nul public function removePluginSetting(string $plugin_id, string $name): bool { $name = $this->getNamespacedPluginSettingName($plugin_id, $name); - return $this->deleteMetadata($name); + return elgg_call(ELGG_DISABLE_SYSTEM_LOG, function() use ($name) { + return $this->deleteMetadata($name); + }); } /** diff --git a/engine/classes/Elgg/Traits/Loggable.php b/engine/classes/Elgg/Traits/Loggable.php index 9660b56845b..dd915707a5c 100644 --- a/engine/classes/Elgg/Traits/Loggable.php +++ b/engine/classes/Elgg/Traits/Loggable.php @@ -57,10 +57,6 @@ public function getLogger() { */ public function log($level, $message, array $context = []) { if ($message instanceof \Throwable) { - if (!isset($message->timestamp)) { - $message->timestamp = time(); - } - $context['exception'] = $message; } diff --git a/engine/classes/Elgg/Traits/Seeding.php b/engine/classes/Elgg/Traits/Seeding.php index 37335ceb9ad..cd6919dd9df 100644 --- a/engine/classes/Elgg/Traits/Seeding.php +++ b/engine/classes/Elgg/Traits/Seeding.php @@ -100,7 +100,6 @@ public function getRandomSubtype(): bool|string { * @param array $options Seeding options * * @return \ElggUser - * @throws Exception * @throws MaxAttemptsException */ public function createUser(array $properties = [], array $options = []): \ElggUser { @@ -381,6 +380,12 @@ public function createGroup(array $properties = [], array $options = []): \ElggG * @throws MaxAttemptsException */ public function createObject(array $properties = [], array $options = []): \ElggObject { + $default_properties = [ + 'title' => true, + 'description' => true, + 'tags' => true, + ]; + $properties = array_merge($default_properties, $properties); $create = function () use ($properties, $options) { $properties['__faker'] = true; @@ -389,20 +394,26 @@ public function createObject(array $properties = [], array $options = []): \Elgg $properties['time_created'] = $this->getRandomCreationTimestamp(); } - if (empty($properties['title'])) { + if ($properties['title'] === true) { $properties['title'] = $this->faker()->sentence(); + } elseif ($properties['title'] === false) { + unset($properties['title']); } - if (empty($properties['description'])) { + if ($properties['description'] === true) { $properties['description'] = $this->faker()->text($this->faker()->numberBetween(500, 1000)); + } elseif ($properties['description'] === false) { + unset($properties['description']); } if (empty($properties['subtype'])) { $properties['subtype'] = $this->getRandomSubtype(); } - if (empty($properties['tags'])) { + if ($properties['tags'] === true) { $properties['tags'] = $this->faker()->words(10); + } elseif ($properties['tags'] === false) { + unset($properties['tags']); } if (!isset($properties['owner_guid'])) { @@ -823,6 +834,7 @@ public function createComments(\ElggEntity $entity, $limit = null): int { $comment->container_guid = $entity->guid; $comment->description = $this->faker()->paragraph; $comment->time_created = $this->getRandomCreationTimestamp(); + $comment->access_id = $entity->access_id; $tries++; if ($comment->save()) { @@ -858,7 +870,7 @@ public function createLikes(\ElggEntity $entity, $limit = null): int { } while ($success < $limit) { - if ($entity->annotate('likes', true, $entity->access_id, $this->getRandomUser()->guid)) { + if ($entity->annotate('likes', 'likes', ACCESS_PUBLIC, $this->getRandomUser()->guid)) { $success++; } } diff --git a/engine/classes/Elgg/Upgrade/Batch.php b/engine/classes/Elgg/Upgrade/Batch.php index 0e373433e9a..f4333580766 100644 --- a/engine/classes/Elgg/Upgrade/Batch.php +++ b/engine/classes/Elgg/Upgrade/Batch.php @@ -14,18 +14,12 @@ abstract class Batch { */ const UNKNOWN_COUNT = -1; - /** - * @var \ElggUpgrade - */ - protected $upgrade; - /** * Constructs a upgrade batch * * @param \ElggUpgrade $upgrade the upgrade related to this batch */ - public function __construct(\ElggUpgrade $upgrade = null) { - $this->upgrade = $upgrade; + public function __construct(protected ?\ElggUpgrade $upgrade = null) { } /** diff --git a/engine/classes/Elgg/Upgrade/Locator.php b/engine/classes/Elgg/Upgrade/Locator.php index 840133a7d18..6aaee24b1f9 100644 --- a/engine/classes/Elgg/Upgrade/Locator.php +++ b/engine/classes/Elgg/Upgrade/Locator.php @@ -15,18 +15,12 @@ */ class Locator { - /** - * @var Plugins $plugins - */ - private $plugins; - /** * Constructor * * @param Plugins $plugins Plugins */ - public function __construct(Plugins $plugins) { - $this->plugins = $plugins; + public function __construct(protected Plugins $plugins) { } /** diff --git a/engine/classes/Elgg/Upgrade/Loop.php b/engine/classes/Elgg/Upgrade/Loop.php index 87352d356f5..8e56768c008 100644 --- a/engine/classes/Elgg/Upgrade/Loop.php +++ b/engine/classes/Elgg/Upgrade/Loop.php @@ -16,45 +16,18 @@ class Loop { use Loggable; - /** - * @var \ElggUpgrade - */ - protected $upgrade; - - /** - * @var Result - */ - protected $result; - /** * @var Batch|false */ protected $batch; - /** - * @var int - */ - protected $max_duration; + protected int $max_duration; - /** - * @var int - */ - protected $count; + protected int $count; - /** - * @var int - */ - protected $processed; + protected int $processed; - /** - * @var int - */ - protected $offset; - - /** - * @var Progress - */ - protected $progress; + protected int $offset; /** * Constructor @@ -67,13 +40,13 @@ class Loop { * @throws RuntimeException */ public function __construct( - \ElggUpgrade $upgrade, - Result $result, - Progress $progress, + protected \ElggUpgrade $upgrade, + protected Result $result, + protected Progress $progress, Logger $logger ) { - $this->upgrade = $upgrade; - + $this->setLogger($logger); + // Get the class taking care of the actual upgrading $this->batch = $upgrade->getBatch(); if (!$this->batch) { @@ -83,10 +56,6 @@ public function __construct( ])); } - $this->result = $result; - $this->progress = $progress; - $this->logger = $logger; - $this->count = $this->batch->countItems(); $this->processed = (int) $upgrade->processed; $this->offset = (int) $upgrade->offset; @@ -95,12 +64,11 @@ public function __construct( /** * Run upgrade loop for a preset number of seconds * - * @param int $max_duration Maximum loop duration + * @param int|null $max_duration Maximum loop duration * * @return void */ - public function loop($max_duration = null): void { - + public function loop(int $max_duration = null): void { $started = microtime(true); $this->upgrade->setStartTime(); @@ -212,17 +180,17 @@ protected function report(): void { /** * Check if the loop cand and should continue * - * @param float $started Timestamp of the loop initiation - * @param int $max_duration Maximum loop duration + * @param float $started Timestamp of the loop initiation + * @param int|null $max_duration Maximum loop duration * * @return bool */ - protected function canContinue($started, $max_duration = null): bool { + protected function canContinue($started, int $max_duration = null): bool { if (!isset($max_duration)) { - $max_duration = elgg_get_config('batch_run_time_in_secs'); + $max_duration = (int) elgg_get_config('batch_run_time_in_secs'); } - if ($max_duration && (microtime(true) - $started) >= $max_duration) { + if ($max_duration > 0 && (microtime(true) - $started) >= $max_duration) { return false; } diff --git a/engine/classes/Elgg/Upgrade/UpgradeController.php b/engine/classes/Elgg/Upgrade/UpgradeController.php index 4823106d174..569eb546d54 100644 --- a/engine/classes/Elgg/Upgrade/UpgradeController.php +++ b/engine/classes/Elgg/Upgrade/UpgradeController.php @@ -32,7 +32,7 @@ public function __invoke(Request $request) { $upgrade = _elgg_services()->upgrades->run(); - $upgrade->done( + $upgrade->then( function () use (&$response, $forward_url) { $response = elgg_ok_response('', elgg_echo('upgrade:core'), $forward_url); }, diff --git a/engine/classes/Elgg/UpgradeService.php b/engine/classes/Elgg/UpgradeService.php index 7ef90e9c1da..4d07b394ca4 100644 --- a/engine/classes/Elgg/UpgradeService.php +++ b/engine/classes/Elgg/UpgradeService.php @@ -23,41 +23,6 @@ class UpgradeService { use Loggable; - /** - * @var Locator - */ - protected $locator; - - /** - * @var Translator - */ - private $translator; - - /** - * @var EventsService - */ - private $events; - - /** - * @var Config - */ - private $config; - - /** - * @var Mutex - */ - private $mutex; - - /** - * @var SystemMessagesService - */ - private $system_messages; - - /** - * @var Progress - */ - protected $progress; - /** * Constructor * @@ -70,28 +35,22 @@ class UpgradeService { * @param Progress $progress Progress */ public function __construct( - Locator $locator, - Translator $translator, - EventsService $events, - Config $config, - Mutex $mutex, - SystemMessagesService $system_messages, - Progress $progress + protected Locator $locator, + protected Translator $translator, + protected EventsService $events, + protected Config $config, + protected Mutex $mutex, + protected SystemMessagesService $system_messages, + protected Progress $progress ) { - $this->locator = $locator; - $this->translator = $translator; - $this->events = $events; - $this->config = $config; - $this->mutex = $mutex; - $this->system_messages = $system_messages; - $this->progress = $progress; } /** * Start an upgrade process + * * @return Promise */ - protected function up() { + protected function up(): Promise { return new Promise(function ($resolve, $reject) { Application::migrate(); @@ -108,15 +67,16 @@ protected function up() { \Elgg\Cache\EventHandlers::disable(); elgg_clear_caches(); - return $resolve(); + return $resolve($resolve); }); } /** * Finish an upgrade process + * * @return Promise */ - protected function down() { + protected function down(): Promise { return new Promise(function ($resolve, $reject) { if (!$this->events->trigger('upgrade', 'system', null)) { return $reject(); @@ -128,7 +88,7 @@ protected function down() { $this->events->triggerAfter('upgrade', 'system', null); - return $resolve(); + return $resolve($resolve); }); } @@ -139,7 +99,7 @@ protected function down() { * * @return Promise */ - protected function runUpgrades($upgrades) { + protected function runUpgrades($upgrades): Promise { $promises = []; foreach ($upgrades as $upgrade) { @@ -149,7 +109,7 @@ protected function runUpgrades($upgrades) { $promises[] = new Promise(function ($resolve, $reject) use ($upgrade) { try { - $result = $this->executeUpgrade($upgrade, false); + $result = $this->executeUpgrade($upgrade, 0); } catch (\Throwable $ex) { return $reject($ex); } @@ -176,7 +136,7 @@ protected function runUpgrades($upgrades) { * * @return Promise */ - public function run($upgrades = null) { + public function run($upgrades = null): Promise { // turn off time limit set_time_limit(3600); @@ -196,13 +156,13 @@ public function run($upgrades = null) { $upgrades = $this->getPendingUpgrades(false); } - $this->up()->done( + $this->up()->then( function () use ($resolve, $reject, $upgrades) { all([ $this->runUpgrades($upgrades), - ])->done( + ])->then( function () use ($resolve, $reject) { - $this->down()->done( + $this->down()->then( function ($result) use ($resolve) { return $resolve($result); }, @@ -225,7 +185,7 @@ function ($result) use ($resolve) { * * @return \ElggUpgrade[] */ - public function getPendingUpgrades($async = true) { + public function getPendingUpgrades(bool $async = true): array { $pending = []; $upgrades = $this->locator->locate(); @@ -259,10 +219,10 @@ public function getPendingUpgrades($async = true) { * * @return \ElggUpgrade[] */ - public function getCompletedUpgrades($async = true) { + public function getCompletedUpgrades(bool $async = true): array { // make sure always to return all upgrade entities return elgg_call( - ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES, + ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES | ELGG_SHOW_DELETED_ENTITIES, function () use ($async) { $completed = []; @@ -307,16 +267,16 @@ function () use ($async) { * Call the upgrade's run() for a specified period of time, or until it completes * * @param \ElggUpgrade $upgrade Upgrade to run - * @param int $max_duration Maximum duration in seconds - * Set to false to execute an entire upgrade + * @param int|null $max_duration Maximum duration in seconds + * Set to 0 to execute an entire upgrade * * @return Result */ - public function executeUpgrade(\ElggUpgrade $upgrade, $max_duration = null) { + public function executeUpgrade(\ElggUpgrade $upgrade, int $max_duration = null): Result { // Upgrade also disabled data, so the compatibility is // preserved in case the data ever gets enabled again return elgg_call( - ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES, + ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES | ELGG_SHOW_DELETED_ENTITIES, function () use ($upgrade, $max_duration) { return $this->events->triggerResultsSequence('upgrade:execute', 'system', ['object' => $upgrade], null, function() use ($upgrade, $max_duration) { $result = new Result(); diff --git a/engine/classes/Elgg/Upgrades/ChangeUserNotificationSettingsNamespace.php b/engine/classes/Elgg/Upgrades/ChangeUserNotificationSettingsNamespace.php index 4bc79203791..f24c1443a5a 100644 --- a/engine/classes/Elgg/Upgrades/ChangeUserNotificationSettingsNamespace.php +++ b/engine/classes/Elgg/Upgrades/ChangeUserNotificationSettingsNamespace.php @@ -2,6 +2,8 @@ namespace Elgg\Upgrades; +use Elgg\Database\EntityTable; +use Elgg\Database\MetadataTable; use Elgg\Upgrade\SystemUpgrade; use Elgg\Upgrade\Result; use Elgg\Database\Select; @@ -39,11 +41,11 @@ public function shouldBeSkipped(): bool { * {@inheritDoc} */ public function countItems(): int { - $select = Select::fromTable('metadata', 'md'); - $entities_table = $select->joinEntitiesTable('md', 'entity_guid'); + $select = Select::fromTable(MetadataTable::TABLE_NAME, MetadataTable::DEFAULT_JOIN_ALIAS); + $entities_table = $select->joinEntitiesTable($select->getTableAlias(), 'entity_guid'); $select->select('count(*) AS total') - ->where($select->compare('md.name', 'like', 'notification:method:%', ELGG_VALUE_STRING)) + ->where($select->compare("{$select->getTableAlias()}.name", 'like', 'notification:method:%', ELGG_VALUE_STRING)) ->andWhere($select->compare("{$entities_table}.type", '=', 'user', ELGG_VALUE_STRING)); $result = _elgg_services()->db->getDataRow($select); @@ -55,11 +57,11 @@ public function countItems(): int { * {@inheritDoc} */ public function run(Result $result, $offset): Result { - $update = Update::table('metadata'); + $update = Update::table(MetadataTable::TABLE_NAME); $update->set('name', 'REPLACE(name, "notification:method:", "notification:default:")') ->where($update->compare('name', 'like', 'notification:method:%', ELGG_VALUE_STRING)); - $users = $update->subquery('entities'); + $users = $update->subquery(EntityTable::TABLE_NAME); $users->select('guid') ->where($update->compare('type', '=', 'user', ELGG_VALUE_STRING)); diff --git a/engine/classes/Elgg/Upgrades/ContentOwnerSubscriptions.php b/engine/classes/Elgg/Upgrades/ContentOwnerSubscriptions.php index dc30e210918..22f8bd9fa4b 100644 --- a/engine/classes/Elgg/Upgrades/ContentOwnerSubscriptions.php +++ b/engine/classes/Elgg/Upgrades/ContentOwnerSubscriptions.php @@ -2,6 +2,7 @@ namespace Elgg\Upgrades; +use Elgg\Database\EntityTable; use Elgg\Database\QueryBuilder; use Elgg\Notifications\SubscriptionsService; use Elgg\Upgrade\AsynchronousUpgrade; @@ -117,7 +118,7 @@ protected function getOptions(array $options = []): array { 'preload_owners' => true, 'wheres' => [ function (QueryBuilder $qb, $main_alias) { - $owner_guids = $qb->subquery('entities'); + $owner_guids = $qb->subquery(EntityTable::TABLE_NAME); $owner_guids->select('guid') ->andWhere($qb->compare('type', '=', 'user', ELGG_VALUE_STRING)); diff --git a/engine/classes/Elgg/Upgrades/MigrateEntityIconCroppingCoordinates.php b/engine/classes/Elgg/Upgrades/MigrateEntityIconCroppingCoordinates.php new file mode 100644 index 00000000000..eadc17fea64 --- /dev/null +++ b/engine/classes/Elgg/Upgrades/MigrateEntityIconCroppingCoordinates.php @@ -0,0 +1,94 @@ +countItems()); + } + + /** + * {@inheritdoc} + */ + public function needsIncrementOffset(): bool { + return false; + } + + /** + * {@inheritdoc} + */ + public function countItems(): int { + return elgg_count_entities($this->getOptions()); + } + + /** + * {@inheritdoc} + */ + public function run(Result $result, $offset): Result { + /* @var $entities \ElggBatch */ + $entities = elgg_get_entities($this->getOptions([ + 'offset' => $offset, + ])); + /* @var $entity \ElggEntity */ + foreach ($entities as $entity) { + $coords = [ + 'x1' => (int) $entity->x1, + 'x2' => (int) $entity->x2, + 'y1' => (int) $entity->y1, + 'y2' => (int) $entity->y2, + ]; + + try { + $entity->saveIconCoordinates($coords, 'icon'); + } catch (\Elgg\Exceptions\ExceptionInterface $e) { + // something went wrong with the coords, probably broken + } + + unset($entity->x1); + unset($entity->x2); + unset($entity->y1); + unset($entity->y2); + + $result->addSuccesses(); + } + + return $result; + } + + /** + * Get options for the upgrade + * + * @param array $options additional options + * + * @return array + * @see elgg_get_entities() + */ + protected function getOptions(array $options = []): array { + $defaults = [ + 'limit' => 50, + 'batch' => true, + 'batch_inc_offset' => $this->needsIncrementOffset(), + 'metadata_names' => [ + 'x1', + 'x2', + 'y1', + 'y2', + ], + ]; + + return array_merge($defaults, $options); + } +} diff --git a/engine/classes/Elgg/Upgrades/NotificationsPrefix.php b/engine/classes/Elgg/Upgrades/NotificationsPrefix.php index 3b3b4e033da..de4541f14fa 100644 --- a/engine/classes/Elgg/Upgrades/NotificationsPrefix.php +++ b/engine/classes/Elgg/Upgrades/NotificationsPrefix.php @@ -4,6 +4,7 @@ use Elgg\Database\Delete; use Elgg\Database\QueryBuilder; +use Elgg\Database\RelationshipsTable; use Elgg\Database\Select; use Elgg\Database\Update; use Elgg\Notifications\SubscriptionsService; @@ -59,27 +60,27 @@ public function run(Result $result, $offset): Result { ])); foreach ($methods as $method) { - $select = Select::fromTable('entity_relationships', 'r1'); + $select = Select::fromTable(RelationshipsTable::TABLE_NAME, 'r1'); // exclude already migrated relationships - $exists = $select->subquery('entity_relationships', 'r2'); + $exists = $select->subquery(RelationshipsTable::TABLE_NAME, 'r2'); $exists->select('1') - ->where($select->compare('r1.guid_one', '=', 'r2.guid_one')) - ->andWhere($select->compare('r1.guid_two', '=', 'r2.guid_two')) - ->andWhere($select->compare('r2.relationship', '=', "{$relationship_prefix}:{$method}", ELGG_VALUE_STRING)); + ->where($select->compare("{$select->getTableAlias()}.guid_one", '=', "{$exists->getTableAlias()}.guid_one")) + ->andWhere($select->compare("{$select->getTableAlias()}.guid_two", '=', "{$exists->getTableAlias()}.guid_two")) + ->andWhere($select->compare("{$exists->getTableAlias()}.relationship", '=', "{$relationship_prefix}:{$method}", ELGG_VALUE_STRING)); // get old relationships $select->select('id') - ->where($select->compare('r1.relationship', '=', "{$relationship_prefix}{$method}", ELGG_VALUE_STRING)) - ->andWhere($select->compare('r1.guid_one', 'in', $guids, ELGG_VALUE_GUID)) - ->andWhere($select->compare(null, 'not exists', $exists->getSQL())); + ->where($select->compare("{$select->getTableAlias()}.relationship", '=', "{$relationship_prefix}{$method}", ELGG_VALUE_STRING)) + ->andWhere($select->compare("{$select->getTableAlias()}.guid_one", 'in', $guids, ELGG_VALUE_GUID)) + ->andWhere("NOT EXISTS ({$exists->getSQL()})"); $ids = _elgg_services()->db->getData($select, function($row) { return (int) $row->id; }); if (!empty($ids)) { // update old relationships to new relationship - $update = Update::table('entity_relationships'); + $update = Update::table(RelationshipsTable::TABLE_NAME); $update->set('relationship', $update->param("{$relationship_prefix}:{$method}", ELGG_VALUE_STRING)) ->where($update->compare('relationship', '=', "{$relationship_prefix}{$method}", ELGG_VALUE_STRING)) ->andWhere($update->compare('id', 'in', $ids, ELGG_VALUE_ID)); @@ -88,7 +89,7 @@ public function run(Result $result, $offset): Result { } // delete old relationships that couldn't be migrated because of key constraints - $delete = Delete::fromTable('entity_relationships'); + $delete = Delete::fromTable(RelationshipsTable::TABLE_NAME); $delete->where($delete->compare('guid_one', 'in', $guids, ELGG_VALUE_GUID)) ->andWhere($delete->compare('relationship', '=', "{$relationship_prefix}{$method}", ELGG_VALUE_STRING)); diff --git a/engine/classes/Elgg/Upgrades/RemoveIcontime.php b/engine/classes/Elgg/Upgrades/RemoveIcontime.php new file mode 100644 index 00000000000..4323e1caafd --- /dev/null +++ b/engine/classes/Elgg/Upgrades/RemoveIcontime.php @@ -0,0 +1,81 @@ +countItems()); + } + + /** + * {@inheritdoc} + */ + public function needsIncrementOffset(): bool { + return false; + } + + /** + * {@inheritdoc} + */ + public function countItems(): int { + return elgg_get_metadata($this->getOptions([ + 'count' => true, + ])); + } + + /** + * {@inheritdoc} + */ + public function run(Result $result, $offset): Result { + /* @var $metadata \ElggBatch */ + $metadata = elgg_get_metadata($this->getOptions([ + 'offset' => $offset, + ])); + + /* @var $md \ElggMetadata */ + foreach ($metadata as $md) { + if (!$md->delete()) { + $metadata->reportFailure(); + $result->addFailures(); + continue; + } + + $result->addSuccesses(); + } + + return $result; + } + + /** + * Get options to metadata queries + * + * @param array $options additional options + * + * @return array + * @see elgg_get_metadata() + */ + protected function getOptions(array $options = []): array { + $defaults = [ + 'metadata_names' => 'icontime', + 'limit' => 50, + 'batch' => true, + 'batch_inc_offset' => $this->needsIncrementOffset(), + ]; + + return array_merge($defaults, $options); + } +} diff --git a/engine/classes/Elgg/Upgrades/RemoveOrphanedThreadedComments.php b/engine/classes/Elgg/Upgrades/RemoveOrphanedThreadedComments.php index d789dce9c40..374c5c48cbf 100644 --- a/engine/classes/Elgg/Upgrades/RemoveOrphanedThreadedComments.php +++ b/engine/classes/Elgg/Upgrades/RemoveOrphanedThreadedComments.php @@ -2,6 +2,7 @@ namespace Elgg\Upgrades; +use Elgg\Database\EntityTable; use Elgg\Database\QueryBuilder; use Elgg\Upgrade\AsynchronousUpgrade; use Elgg\Upgrade\Result; @@ -80,7 +81,7 @@ protected function getOptions(array $options = []): array { ], 'wheres' => [ function (QueryBuilder $qb, $main_alias) { - $sub = $qb->subquery('entities'); + $sub = $qb->subquery(EntityTable::TABLE_NAME); $sub->select('guid') ->where($qb->compare('type', '=', 'object', ELGG_VALUE_STRING)) ->andWhere($qb->compare('subtype', '=', 'comment', ELGG_VALUE_STRING)); diff --git a/engine/classes/Elgg/UploadService.php b/engine/classes/Elgg/UploadService.php index e61b468b694..7ca9ca8f938 100644 --- a/engine/classes/Elgg/UploadService.php +++ b/engine/classes/Elgg/UploadService.php @@ -13,18 +13,12 @@ */ class UploadService { - /** - * @var \Elgg\Http\Request - */ - private $request; - /** * Constructor * * @param \Elgg\Http\Request $request Http request */ - public function __construct(HttpRequest $request) { - $this->request = $request; + public function __construct(protected HttpRequest $request) { } /** diff --git a/engine/classes/Elgg/UserCapabilities.php b/engine/classes/Elgg/UserCapabilities.php index 8f11d34bc57..4b574019ab6 100644 --- a/engine/classes/Elgg/UserCapabilities.php +++ b/engine/classes/Elgg/UserCapabilities.php @@ -13,21 +13,6 @@ */ class UserCapabilities { - /** - * @var EventsService - */ - protected $events; - - /** - * @var EntityTable - */ - protected $entities; - - /** - * @var SessionManagerService - */ - protected $session_manager; - /** * Constructor * @@ -35,10 +20,11 @@ class UserCapabilities { * @param EntityTable $entities Entity table * @param SessionManagerService $session_manager Session */ - public function __construct(EventsService $events, EntityTable $entities, SessionManagerService $session_manager) { - $this->events = $events; - $this->entities = $entities; - $this->session_manager = $session_manager; + public function __construct( + protected EventsService $events, + protected EntityTable $entities, + protected SessionManagerService $session_manager + ) { } /** diff --git a/engine/classes/Elgg/Users/Accounts.php b/engine/classes/Elgg/Users/Accounts.php index aabd9f8f257..3eb161b6abc 100644 --- a/engine/classes/Elgg/Users/Accounts.php +++ b/engine/classes/Elgg/Users/Accounts.php @@ -19,36 +19,6 @@ */ class Accounts { - /** - * @var Config - */ - protected $config; - - /** - * @var Translator - */ - protected $translator; - - /** - * @var PasswordService - */ - protected $passwords; - - /** - * @var EventsService - */ - protected $events; - - /** - * @var EmailService - */ - protected $email; - - /** - * @var PasswordGeneratorService - */ - protected $password_generator; - /** * Constructor * @@ -60,19 +30,13 @@ class Accounts { * @param PasswordGeneratorService $password_generator Password generator service */ public function __construct( - Config $config, - Translator $translator, - PasswordService $passwords, - EventsService $events, - EmailService $email, - PasswordGeneratorService $password_generator + protected Config $config, + protected Translator $translator, + protected PasswordService $passwords, + protected EventsService $events, + protected EmailService $email, + protected PasswordGeneratorService $password_generator ) { - $this->config = $config; - $this->translator = $translator; - $this->passwords = $passwords; - $this->events = $events; - $this->email = $email; - $this->password_generator = $password_generator; } /** @@ -89,43 +53,40 @@ public function __construct( * @return ValidationResults */ public function validateAccountData(string $username, string|array $password, string $name, string $email, bool $allow_multiple_emails = false): ValidationResults { + $results = new ValidationResults(); - return elgg_call(ELGG_SHOW_DISABLED_ENTITIES, function () use ($username, $email, $password, $name, $allow_multiple_emails) { - $results = new ValidationResults(); - - if (empty($name)) { - $error = $this->translator->translate('registration:noname'); - $results->fail('name', $name, $error); - } else { - $results->pass('name', $name); - } + if (empty($name)) { + $error = $this->translator->translate('registration:noname'); + $results->fail('name', $name, $error); + } else { + $results->pass('name', $name); + } - try { - $this->assertValidEmail($email, !$allow_multiple_emails); + try { + $this->assertValidEmail($email, !$allow_multiple_emails); - $results->pass('email', $email); - } catch (RegistrationException $ex) { - $results->fail('email', $email, $ex->getMessage()); - } + $results->pass('email', $email); + } catch (RegistrationException $ex) { + $results->fail('email', $email, $ex->getMessage()); + } - try { - $this->assertValidPassword($password); + try { + $this->assertValidPassword($password); - $results->pass('password', $password); - } catch (RegistrationException $ex) { - $results->fail('password', $password, $ex->getMessage()); - } + $results->pass('password', $password); + } catch (RegistrationException $ex) { + $results->fail('password', $password, $ex->getMessage()); + } - try { - $this->assertValidUsername($username, true); + try { + $this->assertValidUsername($username, true); - $results->pass('username', $username); - } catch (RegistrationException $ex) { - $results->fail('username', $username, $ex->getMessage()); - } + $results->pass('username', $username); + } catch (RegistrationException $ex) { + $results->fail('username', $username, $ex->getMessage()); + } - return $results; - }); + return $results; } /** @@ -281,7 +242,7 @@ public function assertValidUsername(string $username, bool $assert_unregistered } if ($assert_unregistered) { - $exists = elgg_call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES, function () use ($username) { + $exists = elgg_call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES | ELGG_SHOW_DELETED_ENTITIES, function () use ($username) { return elgg_get_user_by_username($username); }); @@ -367,7 +328,7 @@ public function assertValidEmail(string $address, bool $assert_unregistered = fa } if ($assert_unregistered) { - $exists = elgg_call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES, function () use ($address) { + $exists = elgg_call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES | ELGG_SHOW_DELETED_ENTITIES, function () use ($address) { return elgg_get_user_by_email($address); }); diff --git a/engine/classes/Elgg/Validation/ValidationResult.php b/engine/classes/Elgg/Validation/ValidationResult.php index 4b8d34e3080..37e888ab439 100644 --- a/engine/classes/Elgg/Validation/ValidationResult.php +++ b/engine/classes/Elgg/Validation/ValidationResult.php @@ -7,25 +7,9 @@ */ class ValidationResult { - /** - * @var string - */ - protected $name; - - /** - * @var mixed - */ - protected $value; - - /** - * @var string - */ - protected $message; + protected string $message = ''; - /** - * @var string - */ - protected $error; + protected string $error = ''; /** * Constructor @@ -33,9 +17,7 @@ class ValidationResult { * @param string $name Parameter name * @param mixed $value Parameter value */ - public function __construct($name, $value) { - $this->name = $name; - $this->value = $value; + public function __construct(protected string $name, protected $value) { } /** @@ -45,7 +27,7 @@ public function __construct($name, $value) { * * @return void */ - public function pass($message = '') { + public function pass(string $message = ''): void { $this->message = $message; } @@ -56,7 +38,7 @@ public function pass($message = '') { * * @return void */ - public function fail($error = '') { + public function fail(string $error = ''): void { $this->error = $error; } @@ -65,8 +47,8 @@ public function fail($error = '') { * * @return bool */ - public function isValid() { - return !isset($this->error); + public function isValid(): bool { + return $this->error === ''; } /** @@ -74,7 +56,7 @@ public function isValid() { * * @return string */ - public function getName() { + public function getName(): string { return $this->name; } @@ -90,18 +72,18 @@ public function getValue() { /** * Get error message * - * @return mixed + * @return string */ - public function getError() { + public function getError(): string { return $this->error; } /** * Get success message * - * @return mixed + * @return string */ - public function getMessage() { + public function getMessage(): string { return $this->message; } } diff --git a/engine/classes/Elgg/Values.php b/engine/classes/Elgg/Values.php index fb88536b4e3..b6c17381952 100644 --- a/engine/classes/Elgg/Values.php +++ b/engine/classes/Elgg/Values.php @@ -5,7 +5,6 @@ use DateTime as PHPDateTime; use Elgg\I18n\DateTime as ElggDateTime; use Elgg\Exceptions\DataFormatException; -use Exception; /** * Functions for use as event handlers or other situations where you need a @@ -40,6 +39,7 @@ public static function getFalse() { * @since 1.12.0 */ public static function getNull() { + return null; } /** @@ -86,7 +86,7 @@ public static function normalizeTime($time) { } else { $dt = new ElggDateTime(); } - } catch (Exception $e) { + } catch (\Exception $e) { throw new DataFormatException($e->getMessage()); } @@ -170,13 +170,13 @@ public static function normalizeGuids(...$args) { /** * Return array with __view_output set to prevent view output during view_vars event * - * @see ViewsService->renderView() + * @see ViewsService->renderView() * * @return array * @since 3.0 */ public static function preventViewOutput() { - return ['__view_output' => '']; + return [ViewsService::OUTPUT_KEY => '']; } /** @@ -190,7 +190,6 @@ public static function preventViewOutput() { * @since 3.0.0 */ public static function isEmpty($value): bool { - if ($value === 0 || $value === '0' || $value === 0.0) { return false; } @@ -205,8 +204,8 @@ public static function isEmpty($value): bool { * * @param mixed $n input integer or string * @param int $precision number of digits in decimal place (default = 0) - * @return string|int * + * @return string|int * @since 3.1 */ public static function shortFormatOutput($n, $precision = 0) { diff --git a/engine/classes/Elgg/Views/AddAmdModuleNameHandler.php b/engine/classes/Elgg/Views/AddAmdModuleNameHandler.php deleted file mode 100644 index 02bb4021236..00000000000 --- a/engine/classes/Elgg/Views/AddAmdModuleNameHandler.php +++ /dev/null @@ -1,23 +0,0 @@ -filter($event->getParam('view'), $event->getValue()); - } -} diff --git a/engine/classes/Elgg/Views/AutoParagraph.php b/engine/classes/Elgg/Views/AutoParagraph.php index ed0d0d60d55..fd839175a9f 100644 --- a/engine/classes/Elgg/Views/AutoParagraph.php +++ b/engine/classes/Elgg/Views/AutoParagraph.php @@ -152,6 +152,7 @@ public function process($html) { $load_result = $this->_doc->loadHTML($html); // restore warnings + libxml_clear_errors(); libxml_use_internal_errors($use_internal_errors); if (!$load_result) { return false; diff --git a/engine/classes/Elgg/Views/HtmlFormatter.php b/engine/classes/Elgg/Views/HtmlFormatter.php index 4d9195fb78e..8854adf0999 100644 --- a/engine/classes/Elgg/Views/HtmlFormatter.php +++ b/engine/classes/Elgg/Views/HtmlFormatter.php @@ -8,6 +8,7 @@ use Elgg\Traits\Loggable; use Elgg\ViewsService; use Pelago\Emogrifier\CssInliner; +use Pelago\Emogrifier\HtmlProcessor\CssToAttributeConverter; /** * Various helper method for formatting and sanitizing output @@ -36,12 +37,6 @@ class HtmlFormatter { */ public const MENTION_REGEX = '/]*?>.*?<\/a>|<.*?>|(^|\s|\!|\.|\?|>|\G)+(@([^\s<&]+))/iu'; - protected ViewsService $views; - - protected EventsService $events; - - protected AutoParagraph $autop; - /** * Output constructor. * @@ -50,13 +45,10 @@ class HtmlFormatter { * @param AutoParagraph $autop Paragraph wrapper */ public function __construct( - ViewsService $views, - EventsService $events, - AutoParagraph $autop + protected ViewsService $views, + protected EventsService $events, + protected AutoParagraph $autop ) { - $this->views = $views; - $this->events = $events; - $this->autop = $autop; } /** @@ -188,7 +180,7 @@ public function parseMentions(string $text): string { return $preceding_char . $replacement . $period; }; - return preg_replace_callback(self::MENTION_REGEX, $callback, $text); + return preg_replace_callback(self::MENTION_REGEX, $callback, $text) ?? $text; } /** @@ -424,9 +416,10 @@ public function inlineCss(string $html, string $css, bool $body_only = false): s return $html; } - $inliner = CssInliner::fromHtml($html)->disableStyleBlocksParsing()->inlineCss($css); + $html_with_inlined_css = CssInliner::fromHtml($html)->disableStyleBlocksParsing()->inlineCss($css)->render(); + $inlined_attribute_converter = CssToAttributeConverter::fromHtml($html_with_inlined_css)->convertCssToVisualAttributes(); - return $body_only ? $inliner->renderBodyContent() : $inliner->render(); + return $body_only ? $inlined_attribute_converter->renderBodyContent() : $inlined_attribute_converter->render(); } /** diff --git a/engine/classes/Elgg/Views/TableColumn/CallableColumn.php b/engine/classes/Elgg/Views/TableColumn/CallableColumn.php index 200b965c835..7362a1e6667 100644 --- a/engine/classes/Elgg/Views/TableColumn/CallableColumn.php +++ b/engine/classes/Elgg/Views/TableColumn/CallableColumn.php @@ -9,24 +9,18 @@ class CallableColumn implements TableColumn { /** - * @var string + * @var callable rendering function */ - private $heading; - - /** - * @var callable - */ - private $renderer; - + protected $renderer; + /** * Constructor * * @param callable $renderer Rendering function * @param string $heading Heading */ - public function __construct(callable $renderer, $heading) { + public function __construct(callable $renderer, protected $heading) { $this->renderer = $renderer; - $this->heading = $heading; } /** diff --git a/engine/classes/Elgg/Views/TableColumn/ViewColumn.php b/engine/classes/Elgg/Views/TableColumn/ViewColumn.php index 65b84c11e0b..9aa8b053abe 100644 --- a/engine/classes/Elgg/Views/TableColumn/ViewColumn.php +++ b/engine/classes/Elgg/Views/TableColumn/ViewColumn.php @@ -9,20 +9,7 @@ */ class ViewColumn implements TableColumn { - /** - * @var string - */ - private $heading; - - /** - * @var string - */ - private $view; - - /** - * @var array - */ - private $vars; + protected string $heading; /** * Constructor @@ -31,12 +18,9 @@ class ViewColumn implements TableColumn { * @param string $heading Heading * @param array $vars Vars to merge into the view vars */ - public function __construct($view, $heading = null, $vars = []) { - $this->view = $view; - $this->vars = $vars; - + public function __construct(protected string $view, string $heading = null, protected array $vars = []) { if (!is_string($heading)) { - $heading = elgg_echo("ViewColumn:view:$view"); + $heading = elgg_echo("ViewColumn:view:{$view}"); } $this->heading = $heading; diff --git a/engine/classes/Elgg/ViewsService.php b/engine/classes/Elgg/ViewsService.php index 6d20e9984a9..d866a68db80 100644 --- a/engine/classes/Elgg/ViewsService.php +++ b/engine/classes/Elgg/ViewsService.php @@ -2,9 +2,7 @@ namespace Elgg; -use Elgg\Application\CacheHandler; use Elgg\Cache\SystemCache; -use Elgg\Filesystem\Directory; use Elgg\Http\Request as HttpRequest; use Elgg\Project\Paths; use Elgg\Traits\Loggable; @@ -28,70 +26,52 @@ class ViewsService { * @see ViewsService::fileExists() * @var array */ - protected $file_exists_cache = []; + protected array $file_exists_cache = []; /** * @var array * * [viewtype][view] => '/path/to/views/style.css' */ - private $locations = []; + protected array $locations = []; /** * @var array Tracks location changes for views * * [viewtype][view][] => '/path/to/views/style.css' */ - private $overrides = []; - - /** - * @var array Simplecache views (view names are keys) - * - * [view] = true - */ - private $simplecache_views = []; + protected array $overrides = []; /** * @var array * * [view][priority] = extension_view */ - private $extensions = []; + protected array $extensions = []; /** * @var string[] A list of fallback viewtypes */ - private $fallbacks = []; - - /** - * @var EventsService - */ - private $events; - - /** - * @var SystemCache|null This is set if the views are configured via cache - */ - private $cache; - - /** - * @var \Elgg\Http\Request - */ - private $request; + protected array $fallbacks = []; - /** - * @var string - */ - private $viewtype; + protected ?string $viewtype; + + protected bool $locations_loaded_from_cache = false; /** * Constructor * - * @param EventsService $events Events service - * @param \Elgg\Http\Request $request Http Request - */ - public function __construct(EventsService $events, HttpRequest $request) { - $this->events = $events; - $this->request = $request; + * @param EventsService $events Events service + * @param \Elgg\Http\Request $request Http Request + * @param \Elgg\Config $config Elgg configuration + * @param \Elgg\Cache\SystemCache $server_cache Server cache + */ + public function __construct( + protected EventsService $events, + protected HttpRequest $request, + protected Config $config, + protected SystemCache $server_cache + ) { } /** @@ -130,33 +110,21 @@ public function getViewtype(): string { return $this->viewtype; } - /** - * If the current viewtype has no views, reset it to "default" - * - * @return void - */ - public function clampViewtypeToPopulatedViews(): void { - $viewtype = $this->getViewtype(); - if (empty($this->locations[$viewtype])) { - $this->viewtype = 'default'; - } - } - /** * Resolve the initial viewtype * * @return string */ - private function resolveViewtype(): string { + protected function resolveViewtype(): string { if ($this->request) { $view = $this->request->getParam('view', '', false); - if ($this->isValidViewtype($view)) { + if ($this->isValidViewtype($view) && !empty($this->locations[$view])) { return $view; } } - $view = (string) elgg_get_config('view'); - if ($this->isValidViewtype($view)) { + $view = (string) $this->config->view; + if ($this->isValidViewtype($view) && !empty($this->locations[$view])) { return $view; } @@ -182,35 +150,6 @@ public function isValidViewtype(string $viewtype): bool { return true; } - /** - * Takes a view name and returns the canonical name for that view. - * - * @param string $alias The possibly non-canonical view name. - * - * @return string The canonical view name. - */ - public static function canonicalizeViewName(string $alias): string { - - $canonical = $alias; - - $extension = pathinfo($canonical, PATHINFO_EXTENSION); - $hasValidFileExtension = isset(CacheHandler::$extensions[$extension]); - - if (str_starts_with($canonical, 'js/')) { - $canonical = substr($canonical, 3); - if (!$hasValidFileExtension) { - $canonical .= '.js'; - } - } else if (str_starts_with($canonical, 'css/')) { - $canonical = substr($canonical, 4); - if (!$hasValidFileExtension) { - $canonical .= '.css'; - } - } - - return $canonical; - } - /** * Auto-registers views from a location. * @@ -284,33 +223,6 @@ public function findViewFile(string $view, string $viewtype): string { return ''; } - /** - * Set an alternative base location for a view - * - * @param string $view Name of the view - * @param string $location Full path to the view file - * @param string $viewtype The viewtype to register this under - * - * @return void - * - * @see elgg_set_view_location() - */ - public function setViewDir(string $view, string $location, string $viewtype = ''): void { - $view = self::canonicalizeViewName($view); - - if (empty($viewtype)) { - $viewtype = 'default'; - } - - $location = rtrim($location, '/\\'); - - if ($this->fileExists("$location/$viewtype/$view.php")) { - $this->setViewLocation($view, $viewtype, "$location/$viewtype/$view.php"); - } else if ($this->fileExists("$location/$viewtype/$view")) { - $this->setViewLocation($view, $viewtype, "$location/$viewtype/$view"); - } - } - /** * Register a viewtype to fall back to a default view if a view isn't * found for that viewtype. @@ -349,8 +261,6 @@ public function doesViewtypeFallback(string $viewtype): bool { * @see elgg_view() */ public function renderDeprecatedView(string $view, array $vars, string $suggestion, string $version): string { - $view = self::canonicalizeViewName($view); - $rendered = $this->renderView($view, $vars, '', false); if ($rendered) { $this->logDeprecatedMessage("The '{$view}' view has been deprecated. {$suggestion}", $version); @@ -385,9 +295,7 @@ public function getViewList(string $view): array { * * @see elgg_view() */ - public function renderView(string $view, array $vars = [], string $viewtype = '', bool $issue_missing_notice = true, array $extensions_tree = []): string { - $view = self::canonicalizeViewName($view); - + public function renderView(string $view, array $vars = [], string $viewtype = '', bool $issue_missing_notice = null, array $extensions_tree = []): string { // basic checking for bad paths if (str_contains($view, '..')) { return ''; @@ -406,6 +314,10 @@ public function renderView(string $view, array $vars = [], string $viewtype = '' if ($viewtype === '' || !$this->isValidViewtype($viewtype)) { $viewtype = $this->getViewtype(); } + + if (!isset($issue_missing_notice)) { + $issue_missing_notice = $viewtype === 'default'; + } // allow altering $vars $vars_event_params = [ @@ -481,7 +393,7 @@ protected function fileExists(string $path): bool { * * @return string|false output generated by view file inclusion or false */ - private function renderViewFile(string $view, array $vars, string $viewtype, bool $issue_missing_notice): string|false { + protected function renderViewFile(string $view, array $vars, string $viewtype, bool $issue_missing_notice): string|false { $file = $this->findViewFile($view, $viewtype); if (!$file) { if ($issue_missing_notice) { @@ -520,8 +432,6 @@ private function renderViewFile(string $view, array $vars, string $viewtype, boo * @see elgg_view_exists() */ public function viewExists(string $view, string $viewtype = '', bool $recurse = true): bool { - $view = self::canonicalizeViewName($view); - if (empty($view)) { return false; } @@ -568,9 +478,6 @@ public function viewExists(string $view, string $viewtype = '', bool $recurse = * @see elgg_extend_view() */ public function extendView(string $view, string $view_extension, int $priority = 501): void { - $view = self::canonicalizeViewName($view); - $view_extension = self::canonicalizeViewName($view_extension); - if ($view === $view_extension) { // do not allow direct extension on self with self return; @@ -600,9 +507,6 @@ public function extendView(string $view, string $view_extension, int $priority = * @see elgg_unextend_view() */ public function unextendView(string $view, string $view_extension): bool { - $view = self::canonicalizeViewName($view); - $view_extension = self::canonicalizeViewName($view_extension); - if (!isset($this->extensions[$view])) { return false; } @@ -621,71 +525,22 @@ public function unextendView(string $view, string $view_extension): bool { } /** - * Register a view a cacheable - * - * @param string $view the view name - * - * @return void - */ - public function registerCacheableView(string $view): void { - $view = self::canonicalizeViewName($view); - - $this->simplecache_views[$view] = true; - } - - /** - * Is the view cacheable + * Register all views in a given path * - * @param string $view the view name + * @param string $path Base path to scan for views * * @return bool */ - public function isCacheableView(string $view): bool { - $view = self::canonicalizeViewName($view); - if (isset($this->simplecache_views[$view])) { - return true; - } - - // build list of viewtypes to check - $current_viewtype = $this->getViewtype(); - $viewtypes = [$current_viewtype]; - - if ($this->doesViewtypeFallback($current_viewtype) && $current_viewtype != 'default') { - $viewtypes[] = 'default'; - } - - // If a static view file is found in any viewtype, it's considered cacheable - foreach ($viewtypes as $viewtype) { - $file = $this->findViewFile($view, $viewtype); - - if ($file && pathinfo($file, PATHINFO_EXTENSION) !== 'php') { - $this->simplecache_views[$view] = true; - - return true; - } - } - - // Assume not-cacheable by default - return false; - } - - /** - * Register a plugin's views - * - * @param string $path Base path of the plugin - * - * @return bool - */ - public function registerPluginViews(string $path): bool { + public function registerViewsFromPath(string $path): bool { $path = Paths::sanitize($path); $view_dir = "{$path}views/"; - // plugins don't have to have views. + // do not fail on non existing views folder if (!is_dir($view_dir)) { return true; } - // but if they do, they have to be readable + // but if folder exists it has to be readable $handle = opendir($view_dir); if ($handle === false) { $this->getLogger()->notice("Unable to register views from the directory: {$view_dir}"); @@ -726,7 +581,7 @@ public function mergeViewsSpec(array $spec): void { foreach ($paths as $path) { if (!preg_match('~^([/\\\\]|[a-zA-Z]\:)~', $path)) { // relative path - $path = Directory\Local::projectRoot()->getPath($path); + $path = Paths::project() . $path; } if (str_ends_with($view, '/')) { @@ -763,65 +618,99 @@ public function listViews(string $viewtype = 'default'): array { public function getInspectorData(): array { $overrides = $this->overrides; - if ($this->cache) { - $data = $this->cache->load('view_overrides'); + if ($this->server_cache) { + $data = $this->server_cache->load('view_overrides'); if (is_array($data)) { $overrides = $data; } } - + return [ 'locations' => $this->locations, 'overrides' => $overrides, 'extensions' => $this->extensions, - 'simplecache' => $this->simplecache_views, + 'simplecache' => _elgg_services()->simpleCache->getCacheableViews(), ]; } /** * Configure locations from the cache * - * @param SystemCache $cache The system cache - * - * @return bool + * @return void */ - public function configureFromCache(SystemCache $cache): bool { - $data = $cache->load('view_locations'); - if (!is_array($data)) { - return false; + public function configureFromCache(): void { + if (!$this->server_cache->isEnabled()) { + return; } - // format changed, check version - if (empty($data['version']) || $data['version'] !== '2.0') { - return false; + $data = $this->server_cache->load('view_locations'); + if (!is_array($data)) { + return; } $this->locations = $data['locations']; - $this->cache = $cache; - - return true; + $this->locations_loaded_from_cache = true; } /** * Cache the configuration * - * @param SystemCache $cache The system cache - * * @return void */ - public function cacheConfiguration(SystemCache $cache): void { + public function cacheConfiguration(): void { + if (!$this->server_cache->isEnabled()) { + return; + } + + // only cache if not already loaded + if ($this->isViewLocationsLoadedFromCache()) { + return; + } + if (empty($this->locations)) { - $cache->delete('view_locations'); + $this->server_cache->delete('view_locations'); return; } - $cache->save('view_locations', [ - 'version' => '2.0', - 'locations' => $this->locations, - ]); + $this->server_cache->save('view_locations', ['locations' => $this->locations]); // this is saved just for the inspector and is not loaded in loadAll() - $cache->save('view_overrides', $this->overrides); + $this->server_cache->save('view_overrides', $this->overrides); + } + + /** + * Checks if view_locations have been loaded from cache. + * This can be used to determine if there is a need to (re)load view locations + * + * @return bool + */ + public function isViewLocationsLoadedFromCache(): bool { + return $this->locations_loaded_from_cache; + } + + /** + * Returns an array of names of ES modules detected based on view location + * + * @return array + */ + public function getESModules(): array { + $modules = $this->server_cache->load('esmodules'); + if (is_array($modules)) { + return $modules; + } + + $modules = []; + foreach ($this->locations['default'] as $name => $path) { + if (!str_ends_with($name, '.mjs')) { + continue; + } + + $modules[] = $name; + } + + $this->server_cache->save('esmodules', $modules); + + return $modules; } /** @@ -833,8 +722,7 @@ public function cacheConfiguration(SystemCache $cache): void { * * @return void */ - private function setViewLocation(string $view, string $viewtype, string $path): void { - $view = self::canonicalizeViewName($view); + protected function setViewLocation(string $view, string $viewtype, string $path): void { $path = strtr($path, '\\', '/'); if (isset($this->locations[$viewtype][$view]) && $path !== $this->locations[$viewtype][$view]) { @@ -845,6 +733,6 @@ private function setViewLocation(string $view, string $viewtype, string $path): // Test if view is cacheable and push it to the cacheable views stack, // if it's not registered as cacheable explicitly - $this->isCacheableView($view); + _elgg_services()->simpleCache->isCacheableView($view); } } diff --git a/engine/classes/Elgg/WidgetDefinition.php b/engine/classes/Elgg/WidgetDefinition.php index e04b10088ac..d7906fa8ed8 100644 --- a/engine/classes/Elgg/WidgetDefinition.php +++ b/engine/classes/Elgg/WidgetDefinition.php @@ -8,8 +8,8 @@ * WidgetDefinition * * Helper class for defining a widget - * */ +#[\AllowDynamicProperties] class WidgetDefinition { /** diff --git a/engine/classes/ElggAnnotation.php b/engine/classes/ElggAnnotation.php index 17aa51fda65..a5e48c94940 100644 --- a/engine/classes/ElggAnnotation.php +++ b/engine/classes/ElggAnnotation.php @@ -74,27 +74,7 @@ public function save(): bool { public function delete(): bool { return _elgg_services()->annotationsTable->delete($this); } - - /** - * Disable the annotation. - * - * @return bool - * @since 1.8 - */ - public function disable(): bool { - return _elgg_services()->annotationsTable->disable($this); - } - - /** - * Enable the annotation. - * - * @return bool - * @since 1.8 - */ - public function enable(): bool { - return _elgg_services()->annotationsTable->enable($this); - } - + /** * Determines whether or not the user can edit this annotation * diff --git a/engine/classes/ElggComment.php b/engine/classes/ElggComment.php index e1ea50e4cab..0690e897ce9 100644 --- a/engine/classes/ElggComment.php +++ b/engine/classes/ElggComment.php @@ -24,20 +24,46 @@ protected function initializeAttributes() { } /** - * {@inheritDoc} + * {@inheritdoc} + */ + protected function persistentDelete(bool $recursive = true): bool { + $result = parent::persistentDelete($recursive); + + if ($result) { + $this->deleteThreadedComments($recursive, true); + } + + return $result; + } + + /** + * {@inheritdoc} + */ + protected function trash(bool $recursive = true): bool { + $result = parent::trash($recursive); + + if ($result) { + $this->deleteThreadedComments($recursive, false); + } + + return $result; + } + + /** + * {@inheritdoc} */ - public function delete(bool $recursive = true): bool { - $result = parent::delete($recursive); + public function restore(bool $recursive = true): bool { + $result = parent::restore($recursive); if ($result) { - // remove the threaded comments directly below this comment - elgg_call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES, function() use ($recursive) { + // restore threaded comments + elgg_call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES | ELGG_SHOW_DELETED_ENTITIES, function() use ($recursive) { + /* @var $children \ElggBatch */ $children = elgg_get_entities([ 'type' => 'object', 'subtype' => 'comment', 'limit' => false, 'batch' => true, - 'batch_inc_offset' => false, 'metadata_name_value_pairs' => [ 'name' => 'parent_guid', 'value' => $this->guid, @@ -46,7 +72,7 @@ public function delete(bool $recursive = true): bool { /* @var $child \ElggComment */ foreach ($children as $child) { - $child->delete($recursive); + $child->restore($recursive); } }); } @@ -54,6 +80,39 @@ public function delete(bool $recursive = true): bool { return $result; } + /** + * Delete threaded child comments on this comment + * + * @param bool $recursive recursive delete contained entities + * @param bool $persistent persistently remove the threaded comments + * + * @return void + * @since 6.0 + */ + protected function deleteThreadedComments(bool $recursive, bool $persistent): void { + elgg_call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES | ELGG_SHOW_DELETED_ENTITIES, function() use ($recursive, $persistent) { + /* @var $children \ElggBatch */ + $children = elgg_get_entities([ + 'type' => 'object', + 'subtype' => 'comment', + 'limit' => false, + 'batch' => true, + 'batch_inc_offset' => !$persistent, + 'metadata_name_value_pairs' => [ + 'name' => 'parent_guid', + 'value' => $this->guid, + ], + ]); + + /* @var $child \ElggComment */ + foreach ($children as $child) { + if (!$child->delete($recursive, $persistent) && $persistent) { + $children->reportFailure(); + } + } + }); + } + /** * {@inheritDoc} */ diff --git a/engine/classes/ElggEntity.php b/engine/classes/ElggEntity.php index e94c1d5865f..78bfb060b77 100644 --- a/engine/classes/ElggEntity.php +++ b/engine/classes/ElggEntity.php @@ -1,11 +1,11 @@ attributes['time_updated'] = null; $this->attributes['last_action'] = null; $this->attributes['enabled'] = 'yes'; + $this->attributes['deleted'] = 'no'; + $this->attributes['time_deleted'] = null; } /** @@ -200,7 +208,7 @@ public function __clone() { $metadata_names[] = $metadata->name; } - // arrays are stored with multiple enties per name + // arrays are stored with multiple entries per name $metadata_names = array_unique($metadata_names); // move the metadata over @@ -248,6 +256,7 @@ public function __set($name, $value) { switch ($name) { case 'guid': case 'last_action': + case 'time_deleted': case 'time_updated': case 'type': return; @@ -255,6 +264,8 @@ public function __set($name, $value) { throw new ElggInvalidArgumentException(elgg_echo('ElggEntity:Error:SetSubtype', ['setSubtype()'])); case 'enabled': throw new ElggInvalidArgumentException(elgg_echo('ElggEntity:Error:SetEnabled', ['enable() / disable()'])); + case 'deleted': + throw new ElggInvalidArgumentException(elgg_echo('ElggEntity:Error:SetDeleted', ['delete() / restore()'])); case 'access_id': case 'owner_guid': case 'container_guid': @@ -294,6 +305,7 @@ public function getOriginalAttributes(): array { * $name key. * * @param string $name Name of the attribute or metadata + * * @return mixed */ public function __get($name) { @@ -317,6 +329,7 @@ public function getDisplayName(): string { * Sets the title or name of this entity. * * @param string $display_name The title or name of this entity. + * * @return void */ public function setDisplayName(string $display_name): void { @@ -646,6 +659,7 @@ public function removeAllRelatedRiverItems(): void { * @warning Calling this with no or empty arguments will clear all annotations on the entity. * * @param string $name An optional name of annotations to remove. + * * @return bool * @since 1.8 */ @@ -672,6 +686,7 @@ public function deleteAnnotations(string $name = null): bool { * If you pass a name, only annotations matching that name will be deleted. * * @param string $name An optional name of annotations to delete. + * * @return bool * @since 1.8 */ @@ -687,41 +702,12 @@ public function deleteOwnedAnnotations(string $name = null): bool { }); } - /** - * Disables annotations for this entity, optionally based on name. - * - * @param string $name An optional name of annotations to disable. - * @return bool - * @since 1.8 - */ - public function disableAnnotations(string $name = null): bool { - return elgg_disable_annotations([ - 'guid' => $this->guid, - 'limit' => false, - 'annotation_name' => $name, - ]); - } - - /** - * Enables annotations for this entity, optionally based on name. - * - * @param string $name An optional name of annotations to enable. - * @return bool - * @since 1.8 - */ - public function enableAnnotations(string $name = null) { - return elgg_enable_annotations([ - 'guid' => $this->guid, - 'limit' => false, - 'annotation_name' => $name, - ]); - } - /** * Helper function to return annotation calculation results * * @param string $name The annotation name. * @param string $calculation A valid MySQL function to run its values through + * * @return mixed */ private function getAnnotationCalculation($name, $calculation) { @@ -1132,102 +1118,6 @@ public function getURL(): string { return elgg_normalize_url($url); } - /** - * Saves icons using an uploaded file as the source. - * - * @param string $input_name Form input name - * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' - * @param array $coords An array of cropping coordinates x1, y1, x2, y2 - * @return bool - */ - public function saveIconFromUploadedFile(string $input_name, string $type = 'icon', array $coords = []): bool { - return _elgg_services()->iconService->saveIconFromUploadedFile($this, $input_name, $type, $coords); - } - - /** - * Saves icons using a local file as the source. - * - * @param string $filename The full path to the local file - * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' - * @param array $coords An array of cropping coordinates x1, y1, x2, y2 - * @return bool - */ - public function saveIconFromLocalFile(string $filename, string $type = 'icon', array $coords = []): bool { - return _elgg_services()->iconService->saveIconFromLocalFile($this, $filename, $type, $coords); - } - - /** - * Saves icons using a file located in the data store as the source. - * - * @param string $file An ElggFile instance - * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' - * @param array $coords An array of cropping coordinates x1, y1, x2, y2 - * @return bool - */ - public function saveIconFromElggFile(\ElggFile $file, string $type = 'icon', array $coords = []): bool { - return _elgg_services()->iconService->saveIconFromElggFile($this, $file, $type, $coords); - } - - /** - * Returns entity icon as an ElggIcon object - * The icon file may or may not exist on filestore - * - * @param string $size Size of the icon - * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' - * @return \ElggIcon - */ - public function getIcon(string $size, string $type = 'icon'): \ElggIcon { - return _elgg_services()->iconService->getIcon($this, $size, $type); - } - - /** - * Removes all icon files and metadata for the passed type of icon. - * - * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' - * @return bool - */ - public function deleteIcon(string $type = 'icon'): bool { - return _elgg_services()->iconService->deleteIcon($this, $type); - } - - /** - * Returns the timestamp of when the icon was changed. - * - * @param string $size The size of the icon - * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' - * - * @return int|null A unix timestamp of when the icon was last changed, or null if not set. - */ - public function getIconLastChange(string $size, string $type = 'icon'): ?int { - return _elgg_services()->iconService->getIconLastChange($this, $size, $type); - } - - /** - * Returns if the entity has an icon of the passed type. - * - * @param string $size The size of the icon - * @param string $type The name of the icon. e.g., 'icon', 'cover_photo' - * @return bool - */ - public function hasIcon(string $size, string $type = 'icon'): bool { - return _elgg_services()->iconService->hasIcon($this, $size, $type); - } - - /** - * Get the URL for this entity's icon - * - * Plugins can register for the 'entity:icon:url', '' event - * to customize the icon for an entity. - * - * @param mixed $params A string defining the size of the icon (e.g. tiny, small, medium, large) - * or an array of parameters including 'size' - * @return string The URL - * @since 1.8.0 - */ - public function getIconURL(string|array $params = []): string { - return _elgg_services()->iconService->getIconURL($this, $params); - } - /** * {@inheritDoc} */ @@ -1251,10 +1141,10 @@ public function save(): bool { * Saves the base information in the entities table for the entity. Saving * the type-specific information is handled in the calling class method. * - * @return int|false The new entity's GUID or false on failure + * @return int|false The new entity's GUID or false if prevented by an event handler * * @throws \Elgg\Exceptions\DomainException If the entity's type has not been set. - * @throws \Elgg\Exceptions\InvalidArgumentException If the entity's subtype has not been set or access_id is invalid + * @throws \Elgg\Exceptions\InvalidArgumentException If the entity's subtype has not been set, access_id is invalid or something is wrong with the owner or container * @throws \Elgg\Exceptions\Filesystem\IOException If the new row fails to write to the DB. */ protected function create() { @@ -1273,6 +1163,8 @@ protected function create() { $access_id = (int) $this->attributes['access_id']; $now = $this->getCurrentTime()->getTimestamp(); $time_created = isset($this->attributes['time_created']) ? (int) $this->attributes['time_created'] : $now; + $deleted = $this->attributes['deleted']; + $time_deleted = (int) $this->attributes['time_deleted']; $container_guid = $this->attributes['container_guid']; if ($container_guid == 0) { @@ -1282,11 +1174,11 @@ protected function create() { $container_guid = (int) $container_guid; - if ($access_id == ACCESS_DEFAULT) { + if ($access_id === ACCESS_DEFAULT) { throw new ElggInvalidArgumentException('ACCESS_DEFAULT is not a valid access level. See its documentation in constants.php'); } - if ($access_id == ACCESS_FRIENDS) { + if ($access_id === ACCESS_FRIENDS) { throw new ElggInvalidArgumentException('ACCESS_FRIENDS is not a valid access level. See its documentation in constants.php'); } @@ -1298,16 +1190,14 @@ protected function create() { if (!$owner instanceof \ElggEntity) { $error = "User {$user_guid} tried to create a ({$type}, {$subtype}),"; $error .= " but the given owner {$owner_guid} could not be loaded."; - _elgg_services()->logger->error($error); - return false; + throw new ElggInvalidArgumentException($error); } // If different owner than logged in, verify can write to container. if ($user_guid !== $owner_guid && !$owner->canEdit() && !$owner->canWriteToContainer($user_guid, $type, $subtype)) { $error = "User {$user_guid} tried to create a ({$type}, {$subtype}) with owner {$owner_guid},"; $error .= " but the user wasn't permitted to write to the owner's container."; - _elgg_services()->logger->error($error); - return false; + throw new ElggInvalidArgumentException($error); } } @@ -1317,15 +1207,13 @@ protected function create() { if (!$container instanceof \ElggEntity) { $error = "User {$user_guid} tried to create a ({$type}, {$subtype}),"; $error .= " but the given container {$container_guid} could not be loaded."; - _elgg_services()->logger->error($error); - return false; + throw new ElggInvalidArgumentException($error); } if (!$container->canWriteToContainer($user_guid, $type, $subtype)) { $error = "User {$user_guid} tried to create a ({$type}, {$subtype}),"; $error .= " but was not permitted to write to container {$container_guid}."; - _elgg_services()->logger->error($error); - return false; + throw new ElggInvalidArgumentException($error); } } @@ -1343,6 +1231,8 @@ protected function create() { 'time_created' => $time_created, 'time_updated' => $now, 'last_action' => $now, + 'deleted' => $deleted, + 'time_deleted' => $time_deleted ], $this->attributes); if (!$guid) { @@ -1355,6 +1245,8 @@ protected function create() { $this->attributes['time_updated'] = (int) $now; $this->attributes['last_action'] = (int) $now; $this->attributes['container_guid'] = (int) $container_guid; + $this->attributes['deleted'] = $deleted; + $this->attributes['time_deleted'] = (int) $time_deleted; // We are writing this new entity to cache to make sure subsequent calls // to get_entity() load the entity from cache and not from the DB. This @@ -1420,11 +1312,13 @@ protected function update(): bool { $container_guid = (int) $this->container_guid; $time_created = (int) $this->time_created; $time = $this->getCurrentTime()->getTimestamp(); + $deleted = $this->deleted; + $time_deleted = (int) $this->time_deleted; if ($access_id == ACCESS_DEFAULT) { throw new ElggInvalidArgumentException('ACCESS_DEFAULT is not a valid access level. See its documentation in constants.php'); } - + if ($access_id == ACCESS_FRIENDS) { throw new ElggInvalidArgumentException('ACCESS_FRIENDS is not a valid access level. See its documentation in constants.php'); } @@ -1437,6 +1331,8 @@ protected function update(): bool { 'time_created' => $time_created, 'time_updated' => $time, 'guid' => $guid, + 'deleted' => $deleted, + 'time_deleted' => $time_deleted ]); if ($ret === false) { return false; @@ -1520,7 +1416,8 @@ public function disable(string $reason = '', bool $recursive = true): bool { if ($this instanceof ElggUser && !$this->isBanned()) { // temporarily ban to prevent using the site during disable - $this->ban(); + // not using ban function to bypass events + $this->setMetadata('banned', 'yes'); $unban_after = true; } else { $unban_after = false; @@ -1533,7 +1430,7 @@ public function disable(string $reason = '', bool $recursive = true): bool { $guid = (int) $this->guid; if ($recursive) { - elgg_call(ELGG_IGNORE_ACCESS | ELGG_HIDE_DISABLED_ENTITIES, function () use ($guid, $reason) { + elgg_call(ELGG_IGNORE_ACCESS | ELGG_HIDE_DISABLED_ENTITIES | ELGG_SHOW_DELETED_ENTITIES, function () use ($guid, $reason) { $base_options = [ 'wheres' => [ function(QueryBuilder $qb, $main_alias) use ($guid) { @@ -1563,12 +1460,10 @@ function(QueryBuilder $qb, $main_alias) use ($guid) { }); } - $this->disableAnnotations(); - $disabled = _elgg_services()->entityTable->disable($this); if ($unban_after) { - $this->unban(); + $this->setMetadata('banned', 'no'); } if ($disabled) { @@ -1585,7 +1480,7 @@ function(QueryBuilder $qb, $main_alias) use ($guid) { * Enable the entity * * @param bool $recursive Recursively enable all entities disabled with the entity? - * @see access_show_hiden_entities() + * * @return bool */ public function enable(bool $recursive = true): bool { @@ -1601,11 +1496,10 @@ public function enable(bool $recursive = true): bool { return false; } - $result = elgg_call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES, function() use ($recursive) { + $result = elgg_call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES | ELGG_SHOW_DELETED_ENTITIES, function() use ($recursive) { $result = _elgg_services()->entityTable->enable($this); - + $this->deleteMetadata('disable_reason'); - $this->enableAnnotations(); if ($recursive) { $disabled_with_it = elgg_get_entities([ @@ -1655,31 +1549,136 @@ public function isEnabled(): bool { * the entity. That means that if the container_guid = $this->guid, the item will * be deleted regardless of who owns it. * - * @param bool $recursive If true (default) then all entities which are - * owned or contained by $this will also be deleted. + * @param bool $recursive If true (default) then all entities which are owned or contained by $this will also be deleted. + * @param bool|null $persistent persistently delete the entity (default: check the 'restorable' capability) * * @return bool */ - public function delete(bool $recursive = true): bool { - // first check if we can delete this entity - // NOTE: in Elgg <= 1.10.3 this was after the delete event, - // which could potentially remove some content if the user didn't have access + public function delete(bool $recursive = true, bool $persistent = null): bool { if (!$this->canDelete()) { return false; } + if (!elgg_get_config('trash_enabled')) { + $persistent = true; + } + + if (!isset($persistent)) { + $persistent = !$this->hasCapability('restorable'); + } + try { - return _elgg_services()->entityTable->delete($this, $recursive); + if (empty($this->guid) || $persistent) { + return $this->persistentDelete($recursive); + } else { + return $this->trash($recursive); + } } catch (DatabaseException $ex) { elgg_log($ex, 'ERROR'); return false; } } - + + /** + * Permanently delete the entity from the database + * + * @param bool $recursive If true (default) then all entities which are owned or contained by $this will also be deleted. + * + * @return bool + * @since 6.0 + */ + protected function persistentDelete(bool $recursive = true): bool { + return _elgg_services()->entityTable->delete($this, $recursive); + } + + /** + * Move the entity to the trash + * + * @param bool $recursive If true (default) then all entities which are owned or contained by $this will also be trashed. + * + * @return bool + * @since 6.0 + */ + protected function trash(bool $recursive = true): bool { + $result = _elgg_services()->entityTable->trash($this, $recursive); + if ($result) { + $this->attributes['deleted'] = 'yes'; + } + + return $result; + } + + /** + * Restore the entity + * + * @param bool $recursive Recursively restores all entities trashed with the entity? + * + * @return bool + * @since 6.0 + */ + public function restore(bool $recursive = true): bool { + if (!$this->isDeleted()) { + return true; + } + + if (empty($this->guid) || !$this->canEdit()) { + return false; + } + + return _elgg_services()->events->triggerSequence('restore', $this->type, $this, function () use ($recursive) { + return elgg_call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES | ELGG_SHOW_DELETED_ENTITIES, function() use ($recursive) { + $result = _elgg_services()->entityTable->restore($this); + + if ($recursive) { + set_time_limit(0); + + /* @var $deleted_with_it \ElggBatch */ + $deleted_with_it = elgg_get_entities([ + 'relationship' => 'deleted_with', + 'relationship_guid' => $this->guid, + 'inverse_relationship' => true, + 'limit' => false, + 'batch' => true, + 'batch_inc_offset' => false, + ]); + + /* @var $e \ElggEntity */ + foreach ($deleted_with_it as $e) { + if (!$e->restore($recursive)) { + $deleted_with_it->reportFailure(); + continue; + } + + $e->removeRelationship($this->guid, 'deleted_with'); + } + } + + $this->removeAllRelationships('deleted_by', true); + + if ($result) { + $this->attributes['deleted'] = 'no'; + $this->attributes['time_deleted'] = 0; + } + + return $result; + }); + }); + } + + /** + * Is the entity marked as deleted + * + * @return bool + */ + public function isDeleted(): bool { + return $this->deleted === 'yes'; + } + /** * Export an entity * * @param array $params Params to pass to the event + * * @return \Elgg\Export\Entity */ public function toObject(array $params = []) { @@ -1694,6 +1693,7 @@ public function toObject(array $params = []) { * Prepare an object copy for toObject() * * @param \Elgg\Export\Entity $object Object representation of the entity + * * @return \Elgg\Export\Entity */ protected function prepareObject(\Elgg\Export\Entity $object) { @@ -1763,41 +1763,6 @@ public function getObjectFromID(int $id): ?\ElggEntity { return get_entity($id); } - /** - * Returns tags for this entity. - * - * @param array $tag_names Optionally restrict by tag metadata names. Defaults to metadata with the name 'tags'. - * - * @return array - */ - public function getTags($tag_names = null) { - if (!isset($tag_names)) { - $tag_names = ['tags']; - } - - if ($tag_names && !is_array($tag_names)) { - $tag_names = [$tag_names]; - } - - $entity_tags = []; - foreach ($tag_names as $tag_name) { - $tags = $this->$tag_name; - if (elgg_is_empty($tags)) { - continue; - } - - // if a single tag, metadata returns a string. - // if multiple tags, metadata returns an array. - if (is_array($tags)) { - $entity_tags = array_merge($entity_tags, $tags); - } else { - $entity_tags[] = $tags; - } - } - - return $entity_tags; - } - /** * Remove the membership of all access collections for this entity (if the entity is a user) * @@ -1861,6 +1826,7 @@ public function deleteOwnedAccessCollections() { * while last_action is only set when explicitly called. * * @param int $posted Timestamp of last action + * * @return int * @internal */ @@ -1869,10 +1835,27 @@ public function updateLastAction(int $posted = null): int { $this->attributes['last_action'] = $posted; $this->cache(); - + return $posted; } + /** + * Update the time_deleted column in the entities table. + * + * @param int $deleted Timestamp of deletion + * + * @return int + * @internal + */ + public function updateTimeDeleted(int $deleted = null): int { + $deleted = _elgg_services()->entityTable->updateTimeDeleted($this, $deleted); + + $this->attributes['time_deleted'] = $deleted; + $this->cache(); + + return $deleted; + } + /** * Disable runtime caching for entity * @@ -1915,32 +1898,17 @@ public function isCacheable(): bool { } /** - * Cache the entity in a session and persisted caches - * - * @param bool $persist Store in persistent cache + * Cache the entity in a session cache * * @return void * @internal */ - public function cache(bool $persist = true): void { + public function cache(): void { if (!$this->isCacheable()) { return; } _elgg_services()->entityCache->save($this); - - if (!$persist) { - return; - } - - $tmp = $this->volatile; - - // don't store volatile data - $this->volatile = []; - - _elgg_services()->sessionCache->entities->save($this->guid, $this); - - $this->volatile = $tmp; } /** diff --git a/engine/classes/ElggFile.php b/engine/classes/ElggFile.php index 13a16369ee3..79c14e52174 100644 --- a/engine/classes/ElggFile.php +++ b/engine/classes/ElggFile.php @@ -231,20 +231,30 @@ public function close(): bool { } /** - * Delete this file. - * - * @param bool $follow_symlinks If true, will also delete the target file if the current file is a symlink - * - * @return bool + * {@inheritdoc} */ - public function delete(bool $follow_symlinks = true): bool { - $result = $this->getFilestore()->delete($this, $follow_symlinks); - - if ($this->getGUID() && $result) { - $result = parent::delete(); + public function delete(bool $recursive = true, bool $persistent = null): bool { + if (!$this->guid) { + return $this->persistentDelete($recursive); } - - return $result; + + return parent::delete($recursive, $persistent); + } + + /** + * {@inheritdoc} + */ + protected function persistentDelete(bool $recursive = true): bool { + if ($this->guid) { + $result = parent::persistentDelete($recursive); + if ($result) { + $this->getFilestore()->delete($this); + } + + return $result; + } + + return $this->getFilestore()->delete($this); } /** diff --git a/engine/classes/ElggGroup.php b/engine/classes/ElggGroup.php index 85cfd81bc74..453c0cb1087 100644 --- a/engine/classes/ElggGroup.php +++ b/engine/classes/ElggGroup.php @@ -9,6 +9,7 @@ * @property string $name A short name that captures the purpose of the group * @property string $description A longer body of content that gives more details about the group * @property-read string $content_access_mode Content access mode for this group + * @property int $membership Type of group membership */ class ElggGroup extends \ElggEntity { @@ -57,7 +58,7 @@ public function getMembers(array $options = []) { * @return bool */ public function isPublicMembership(): bool { - return ($this->membership == ACCESS_PUBLIC); + return ($this->membership === ACCESS_PUBLIC); } /** diff --git a/engine/classes/ElggInstaller.php b/engine/classes/ElggInstaller.php index 15447726b85..c3cc2a5bba7 100644 --- a/engine/classes/ElggInstaller.php +++ b/engine/classes/ElggInstaller.php @@ -40,9 +40,9 @@ */ class ElggInstaller { - public const MARIADB_MINIMAL_VERSION = '10.3'; - public const MYSQL_MINIMAL_VERSION = '5.7'; - public const PHP_MINIMAL_VERSION = '8.0.0'; + public const MARIADB_MINIMAL_VERSION = '10.6'; + public const MYSQL_MINIMAL_VERSION = '8.0'; + public const PHP_MINIMAL_VERSION = '8.1.0'; protected array $steps = [ 'welcome', @@ -139,7 +139,7 @@ protected function getApp(): Application { $this->app = $app; $app->internal_services->boot->getCache()->disable(); - $app->internal_services->plugins->getCache()->disable(); + $app->internal_services->pluginsCache->disable(); $app->internal_services->sessionCache->disable(); $app->internal_services->dataCache->disable(); $app->internal_services->autoloadManager->getCache()->disable(); @@ -160,7 +160,7 @@ protected function getApp(): Application { $app->internal_services->views->setViewtype('installation'); $app->internal_services->views->registerViewtypeFallback('installation'); - $app->internal_services->views->registerPluginViews(Paths::elgg()); + $app->internal_services->views->registerViewsFromPath(Paths::elgg()); $app->internal_services->translator->registerTranslations(Paths::elgg() . 'install/languages/', true); return $this->app; @@ -753,7 +753,7 @@ protected function determineInstallStatus(): void { } // check that the config table has entries - $qb = \Elgg\Database\Select::fromTable('config'); + $qb = \Elgg\Database\Select::fromTable(\Elgg\Database\ConfigTable::TABLE_NAME); $qb->select('COUNT(*) AS total'); $result = $db->getDataRow($qb); @@ -764,7 +764,7 @@ protected function determineInstallStatus(): void { } // check that the users entity table has an entry - $qb = \Elgg\Database\Select::fromTable('entities', 'e'); + $qb = \Elgg\Database\Select::fromTable(\Elgg\Database\EntityTable::TABLE_NAME, \Elgg\Database\EntityTable::DEFAULT_JOIN_ALIAS); $qb->select('COUNT(*) AS total') ->where($qb->compare('type', '=', 'user', ELGG_VALUE_STRING)); @@ -992,6 +992,7 @@ protected function checkPhpExtensions(array &$phpReport): void { 'json', 'xml', 'gd', + 'intl', ]; foreach ($requiredExtensions as $extension) { if (!in_array($extension, $extensions)) { @@ -1212,7 +1213,7 @@ protected function checkDatabaseSettings(string $user, string $password, string 'dbname' => $dbname, 'dbencoding' => 'utf8mb4', ]); - $db = new Database($config, $app->internal_services->queryCache); + $db = new Database($config, $app->internal_services->queryCache, $app->internal_services->config); try { $db->getConnection('read')->executeQuery('SELECT 1'); @@ -1250,7 +1251,7 @@ protected function checkDatabaseSettings(string $user, string $password, string protected function createSettingsFile(array $params): bool { $app = $this->getApp(); - $template = Application::elggDir()->getContents('elgg-config/settings.example.php'); + $template = file_get_contents(Paths::elgg() . 'elgg-config/settings.example.php'); if (!$template) { $app->internal_services->system_messages->addErrorMessage(elgg_echo('install:error:readsettingsphp')); @@ -1451,7 +1452,7 @@ protected function saveSiteSettings(array $submissionVars): bool { $app->internal_services->reset('plugins'); if (elgg_extract('activate_plugins', $submissionVars, true)) { - $plugins = $app->internal_services->plugins->find('any'); + $plugins = $app->internal_services->plugins->find('all'); foreach ($plugins as $plugin) { $plugin_config = $plugin->getStaticConfig('plugin', []); diff --git a/engine/classes/ElggMenuItem.php b/engine/classes/ElggMenuItem.php index ef2cb0f5575..9c7291815d4 100644 --- a/engine/classes/ElggMenuItem.php +++ b/engine/classes/ElggMenuItem.php @@ -53,7 +53,7 @@ class ElggMenuItem implements \Elgg\Collections\CollectionItemInterface { // array Classes to apply to the anchor tag 'linkClass' => [], - // array AMD modules required by this menu item + // array ES modules required by this menu item 'deps' => [], // which view should be used to output the menu item contents @@ -118,7 +118,7 @@ public function __construct($name, $text, $href) { * title => STR Menu item tooltip * selected => BOOL Is this menu item currently selected? * confirm => STR If set, the link will be drawn with the output/confirmlink view instead of output/url. - * deps => ARR AMD modules required by this menu item + * deps => ARR ES modules required by this menu item * child_menu => ARR Options for the child menu * data => ARR Custom attributes stored in the menu item. * @@ -423,9 +423,9 @@ public function addLinkClass($class) { } /** - * Set required AMD modules + * Set required ES modules * - * @param string[]|string $modules One or more required AMD modules + * @param string[]|string $modules One or more required ES modules * * @return void */ @@ -434,7 +434,7 @@ public function setDeps($modules) { } /** - * Get required AMD modules + * Get required ES modules * * @return string[] */ @@ -446,9 +446,9 @@ public function getDeps() { } /** - * Add required AMD modules + * Add required ES modules * - * @param string[]|string $modules One or more required AMD modules + * @param string[]|string $modules One or more required ES modules * * @return void */ diff --git a/engine/classes/ElggPlugin.php b/engine/classes/ElggPlugin.php index 32e735b061c..76de55588c8 100644 --- a/engine/classes/ElggPlugin.php +++ b/engine/classes/ElggPlugin.php @@ -1,6 +1,7 @@ setMetadata($name, $value); + return elgg_call(ELGG_DISABLE_SYSTEM_LOG, function() use ($name, $value) { + return $this->setMetadata($name, $value); + }); } /** @@ -356,7 +359,9 @@ public function setSetting(string $name, $value): bool { * @return bool */ public function unsetSetting(string $name): bool { - return (bool) $this->deleteMetadata($name); + return elgg_call(ELGG_DISABLE_SYSTEM_LOG, function() use ($name) { + return (bool) $this->deleteMetadata($name); + }); } /** @@ -388,7 +393,7 @@ public function unsetAllEntityAndPluginSettings(): bool { $result = $this->unsetAllSettings(); // entity plugin settings are stored with the entity - $delete = Delete::fromTable('metadata'); + $delete = Delete::fromTable(MetadataTable::TABLE_NAME); $delete->andWhere($delete->compare('name', 'like', "plugin:%_setting:{$this->getID()}:%", ELGG_VALUE_STRING)); try { @@ -767,7 +772,6 @@ public function init(): void { $this->registerActions(); $this->registerEntities(); $this->registerWidgets(); - $this->registerHooks(); $this->registerEvents(); $this->registerViewExtensions(); $this->registerGroupTools(); @@ -883,7 +887,7 @@ protected function registerPublicServices(): void { * @throws \Elgg\Exceptions\PluginException */ protected function registerViews(): void { - if (_elgg_services()->config->system_cache_loaded) { + if (_elgg_services()->views->isViewLocationsLoadedFromCache()) { return; } @@ -896,7 +900,7 @@ protected function registerViews(): void { } // Allow /views directory files to override - if (!$views->registerPluginViews($this->getPath())) { + if (!$views->registerViewsFromPath($this->getPath())) { $msg = elgg_echo('ElggPlugin:Exception:CannotRegisterViews', [$this->getID(), $this->guid, $this->getPath()]); throw PluginException::factory([ @@ -1070,43 +1074,6 @@ protected function deactivateEntities(): void { } } - /** - * Registers the plugin's hooks provided in the plugin config file - * - * @note using hooks in the static config is deprecated - * - * @return void - */ - protected function registerHooks(): void { - $events = _elgg_services()->events; - - $spec = (array) $this->getStaticConfig('hooks', []); - - if (!empty($spec)) { - elgg_deprecated_notice("The plugin {$this->getID()} still has hooks definitions in the elgg-plugin.php. This should be moved to the events configuration.", '5.0'); - } - - foreach ($spec as $name => $types) { - foreach ($types as $type => $callbacks) { - foreach ($callbacks as $callback => $hook_spec) { - if (!is_array($hook_spec)) { - continue; - } - - $unregister = (bool) elgg_extract('unregister', $hook_spec, false); - - if ($unregister) { - $events->unregisterHandler($name, $type, $callback); - } else { - $priority = (int) elgg_extract('priority', $hook_spec, 500); - - $events->registerHandler($name, $type, $callback, $priority); - } - } - } - } - } - /** * Registers the plugin's events provided in the plugin config file * @@ -1214,7 +1181,7 @@ protected function registerViewOptions(): void { } if (isset($options['simplecache']) && $options['simplecache'] === true) { - _elgg_services()->views->registerCacheableView($view_name); + _elgg_services()->simpleCache->registerCacheableView($view_name); } } } @@ -1335,23 +1302,13 @@ protected function setStatus(bool $active): bool { public function isCacheable(): bool { return true; } - - /** - * {@inheritdoc} - */ - public function cache(bool $persist = true): void { - _elgg_services()->plugins->cache($this); - - parent::cache($persist); - } - + /** * {@inheritdoc} */ public function invalidateCache(): void { - _elgg_services()->boot->clearCache(); - _elgg_services()->plugins->invalidateCache($this->getID()); + _elgg_services()->pluginsCache->delete($this->getID()); parent::invalidateCache(); } diff --git a/engine/classes/ElggSession.php b/engine/classes/ElggSession.php index 5c5e8e25add..edbca7bd96f 100644 --- a/engine/classes/ElggSession.php +++ b/engine/classes/ElggSession.php @@ -47,6 +47,8 @@ public function boot(): void { $this->start(); + $migrate_session = false; + // test whether we have a user session if ($this->has('guid')) { $user = _elgg_services()->entityTable->get($this->get('guid'), 'user'); @@ -62,11 +64,12 @@ public function boot(): void { $user = _elgg_services()->persistentLogin->bootSession(); if ($user instanceof ElggUser) { _elgg_services()->persistentLogin->updateTokenUsage($user); + $migrate_session = true; } } if ($user instanceof ElggUser) { - _elgg_services()->session_manager->setLoggedInUser($user); + _elgg_services()->session_manager->setLoggedInUser($user, $migrate_session); $user->setLastAction(); // logout a user with open session who has been banned @@ -103,7 +106,7 @@ public function start() { * @return boolean * @since 1.9 */ - public function migrate($destroy = false) { + public function migrate(bool $destroy = true) { return $this->storage->migrate($destroy); } @@ -280,6 +283,7 @@ public static function fromDatabase(Config $config, Database $db) { 'cookie_secure' => $params['secure'], 'cookie_httponly' => $params['httponly'], 'cookie_lifetime' => $params['lifetime'], + 'cookie_samesite' => $params['samesite'], ]; $handler = new ElggSessionHandler($db); diff --git a/engine/classes/ElggSite.php b/engine/classes/ElggSite.php index dc70451de0b..3d7fef8e204 100644 --- a/engine/classes/ElggSite.php +++ b/engine/classes/ElggSite.php @@ -1,5 +1,7 @@ attributes['time_updated'] = null; $this->attributes['last_action'] = null; $this->attributes['enabled'] = 'yes'; + $this->attributes['deleted'] = 'no'; + $this->attributes['time_deleted'] = null; } /** @@ -56,13 +60,11 @@ public function getType(): string { * {@inheritdoc} */ public function save(): bool { - $db = $this->getDatabase(); - $qb = \Elgg\Database\Select::fromTable('entities', 'e'); - $qb->select('e.*') - ->where($qb->compare('e.type', '=', 'site', ELGG_VALUE_STRING)); - - $row = $db->getDataRow($qb); + $qb = Select::fromTable(EntityTable::TABLE_NAME); + $qb->select('*') + ->where($qb->compare('type', '=', 'site', ELGG_VALUE_STRING)); + $row = $this->getDatabase()->getDataRow($qb); if (!empty($row)) { if ($row->guid == $this->attributes['guid']) { // can save active site @@ -77,23 +79,16 @@ public function save(): bool { } /** - * Delete the site. - * - * @note You cannot delete the current site. - * - * @param bool $recursive If true (default) then all entities which are owned or contained by $this will also be deleted. - * - * @return bool - * @throws SecurityException + * {@inheritdoc} */ - public function delete(bool $recursive = true): bool { - if ($this->guid == 1) { + public function delete(bool $recursive = true, bool $persistent = null): bool { + if ($this->guid === 1) { throw new SecurityException('You cannot delete the current site'); } - - return parent::delete($recursive); + + return parent::delete($recursive, $persistent); } - + /** * Disable the site * diff --git a/engine/classes/ElggUser.php b/engine/classes/ElggUser.php index 554633cec1d..5d48fa80518 100644 --- a/engine/classes/ElggUser.php +++ b/engine/classes/ElggUser.php @@ -238,7 +238,6 @@ public function removeAdmin(): bool { * @return void */ public function setLastLogin(): void { - $time = $this->getCurrentTime()->getTimestamp(); if ($this->last_login == $time) { @@ -246,9 +245,11 @@ public function setLastLogin(): void { return; } - // these writes actually work, we just type hint read-only. - $this->prev_last_login = $this->last_login; - $this->last_login = $time; + elgg_call(ELGG_IGNORE_ACCESS | ELGG_DISABLE_SYSTEM_LOG, function() use ($time) { + // these writes actually work, we just type hint read-only. + $this->prev_last_login = $this->last_login; + $this->last_login = $time; + }); } /** @@ -351,16 +352,17 @@ public function getObjects(array $options = []) { /** * Get a user's owner GUID * - * Returns it's own GUID if the user is not owned. + * Returns its own GUID if the user is not owned. * * @return int */ public function getOwnerGUID(): int { - if ($this->owner_guid == 0) { - return $this->guid; + $owner_guid = parent::getOwnerGUID(); + if ($owner_guid === 0) { + $owner_guid = (int) $this->guid; } - return $this->owner_guid; + return $owner_guid; } /** @@ -446,10 +448,10 @@ public function getNotificationSettings(string $purpose = 'default'): array { } /** - * {@inheritDoc} + * {@inheritdoc} */ - public function delete(bool $recursive = true): bool { - $result = parent::delete($recursive); + public function persistentDelete(bool $recursive = true): bool { + $result = parent::persistentDelete($recursive); if ($result) { // cleanup remember me cookie records _elgg_services()->users_remember_me_cookies_table->deleteAllHashes($this); diff --git a/engine/events.php b/engine/events.php index 461332bd896..9cbe7977297 100644 --- a/engine/events.php +++ b/engine/events.php @@ -51,9 +51,6 @@ 'css' => [ \Elgg\Views\PreProcessCssHandler::class => [], ], - 'js' => [ - \Elgg\Views\AddAmdModuleNameHandler::class => [], - ], ], 'cache:invalidate' => [ 'system' => [ @@ -113,6 +110,9 @@ 'Elgg\Users\Validation::notifyAdminsAboutPendingUsers' => [], \Elgg\Users\CleanupPersistentLoginHandler::class => [], ], + 'hourly' => [ + \Elgg\Entity\RemoveDeletedEntitiesHandler::class => [], + ], 'minute' => [ \Elgg\Notifications\ProcessQueueCronHandler::class => ['priority' => 100], ], @@ -136,9 +136,6 @@ ], 'elgg.data' => [ 'page' => [ - \Elgg\Javascript\AddSRIConfig::class => [], - ], - 'site' => [ \Elgg\Javascript\SetLightboxConfigHandler::class => [], ], ], @@ -163,6 +160,9 @@ ], ], 'form:prepare:fields' => [ + 'admin/security/security_txt' => [ + \Elgg\Forms\PrepareSecurityTxt::class => [], + ], 'all' => [ \Elgg\Forms\PrepareFields::class => ['priority' => 9999], ], @@ -223,6 +223,7 @@ 'Elgg\Menus\AdminUsersBulk::disableItems' => [], ], 'menu:breadcrumbs' => [ + '\Elgg\Menus\Breadcrumbs::addHomeItem' => ['priority' => 10000], '\Elgg\Menus\Breadcrumbs::cleanupBreadcrumbs' => ['priority' => 9999], ], 'menu:site' => [ @@ -256,6 +257,7 @@ 'Elgg\Menus\AdminHeader::registerAdminConfigure' => [], 'Elgg\Menus\AdminHeader::registerAdminDefaultWidgets' => [], 'Elgg\Menus\AdminHeader::registerAdminInformation' => [], + 'Elgg\Menus\AdminHeader::registerAdminUtilities' => [], ], 'menu:admin_footer' => [ 'Elgg\Menus\AdminFooter::registerHelpResources' => [], @@ -269,15 +271,23 @@ 'menu:entity' => [ 'Elgg\Menus\Entity::registerDelete' => [], 'Elgg\Menus\Entity::registerEdit' => [], + 'Elgg\Menus\Entity::registerTrash' => ['priority' => 501], // needs to be after registerDelete 'Elgg\Menus\Entity::registerUserHoverAdminSection' => [], 'Elgg\Menus\UserHover::registerLoginAs' => [], ], + 'menu:entity:object:comment' => [ + 'Elgg\Menus\Entity::registerComment' => [], + ], 'menu:entity:object:elgg_upgrade' => [ 'Elgg\Menus\Entity::registerUpgrade' => [], ], 'menu:entity:object:plugin' => [ 'Elgg\Menus\Entity::registerPlugin' => [], ], + 'menu:entity:trash' => [ + 'Elgg\Menus\Entity::registerDelete' => [], + 'Elgg\Menus\EntityTrash::registerRestore' => [], + ], 'menu:entity_navigation' => [ 'Elgg\Menus\EntityNavigation::registerPreviousNext' => [], ], @@ -311,7 +321,6 @@ 'Elgg\Menus\Page::registerAdminPluginSettings' => [], 'Elgg\Menus\Page::registerUserSettings' => [], 'Elgg\Menus\Page::registerUserSettingsPlugins' => [], - 'Elgg\Menus\Page::moveOldAdminSectionsToAdminHeader' => ['priority' => 9999], ], 'menu:river' => [ 'Elgg\Menus\River::registerDelete' => [], @@ -403,7 +412,6 @@ \Elgg\Views\MinifyHandler::class => [], ], 'js' => [ - \Elgg\Views\AddAmdModuleNameHandler::class => [], \Elgg\Views\CalculateSRI::class => ['priority' => 999], \Elgg\Views\MinifyHandler::class => [], ], diff --git a/engine/internal_services.php b/engine/internal_services.php index 26079ee764d..ccc9790a683 100644 --- a/engine/internal_services.php +++ b/engine/internal_services.php @@ -12,11 +12,6 @@ 'accounts' => DI\autowire(\Elgg\Users\Accounts::class), 'adminNotices' => DI\autowire(\Elgg\Database\AdminNotices::class), 'ajax' => DI\autowire(\Elgg\Ajax\Service::class), - 'amdConfig' => DI\factory(function (ContainerInterface $c) { - $obj = new \Elgg\Amd\Config($c->events); - $obj->setBaseUrl($c->simpleCache->getRoot()); - return $obj; - }), 'annotationsTable' => DI\autowire(\Elgg\Database\AnnotationsTable::class), 'apiUsersTable' => DI\autowire(\Elgg\Database\ApiUsersTable::class), 'authentication' => DI\autowire(\Elgg\AuthenticationService::class), @@ -54,6 +49,7 @@ 'entity_capabilities' => DI\autowire(\Elgg\EntityCapabilitiesService::class), 'entityPreloader' => DI\autowire(\Elgg\EntityPreloader::class), 'entityTable' => DI\autowire(\Elgg\Database\EntityTable::class), + 'esm' => DI\autowire(\Elgg\Javascript\ESMService::class), 'events' => DI\autowire(\Elgg\EventsService::class), 'externalFiles' => DI\autowire(\Elgg\Assets\ExternalFiles::class)->constructorParameter('serverCache', DI\get('serverCache')), 'fields' => DI\autowire(\Elgg\Forms\FieldsService::class), @@ -117,7 +113,7 @@ 'plugins' => DI\autowire(\Elgg\Database\Plugins::class)->constructorParameter('cache', DI\get('pluginsCache')), 'pluginsCache' => DI\factory(function (ContainerInterface $c) { return new \Elgg\Cache\CompositeCache('plugins', $c->config, ELGG_CACHE_RUNTIME); - }), + }), 'publicDb' => DI\autowire(\Elgg\Application\Database::class), 'queryCache' => DI\factory(function (ContainerInterface $c) { $config_disabled = $c->config->db_disable_query_cache === true; @@ -168,19 +164,15 @@ 'translator' => DI\autowire(\Elgg\I18n\Translator::class), 'uploads' => DI\autowire(\Elgg\UploadService::class), 'upgrades' => DI\autowire(\Elgg\UpgradeService::class), - 'urlGenerator' => DI\factory(function (ContainerInterface $c) { - return new \Elgg\Router\UrlGenerator($c->routeCollection, $c->requestContext); - }), - 'urlMatcher' => DI\factory(function (ContainerInterface $c) { - return new \Elgg\Router\UrlMatcher($c->routeCollection, $c->requestContext); - }), + 'urlGenerator' => DI\autowire(\Elgg\Router\UrlGenerator::class), + 'urlMatcher' => DI\autowire(\Elgg\Router\UrlMatcher::class), 'urlSigner' => DI\autowire(\Elgg\Security\UrlSigner::class), 'urls' => DI\autowire(\Elgg\Http\Urls::class), 'userCapabilities' => DI\autowire(\Elgg\UserCapabilities::class), 'usersApiSessionsTable' => DI\autowire(\Elgg\Database\UsersApiSessionsTable::class), 'users_remember_me_cookies_table' => DI\autowire(\Elgg\Database\UsersRememberMeCookiesTable::class), 'upgradeLocator' => DI\autowire(\Elgg\Upgrade\Locator::class), - 'views' => DI\autowire(\Elgg\ViewsService::class), + 'views' => DI\autowire(\Elgg\ViewsService::class)->constructorParameter('server_cache', DI\get('serverCache')), 'viewCacher' => DI\autowire(\Elgg\Cache\ViewCacher::class), 'widgets' => DI\autowire(\Elgg\WidgetsService::class), @@ -188,7 +180,6 @@ \ElggSession::class => DI\get('session'), \Elgg\ActionsService::class => DI\get('actions'), \Elgg\Ajax\Service::class => DI\get('ajax'), - \Elgg\Amd\Config::class => DI\get('amdConfig'), \Elgg\Application\CacheHandler::class => DI\get('cacheHandler'), \Elgg\Application\Database::class => DI\get('publicDb'), \Elgg\Application\ServeFileHandler::class => DI\get('serveFileHandler'), @@ -249,6 +240,7 @@ \Elgg\I18n\LocaleService::class => DI\get('locale'), \Elgg\I18n\Translator::class => DI\get('translator'), \Elgg\ImageService::class => DI\get('imageService'), + \Elgg\Javascript\ESMService::class => DI\get('esm'), \Elgg\Invoker::class => DI\get('invoker'), \Elgg\Logger::class => DI\get('logger'), \Elgg\Menu\Service::class => DI\get('menus'), diff --git a/engine/lib/annotations.php b/engine/lib/annotations.php index 363bb47c31d..f1074f8ad5a 100644 --- a/engine/lib/annotations.php +++ b/engine/lib/annotations.php @@ -38,9 +38,7 @@ function elgg_delete_annotation_by_id(int $id): bool { * * Accepts all options supported by {@link elgg_get_entities()} * - * The default 'order_by' is 'n_table.time_created, n_table.id', - * - * @see elgg_get_entities() + * The default 'order_by' is 'a_table.time_created, a_table.id', * * @param array $options Options * @@ -88,32 +86,6 @@ function elgg_delete_annotations(array $options): bool { return _elgg_services()->annotationsTable->deleteAll($options); } -/** - * Disables annotations based on $options. - * - * @warning Unlike elgg_get_annotations() this will not accept an empty options array! - * - * @param array $options An options array. {@link elgg_get_annotations()} - * @return bool true on success, false on failure - * @since 1.8.0 - */ -function elgg_disable_annotations(array $options): bool { - return _elgg_services()->annotationsTable->disableAll($options); -} - -/** - * Enables annotations based on $options. - * - * @warning Unlike elgg_get_annotations() this will not accept an empty options array! - * - * @param array $options An options array. {@link elgg_get_annotations()} - * @return bool true on success, false on failure - * @since 1.8.0 - */ -function elgg_enable_annotations(array $options): bool { - return _elgg_services()->annotationsTable->enableAll($options); -} - /** * Check to see if a user has already created an annotation on an object * diff --git a/engine/lib/breadcrumbs.php b/engine/lib/breadcrumbs.php index 1834657e4fe..80ac2ff2453 100644 --- a/engine/lib/breadcrumbs.php +++ b/engine/lib/breadcrumbs.php @@ -26,20 +26,22 @@ function elgg_push_breadcrumb(string $text, string|false $href = false): void { /** * Resolves and pushes entity breadcrumbs based on named routes * - * @param \ElggEntity $entity Entity - * @param bool $link_self Use entity link in the last crumb + * @param \ElggEntity $entity Entity * * @return void */ -function elgg_push_entity_breadcrumbs(\ElggEntity $entity, bool $link_self = true): void { +function elgg_push_entity_breadcrumbs(\ElggEntity $entity): void { elgg_push_collection_breadcrumbs($entity->type, $entity->subtype, $entity->getContainerEntity()); - elgg_register_menu_item('breadcrumbs', [ - 'name' => 'entity', - 'text' => $entity->getDisplayName(), - 'href' => $link_self ? $entity->getURL() : false, - ]); + $link_self = elgg_get_current_route_name() !== "view:{$entity->type}:{$entity->subtype}"; + if ($link_self) { + elgg_register_menu_item('breadcrumbs', [ + 'name' => 'entity', + 'text' => $entity->getDisplayName(), + 'href' => $entity->getURL(), + ]); + } } /** @@ -53,9 +55,9 @@ function elgg_push_entity_breadcrumbs(\ElggEntity $entity, bool $link_self = tru * @return void */ function elgg_push_collection_breadcrumbs(string $entity_type, string $entity_subtype, \ElggEntity $container = null, bool $friends = false): void { - + if ($container) { - if (!$container instanceof \ElggSite) { + if (!$container instanceof \ElggSite && $entity_type !== 'group') { elgg_register_menu_item('breadcrumbs', [ 'name' => 'container', 'text' => $container->getDisplayName(), @@ -65,15 +67,21 @@ function elgg_push_collection_breadcrumbs(string $entity_type, string $entity_su if ($friends) { $collection_route = "collection:{$entity_type}:{$entity_subtype}:friends"; - } else if ($container instanceof ElggUser) { + } elseif ($entity_type === 'group') { + $collection_route = "collection:{$entity_type}:{$entity_subtype}:all"; + } elseif ($container instanceof \ElggUser) { $collection_route = "collection:{$entity_type}:{$entity_subtype}:owner"; - } else if ($container instanceof ElggGroup) { + } elseif ($container instanceof \ElggGroup) { $collection_route = "collection:{$entity_type}:{$entity_subtype}:group"; - } else if ($container instanceof ElggSite) { + } elseif ($container instanceof \ElggSite) { $collection_route = "collection:{$entity_type}:{$entity_subtype}:all"; } else { $collection_route = "collection:{$entity_type}:{$entity_subtype}:container"; } + + if ($collection_route === elgg_get_current_route_name()) { + return; + } $parameters = _elgg_services()->routes->resolveRouteParameters($collection_route, $container); if ($parameters !== false) { @@ -86,17 +94,26 @@ function elgg_push_collection_breadcrumbs(string $entity_type, string $entity_su } } - elgg_register_menu_item('breadcrumbs', [ - 'name' => 'collection', - 'text' => $label, - 'href' => elgg_generate_url($collection_route, $parameters), - ]); + if (elgg_route_exists($collection_route)) { + elgg_register_menu_item('breadcrumbs', [ + 'name' => 'collection', + 'text' => $label, + 'href' => elgg_generate_url($collection_route, $parameters), + ]); + } } - } else { - elgg_register_menu_item('breadcrumbs', [ - 'name' => 'collection', - 'text' => elgg_echo("collection:{$entity_type}:{$entity_subtype}"), - 'href' => elgg_generate_url("collection:{$entity_type}:{$entity_subtype}:all"), - ]); + + return; } + + $all_route_name = "collection:{$entity_type}:{$entity_subtype}:all"; + if (!elgg_route_exists($all_route_name) || ($all_route_name === elgg_get_current_route_name())) { + return; + } + + elgg_register_menu_item('breadcrumbs', [ + 'name' => 'collection', + 'text' => elgg_echo("collection:{$entity_type}:{$entity_subtype}"), + 'href' => elgg_generate_url($all_route_name), + ]); } diff --git a/engine/lib/cache.php b/engine/lib/cache.php index 673d98796b7..fc99a9cabb5 100644 --- a/engine/lib/cache.php +++ b/engine/lib/cache.php @@ -109,35 +109,26 @@ function elgg_disable_system_cache(): void { * @since 1.8.0 */ function elgg_register_simplecache_view(string $view_name): void { - _elgg_services()->views->registerCacheableView($view_name); + _elgg_services()->simpleCache->registerCacheableView($view_name); } /** * Get the URL for the cached view. * - * Recommended usage is to just pass the entire view name as the first and only arg: - * * ``` * $blog_js = elgg_get_simplecache_url('elgg/blog/save_draft.js'); * $favicon = elgg_get_simplecache_url('favicon.ico'); * ``` * - * For backwards compatibility with older versions of Elgg, this function supports - * "js" or "css" as the first arg, with the rest of the view name as the second arg: - * - * ``` - * $blog_js = elgg_get_simplecache_url('js', 'elgg/blog/save_draft.js'); - * ``` - * * This automatically registers the view with Elgg's simplecache. * - * @param string $view The full view name - * @param string $subview If the first arg is "css" or "js", the rest of the view name + * @param string $view The full view name + * * @return string * @since 1.8.0 */ -function elgg_get_simplecache_url(string $view, string $subview = ''): string { - return _elgg_services()->simpleCache->getUrl($view, $subview); +function elgg_get_simplecache_url(string $view): string { + return _elgg_services()->simpleCache->getUrl($view); } /** diff --git a/engine/lib/constants.php b/engine/lib/constants.php index dba96a19770..5960dced535 100644 --- a/engine/lib/constants.php +++ b/engine/lib/constants.php @@ -133,3 +133,5 @@ const ELGG_HIDE_DISABLED_ENTITIES = 8; const ELGG_DISABLE_SYSTEM_LOG = 16; const ELGG_ENABLE_SYSTEM_LOG = 32; +const ELGG_SHOW_DELETED_ENTITIES = 64; +const ELGG_HIDE_DELETED_ENTITIES = 128; diff --git a/engine/lib/deprecated-5.0.php b/engine/lib/deprecated-5.0.php deleted file mode 100644 index 8164849cceb..00000000000 --- a/engine/lib/deprecated-5.0.php +++ /dev/null @@ -1,195 +0,0 @@ -select('type') - ->addSelect('subtype') - ->addSelect('count(*) AS total') - ->where($select->compare('enabled', '=', 'yes', ELGG_VALUE_STRING)) - ->groupBy('type') - ->addGroupBy('subtype') - ->orderBy('total', 'desc'); +function elgg_get_entity_statistics(array $options = []): array { + $required = [ + 'selects' => [ + 'count(*) AS total', + ], + 'group_by' => [ + function(QueryBuilder $qb, $main_alias) { + return "{$main_alias}.type"; + }, + function(QueryBuilder $qb, $main_alias) { + return "{$main_alias}.subtype"; + }, + ], + 'order_by' => [ + new OrderByClause('total', 'desc'), + ], + 'callback' => function($row) { + return (object) [ + 'type' => $row->type, + 'subtype' => $row->subtype, + 'total' => $row->total, + ]; + }, + 'limit' => false, + ]; - if (!empty($owner_guid)) { - $select->andWhere($select->compare('owner_guid', '=', $owner_guid, ELGG_VALUE_GUID)); - } + $options = array_merge($options, $required); - $entity_stats = []; + $rows = elgg_call(ELGG_IGNORE_ACCESS, function() use ($options) { + return elgg_get_entities($options); + }); - $rows = _elgg_services()->db->getData($select); + $entity_stats = []; foreach ($rows as $row) { $type = $row->type; if (!isset($entity_stats[$type]) || !is_array($entity_stats[$type])) { diff --git a/engine/lib/external_files.php b/engine/lib/external_files.php index 6d9402c1884..def7e9ba605 100644 --- a/engine/lib/external_files.php +++ b/engine/lib/external_files.php @@ -4,65 +4,30 @@ */ /** - * Defines a JS lib as an AMD module. This is useful for shimming - * traditional JS or for setting the paths of AMD modules. + * Request that Elgg load an ES module onto the page. * - * Calling multiple times for the same name will: - * * set the preferred path to the last call setting a path - * * overwrite the shimmed AMD modules with the last call setting a shimmed module - * - * Use elgg_require_js($name) to load on the current page. - * - * Calling this function is not needed if your JS are in views named like `module/name.js` - * Instead, simply call elgg_require_js("module/name"). - * - * @note The configuration is cached in simplecache, so logic should not depend on user- - * specific values like elgg_get_current_language(). - * - * @param string $name The module name - * @param array $config An array like the following: - * array 'deps' An array of AMD module dependencies - * string 'exports' The name of the exported module - * string 'src' The URL to the JS. Can be relative. + * @param string $name The ES module name * * @return void - */ -function elgg_define_js(string $name, array $config): void { - $src = elgg_extract('src', $config); - - if (!empty($src)) { - $url = elgg_normalize_url($src); - _elgg_services()->amdConfig->addPath($name, $url); - } - - // shimmed module - if (isset($config['deps']) || isset($config['exports'])) { - _elgg_services()->amdConfig->addShim($name, $config); - } -} - -/** - * Request that Elgg load an AMD module onto the page. * - * @param string $name The AMD module name - * - * @return void - * @since 1.9.0 + * @since 6.0 */ -function elgg_require_js(string $name): void { - _elgg_services()->amdConfig->addDependency($name); +function elgg_import_esm(string $name): void { + _elgg_services()->esm->import($name); } /** - * Cancel a request to load an AMD module onto the page. + * Registers an ES module to the import map * - * @param string $name The AMD module name + * @param string $name name of the module + * @param string $href location where the module should be imported from * * @return void - * @since 2.1.0 + * + * @since 6.0 */ -function elgg_unrequire_js(string $name): void { - _elgg_services()->amdConfig->removeDependency($name); +function elgg_register_esm(string $name, string $href): void { + _elgg_services()->esm->register($name, $href); } /** @@ -83,18 +48,6 @@ function elgg_require_css(string $view): void { elgg_load_external_file('css', $view); } -/** - * Unregister a CSS view name to be included in the HTML head - * - * @param string $view The css view name - * - * @return void - * @since 3.1 - */ -function elgg_unrequire_css(string $view): void { - elgg_unregister_external_file('css', $view); -} - /** * Core registration function for external files * diff --git a/engine/lib/input.php b/engine/lib/input.php index 53205c0e9ce..481ecc732a5 100644 --- a/engine/lib/input.php +++ b/engine/lib/input.php @@ -184,15 +184,14 @@ function elgg_is_empty($value): bool { * * This function triggers the 'attributes', 'htmlawed' event. * - * @param string $tag The tag element name - * @param array|false $attributes An array of attributes (false indicates a closing tag) + * @param string $tag The tag element name + * @param array|int $attributes An array of attributes (int 0 indicates a closing tag) * * @return string * @internal */ -function _elgg_htmlawed_tag_post_processor(string $tag, array|false $attributes = false): string { - - if ($attributes === false) { +function _elgg_htmlawed_tag_post_processor(string $tag, array|int $attributes = 0): string { + if ($attributes === 0) { // This is a closing tag. Prevent further processing to avoid inserting a duplicate tag return ""; } diff --git a/engine/lib/mb_wrapper.php b/engine/lib/mb_wrapper.php index b27df24bc4a..53e082c4cdd 100644 --- a/engine/lib/mb_wrapper.php +++ b/engine/lib/mb_wrapper.php @@ -77,42 +77,6 @@ function elgg_strpos() { return call_user_func_array('strpos', $args); } -/** - * Wrapper function for mb_strrchr(). Falls back to strrchr() if - * mb_strrchr() isn't available. Parameters are passed to the - * wrapped function in the same order they are passed to this - * function. - * - * @return false|string - * @since 1.7.0 - */ -function elgg_strrchr() { - $args = func_get_args(); - if (is_callable('mb_strrchr')) { - return call_user_func_array('mb_strrchr', $args); - } - - return call_user_func_array('strrchr', $args); -} - -/** - * Wrapper function for mb_strripos(). Falls back to strripos() if - * mb_strripos() isn't available. Parameters are passed to the - * wrapped function in the same order they are passed to this - * function. - * - * @return false|int - * @since 1.7.0 - */ -function elgg_strripos() { - $args = func_get_args(); - if (is_callable('mb_strripos')) { - return call_user_func_array('mb_strripos', $args); - } - - return call_user_func_array('strripos', $args); -} - /** * Wrapper function for mb_strrpos(). Falls back to strrpos() if * mb_strrpos() isn't available. Parameters are passed to the @@ -189,6 +153,7 @@ function elgg_strtoupper() { * Wrapper for mb_convert_case($str, MB_CASE_TITLE) * * @param string $str String + * * @return string * @since 2.3 */ @@ -224,7 +189,7 @@ function elgg_substr_count() { * wrapped function in the same order they are passed to this * function. * - * @return false|string + * @return string * @since 1.7.0 */ function elgg_substr() { diff --git a/engine/lib/navigation.php b/engine/lib/navigation.php index 15a104423ee..84d78c83ca3 100644 --- a/engine/lib/navigation.php +++ b/engine/lib/navigation.php @@ -68,7 +68,7 @@ * parent_name => STR Identifier of the parent menu item * link_class => STR A class or classes for the tag * item_class => STR A class or classes for the
  • tag - * deps => STR One or more AMD modules to require + * deps => STR One or more ES modules to require * * Additional options that the view output/url takes can be * passed in the array. Custom options can be added by using diff --git a/engine/lib/output.php b/engine/lib/output.php index 8b8b3c69ab7..fdec2b0f580 100644 --- a/engine/lib/output.php +++ b/engine/lib/output.php @@ -200,10 +200,11 @@ function elgg_get_friendly_title(string $title): string { // titles are often stored HTML encoded $title = html_entity_decode($title ?? '', ENT_QUOTES, 'UTF-8'); - $title = \Elgg\Translit::urlize($title); + // limit length to prevent issues with too long URLS (Request-URI Too Large) #13228 + // limit the length before urlize() to prevent multibyte chars from being cut of in the middle #14577 + $title = elgg_substr($title, 0, 100); - // limit length to prevent issues with too long URLS (Request-URI Too Large) - return elgg_substr($title, 0, 100); + return \Elgg\Translit::urlize($title); } /** diff --git a/engine/lib/pagehandler.php b/engine/lib/pagehandler.php index 39544dd3c52..065d49ca890 100644 --- a/engine/lib/pagehandler.php +++ b/engine/lib/pagehandler.php @@ -256,18 +256,19 @@ function elgg_error_response(string|array $message = '', string $forward_url = R /** * Prepare a silent redirect response to be returned by a page or an action handler * - * @param string $forward_url Redirection URL - * Relative or absolute URL to redirect the client to - * @param int $status_code HTTP status code - * Status code of the HTTP response - * Note that the Router and AJAX API will treat these responses - * as redirection in spite of the HTTP code assigned - * Note that non-redirection HTTP codes will throw an exception + * @param string $forward_url Redirection URL + * Relative or absolute URL to redirect the client to + * @param int $status_code HTTP status code + * Status code of the HTTP response + * Note that the Router and AJAX API will treat these responses + * as redirection in spite of the HTTP code assigned + * Note that non-redirection HTTP codes will throw an exception + * @param bool $secure_forward_url Determines if the forward url needs to be secure * * @return \Elgg\Http\RedirectResponse */ -function elgg_redirect_response(string $forward_url = REFERRER, int $status_code = ELGG_HTTP_FOUND): \Elgg\Http\RedirectResponse { - return new Elgg\Http\RedirectResponse($forward_url, $status_code); +function elgg_redirect_response(string $forward_url = REFERRER, int $status_code = ELGG_HTTP_FOUND, bool $secure_forward_url = true): \Elgg\Http\RedirectResponse { + return new Elgg\Http\RedirectResponse($forward_url, $status_code, $secure_forward_url); } /** diff --git a/engine/lib/views.php b/engine/lib/views.php index 80adf6a37d7..df26c32725a 100644 --- a/engine/lib/views.php +++ b/engine/lib/views.php @@ -38,9 +38,6 @@ * * @note Internal: Plugin views are autoregistered before their init functions * are called, so the init order doesn't affect views. - * - * @note Internal: The file that determines the output of the view is the last - * registered by {@link elgg_set_view_location()}. */ use Elgg\Exceptions\Http\PageNotFoundException; @@ -120,24 +117,6 @@ function elgg_unregister_ajax_view(string $view): void { _elgg_services()->ajax->unregisterView($view); } -/** - * Set an alternative base location for a view. - * - * Views are expected to be in plugin_name/views/. This function can - * be used to change that location. - * - * @tip This is useful to optionally register views in a plugin. - * - * @param string $view The name of the view - * @param string $location The full path to the view - * @param string $viewtype The view type - * - * @return void - */ -function elgg_set_view_location(string $view, string $location, string $viewtype = ''): void { - _elgg_services()->views->setViewDir($view, $location, $viewtype); -} - /** * Returns whether the specified view exists * @@ -1327,74 +1306,29 @@ function _elgg_has_rss_link(): bool { function elgg_views_boot(): void { _elgg_services()->viewCacher->registerCoreViews(); - // jQuery and UI must come before require. See #9024 - elgg_register_external_file('js', 'jquery', elgg_get_simplecache_url('jquery.js')); - elgg_load_external_file('js', 'jquery'); - - elgg_extend_view('require.js', 'elgg/require_config.js', 100); - - elgg_register_external_file('js', 'require', elgg_get_simplecache_url('require.js')); - elgg_load_external_file('js', 'require'); - - elgg_register_external_file('js', 'elgg', elgg_get_simplecache_url('elgg.js')); - elgg_load_external_file('js', 'elgg'); - elgg_register_external_file('css', 'font-awesome', elgg_get_simplecache_url('font-awesome/css/all.min.css')); elgg_load_external_file('css', 'font-awesome'); - elgg_define_js('cropperjs', [ - 'src' => elgg_get_simplecache_url('cropperjs/cropper.min.js'), - ]); - elgg_define_js('jquery-cropper/jquery-cropper', [ - 'src' => elgg_get_simplecache_url('jquery-cropper/jquery-cropper.min.js'), - ]); - - elgg_require_css('elgg'); - - elgg_extend_view('initialize_elgg.js', 'elgg/prevent_clicks.js', 1); - elgg_extend_view('elgg.css', 'lightbox/elgg-colorbox-theme/colorbox.css'); elgg_extend_view('elgg.css', 'entity/edit/icon/crop.css'); + + elgg_require_css('elgg'); + + elgg_register_esm('cropperjs', elgg_get_simplecache_url('cropperjs/cropper.esm.js')); + elgg_register_esm('jquery', elgg_get_simplecache_url('elgg/jquery.mjs')); + elgg_register_esm('jquery-ui', elgg_get_simplecache_url('jquery-ui.js')); + elgg_register_esm('jquery-cropper/jquery-cropper', elgg_get_simplecache_url('jquery-cropper/jquery-cropper.esm.js')); + + elgg_import_esm('elgg'); + elgg_import_esm('elgg/lightbox'); + elgg_import_esm('elgg/security'); - elgg_define_js('jquery.ui.autocomplete.html', [ - 'deps' => ['jquery-ui/widgets/autocomplete'], - ]); - - elgg_register_simplecache_view('elgg/touch_punch.js'); - elgg_define_js('jquery-ui/widgets/sortable', [ - 'deps' => ['elgg/touch_punch'], - ]); + elgg_extend_view('jquery-ui.js', 'jquery.ui.touch-punch.js'); + elgg_extend_view('initialize_elgg.js', 'elgg/prevent_clicks.js', 1); elgg_register_ajax_view('languages.js'); } -/** - * Get the site data to be merged into "elgg" in elgg.js. - * - * Unlike _elgg_get_js_page_data(), the keys returned are literal expressions. - * - * @return array - * @internal - */ -function _elgg_get_js_site_data(): array { - - $message_delay = (int) elgg_get_config('message_delay'); - if ($message_delay < 1) { - $message_delay = 6; - } - - return [ - 'elgg.data' => (object) elgg_trigger_event_results('elgg.data', 'site', [], []), - 'elgg.release' => elgg_get_release(), - 'elgg.config.wwwroot' => elgg_get_site_url(), - 'elgg.config.message_delay' => $message_delay * 1000, - - // refresh token 3 times during its lifetime (in microseconds 1000 * 1/3) - 'elgg.security.interval' => (int) _elgg_services()->csrf->getActionTokenTimeout() * 333, - 'elgg.config.language' => _elgg_services()->config->language ?: 'en', - ]; -} - /** * Get the initial contents of "elgg" client side. Will be extended by elgg.js. * @@ -1409,6 +1343,11 @@ function _elgg_get_js_page_data(array $params = []): array { elgg_log('"elgg.data" Event handlers must return an array. Returned ' . gettype($data) . '.', 'ERROR'); $data = []; } + + $message_delay = (int) elgg_get_config('message_delay'); + if ($message_delay < 1) { + $message_delay = 6; + } $elgg = [ 'config' => [ @@ -1416,8 +1355,15 @@ function _elgg_get_js_page_data(array $params = []): array { 'viewtype' => elgg_get_viewtype(), 'simplecache_enabled' => (int) elgg_is_simplecache_enabled(), 'current_language' => elgg_get_current_language(), + 'language' => _elgg_services()->config->language ?: 'en', + 'wwwroot' => elgg_get_site_url(), + 'message_delay' => $message_delay * 1000, ], + 'release' => elgg_get_release(), 'security' => [ + // refresh token 3 times during its lifetime (in microseconds 1000 * 1/3) + 'interval' => (int) _elgg_services()->csrf->getActionTokenTimeout() * 333, + 'token' => [ '__elgg_ts' => $ts = _elgg_services()->csrf->getCurrentTime()->getTimestamp(), '__elgg_token' => _elgg_services()->csrf->generateActionToken($ts), @@ -1427,7 +1373,7 @@ function _elgg_get_js_page_data(array $params = []): array { 'user' => null, 'token' => _elgg_services()->session->get('__elgg_session'), ], - '_data' => (object) $data, + 'data' => $data, ]; $user = elgg_get_logged_in_user_entity(); diff --git a/engine/routes.php b/engine/routes.php index 3f21cba261c..75351557784 100644 --- a/engine/routes.php +++ b/engine/routes.php @@ -150,6 +150,11 @@ 'match_on' => '\w+', ], ], + 'security.txt' => [ + 'path' => '/security.txt', + 'controller' => \Elgg\Controllers\SecurityTxt::class, + 'walled' => false, + ], 'settings:index' => [ 'path' => '/settings', 'resource' => 'settings/account', @@ -209,13 +214,6 @@ 'path' => '/comment/view/{guid}/{container_guid?}', 'controller' => \Elgg\Controllers\CommentEntityRedirector::class, ], - 'edit:object:comment' => [ - 'path' => '/comment/edit/{guid}', - 'resource' => 'comments/edit', - 'middleware' => [ - \Elgg\Router\Middleware\Gatekeeper::class, - ], - ], 'view:user' => [ 'path' => '/user/{guid}', 'resource' => 'user/view', @@ -246,4 +244,20 @@ ], 'walled' => false, ], + 'trash:owner' => [ + 'path' => '/settings/trash/{username}', + 'resource' => 'trash/owner', + 'middleware' => [ + \Elgg\Router\Middleware\Gatekeeper::class, + \Elgg\Router\Middleware\UserPageOwnerCanEditGatekeeper::class, + ], + ], + 'trash:group' => [ + 'path' => '/trash/group/{guid}', + 'resource' => 'trash/group', + 'middleware' => [ + \Elgg\Router\Middleware\Gatekeeper::class, + \Elgg\Router\Middleware\GroupPageOwnerCanEditGatekeeper::class, + ], + ], ]; diff --git a/engine/schema/migrations/20170728074600_create_entities_table.php b/engine/schema/migrations/20170728074600_create_entities_table.php index de14ccb4f86..201e22954cc 100644 --- a/engine/schema/migrations/20170728074600_create_entities_table.php +++ b/engine/schema/migrations/20170728074600_create_entities_table.php @@ -45,7 +45,7 @@ public function change() { 'limit' => MysqlAdapter::INT_BIG, 'precision' => 20, 'signed' => false, - 'identity' => 'enable', + 'identity' => true, ]); $table->addColumn('type', 'enum', [ diff --git a/engine/schema/migrations/20230606155735_add_delete_columns_to_entities_tables.php b/engine/schema/migrations/20230606155735_add_delete_columns_to_entities_tables.php new file mode 100644 index 00000000000..b62614aee88 --- /dev/null +++ b/engine/schema/migrations/20230606155735_add_delete_columns_to_entities_tables.php @@ -0,0 +1,46 @@ +table('entities'); + if (!$table->hasColumn('deleted')) { + $table->addColumn('deleted', 'enum', [ + 'null' => false, + 'default' => 'no', + 'limit' => 3, + 'values' => [ + 'yes', + 'no', + ], + ]); + + $table->addIndex(['deleted'], [ + 'name' => 'deleted', + 'unique' => false, + ]); + } + + if (!$table->hasColumn('time_deleted')) { + $table->addColumn('time_deleted', 'integer', [ + 'null' => false, + 'default' => '0', + 'limit' => MysqlAdapter::INT_REGULAR, + 'precision' => 11, + ]); + + $table->addIndex(['time_deleted'], [ + 'name' => 'time_deleted', + 'unique' => false, + ]); + } + + $table->update(); + } +} diff --git a/engine/schema/migrations/20240318105727_remove_annotations_enabled_column.php b/engine/schema/migrations/20240318105727_remove_annotations_enabled_column.php new file mode 100644 index 00000000000..1ca220b9186 --- /dev/null +++ b/engine/schema/migrations/20240318105727_remove_annotations_enabled_column.php @@ -0,0 +1,22 @@ +hasTable('annotations')) { + $table = $this->table('annotations'); + + if ($table->hasColumn('enabled')) { + $table->removeColumn('enabled'); + } + + $table->save(); + } + } +} diff --git a/engine/tests/classes/Elgg/Actions/RegistrationIntegrationTestCase.php b/engine/tests/classes/Elgg/Actions/RegistrationIntegrationTestCase.php index b8725ac214c..80a31d308ec 100644 --- a/engine/tests/classes/Elgg/Actions/RegistrationIntegrationTestCase.php +++ b/engine/tests/classes/Elgg/Actions/RegistrationIntegrationTestCase.php @@ -30,7 +30,7 @@ public function up() { _elgg_services()->reset('routeCollection'); } - abstract public function actionsProvider(): array; + abstract public static function actionsProvider(): array; /** * @dataProvider actionsProvider diff --git a/engine/tests/classes/Elgg/BaseIntegrationTestCase.php b/engine/tests/classes/Elgg/BaseIntegrationTestCase.php index 749fd9fc00a..2eae91c7cdf 100644 --- a/engine/tests/classes/Elgg/BaseIntegrationTestCase.php +++ b/engine/tests/classes/Elgg/BaseIntegrationTestCase.php @@ -3,7 +3,6 @@ namespace Elgg; use Elgg\Database\DbConfig; -use ElggSession; use Psr\Log\LogLevel; use Symfony\Component\Console\Output\NullOutput; use Symfony\Component\Console\Output\OutputInterface; @@ -24,7 +23,6 @@ abstract class BaseIntegrationTestCase extends BaseTestCase { * {@inheritdoc} */ public static function createApplication(array $params = []) { - $isolate = elgg_extract('isolate', $params, false); unset($params['isolate']); @@ -65,7 +63,7 @@ public static function createApplication(array $params = []) { $app->setGlobalConfig($app); $app->internal_services->set('session', function () { - return ElggSession::getMock(); + return \ElggSession::getMock(); }); $app->internal_services->set('mailer', function () { diff --git a/engine/tests/classes/Elgg/BaseTestCase.php b/engine/tests/classes/Elgg/BaseTestCase.php index 9123deb30a2..7a3a78f8eea 100644 --- a/engine/tests/classes/Elgg/BaseTestCase.php +++ b/engine/tests/classes/Elgg/BaseTestCase.php @@ -181,7 +181,7 @@ protected function tearDown(): void { $admin = $this->_testing_admin; unset($this->_testing_admin); if ($admin instanceof \ElggUser) { - $admin->delete(); + $admin->delete(true, true); } // clear all message registers @@ -189,12 +189,32 @@ protected function tearDown(): void { _elgg_services()->system_messages->dumpRegister(); } - CacheManager::clearInstances(); - // close the database connections to prevent 'too many connections' _elgg_services()->db->closeConnections(); } - + + /** + * {@inheritdoc} + */ + public static function tearDownAfterClass(): void { + // performing some additional cleanup as we can't rely on php garbage collection + foreach (CacheManager::getInstances() as $instance) { + if ($instance instanceof \Phpfastcache\Drivers\Memcached\Driver) { + $memcached_software = $this->getInaccessableProperty($instance, 'instance'); + $memcached_software->flush(); + $memcached_software->quit(); + } elseif ($instance instanceof \Phpfastcache\Drivers\Redis\Driver) { + $redis_software = $this->getInaccessableProperty($instance, 'instance'); + $redis_software->flushAll(); + $redis_software->close(); + } + } + + CacheManager::clearInstances(); + + parent::tearDownAfterClass(); + } + /** * Called after setUp() method and can be used by test cases to setup their test logic * @return mixed @@ -214,22 +234,16 @@ public function down() { * @return \Doctrine\DBAL\Platforms\AbstractPlatform|MockObject */ public function getDatabasePlatformMock() { - $mock = $this->getAbstractMock( - 'Doctrine\DBAL\Platforms\AbstractPlatform', - [ - 'getName', + $mock = $this->getMockBuilder('Doctrine\DBAL\Platforms\MySQLPlatform') + ->onlyMethods([ 'getTruncateTableSQL', - ] - ); - - $mock->expects($this->any()) - ->method('getName') - ->will($this->returnValue('mysql')); + ]) + ->getMock(); $mock->expects($this->any()) ->method('getTruncateTableSQL') ->with($this->anything()) - ->will($this->returnValue('#TRUNCATE {table}')); + ->willReturn('#TRUNCATE {table}'); return $mock; } @@ -241,95 +255,45 @@ public function getDatabasePlatformMock() { public function getConnectionMock() { $mock = $this->getMockBuilder('Doctrine\DBAL\Connection') ->disableOriginalConstructor() - ->setMethods( + ->onlyMethods( [ 'beginTransaction', 'commit', 'rollback', 'prepare', - 'query', 'executeQuery', 'executeStatement', - 'executeUpdate', 'getDatabasePlatform', 'lastInsertId', - 'getExpressionBuilder', 'quote', ] ) ->getMock(); - - $mock->expects($this->any()) - ->method('prepare') - ->will($this->returnValue($this->getStatementMock())); - -// $mock->expects($this->any()) -// ->method('query') -// ->will($this->returnValue($this->getStatementMock())); - + $mock->expects($this->any()) ->method('getDatabasePlatform') - ->will($this->returnValue($this->getDatabasePlatformMock())); - - return $mock; - } - - /** - * @source https://gist.github.com/gnutix/7746893 - * @return \Doctrine\DBAL\Driver\Statement|MockObject - */ - public function getStatementMock() { - $mock = $this->getAbstractMock( - 'Doctrine\DBAL\Driver\Statement', - [ - 'bindValue', - 'execute', - 'rowCount', - 'fetchColumn', - ] - ); - - $mock->expects($this->any()) - ->method('fetchColumn') - ->will($this->returnValue(1)); + ->willReturn($this->getDatabasePlatformMock()); return $mock; } - + /** - * @source https://gist.github.com/gnutix/7746893 + * Tests if two inputs are equal. If the inputs are \ElggData object they will be transformed to plain objects * - * @param string $class The class name - * @param array $methods The available methods - * - * @return MockObject - */ - protected function getAbstractMock($class, array $methods) { - return $this->getMockForAbstractClass( - $class, - [], - '', - true, - true, - true, - $methods, - false - ); - } - - /** - * {@inheritdoc} + * @param mixed $expected Expected result + * @param mixed $actual Actual results + * @param string $message Message to report */ - public static function assertEquals($expected, $actual, $message = '', $delta = 0.0, $maxDepth = 10, $canonicalize = false, $ignoreCase = false): void { + public static function assertElggDataEquals(mixed $expected, mixed $actual, string $message = ''): void { if ($expected instanceof \ElggData) { $expected = $expected->toObject(); } - + if ($actual instanceof \ElggData) { $actual = $actual->toObject(); } - - parent::assertEquals($expected, $actual, $message, $delta, $maxDepth, $canonicalize, $ignoreCase); + + parent::assertEquals($expected, $actual, $message); } /** @@ -341,13 +305,10 @@ public static function assertEquals($expected, $actual, $message = '', $delta = * * @return mixed */ - protected function invokeInaccessableMethod($argument, string $method, ...$args) { + protected static function invokeInaccessableMethod($argument, string $method, ...$args) { $reflector = new \ReflectionClass($argument); - $inaccessable_method = $reflector->getMethod($method); - $inaccessable_method->setAccessible(true); - - return $inaccessable_method->invoke($argument, ...$args); + return $reflector->getMethod($method)->invoke($argument, ...$args); } /** @@ -358,11 +319,9 @@ protected function invokeInaccessableMethod($argument, string $method, ...$args) * * @return mixed */ - protected function getInaccessableProperty($argument, string $property) { + protected static function getInaccessableProperty($argument, string $property) { $reflector = new \ReflectionClass($argument); - $property = $reflector->getProperty($property); - $property->setAccessible(true); - return $property->getValue($argument); + return $reflector->getProperty($property)->getValue($argument); } } diff --git a/engine/tests/classes/Elgg/Cache/BaseCacheUnitTestCase.php b/engine/tests/classes/Elgg/Cache/BaseCacheUnitTestCase.php index e308b352a43..408d581d2b7 100644 --- a/engine/tests/classes/Elgg/Cache/BaseCacheUnitTestCase.php +++ b/engine/tests/classes/Elgg/Cache/BaseCacheUnitTestCase.php @@ -36,7 +36,7 @@ public function up() { */ abstract function createCache(string $namespace); - public function cacheableValuesProvider() { + public static function cacheableValuesProvider() { return [ ['lorem ipsum'], [[1, 2, 'abc', true]], @@ -82,6 +82,7 @@ public function testCanSaveAndLoadWithTTL() { $this->assertNull($this->cache->load($key)); + $this->assertTrue($this->cache->save($key, $value)); // need to do double save for Redis $this->assertTrue($this->cache->save($key, $value, \Elgg\Values::normalizeTime('-1 second'))); // need to detach to make sure the item is loaded from the backend and does not use static cache diff --git a/engine/tests/classes/Elgg/Filesystem/DirectoryUnitTestCase.php b/engine/tests/classes/Elgg/Filesystem/DirectoryUnitTestCase.php deleted file mode 100644 index bf79bfe09f9..00000000000 --- a/engine/tests/classes/Elgg/Filesystem/DirectoryUnitTestCase.php +++ /dev/null @@ -1,136 +0,0 @@ -putContents('/foo/bar/bar.php', 'bar'); - $directory->putContents('/foo/baz/baz.php', 'baz'); - $directory->putContents('/foo/foo.php', 'foo'); - $directory->putContents('/qux.php', 'qux'); - - $this->assertEquals(4, count($directory->getFiles())); - $this->assertEquals(1, count($directory->getFiles('', false))); - - $this->assertEquals(3, count($directory->getDirectories())); - $this->assertEquals(1, count($directory->getDirectories('', false))); - } - - /** - * @dataProvider emptyDirectoryProvider - */ - public function testListFilesAndDirsInASubdirectory(Directory $directory) { - $directory->putContents('/foo/bar/bar.php', 'bar'); - $directory->putContents('/foo/baz/baz.php', 'baz'); - $directory->putContents('/foo/baz/bing/foo.php', 'foo'); - $directory->putContents('/foo/foo.php', 'foo'); - $directory->putContents('/qux.php', 'qux'); - - foreach (['foo', '/foo', 'foo/', '/foo/'] as $path) { - $this->assertEquals(4, count($directory->getFiles($path))); - $this->assertEquals(1, count($directory->getFiles($path, false))); - - $this->assertEquals(3, count($directory->getDirectories($path))); - $this->assertEquals(2, count($directory->getDirectories($path, false))); - } - } - - /** - * @dataProvider emptyDirectoryProvider - */ - public function testChrootReturnsANewDirectoryThatOnlyHasAccessToTheGivenSubdir(Directory $directory) { - $directory->putContents('/foo/bar/bar.php', 'bar'); - $directory->putContents('/foo/baz/baz.php', 'baz'); - $directory->putContents('/foo/foo.php', 'foo'); - $directory->putContents('/qux.php', 'qux'); - - $this->assertEquals(3, count($directory->chroot('/foo/')->getFiles())); - $this->assertEquals(3, count($directory->chroot('foo/')->getFiles())); - $this->assertEquals(3, count($directory->chroot('/foo')->getFiles())); - $this->assertEquals(3, count($directory->chroot('foo')->getFiles())); - - $this->assertEquals(1, count($directory->chroot('/foo/bar/')->getFiles())); - $this->assertEquals(1, count($directory->chroot('foo/bar/')->getFiles())); - $this->assertEquals(1, count($directory->chroot('/foo/bar')->getFiles())); - $this->assertEquals(1, count($directory->chroot('foo/bar')->getFiles())); - } - - /** - * @dataProvider emptyDirectoryProvider - */ - public function testCanGetAnyFileInThisDirectoryEvenIfTheFileDoesNotExistYet(Directory $directory) { - $this->assertFalse($directory->getFile('foo.php')->exists()); - } - - /** - * @dataProvider emptyDirectoryProvider - */ - public function testPathsCannotContainDots(Directory $directory) { - $funcs = [ - function () use ($directory) { - $directory->chroot('.'); - }, - function () use ($directory) { - $directory->chroot('..'); - }, - function () use ($directory) { - $directory->getFile('.'); - }, - function () use ($directory) { - $directory->getFile('..'); - }, - ]; - - foreach ($funcs as $i => $f) { - try { - $f(); - $this->fail("A path was allowed to contain . or .. in function #$i"); - } catch (InvalidArgumentException $e) { - - } - } - } - - /** - * @dataProvider emptyDirectoryProvider - */ - public function testCanGetFileInsideItself(Directory $directory) { - $directory->putContents('/foo/bar.php', 'bar'); - - $file = $directory->chroot('foo')->getFile('bar.php'); - - $this->assertInstanceOf(File::class, $file); - - $this->assertEquals('bar', $file->getContents()); - } - - /** - * @dataProvider emptyDirectoryProvider - */ - public function testCanGetDirectoryInsideItself(Directory $directory) { - $directory->putContents('/foo/bar/bang.php', 'bang'); - $directory->putContents('/foo/boom/bang.php', 'bang'); - - $dirs = $directory->getDirectories('foo'); - $this->assertCount(2, $dirs); - foreach ($dirs as $dir) { - $this->assertInstanceOf(Directory::class, $dir); - $this->assertEquals('bang', $dir->getFile('bang.php')->getContents()); - } - } -} diff --git a/engine/tests/classes/Elgg/Helpers/ElggExtenderExtension.php b/engine/tests/classes/Elgg/Helpers/ElggExtenderExtension.php new file mode 100644 index 00000000000..ded6ea13a91 --- /dev/null +++ b/engine/tests/classes/Elgg/Helpers/ElggExtenderExtension.php @@ -0,0 +1,24 @@ +attributes; - } -} diff --git a/engine/tests/classes/Elgg/Http/ResponseUnitTestCase.php b/engine/tests/classes/Elgg/Http/ResponseUnitTestCase.php index ede16a50e12..e24c811ba5f 100644 --- a/engine/tests/classes/Elgg/Http/ResponseUnitTestCase.php +++ b/engine/tests/classes/Elgg/Http/ResponseUnitTestCase.php @@ -25,7 +25,7 @@ public function testCanSetContent($value) { $this->assertEquals($value, $response->getContent()); } - public function validContentValuesProvider() { + public static function validContentValuesProvider() { return [ ['foo'], [['foo' => 'bar']], @@ -50,7 +50,7 @@ public function testThrowsExceptionForInvalidContent($value) { $response->setContent($value); } - public function invalidContentValuesProvider() { + public static function invalidContentValuesProvider() { self::createApplication(); return [ @@ -75,7 +75,7 @@ public function testCanSetStatusCode($value) { $this->assertEquals($value, $response->getStatusCode()); } - public function validStatusCodesProvider() { + public static function validStatusCodesProvider() { return [ [100], [200], @@ -95,7 +95,7 @@ public function testThrowsExceptionForInvalidStatusCodes($value) { $response->setStatusCode($value); } - public function invalidStatusCodesProvider() { + public static function invalidStatusCodesProvider() { return [ [true], [false], @@ -118,7 +118,7 @@ public function testThrowsExceptionForInvalidStatusCodesTypes($value) { $response->setStatusCode($value); } - public function invalidStatusCodesTypesProvider() { + public static function invalidStatusCodesTypesProvider() { return [ ['foo'], [[200]], @@ -139,13 +139,13 @@ public function testCanSetForwardURL($value) { $this->assertEquals($value, $response->getForwardURL()); } - public function validForwardURLsProvider() { + public static function validForwardURLsProvider() { return [ [REFERRER], ['foo'], ['/foo'], - ['http://localhost/'], - ['?foo=bar'], + [self::getTestingConfig()->wwwroot], + ['a?foo=bar'], ]; } @@ -175,7 +175,7 @@ public function testCanResolveStatusCodes($code, $status) { $this->assertEquals($status[6], $response->isNotModified()); } - public function statusCodesProvider() { + public static function statusCodesProvider() { $codes = []; foreach (range(100, 599) as $code) { $codes[] = [ diff --git a/engine/tests/classes/Elgg/IntegrationTestCase.php b/engine/tests/classes/Elgg/IntegrationTestCase.php index c10e21b74a6..95bd9a5df41 100644 --- a/engine/tests/classes/Elgg/IntegrationTestCase.php +++ b/engine/tests/classes/Elgg/IntegrationTestCase.php @@ -2,13 +2,6 @@ namespace Elgg; -use Elgg\Database\DbConfig; -use ElggSession; -use Psr\Log\LogLevel; -use Symfony\Component\Console\Output\NullOutput; -use Symfony\Component\Console\Output\OutputInterface; -use Laminas\Mail\Transport\InMemory; - /** * Integration test abstraction * diff --git a/engine/tests/classes/Elgg/Mocks/Database.php b/engine/tests/classes/Elgg/Mocks/Database.php index 29337a02475..112ac2b3006 100644 --- a/engine/tests/classes/Elgg/Mocks/Database.php +++ b/engine/tests/classes/Elgg/Mocks/Database.php @@ -3,7 +3,6 @@ namespace Elgg\Mocks; use Doctrine\DBAL\Connection; -use Doctrine\DBAL\Query\Expression\ExpressionBuilder; use Elgg\BaseTestCase; use Elgg\Database as DbDatabase; use Elgg\Exceptions\DatabaseException; @@ -19,7 +18,7 @@ class Database extends DbDatabase { /** * @var int */ - protected $last_insert_id = null; + protected $last_insert_id = 0; /** * {@inheritdoc} @@ -41,35 +40,25 @@ public function connect(string $type = 'readwrite'): void { public function getConnection(string $type): Connection { $connection = BaseTestCase::$_instance->getConnectionMock(); - $connection->expects(BaseTestCase::$_instance->any()) - ->method('query') - ->will(BaseTestCase::$_instance->returnCallback([$this, 'executeDatabaseQuery'])); - $connection->expects(BaseTestCase::$_instance->any()) ->method('executeQuery') - ->will(BaseTestCase::$_instance->returnCallback([$this, 'executeDatabaseQuery'])); + ->willReturnCallback([$this, 'executeDatabaseQuery']); $connection->expects(BaseTestCase::$_instance->any()) ->method('executeStatement') - ->will(BaseTestCase::$_instance->returnCallback([$this, 'executeDatabaseStatement'])); + ->willReturnCallback([$this, 'executeDatabaseStatement']); $connection->expects(BaseTestCase::$_instance->any()) ->method('lastInsertId') - ->will(BaseTestCase::$_instance->returnCallback(function () { + ->willReturnCallback(function () { return $this->last_insert_id; - })); - - $expression_builder = new ExpressionBuilder($connection); - - $connection->expects(BaseTestCase::$_instance->any()) - ->method('getExpressionBuilder') - ->willReturn($expression_builder); + }); $connection->expects(BaseTestCase::$_instance->any()) ->method('quote') - ->will(BaseTestCase::$_instance->returnCallback(function ($input, $type = null) { + ->willReturnCallback(function ($input, $type = null) { return "'" . $input . "''"; - })); + }); return $connection; @@ -147,7 +136,7 @@ public function executeDatabaseQuery($sql, $params = []) { $sql = $this->normalizeSql($sql); $results = []; $row_count = 0; - $this->last_insert_id = null; + $this->last_insert_id = 0; $hash = sha1(serialize([$sql, $params])); $match = elgg_extract($hash, $this->query_specs); @@ -195,19 +184,20 @@ public function executeDatabaseQuery($sql, $params = []) { $result->expects(BaseTestCase::$_instance->any()) ->method('fetchAssociative') - ->will(BaseTestCase::$_instance->returnCallback(function () use (&$results) { - return array_shift($results); - })); + ->willReturnCallback(function () use (&$results) { + $result = array_shift($results); + return isset($result) ? (array) $result : false; + }); $result->expects(BaseTestCase::$_instance->any()) ->method('fetchAllAssociative') - ->will(BaseTestCase::$_instance->returnCallback(function () use ($results) { + ->willReturnCallback(function () use ($results) { return $results; - })); + }); $result->expects(BaseTestCase::$_instance->any()) ->method('rowCount') - ->will(BaseTestCase::$_instance->returnValue($row_count)); + ->willReturn($row_count); return $result; } diff --git a/engine/tests/classes/Elgg/Mocks/Database/AnnotationsTable.php b/engine/tests/classes/Elgg/Mocks/Database/AnnotationsTable.php index 90fe5623908..bea1859087c 100644 --- a/engine/tests/classes/Elgg/Mocks/Database/AnnotationsTable.php +++ b/engine/tests/classes/Elgg/Mocks/Database/AnnotationsTable.php @@ -8,7 +8,6 @@ use Elgg\Database\Insert; use Elgg\Database\Select; use Elgg\Database\Update; -use ElggAnnotation; class AnnotationsTable extends DbAnnotations { @@ -33,10 +32,10 @@ class AnnotationsTable extends DbAnnotations { */ public function get(int $id): ?\ElggAnnotation { if (empty($this->rows[$id])) { - return false; + return null; } - $annotation = new ElggAnnotation($this->rows[$id]); + $annotation = new \ElggAnnotation($this->rows[$id]); if ($annotation->access_id == ACCESS_PUBLIC) { // Public entities are always accessible @@ -65,7 +64,7 @@ public function get(int $id): ?\ElggAnnotation { /** * {@inheritdoc} */ - public function create(ElggAnnotation $annotation, \ElggEntity $entity): int|bool { + public function create(\ElggAnnotation $annotation, \ElggEntity $entity): int|bool { self::$iterator++; $id = self::$iterator; @@ -82,7 +81,6 @@ public function create(ElggAnnotation $annotation, \ElggEntity $entity): int|boo 'value' => $annotation->value, 'value_type' => $annotation->value_type, 'time_created' => $this->getCurrentTime()->getTimestamp(), - 'enabled' => $annotation->enabled, ]; $this->rows[$id] = $row; @@ -100,7 +98,7 @@ public function create(ElggAnnotation $annotation, \ElggEntity $entity): int|boo /** * {@inheritdoc} */ - public function update(ElggAnnotation $annotation): bool { + public function update(\ElggAnnotation $annotation): bool { $id = $annotation->id; if (!isset($this->rows[$id])) { return false; @@ -127,7 +125,7 @@ public function getAll(array $options = array()) { $rows = []; foreach ($this->rows as $row) { if (empty($guids) || in_array($row->entity_guid, $guids)) { - $rows[] = new ElggAnnotation($row); + $rows[] = new \ElggAnnotation($row); } } @@ -137,7 +135,7 @@ public function getAll(array $options = array()) { /** * {@inheritdoc} */ - public function delete(ElggAnnotation $annotation): bool { + public function delete(\ElggAnnotation $annotation): bool { parent::delete($annotation); if (!isset($this->rows[$annotation->id])) { @@ -155,6 +153,7 @@ public function delete(ElggAnnotation $annotation): bool { * Clear query specs * * @param \stdClass $row Data row + * * @return void */ protected function clearQuerySpecs(\stdClass $row) { @@ -174,10 +173,9 @@ protected function clearQuerySpecs(\stdClass $row) { * @return void */ protected function addQuerySpecs(\stdClass $row) { - $this->clearQuerySpecs($row); - $qb = Select::fromTable('annotations'); + $qb = Select::fromTable(self::TABLE_NAME); $qb->select('*'); $where = new AnnotationWhereClause(); @@ -196,7 +194,7 @@ protected function addQuerySpecs(\stdClass $row) { }, ]); - $qb = Insert::intoTable('annotations'); + $qb = Insert::intoTable(self::TABLE_NAME); $qb->values([ 'entity_guid' => $qb->param($row->entity_guid, ELGG_VALUE_INTEGER), 'name' => $qb->param($row->name, ELGG_VALUE_STRING), @@ -213,7 +211,7 @@ protected function addQuerySpecs(\stdClass $row) { 'insert_id' => $row->id, ]); - $qb = Update::table('annotations'); + $qb = Update::table(self::TABLE_NAME); $qb->set('name', $qb->param($row->name, ELGG_VALUE_STRING)) ->set('value', $qb->param($row->value, $row->value_type === 'integer' ? ELGG_VALUE_INTEGER : ELGG_VALUE_STRING)) ->set('value_type', $qb->param($row->value_type, ELGG_VALUE_STRING)) @@ -233,7 +231,7 @@ protected function addQuerySpecs(\stdClass $row) { }, ]); - $qb = Delete::fromTable('annotations'); + $qb = Delete::fromTable(self::TABLE_NAME); $qb->where($qb->compare('id', '=', $row->id, ELGG_VALUE_INTEGER)); $this->query_specs[$row->id][] = $this->db->addQuerySpec([ diff --git a/engine/tests/classes/Elgg/Mocks/Database/DelayedEmailQueueTable.php b/engine/tests/classes/Elgg/Mocks/Database/DelayedEmailQueueTable.php index 1ffcd541c1d..b22be088f35 100644 --- a/engine/tests/classes/Elgg/Mocks/Database/DelayedEmailQueueTable.php +++ b/engine/tests/classes/Elgg/Mocks/Database/DelayedEmailQueueTable.php @@ -32,13 +32,7 @@ class DelayedEmailQueueTable extends DbDelayedEmailQueueTable{ protected static $iterator = 100; /** - * Insert a delayed email into the queue - * - * @param int $recipient_guid the recipient of the email - * @param string $delivery_interval the desired interval of the recipient - * @param mixed $item the email to queue - * - * @return bool + * {@inheritdoc} */ public function queueEmail(int $recipient_guid, string $delivery_interval, $item): bool { self::$iterator++; @@ -65,15 +59,9 @@ public function queueEmail(int $recipient_guid, string $delivery_interval, $item } /** - * Get all the rows in the queue for a given recipient - * - * @param int $recipient_guid the recipient - * @param string $delivery_interval the interval for the recipient - * @param int $timestamp (optional) all queue items before time (default: now) - * - * @return DatabaseRecord[] database rows + * {@inheritdoc} */ - public function getRecipientRows(int $recipient_guid, string $delivery_interval, int $timestamp = null): array { + public function getRecipientRows(int $recipient_guid, string $delivery_interval, int $timestamp = null, int $max_results = 0): array { $result = []; $timestamp = $timestamp ?? $this->getCurrentTime()->getTimestamp(); @@ -94,49 +82,23 @@ public function getRecipientRows(int $recipient_guid, string $delivery_interval, $result[] = $this->rowToRecord($row); } - return $result; - } - - /** - * Get the queued items from the database for a given interval - * - * @param string $delivery_interval the delivery interval to get - * @param int $timestamp (optional) all queue items before time (default: now) - * - * @return DatabaseRecord[] - */ - public function getIntervalRows(string $delivery_interval, int $timestamp = null): array { - $result = []; - - $timestamp = $timestamp ?? $this->getCurrentTime()->getTimestamp(); - - foreach ($this->rows as $row) { - if ($row->delivery_interval !== $delivery_interval) { - continue; - } + if ($max_results > 0) { + // first order + usort($result, function($row_a, $row_b) { + // this should be based on timestamp and id, but that's harder + return $row_a->id - $row_b->id; + }); - if ($row->timestamp >= $timestamp) { - continue; - } - - $result[$row->timestamp . '_' . $row->recipient_guid] = $this->rowToRecord($row); + return array_slice($result, 0, $max_results); } - uksort($result, 'strnatcasecmp'); - - return array_values($result); + return $result; } /** - * Delete all the queue items from the database for the given recipient and interval - * - * @param int $recipient_guid the recipient - * @param string $delivery_interval the interval for the recipient - * @param int $timestamp (optional) all queue items before time (default: now) - * - * @return int number of deleted rows + * {@inheritdoc} */ - public function deleteRecipientRows(int $recipient_guid, string $delivery_interval, int $timestamp = null): int { + public function deleteRecipientRows(int $recipient_guid, string $delivery_interval, int $timestamp = null, int $max_id = 0): int { $result = 0; $timestamp = $timestamp ?? $this->getCurrentTime()->getTimestamp(); @@ -154,6 +116,10 @@ public function deleteRecipientRows(int $recipient_guid, string $delivery_interv continue; } + if ($max_id > 0 && $id > $max_id) { + continue; + } + $this->clearQuerySpecs($row); unset($this->rows[$id]); @@ -164,11 +130,7 @@ public function deleteRecipientRows(int $recipient_guid, string $delivery_interv } /** - * Delete all the queue items from the database for the given recipient and interval - * - * @param int $recipient_guid the recipient - * - * @return int number of deleted rows + * {@inheritdoc} */ public function deleteAllRecipientRows(int $recipient_guid): int { $result = 0; @@ -188,12 +150,7 @@ public function deleteAllRecipientRows(int $recipient_guid): int { } /** - * Update the queued notifications for the recipient to a new delivery interval - * - * @param int $recipient_guid the recipient - * @param string $delivery_interval the new delivery interval - * - * @return bool + * {@inheritdoc} */ public function updateRecipientInterval(int $recipient_guid, string $delivery_interval): bool { foreach ($this->rows as $row) { diff --git a/engine/tests/classes/Elgg/Mocks/Database/EntityTable.php b/engine/tests/classes/Elgg/Mocks/Database/EntityTable.php index a09421e9873..367c25513a6 100644 --- a/engine/tests/classes/Elgg/Mocks/Database/EntityTable.php +++ b/engine/tests/classes/Elgg/Mocks/Database/EntityTable.php @@ -51,6 +51,8 @@ public function getRow(int $guid, int $user_guid = null): ?\stdClass { 'time_updated' => time(), 'last_action' => time(), 'enabled' => 'yes', + 'deleted' => 'no', + 'time_deleted' => 0, ]; } @@ -152,6 +154,8 @@ public function setup($guid, $type, $subtype, array $attributes = []) { 'time_updated' => $time, 'last_action' => $time, 'enabled' => 'yes', + 'deleted' => 'no', + 'time_deleted' => 0, ]; $map = array_merge($primary_attributes, $attributes); @@ -296,8 +300,8 @@ protected function addSelectQuerySpecs(\stdClass $row) { $where->viewer_guid = $access_combination['user_guid']; $where->guids = $row->guid; - $select = Select::fromTable('entities', 'e'); - $select->select('e.*'); + $select = Select::fromTable(self::TABLE_NAME, self::DEFAULT_JOIN_ALIAS); + $select->select("{$select->getTableAlias()}.*"); $select->addClause($where); $this->query_specs[$row->guid][] = $this->db->addQuerySpec([ @@ -331,7 +335,6 @@ protected function addSelectQuerySpecs(\stdClass $row) { * @return bool */ protected function validateRowAccess($row) { - if (elgg_get_ignore_access()) { return true; } @@ -362,7 +365,7 @@ protected function validateRowAccess($row) { } $access_array = _elgg_services()->accessCollections->getAccessArray($user->guid); - return in_array($row->access_id, $access_array);; + return in_array($row->access_id, $access_array); } /** @@ -444,6 +447,28 @@ protected function addUpdateQuerySpecs(\stdClass $row) { 'times' => 1, ]); + // delete + $qb = Update::table(self::TABLE_NAME); + $qb->set('deleted', $qb->param('yes', ELGG_VALUE_STRING)) + ->where($qb->compare('guid', '=', $row->guid, ELGG_VALUE_GUID)); + + $this->query_specs[$row->guid][] = $this->db->addQuerySpec([ + 'sql' => $qb->getSQL(), + 'params' => $qb->getParameters(), + 'results' => function () use ($row) { + if (isset($this->rows[$row->guid])) { + $row->deleted = 'yes'; + $this->rows[$row->guid] = $row; + $this->addQuerySpecs($row); + + return [$row->guid]; + } + + return []; + }, + 'times' => 1, + ]); + // Enable $qb = Update::table(self::TABLE_NAME); $qb->set('enabled', $qb->param('yes', ELGG_VALUE_STRING)) @@ -466,6 +491,28 @@ protected function addUpdateQuerySpecs(\stdClass $row) { 'times' => 1, ]); + // restore + $qb = Update::table(self::TABLE_NAME); + $qb->set('deleted', $qb->param('no', ELGG_VALUE_STRING)) + ->where($qb->compare('guid', '=', $row->guid, ELGG_VALUE_GUID)); + + $this->query_specs[$row->guid][] = $this->db->addQuerySpec([ + 'sql' => $qb->getSQL(), + 'params' => $qb->getParameters(), + 'results' => function () use ($row) { + if (isset($this->rows[$row->guid])) { + $row->deleted = 'no'; + $this->rows[$row->guid] = $row; + $this->addQuerySpecs($row); + + return [$row->guid]; + } + + return []; + }, + 'times' => 1, + ]); + // Update last action $time = $this->getCurrentTime()->getTimestamp(); @@ -498,8 +545,7 @@ protected function addUpdateQuerySpecs(\stdClass $row) { * @return void */ protected function addDeleteQuerySpecs(\stdClass $row) { - - $qb = Delete::fromTable('entities'); + $qb = Delete::fromTable(self::TABLE_NAME); $qb->where($qb->compare('guid', '=', $row->guid, ELGG_VALUE_INTEGER)); $this->query_specs[$row->guid][] = $this->db->addQuerySpec([ @@ -524,7 +570,7 @@ protected function addDeleteQuerySpecs(\stdClass $row) { // and not in the relationships table mock // @todo: figure out a way to remove this from relationships table foreach (['guid_one', 'guid_two'] as $column) { - $delete = Delete::fromTable('entity_relationships'); + $delete = Delete::fromTable(\Elgg\Database\RelationshipsTable::TABLE_NAME); $delete->where($delete->compare($column, '=', $row->guid, ELGG_VALUE_GUID)); $this->query_specs[$row->guid][] = $this->db->addQuerySpec([ diff --git a/engine/tests/classes/Elgg/Mocks/Database/MetadataTable.php b/engine/tests/classes/Elgg/Mocks/Database/MetadataTable.php index c4f9d8dd27b..899cbe588e8 100644 --- a/engine/tests/classes/Elgg/Mocks/Database/MetadataTable.php +++ b/engine/tests/classes/Elgg/Mocks/Database/MetadataTable.php @@ -8,7 +8,6 @@ use Elgg\Database\MetadataTable as DbMetadataTabe; use Elgg\Database\Select; use Elgg\Database\Update; -use ElggMetadata; class MetadataTable extends DbMetadataTabe { @@ -31,7 +30,7 @@ class MetadataTable extends DbMetadataTabe { /** * {@inheritdoc} */ - public function create(ElggMetadata $metadata, bool $allow_multiple = false): int|false { + public function create(\ElggMetadata $metadata, bool $allow_multiple = false): int|false { if (!isset($metadata->value) || !isset($metadata->entity_guid)) { elgg_log("Metadata must have a value and entity guid", 'ERROR'); return false; @@ -101,7 +100,7 @@ public function create(ElggMetadata $metadata, bool $allow_multiple = false): in /** * {@inheritdoc} */ - public function update(ElggMetadata $metadata): bool { + public function update(\ElggMetadata $metadata): bool { if (!$this->entityTable->exists($metadata->entity_guid)) { elgg_log("Can't updated metadata to a non-existing entity_guid", 'ERROR'); return false; @@ -144,7 +143,6 @@ public function getAll(array $options = array()) { * {@inheritdoc} */ public function getRowsForGuids(array $guids): array { - $rows = []; foreach ($this->rows as $row) { if (in_array($row->entity_guid, $guids)) { @@ -155,10 +153,43 @@ public function getRowsForGuids(array $guids): array { return $rows; } + /** + * {@inheritdoc} + */ + public function deleteAll(array $options): bool { + $guids = elgg_extract('guids', $options, (array) elgg_extract('guid', $options)); + + $rows = []; + foreach ($this->rows as $row) { + if (empty($guids) || in_array($row->entity_guid, $guids)) { + $rows[] = $row; + } + } + + if (empty($rows)) { + return parent::deleteAll($options); + } + + $names = elgg_extract('metadata_names', $options, (array) elgg_extract('metadata_name', $options)); + if (!empty($names)) { + $rows = array_filter($rows, function($row) use ($names) { + return in_array($row->name, $names); + }); + } + + foreach ($rows as $row) { + unset($this->rows[$row->id]); + $this->clearQuerySpecs($row); + } + + return parent::deleteAll($options); + } + /** * Clear query specs * * @param \stdClass $row Data row + * * @return void */ protected function clearQuerySpecs(\stdClass $row) { @@ -178,10 +209,9 @@ protected function clearQuerySpecs(\stdClass $row) { * @return void */ protected function addQuerySpecs(\stdClass $row) { - $this->clearQuerySpecs($row); - $qb = Select::fromTable('metadata'); + $qb = Select::fromTable(self::TABLE_NAME); $qb->select('*'); $where = new MetadataWhereClause(); @@ -200,7 +230,7 @@ protected function addQuerySpecs(\stdClass $row) { ]); // getIDsByName - $qb = Select::fromTable('metadata'); + $qb = Select::fromTable(self::TABLE_NAME); $qb->select('id'); $qb->where($qb->compare('entity_guid', '=', $row->entity_guid, ELGG_VALUE_INTEGER)) ->andWhere($qb->compare('name', '=', $row->name, ELGG_VALUE_STRING)); @@ -216,7 +246,7 @@ protected function addQuerySpecs(\stdClass $row) { }, ]); - $qb = Insert::intoTable('metadata'); + $qb = Insert::intoTable(self::TABLE_NAME); $qb->values([ 'name' => $qb->param($row->name, ELGG_VALUE_STRING), 'entity_guid' => $qb->param($row->entity_guid, ELGG_VALUE_INTEGER), @@ -231,7 +261,7 @@ protected function addQuerySpecs(\stdClass $row) { 'insert_id' => $row->id, ]); - $qb = Update::table('metadata'); + $qb = Update::table(self::TABLE_NAME); $qb->set('name', $qb->param($row->name, ELGG_VALUE_STRING)) ->set('value', $qb->param($row->value, $row->value_type === 'integer' ? ELGG_VALUE_INTEGER : ELGG_VALUE_STRING)) ->set('value_type', $qb->param($row->value_type, ELGG_VALUE_STRING)) @@ -248,7 +278,7 @@ protected function addQuerySpecs(\stdClass $row) { }, ]); - $qb = Delete::fromTable('metadata'); + $qb = Delete::fromTable(self::TABLE_NAME); $qb->where($qb->compare('id', '=', $row->id, ELGG_VALUE_INTEGER)); $this->query_specs[$row->id][] = $this->db->addQuerySpec([ diff --git a/engine/tests/classes/Elgg/Mocks/Database/Plugins.php b/engine/tests/classes/Elgg/Mocks/Database/Plugins.php index a25b82487d6..44ce0037834 100644 --- a/engine/tests/classes/Elgg/Mocks/Database/Plugins.php +++ b/engine/tests/classes/Elgg/Mocks/Database/Plugins.php @@ -4,7 +4,6 @@ use Elgg\BaseTestCase; use Elgg\Database\Plugins as DbPlugins; -use ElggPlugin; use Elgg\Testing; class Plugins extends DbPlugins { @@ -12,7 +11,7 @@ class Plugins extends DbPlugins { use Testing; /** - * @var ElggPlugin[] + * @var \ElggPlugin[] */ protected $_plugins = []; @@ -43,6 +42,7 @@ class Plugins extends DbPlugins { 'site_notifications', 'system_log', 'tagcloud', + 'theme_sandbox', 'thewire', 'uservalidationbyemail', 'web_services', @@ -73,7 +73,7 @@ public function find(string $status = 'active'): array { public function generateEntities(): bool { parent::generateEntities(); - $this->addTestingPlugin(ElggPlugin::fromId('test_plugin', $this->normalizeTestFilePath('mod/'))); + $this->addTestingPlugin(\ElggPlugin::fromId('test_plugin', $this->normalizeTestFilePath('mod/'))); return true; } @@ -85,8 +85,7 @@ public function isActive(string $plugin_id): bool { return array_key_exists($plugin_id, $this->_plugins); } - public function setPriority(ElggPlugin $plugin, int $priority): int|false { - + public function setPriority(\ElggPlugin $plugin, int $priority): int|false { $old_priority = $plugin->getPriority(); foreach ($this->find() as $sibling) { diff --git a/engine/tests/classes/Elgg/Mocks/Database/RelationshipsTable.php b/engine/tests/classes/Elgg/Mocks/Database/RelationshipsTable.php index 8131e10e2b0..b8b11c27103 100644 --- a/engine/tests/classes/Elgg/Mocks/Database/RelationshipsTable.php +++ b/engine/tests/classes/Elgg/Mocks/Database/RelationshipsTable.php @@ -3,7 +3,6 @@ namespace Elgg\Mocks\Database; use Elgg\Database\RelationshipsTable as DbRelationshipsTable; -use stdClass; use Elgg\Database\Insert; use Elgg\Database\Select; use Elgg\Database\Delete; @@ -20,7 +19,7 @@ class RelationshipsTable extends DbRelationshipsTable { /** - * @var stdClass[] + * @var \stdClass[] */ protected $rows = []; @@ -81,6 +80,7 @@ public function add(int $guid_one, string $relationship, int $guid_two, bool $re * Clear query specs * * @param int $id Relationship ID + * * @return void */ protected function clearQuerySpecs($id) { @@ -94,15 +94,15 @@ protected function clearQuerySpecs($id) { /** * Add query specs for a relationship data row * - * @param stdClass $row Data row + * @param \stdClass $row Data row + * * @return void */ - protected function addQuerySpecs(stdClass $row) { - + protected function addQuerySpecs(\stdClass $row) { $this->clearQuerySpecs($row->id); // Insert a new relationship - $insert = Insert::intoTable('entity_relationships'); + $insert = Insert::intoTable(self::TABLE_NAME); $insert->values([ 'guid_one' => $insert->param($row->guid_one, ELGG_VALUE_GUID), 'relationship' => $insert->param($row->relationship, ELGG_VALUE_STRING), @@ -117,7 +117,7 @@ protected function addQuerySpecs(stdClass $row) { ]); // Get relationship by its ID - $select = Select::fromTable('entity_relationships'); + $select = Select::fromTable(self::TABLE_NAME); $select->select('*') ->where($select->compare('id', '=', $row->id, ELGG_VALUE_ID)); @@ -133,7 +133,7 @@ protected function addQuerySpecs(stdClass $row) { ]); // Delete relationship by its ID - $delete = Delete::fromTable('entity_relationships'); + $delete = Delete::fromTable(self::TABLE_NAME); $delete->where($delete->compare('id', '=', $row->id, ELGG_VALUE_ID)); $this->query_specs[$row->id][] = $this->db->addQuerySpec([ @@ -151,7 +151,7 @@ protected function addQuerySpecs(stdClass $row) { ]); // Check relationship between two GUIDs - $select = Select::fromTable('entity_relationships'); + $select = Select::fromTable(self::TABLE_NAME); $select->select('*') ->where($select->compare('guid_one', '=', $row->guid_one, ELGG_VALUE_GUID)) ->andWhere($select->compare('relationship', '=', $row->relationship, ELGG_VALUE_STRING)) diff --git a/engine/tests/classes/Elgg/Mocks/Di/InternalContainer.php b/engine/tests/classes/Elgg/Mocks/Di/InternalContainer.php index 6209a0445e4..d5b235f7005 100644 --- a/engine/tests/classes/Elgg/Mocks/Di/InternalContainer.php +++ b/engine/tests/classes/Elgg/Mocks/Di/InternalContainer.php @@ -48,7 +48,7 @@ public static function factory(array $options = []): self { $container->set('plugins', function (ContainerInterface $c) { return new \Elgg\Mocks\Database\Plugins( - $c->dataCache->plugins, + $c->pluginsCache, $c->db, $c->session_manager, $c->events, @@ -56,6 +56,7 @@ public static function factory(array $options = []): self { $c->views, $c->config, $c->system_messages, + $c->invoker, $c->request ); }); diff --git a/engine/tests/classes/Elgg/Notifications/NotificationsServiceIntegrationTestCase.php b/engine/tests/classes/Elgg/Notifications/NotificationsServiceIntegrationTestCase.php index 64813ba8275..d64019f67ca 100644 --- a/engine/tests/classes/Elgg/Notifications/NotificationsServiceIntegrationTestCase.php +++ b/engine/tests/classes/Elgg/Notifications/NotificationsServiceIntegrationTestCase.php @@ -279,7 +279,7 @@ public function testStoppingEnqueueEvent() { $mock = $this->createMock(EventsService::class, ['trigger']); $mock->expects($this->once()) ->method('triggerResults') - ->will($this->returnValue(false)); + ->willReturn(false); $this->events = $mock; @@ -305,7 +305,7 @@ public function testProcessQueueThreeEvents() { $mock = $this->createMock(SubscriptionsService::class, ['getNotificationEventSubscriptions'], [], '', false); $mock->expects($this->exactly(3)) ->method('getNotificationEventSubscriptions') - ->will($this->returnValue([])); + ->willReturn([]); _elgg_services()->subscriptions = $mock; @@ -336,8 +336,8 @@ public function testProcessQueueTimesout() { $mock = $this->createMock(SubscriptionsService::class, ['getNotificationEventSubscriptions'], [], '', false); $mock->expects($this->exactly(0)) ->method('getNotificationEventSubscriptions') - ->will($this->returnValue([])); - + ->willReturn([]); + _elgg_services()->subscriptions = $mock; $this->setupServices(); @@ -376,12 +376,12 @@ public function testCanUseEnqueueEventToPreventSubscriptionNotificationEventFrom $mock = $this->createMock(SubscriptionsService::class, ['getNotificationEventSubscriptions'], [], '', false); $mock->expects($this->exactly(0)) ->method('getNotificationEventSubscriptions') - ->will($this->returnValue([ + ->willReturn([ $recipient->guid => [ 'test_method', 'bad_method' ], - ])); + ]); _elgg_services()->subscriptions = $mock; @@ -430,10 +430,10 @@ public function testCanUseEventsBeforeAndAfterSubscriptionNotificationsQueue() { $mock = $this->createMock(SubscriptionsService::class, ['getNotificationEventSubscriptions'], [], '', false); $mock->expects($this->exactly(1)) ->method('getNotificationEventSubscriptions') - ->will($this->returnValue($subscribers)); + ->willReturn($subscribers); $mock->expects($this->exactly(1)) ->method('filterSubscriptions') - ->will($this->returnValue($subscribers)); + ->willReturn($subscribers); _elgg_services()->subscriptions = $mock; @@ -487,20 +487,20 @@ public function testCanProcessSubscriptionNotificationsQueue() { $mock = $this->createMock(SubscriptionsService::class, ['getNotificationEventSubscriptions'], [], '', false); $mock->expects($this->exactly(1)) ->method('getNotificationEventSubscriptions') - ->will($this->returnValue([ + ->willReturn([ $recipient->guid => [ 'test_method', 'bad_method' ], - ])); + ]); $mock->expects($this->exactly(1)) ->method('filterSubscriptions') - ->will($this->returnValue([ + ->willReturn([ $recipient->guid => [ 'test_method', 'bad_method' ], - ])); + ]); _elgg_services()->subscriptions = $mock; @@ -535,7 +535,7 @@ public function testCanProcessSubscriptionNotificationsQueue() { $event = $this->queue->dequeue(); $this->assertInstanceOf(SubscriptionNotificationEvent::class, $event); $this->assertEquals(elgg_get_logged_in_user_entity(), $event->getActor()); - $this->assertEquals($object, $event->getObject()); + $this->assertElggDataEquals($object, $event->getObject()); $this->assertEquals("test_event:{$object->getType()}:{$object->getSubtype()}", $event->getDescription()); $this->notifications->enqueueEvent('test_event', $object); @@ -572,20 +572,20 @@ public function testCanAlterSubscriptionNotificationTranslations() { $mock = $this->createMock(SubscriptionsService::class, ['getNotificationEventSubscriptions'], [], '', false); $mock->expects($this->exactly(1)) ->method('getNotificationEventSubscriptions') - ->will($this->returnValue([ + ->willReturn([ $recipient->guid => [ 'test_method', 'bad_method' ], - ])); + ]); $mock->expects($this->exactly(1)) ->method('filterSubscriptions') - ->will($this->returnValue([ + ->willReturn([ $recipient->guid => [ 'test_method', 'bad_method' ], - ])); + ]); _elgg_services()->subscriptions = $mock; @@ -657,13 +657,12 @@ public function testCanPrepareSubscriptionNotification() { $mock = $this->createMock(SubscriptionsService::class, ['getNotificationEventSubscriptions'], [], '', false); $mock->expects($this->exactly(1)) ->method('getNotificationEventSubscriptions') - ->will($this->returnValue([ - $recipient->guid => [ - 'test_method', - 'bad_method' - ], - ] - )); + ->willReturn([ + $recipient->guid => [ + 'test_method', + 'bad_method' + ], + ]); _elgg_services()->subscriptions = $mock; @@ -725,7 +724,7 @@ public function testValidatesObjectExistenceForDequeuedSubscriptionNotificationE $mock = $this->createMock(SubscriptionsService::class, ['getNotificationEventSubscriptions'], [], '', false); $mock->expects($this->exactly(0)) ->method('getNotificationEventSubscriptions') - ->will($this->returnValue([])); + ->willReturn([]); _elgg_services()->subscriptions = $mock; @@ -757,7 +756,7 @@ public function testValidatesActorExistenceForDequeuedSubscriptionNotificationEv $mock = $this->createMock(SubscriptionsService::class, ['getNotificationEventSubscriptions'], [], '', false); $mock->expects($this->exactly(0)) ->method('getNotificationEventSubscriptions') - ->will($this->returnValue([])); + ->willReturn([]); _elgg_services()->subscriptions = $mock; diff --git a/engine/tests/classes/Elgg/Plugins/RouteResponseIntegrationTestCase.php b/engine/tests/classes/Elgg/Plugins/RouteResponseIntegrationTestCase.php index edd20ae7b00..3661a0ad0fa 100644 --- a/engine/tests/classes/Elgg/Plugins/RouteResponseIntegrationTestCase.php +++ b/engine/tests/classes/Elgg/Plugins/RouteResponseIntegrationTestCase.php @@ -28,7 +28,7 @@ public function up() { * Get object subtype * @return mixed */ - abstract function getSubtype(); + abstract protected static function getSubtype(); /** * {@inheritDoc} @@ -325,7 +325,7 @@ public function testViewRouteRespondsOk() { */ public function testCollectionRoutesRespondOk($route, $params) { if ($params instanceof \Closure) { - $params = $params(); + $params = $params($this); } $request = $this->prepareHttpRequest(elgg_generate_url($route, $params)); @@ -342,19 +342,19 @@ public function testCollectionRoutesRespondOk($route, $params) { /** * @dataProvider groupRoutesProtectedByToolOption */ - public function testProtectedGroupRoutesThrowException($route_name, $tool_option) { + public function testProtectedGroupRoutesThrowException($route, $tool) { $group = $this->createGroup([ 'access_id' => ACCESS_PUBLIC, 'membership' => ACCESS_PUBLIC, 'content_access_mode'=> \ElggGroup::CONTENT_ACCESS_MODE_UNRESTRICTED, ]); - // make sure tool option is registerd - elgg()->group_tools->register($tool_option); + // make sure tool option is registered + elgg()->group_tools->register($tool); - $this->assertTrue($group->disableTool($tool_option)); + $this->assertTrue($group->disableTool($tool)); - $request = $this->prepareHttpRequest(elgg_generate_url($route_name, [ + $request = $this->prepareHttpRequest(elgg_generate_url($route, [ 'guid' => $group->guid, ])); @@ -365,19 +365,19 @@ public function testProtectedGroupRoutesThrowException($route_name, $tool_option /** * @dataProvider groupRoutesProtectedByToolOption */ - public function testProtectedGroupRoutesRespondOk($route_name, $tool_option) { + public function testProtectedGroupRoutesRespondOk($route, $tool) { $group = $this->createGroup([ 'access_id' => ACCESS_PUBLIC, 'membership' => ACCESS_PUBLIC, 'content_access_mode'=> \ElggGroup::CONTENT_ACCESS_MODE_UNRESTRICTED, ]); - // make sure tool option is registerd - elgg()->group_tools->register($tool_option); + // make sure tool option is registered + elgg()->group_tools->register($tool); - $this->assertTrue($group->enableTool($tool_option)); + $this->assertTrue($group->enableTool($tool)); - $request = $this->prepareHttpRequest(elgg_generate_url($route_name, [ + $request = $this->prepareHttpRequest(elgg_generate_url($route, [ 'guid' => $group->guid, ])); @@ -390,30 +390,32 @@ public function testProtectedGroupRoutesRespondOk($route_name, $tool_option) { $this->assertEquals(ELGG_HTTP_OK, $response->getStatusCode()); } - public function collectionRoutes() { + public static function collectionRoutes() { self::createApplication(); + $subtype = static::getSubtype(); + $result = [ [ - 'route' => "default:object:{$this->getSubtype()}", + 'route' => "default:object:{$subtype}", 'params' => [], ], [ - 'route' => "collection:object:{$this->getSubtype()}:all", + 'route' => "collection:object:{$subtype}:all", 'params' => [], ], [ - 'route' => "collection:object:{$this->getSubtype()}:owner", - 'params' => function () { + 'route' => "collection:object:{$subtype}:owner", + 'params' => function (RouteResponseIntegrationTestCase $testcase) { return [ - 'username' => $this->createUser()->username, + 'username' => $testcase->createUser()->username, ]; }, ], [ - 'route' => "collection:object:{$this->getSubtype()}:group", - 'params' => function () { + 'route' => "collection:object:{$subtype}:group", + 'params' => function (RouteResponseIntegrationTestCase $testcase) { return [ - 'guid' => $this->createGroup([ + 'guid' => $testcase->createGroup([ 'access_id' => ACCESS_PUBLIC, 'membership' => ACCESS_PUBLIC, 'content_access_mode'=> \ElggGroup::CONTENT_ACCESS_MODE_UNRESTRICTED, @@ -422,17 +424,17 @@ public function collectionRoutes() { }, ], [ - 'route' => "collection:object:{$this->getSubtype()}:friends", - 'params' => function () { + 'route' => "collection:object:{$subtype}:friends", + 'params' => function (RouteResponseIntegrationTestCase $testcase) { return [ - 'username' => $this->createUser()->username, + 'username' => $testcase->createUser()->username, ]; }, ], ]; $router = _elgg_services()->routes; - $protected_routes = $this->groupRoutesProtectedByToolOption(); + $protected_routes = static::groupRoutesProtectedByToolOption(); foreach ($result as $key => $route) { $route_name = $route['route']; @@ -460,7 +462,7 @@ public function collectionRoutes() { * * @return array */ - public function groupRoutesProtectedByToolOption() { + public static function groupRoutesProtectedByToolOption() { return []; } } diff --git a/engine/tests/classes/Elgg/PluginsIntegrationTestCase.php b/engine/tests/classes/Elgg/PluginsIntegrationTestCase.php index f54cd9708ee..74f31973753 100644 --- a/engine/tests/classes/Elgg/PluginsIntegrationTestCase.php +++ b/engine/tests/classes/Elgg/PluginsIntegrationTestCase.php @@ -22,8 +22,8 @@ public function up() { * * @return array */ - public function activePluginsProvider(): array { - $this->createApplication([ + public static function activePluginsProvider(): array { + self::createApplication([ 'isolate' => true, ]); diff --git a/engine/tests/classes/Elgg/TestSeeding.php b/engine/tests/classes/Elgg/TestSeeding.php index 36e53d5391d..b35a522ff50 100644 --- a/engine/tests/classes/Elgg/TestSeeding.php +++ b/engine/tests/classes/Elgg/TestSeeding.php @@ -25,7 +25,7 @@ public function clearSeeds(): void { continue; } - $seed->delete(); + $seed->delete(true, true); } }); } diff --git a/engine/tests/classes/Elgg/Testable.php b/engine/tests/classes/Elgg/Testable.php index 603c4f20f18..15e3adedf14 100644 --- a/engine/tests/classes/Elgg/Testable.php +++ b/engine/tests/classes/Elgg/Testable.php @@ -14,7 +14,7 @@ interface Testable { * * @return string */ - public function normalizeTestFilePath($filename = ''); + public static function normalizeTestFilePath($filename = ''); /** * Create an HTTP request diff --git a/engine/tests/classes/Elgg/TestableEvent.php b/engine/tests/classes/Elgg/TestableEvent.php index 917b08595fe..1d3013f6f5f 100644 --- a/engine/tests/classes/Elgg/TestableEvent.php +++ b/engine/tests/classes/Elgg/TestableEvent.php @@ -140,7 +140,7 @@ public function assertObject($object) { * @param mixed $value Value */ public function assertParamBefore($name, $value) { - $this->test_case->assertEquals($this->before_state->getParam($name), $value); + $this->test_case->assertElggDataEquals($this->before_state->getParam($name), $value); } /** @@ -150,7 +150,7 @@ public function assertParamBefore($name, $value) { * @param mixed $value Value */ public function assertParamAfter($name, $value) { - $this->test_case->assertEquals($this->after_state->getParam($name), $value); + $this->test_case->assertElggDataEquals($this->after_state->getParam($name), $value); } /** @@ -159,7 +159,7 @@ public function assertParamAfter($name, $value) { * @param mixed $value Value */ public function assertValueBefore($value) { - $this->test_case->assertEquals($this->before_state->getValue(), $value); + $this->test_case->assertElggDataEquals($this->before_state->getValue(), $value); } /** @@ -168,6 +168,6 @@ public function assertValueBefore($value) { * @param mixed $value Value */ public function assertValueAfter($value) { - $this->test_case->assertEquals($this->after_state->getValue(), $value); + $this->test_case->assertElggDataEquals($this->after_state->getValue(), $value); } } diff --git a/engine/tests/classes/Elgg/Testing.php b/engine/tests/classes/Elgg/Testing.php index cf86ebf59cd..2fe8b2adea5 100644 --- a/engine/tests/classes/Elgg/Testing.php +++ b/engine/tests/classes/Elgg/Testing.php @@ -2,10 +2,9 @@ namespace Elgg; +use Elgg\Exceptions\RuntimeException; use Elgg\Http\Request; use Elgg\Project\Paths; -use ElggUser; -use RuntimeException; /** * Testing trait that provides utility methods agnostic to testing framework @@ -13,7 +12,7 @@ trait Testing { /** - * @var ElggUser + * @var \ElggUser */ protected $_testing_admin; @@ -24,10 +23,10 @@ trait Testing { * * @return string */ - public function normalizeTestFilePath($filename = '') { + public static function normalizeTestFilePath($filename = '') { $filename = ltrim($filename, '/'); $append_slash = substr($filename, -1, 1) === '/'; - return Paths::sanitize(Paths::elgg() . "/engine/tests/test_files/$filename", $append_slash); + return Paths::sanitize(Paths::elgg() . "/engine/tests/test_files/{$filename}", $append_slash); } /** @@ -42,16 +41,13 @@ public function normalizeTestFilePath($filename = '') { * @return Request */ public static function prepareHttpRequest($uri = '', $method = 'GET', $parameters = [], $ajax = 0, $add_csrf_tokens = false) { - $site_url = elgg_get_site_url(); - $path = '/' . ltrim(substr(elgg_normalize_url($uri), strlen($site_url)), '/'); - if ($add_csrf_tokens) { $ts = _elgg_services()->csrf->getCurrentTime()->getTimestamp(); $parameters['__elgg_ts'] = $ts; $parameters['__elgg_token'] = _elgg_services()->csrf->generateActionToken($ts); } - $request = Request::create($path, $method, $parameters); + $request = Request::create(elgg_normalize_url($uri), $method, $parameters); $cookie_name = _elgg_services()->config->getCookieConfig()['session']['name']; $session_id = _elgg_services()->session->getID(); @@ -71,11 +67,11 @@ public static function prepareHttpRequest($uri = '', $method = 'GET', $parameter /** * Returns an admin user. This user will persist within a test case. - * @return ElggUser + * + * @return \ElggUser * @throws RuntimeException */ public function getAdmin() { - $admin = $this->_testing_admin; if (!$admin) { $admins = elgg_get_admins([ diff --git a/engine/tests/classes/Elgg/Traits/Entity/IconsIntegrationTestCase.php b/engine/tests/classes/Elgg/Traits/Entity/IconsIntegrationTestCase.php new file mode 100644 index 00000000000..69bcc2feeed --- /dev/null +++ b/engine/tests/classes/Elgg/Traits/Entity/IconsIntegrationTestCase.php @@ -0,0 +1,181 @@ +entity = $this->getEntity(); + } + + abstract protected function getEntity(): \ElggEntity; + + /** + * @dataProvider tooFewCoordinatesProvider + */ + public function testSaveIconCoordinatesWithTooFewCoordinates($x1, $x2, $y1, $y2, $icon_type) { + $coords = [ + 'x1' => $x1, + 'x2' => $x2, + 'y1' => $y1, + 'y2' => $y2, + ]; + + $this->expectException(InvalidArgumentException::class); + $this->entity->saveIconCoordinates($coords, $icon_type); + } + + public static function tooFewCoordinatesProvider(): array { + return [ + [100, 100, 200, null, 'icon'], + [100, 100, null, 200, 'icon'], + [100, null, 200, 200, 'icon'], + [null, 100, 200, 200, 'icon'], + [100, 100, 200, null, 'avatar'], + [100, 100, null, 200, 'avatar'], + [100, null, 200, 200, 'avatar'], + [null, 100, 200, 200, 'avatar'], + ]; + } + + /** + * @dataProvider invalidCoordinatesProvider + */ + public function testSaveIconCoordinatesWithTooInvalidCoordinates($x1, $x2, $y1, $y2, $icon_type) { + $coords = [ + 'x1' => $x1, + 'x2' => $x2, + 'y1' => $y1, + 'y2' => $y2, + ]; + + $this->expectException(RangeException::class); + $this->entity->saveIconCoordinates($coords, $icon_type); + } + + public static function invalidCoordinatesProvider(): array { + return [ + [-100, 100, 200, 200, 'icon'], + [100, -100, 200, 200, 'icon'], + [100, 100, -200, 200, 'icon'], + [100, 100, 200, -200, 'icon'], + [-100, 100, 200, 200, 'avatar'], + [100, -100, 200, 200, 'avatar'], + [100, 100, -200, 200, 'avatar'], + [100, 100, 200, -200, 'avatar'], + ]; + } + + public function testCRUDIconCoordinates() { + $entity = $this->entity; + + $icon_type1 = 'icon'; + $icon_type2 = 'avatar'; + + // start empty + $current1 = $entity->getIconCoordinates($icon_type1); + $this->assertIsArray($current1); + $this->assertEmpty($current1); + + $current2 = $entity->getIconCoordinates($icon_type2); + $this->assertIsArray($current2); + $this->assertEmpty($current2); + + // save coordinates + $coords1 = [ + 'x1' => $this->faker()->numberBetween(1, 1000), + 'x2' => $this->faker()->numberBetween(1, 1000), + 'y1' => $this->faker()->numberBetween(1, 1000), + 'y2' => $this->faker()->numberBetween(1, 1000), + ]; + $coords2 = [ + 'x1' => $this->faker()->numberBetween(1, 1000), + 'x2' => $this->faker()->numberBetween(1, 1000), + 'y1' => $this->faker()->numberBetween(1, 1000), + 'y2' => $this->faker()->numberBetween(1, 1000), + ]; + + $entity->saveIconCoordinates($coords1, $icon_type1); + + $entity->invalidateCache(); + $current1 = $entity->getIconCoordinates($icon_type1); + $this->assertNotEmpty($current1); + $this->assertEquals($coords1, $current1); + + // shouldn't be saved to a different icon + $this->assertEmpty($entity->getIconCoordinates($icon_type2)); + + // update coordinates + $entity->saveIconCoordinates($coords2, $icon_type1); + + $entity->invalidateCache(); + $current1 = $entity->getIconCoordinates($icon_type1); + $this->assertNotEmpty($current1); + $this->assertEquals($coords2, $current1); + + // save to different icon + $entity->saveIconCoordinates($coords1, $icon_type2); + + $entity->invalidateCache(); + $current2 = $entity->getIconCoordinates($icon_type2); + $this->assertNotEmpty($current2); + $this->assertEquals($coords1, $current2); + + $this->assertNotEquals($current1, $current2); + + // remove coordinates + $entity->removeIconCoordinates($icon_type1); + + $entity->invalidateCache(); + $this->assertEmpty($entity->getIconCoordinates($icon_type1)); + $this->assertNotEmpty($entity->getIconCoordinates($icon_type2)); + + $entity->removeIconCoordinates($icon_type2); + $this->assertEmpty($entity->getIconCoordinates($icon_type2)); + } + + public function testIconGenerationLocking() { + $entity = $this->entity; + + $icon_type1 = 'icon'; + $icon_type2 = 'avatar'; + + $this->assertFalse($entity->isIconThumbnailGenerationLocked($icon_type1)); + $this->assertFalse($entity->isIconThumbnailGenerationLocked($icon_type2)); + + // lock generation + $entity->lockIconThumbnailGeneration($icon_type1); + + $this->assertTrue($entity->isIconThumbnailGenerationLocked($icon_type1)); + $this->assertFalse($entity->isIconThumbnailGenerationLocked($icon_type2)); + + // check ttl + $this->assertFalse($entity->isIconThumbnailGenerationLocked($icon_type1, -1)); + + // lock other icon generation + $entity->lockIconThumbnailGeneration($icon_type2); + + $this->assertTrue($entity->isIconThumbnailGenerationLocked($icon_type1)); + $this->assertTrue($entity->isIconThumbnailGenerationLocked($icon_type2)); + + // unlock + $entity->unlockIconThumbnailGeneration($icon_type1); + + $this->assertFalse($entity->isIconThumbnailGenerationLocked($icon_type1)); + $this->assertTrue($entity->isIconThumbnailGenerationLocked($icon_type2)); + + // unlock other icon + $entity->unlockIconThumbnailGeneration($icon_type2); + + $this->assertFalse($entity->isIconThumbnailGenerationLocked($icon_type1)); + $this->assertFalse($entity->isIconThumbnailGenerationLocked($icon_type2)); + } +} diff --git a/engine/tests/classes/Elgg/Traits/Entity/PluginSettingsIntegrationTestCase.php b/engine/tests/classes/Elgg/Traits/Entity/PluginSettingsIntegrationTestCase.php index 2a830eba114..3322ae0a0a2 100644 --- a/engine/tests/classes/Elgg/Traits/Entity/PluginSettingsIntegrationTestCase.php +++ b/engine/tests/classes/Elgg/Traits/Entity/PluginSettingsIntegrationTestCase.php @@ -42,7 +42,7 @@ public function testGetNamespacedPluginSettingName(string $plugin_id, string $se $this->assertEquals("plugin:{$this->entity->getType()}_setting:{$plugin_id}:{$setting_name}", $result); } - public function namespaceProvider() { + public static function namespaceProvider() { return [ ['test_plugin', 'foo'], ['test_plugin', 'bar'], @@ -73,7 +73,7 @@ public function testSetGetRemovePluginSettings(string $plugin_id, string $settin $this->assertEmpty($this->entity->getMetadata($plugin_setting_name)); } - public function setPluginSettingProvider() { + public static function setPluginSettingProvider() { return [ ['test_plugin', 'foo', 'bar'], ['test_plugin', 'bar', 'foo'], @@ -110,7 +110,7 @@ public function testUseEventToConvertInvalidPluginSettingValue($invalid_value) { $this->assertEquals(serialize($invalid_value), $this->entity->getPluginSetting('test_plugin', 'foo')); } - public function invalidPluginSettingValueProvider() { + public static function invalidPluginSettingValueProvider() { return [ [new \stdClass()], ]; diff --git a/engine/tests/classes/Elgg/Traits/Entity/SubscriptionsIntegrationTestCase.php b/engine/tests/classes/Elgg/Traits/Entity/SubscriptionsIntegrationTestCase.php index abbaa103902..456c82277d5 100644 --- a/engine/tests/classes/Elgg/Traits/Entity/SubscriptionsIntegrationTestCase.php +++ b/engine/tests/classes/Elgg/Traits/Entity/SubscriptionsIntegrationTestCase.php @@ -104,7 +104,7 @@ public function testRemoveSubscriptionWithInvalidMethod($methods) { $this->target->removeSubscription($this->user->guid, $methods); } - public function invalidMethodsProvider() { + public static function invalidMethodsProvider() { return [ [''], [['']], diff --git a/engine/tests/classes/Elgg/UnitTestCase.php b/engine/tests/classes/Elgg/UnitTestCase.php index 7d7eff3c67e..e782c0cd1eb 100644 --- a/engine/tests/classes/Elgg/UnitTestCase.php +++ b/engine/tests/classes/Elgg/UnitTestCase.php @@ -55,6 +55,7 @@ public static function createApplication(array $params = []) { } // Invalidate caches + $app->internal_services->serverCache->reset(); $app->internal_services->dataCache->clear(); $app->internal_services->sessionCache->clear(); diff --git a/engine/tests/classes/Elgg/Views/ViewRenderingIntegrationTestCase.php b/engine/tests/classes/Elgg/Views/ViewRenderingIntegrationTestCase.php index 8095cf25e95..878226b9a82 100644 --- a/engine/tests/classes/Elgg/Views/ViewRenderingIntegrationTestCase.php +++ b/engine/tests/classes/Elgg/Views/ViewRenderingIntegrationTestCase.php @@ -19,7 +19,7 @@ public function up() { * * @return array */ - abstract public function getViewNames(); + abstract public static function getViewNames(); /** * Returns default view vars to testing rendering @@ -32,7 +32,7 @@ abstract public function getDefaultViewVars(); * * @return array */ - public function viewListProvider() { + public static function viewListProvider() { self::createApplication(); $provides = []; @@ -41,7 +41,7 @@ public function viewListProvider() { foreach ($data['locations'] as $viewtype => $views) { foreach ($views as $view => $path) { - if (in_array($view, $this->getViewNames())) { + if (in_array($view, static::getViewNames())) { $provides[] = [$view, $viewtype]; } } diff --git a/engine/tests/js/ElggAjaxTest.js b/engine/tests/js/ElggAjaxTest.js deleted file mode 100644 index 3b92a507681..00000000000 --- a/engine/tests/js/ElggAjaxTest.js +++ /dev/null @@ -1,596 +0,0 @@ -define(function(require) { - - var elgg = require('elgg'); - var $ = require('jquery'); - require('jquery-mockjax'); - var security = require('elgg/security'); - var i18n = require('elgg/i18n'); - var Ajax = require('elgg/Ajax'); - var hooks = require('elgg/hooks'); - var system_messages = require('elgg/system_messages'); - var ajax = new Ajax(); - - $.mockjaxSettings.responseTime = 10; - - describe("elgg/ajax", function() { - var captured_hook, - root = elgg.get_site_url(); - - beforeEach(function() { - captured_hook = null; - - $.mockjaxSettings.logging = false; - $.mockjax.clear(); - - hooks.reset(); - - // note, "all" type > always higher priority than specific types - hooks.register(Ajax.REQUEST_DATA_HOOK, 'all', function (h, t, p, v) { - captured_hook = { - t: t, - p: p, - v: v - }; - }); - }); - - it("passes unwrapped value to both success and deferred", function(done) { - //$.mockjaxSettings.logging = true; - $.mockjax({ - url: elgg.normalize_url("foo"), - responseText: { - value: 1 - } - }); - - var def1 = $.Deferred(), - def2 = $.Deferred(); - - ajax.path('foo', { - success: function (val) { - expect(val).toBe(1); - def1.resolve(); - } - }).done(function (val) { - expect(val).toBe(1); - def2.resolve(); - }); - - $.when(def1, def2).then(done); - }); - - it("allows filtering response wrapper by hook, called only once", function(done) { - //$.mockjaxSettings.logging = true; - $.mockjax({ - url: elgg.normalize_url("foo"), - responseText: { - value: 1, - foo: 2 - } - }); - - var hook_calls = 0; - - hooks.register(Ajax.RESPONSE_DATA_HOOK, 'path:foo', function (h, t, p, v) { - hook_calls++; - expect(v).toEqual({ - value: 1, - foo: 2, - status: 0 - }); - expect(p.options.url).toBe('foo'); - v.value = 3; - return v; - }); - - var def1 = $.Deferred(), - def2 = $.Deferred(); - - ajax.path('foo', { - success: function (val) { - expect(val).toBe(3); - def1.resolve(); - } - }).done(function (val) { - expect(val).toBe(3); - def2.resolve(); - }); - - $.when(def1, def2).then(function () { - expect(hook_calls).toBe(1); - done(); - }); - }); - - $.each(['path', 'action', 'form', 'view'], function (i, method) { - it("method " + method + "() sends special header", function() { - ajax[method]('foo'); - expect(ajax._ajax_options.headers).toEqual({ 'X-Elgg-Ajax-API' : '2' }); - }); - - it("method " + method + "() uses dataType json", function() { - ajax[method]('foo'); - expect(ajax._ajax_options.dataType).toEqual('json'); - }); - }); - - it("action() defaults to POST", function() { - ajax.action('foo'); - expect(ajax._ajax_options.method).toEqual('POST'); - }); - - it("path(): non-empty object data changes default to POST", function() { - ajax.path('foo', { - data: {bar: 'bar'} - }); - expect(ajax._ajax_options.method).toEqual('POST'); - }); - - it("path(): non-empty string data changes default to POST", function() { - ajax.path('foo', { - data: '?bar=bar' - }); - expect(ajax._ajax_options.method).toEqual('POST'); - }); - - $.each(['form', 'view'], function (i, method) { - it(method + "(): non-empty object data left as GET", function() { - ajax[method]('foo', { - data: {bar: 'bar'} - }); - expect(ajax._ajax_options.method).toEqual('GET'); - }); - }); - - $.each(['path', 'form', 'view'], function (i, method) { - - it(method + "() defaults to GET", function() { - ajax[method]('foo'); - expect(ajax._ajax_options.method).toEqual('GET'); - }); - - it(method + "(): empty string data leaves default as GET", function() { - ajax[method]('foo', { - data: '' - }); - expect(ajax._ajax_options.method).toEqual('GET'); - }); - - it(method + "(): empty object data leaves default as GET", function() { - ajax[method]('foo', { - data: {} - }); - expect(ajax._ajax_options.method).toEqual('GET'); - }); - }); - - it("allows altering value via hook", function(done) { - hooks.register(Ajax.REQUEST_DATA_HOOK, 'path:foo/bar', function (h, t, p, v) { - v.arg3 = 3; - return v; - }, 900); - - //$.mockjaxSettings.logging = true; - $.mockjax({ - url: elgg.normalize_url("foo/bar/?arg1=1"), - responseText: { - value: 1, - foo: 2 - } - }); - - ajax.path('/foo/bar/?arg1=1#target', { - data: {arg2: 2} - }).done(function () { - expect(captured_hook.v).toEqual({arg2: 2, arg3: 3}); - expect(captured_hook.p.options.data).toEqual({arg2: 2, arg3: 3}); - done(); - }); - - expect(ajax._ajax_options.data).toEqual({ - arg2: 2, - arg3: 3 - }); - }); - - it("normalizes argument paths/URLs", function() { - ajax.path('/foo/bar/?arg1=1#target'); - expect(ajax._fetch_args.hook_type).toEqual('path:foo/bar'); - expect(ajax._fetch_args.options.url).toEqual(root + 'foo/bar/?arg1=1'); - - ajax.path(root + 'foo/bar/?arg1=1#target'); - expect(ajax._fetch_args.hook_type).toEqual('path:foo/bar'); - expect(ajax._fetch_args.options.url).toEqual(root + 'foo/bar/?arg1=1'); - - ajax.action('/foo/bar/?arg1=1#target'); - expect(ajax._fetch_args.hook_type).toEqual('action:foo/bar'); - expect(ajax._fetch_args.options.url).toEqual(root + 'action/foo/bar/?arg1=1'); - - ajax.action(root + 'action/foo/bar/?arg1=1#target'); - expect(ajax._fetch_args.hook_type).toEqual('action:foo/bar'); - expect(ajax._fetch_args.options.url).toEqual(root + 'action/foo/bar/?arg1=1'); - - ajax.view('foo/bar?arg1=1'); - expect(ajax._fetch_args.hook_type).toEqual('view:foo/bar'); - expect(ajax._fetch_args.options.url).toEqual(root + 'ajax/view/foo/bar?arg1=1'); - - ajax.form('/foo/bar/?arg1=1#target'); - expect(ajax._fetch_args.hook_type).toEqual('form:foo/bar'); - expect(ajax._fetch_args.options.url).toEqual(root + 'ajax/form/foo/bar/?arg1=1'); - }); - - it("refuses to accept external URLs", function() { - expect(function () { - ajax.action('http://other.com/action/foo'); - }).toThrowError(); - - expect(function () { - ajax.path('http://other.com/foo'); - }).toThrowError(); - }); - - it("form() and view() refuse to accept any URL", function() { - expect(function () { - ajax.view(root + 'ajax/view/foo'); - }).toThrowError(); - - expect(function () { - ajax.form(root + 'action/foo'); - }).toThrowError(); - }); - - it("adds CSRF tokens to action data", function() { - var ts = elgg.security.token.__elgg_ts; - - ajax.action('foo'); - expect(ajax._ajax_options.data.__elgg_ts).toBe(ts); - - ajax.action('foo', { - data: "?arg1=1" - }); - expect(ajax._ajax_options.data).toContain('__elgg_ts=' + ts); - }); - - it("does not add tokens if already in action URL", function() { - var ts = elgg.security.token.__elgg_ts; - - var url = security.addToken(root + 'action/foo'); - - ajax.action(url); - expect(ajax._ajax_options.data.__elgg_ts).toBe(undefined); - }); - - it("path() accepts empty argument for fetching home page", function() { - ajax.path(""); - }); - - $.each(['action', 'form', 'view'], function (i, method) { - it(method + "() does not accept empty argument", function () { - expect(function () { - ajax[method](''); - }).toThrowError(); - }); - }); - - it("handles server-sent messages and dependencies", function(done) { - var tmp_system_message = system_messages.success; - var tmp_register_error = system_messages.error; - var tmp_require = Ajax._require; - var captured = {}; - - system_messages.success = function (arg) { - captured.msg = arg; - }; - system_messages.error = function (arg) { - captured.error = arg; - }; - Ajax._require = function (arg) { - captured.deps = arg; - }; - - //$.mockjaxSettings.logging = true; - $.mockjax({ - url: elgg.normalize_url("foo"), - responseText: { - value: 1, - _elgg_msgs: { - error: ['fail'], - success: ['yay'] - }, - _elgg_deps: ['foo'] - } - }); - - ajax.path('foo').done(function () { - expect(captured).toEqual({ - msg: ['yay'], - error: ['fail'], - deps: ['foo'] - }); - - system_messages.success = tmp_system_message; - system_messages.error = tmp_register_error; - Ajax._require = tmp_require; - - done(); - }); - }); - - it("can prevent output of server-sent messages and dependencies", function(done) { - var tmp_system_message = system_messages.success; - var tmp_register_error = system_messages.error; - var tmp_require = Ajax._require; - var captured = {}; - - system_messages.success = function (arg) { - captured.msg = arg; - }; - system_messages.error = function (arg) { - captured.error = arg; - }; - Ajax._require = function (arg) { - captured.deps = arg; - }; - - //$.mockjaxSettings.logging = true; - $.mockjax({ - url: elgg.normalize_url("foo"), - responseText: { - value: 1, - _elgg_msgs: { - error: ['fail'], - success: ['yay'] - }, - _elgg_deps: ['foo'] - } - }); - - ajax.path('foo', {showErrorMessages: false, showSuccessMessages: false}).done(function () { - expect(captured).toEqual({ - deps: ['foo'] - }); - - system_messages.success = tmp_system_message; - system_messages.error = tmp_register_error; - Ajax._require = tmp_require; - - done(); - }); - }); - - it("error handler still handles server-sent messages and dependencies", function (done) { - var tmp_system_message = system_messages.success; - var tmp_register_error = system_messages.error; - var tmp_require = Ajax._require; - var captured = {}; - - system_messages.success = function (arg) { - captured.msg = arg; - }; - system_messages.error = function (arg) { - captured.error = arg; - }; - Ajax._require = function (arg) { - captured.deps = arg; - }; - - //$.mockjaxSettings.logging = true; - $.mockjax({ - url: elgg.normalize_url("foo"), - status: 500, - responseText: { - value: null, - _elgg_msgs: { - error: ['fail'], - success: ['yay'] - }, - _elgg_deps: ['foo'] - } - }); - - ajax.path('foo').fail(function () { - expect(captured).toEqual({ - msg: ['yay'], - error: ['fail'], - deps: ['foo'] - }); - - system_messages.success = tmp_system_message; - system_messages.error = tmp_register_error; - Ajax._require = tmp_require; - - done(); - }); - }); - - it("outputs the generic error if no server-sent message", function (done) { - var tmp_register_error = system_messages.error; - var captured = {}; - - system_messages.error = function (arg) { - captured.error = arg; - }; - - //$.mockjaxSettings.logging = true; - $.mockjax({ - url: elgg.normalize_url("foo"), - status: 500, - responseText: {} - }); - - ajax.path('foo').fail(function () { - expect(captured).toEqual({ - error: i18n.echo('ajax:error') - }); - - system_messages.error = tmp_register_error; - - done(); - }); - }); - - it("outputs the error message of the non-200 response", function (done) { - var tmp_register_error = system_messages.error; - var captured = {}; - - system_messages.error = function (arg) { - captured.error = arg; - }; - - //$.mockjaxSettings.logging = true; - $.mockjax({ - url: elgg.normalize_url("foo"), - status: 500, - responseText: { - error: 'Server throws' - } - }); - - ajax.path('foo').fail(function () { - expect(captured).toEqual({ - error: 'Server throws' - }); - - system_messages.error = tmp_register_error; - - done(); - }); - }); - - it("copies data to jqXHR.AjaxData", function (done) { - //$.mockjaxSettings.logging = true; - $.mockjax({ - url: elgg.normalize_url("foo"), - responseText: { - value: 1, - other: 2 - } - }); - - ajax.path('foo').done(function (value, textStatus, jqXHR) { - expect(jqXHR.AjaxData).toEqual({ - value: 1, - other: 2, - status: 0 - }); - done(); - }); - }); - - it("sets jqXHR.AjaxData.status to 0 or -1 depending on presence of server error", function (done) { - //$.mockjaxSettings.logging = true; - $.mockjax({ - url: elgg.normalize_url("good"), - responseText: { - value: 1 - } - }); - $.mockjax({ - url: elgg.normalize_url("bad"), - responseText: { - value: 1, - _elgg_msgs: { - error: ['fail'] - } - } - }); - - ajax.path('good').done(function (value, textStatus, jqXHR) { - expect(jqXHR.AjaxData.status).toBe(0); - - ajax.path('bad').done(function (value, textStatus, jqXHR) { - expect(jqXHR.AjaxData.status).toBe(-1); - done(); - }); - }); - }); - - describe("ajax.objectify", function() { - - var $form = $("
    " + - "