mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-08-30 05:00:51 +08:00
Compare commits
254 commits
df2352419e
...
bde2eb8fbe
Author | SHA1 | Date | |
---|---|---|---|
|
bde2eb8fbe | ||
|
af71409850 | ||
|
c8ae55c6aa | ||
|
9d53b4ecf7 | ||
|
9c688efbeb | ||
|
3b80ec8333 | ||
|
54980aff73 | ||
|
8e8ad4ff28 | ||
|
d221544442 | ||
|
7905fe29ad | ||
|
46eeeb0b36 | ||
|
11ef14b13c | ||
|
6856448c63 | ||
|
1c2d7e032a | ||
|
d1afbe4a46 | ||
|
2925b73430 | ||
|
224900c6a4 | ||
|
720acca8a5 | ||
|
ddb0ae3b11 | ||
|
4c9ca19ec8 | ||
|
e2fb54c7a9 | ||
|
060a86f5c9 | ||
|
4faef951de | ||
|
2ab3b5ef54 | ||
|
fef445c928 | ||
|
7453207e17 | ||
|
1c2403092b | ||
|
b32d4eec46 | ||
|
c92ae6bca2 | ||
|
71472084de | ||
|
8aa1948ef9 | ||
|
221786087a | ||
|
0535faad10 | ||
|
f6b26a33ac | ||
|
88d7fc86c0 | ||
|
4e949b0733 | ||
|
e3549abd8d | ||
|
d372194d64 | ||
|
b1c1c23d91 | ||
|
27412ebadd | ||
|
e3d8cf0b8a | ||
|
184b5d1caa | ||
|
49f4c5b162 | ||
|
0572f674ca | ||
|
671bfb5e3a | ||
|
6ebda200b7 | ||
|
6b84fa00f7 | ||
|
f1433f94e8 | ||
|
63426a67f3 | ||
|
d84a7dd5bb | ||
|
56283c6afb | ||
|
8d5b2b7930 | ||
|
619a2468df | ||
|
ea88086170 | ||
|
362cb40e30 | ||
|
3d7654b2ea | ||
|
ef86785d43 | ||
|
1179a17ae3 | ||
|
628c83b7b9 | ||
|
95e85ec51c | ||
|
63ecb23039 | ||
|
e8c01c216c | ||
|
6d926b9dcc | ||
|
0d9a40b851 | ||
|
e2402ccf97 | ||
|
5642c6ec0a | ||
|
7efb0dfcf1 | ||
|
9443aecfaf | ||
|
3467d39eca | ||
|
0ece1fb9b2 | ||
|
3f3c43ed2e | ||
|
728ea64b0c | ||
|
bc33c726f2 | ||
|
5c3afb574a | ||
|
e04761028d | ||
|
9c0bc66369 | ||
|
40f08f4cfc | ||
|
9bd47e8948 | ||
|
0456f5bbbd | ||
|
714c42aafc | ||
|
527f414378 | ||
|
24009daa16 | ||
|
249bd383db | ||
|
41f8f1c0c8 | ||
|
6e81a4cb62 | ||
|
5053adf8d8 | ||
|
1dcf6884c0 | ||
|
804f210f1f | ||
|
9d6d36ee1d | ||
|
5224cd46e3 | ||
|
84f926eafa | ||
|
f0ab438208 | ||
|
e2839f63f6 | ||
|
4c59a81e22 | ||
|
efb5c4afd3 | ||
|
afd39b28df | ||
|
0d3eddfe3d | ||
|
1ad92bb26d | ||
|
fbd7d843ff | ||
|
9ed0c49bc9 | ||
|
dad1d4bb35 | ||
|
2468f4d918 | ||
|
2ec6daca38 | ||
|
f93cfaa3e1 | ||
|
522e5a05f8 | ||
|
e1c8b223d2 | ||
|
bb0fc025e0 | ||
|
b8a979fc5f | ||
|
f3598eb1da | ||
|
64c140ab23 | ||
|
0ed05ac1ea | ||
|
03f68dc545 | ||
|
0d1fdb11e4 | ||
|
38f7355db1 | ||
|
f412c507e5 | ||
|
8e1307cae6 | ||
|
a3313148eb | ||
|
0eb932a73e | ||
|
ca86cb83ae | ||
|
4a985fcb2c | ||
|
f42721fc86 | ||
|
638ea5e141 | ||
|
e52866bae0 | ||
|
ea1a9a0951 | ||
|
af18a7bcdd | ||
|
7c8532da62 | ||
|
0b6046ad73 | ||
|
95e579525e | ||
|
ff38eb06ec | ||
|
4f64b4fa0b | ||
|
5e1148bd0d | ||
|
22a207913b | ||
|
206804cab0 | ||
|
70271d53b4 | ||
|
c48f3e6d2a | ||
|
9bf1042a01 | ||
|
f0e88a65d8 | ||
|
d975a552a2 | ||
|
1fdff2c44e | ||
|
05e24ea0a9 | ||
|
d7a45138ff | ||
|
f32c013677 | ||
|
cdf43b5023 | ||
|
b97da8dda0 | ||
|
3587074bab | ||
|
7e43288f74 | ||
|
0108779972 | ||
|
96c7f8a6e9 | ||
|
fc9c350e80 | ||
|
3be262a1f4 | ||
|
80b4969555 | ||
|
1a4697a31b | ||
|
31e46a8e17 | ||
|
8a48732966 | ||
|
b631692bc6 | ||
|
4a549f6625 | ||
|
425e4c5ecc | ||
|
d62bbae893 | ||
|
05ba1d49eb | ||
|
14cf824a13 | ||
|
e2a19b025d | ||
|
fd87f93673 | ||
|
a1902902a8 | ||
|
37a465ca89 | ||
|
bd51ff22aa | ||
|
8db2078d5a | ||
|
2c4c2e0eac | ||
|
11741da4c0 | ||
|
392bc75d6d | ||
|
094263a928 | ||
|
69765ed47b | ||
|
09ef2befd7 | ||
|
f106645513 | ||
|
d8dbe206d2 | ||
|
e75d7085e0 | ||
|
0b75c7fab8 | ||
|
1062e548f2 | ||
|
3c4114f84a | ||
|
bdaa16f3b8 | ||
|
9cfd827e27 | ||
|
7835222484 | ||
|
4fcefe3773 | ||
|
28adbcd649 | ||
|
efe753de42 | ||
|
416ce86973 | ||
|
f3c3cac111 | ||
|
70336ea458 | ||
|
6642e7d208 | ||
|
41344aa57d | ||
|
25ad8b4b9c | ||
|
0385aad301 | ||
|
33b27e5ee4 | ||
|
546a775c49 | ||
|
ecb46a9ec7 | ||
|
c4db1ac53a | ||
|
8fccfd637f | ||
|
086fe17983 | ||
|
f1ed2233f3 | ||
|
521099b16d | ||
|
038ee9821b | ||
|
576b70c3c4 | ||
|
ac2bfa13af | ||
|
6cccb0c973 | ||
|
749ffe0f76 | ||
|
5a2b079f80 | ||
|
0d265f5aa1 | ||
|
fbe13cb7dd | ||
|
06c000b42b | ||
|
57e36ed954 | ||
|
450e4eb6aa | ||
|
fff4f5bb84 | ||
|
86696e91b5 | ||
|
bea875a83b | ||
|
efed7b793a | ||
|
c9795e8b4d | ||
|
7973fd433e | ||
|
0fc54d1df5 | ||
|
4e93aca57a | ||
|
e3eee0970d | ||
|
3001245c3b | ||
|
bb04e0ebe8 | ||
|
0be7304b11 | ||
|
13f8a63e8f | ||
|
fadd2f5b40 | ||
|
3ba91e8f44 | ||
|
bd9343c893 | ||
|
fb35981e49 | ||
|
7744355751 | ||
|
b0e9d8fb2c | ||
|
709e014db4 | ||
|
579f9989c0 | ||
|
95239b51ae | ||
|
b483115883 | ||
|
238ebc0949 | ||
|
86cae6ca4a | ||
|
943a0d197c | ||
|
235a9f45cf | ||
|
1cf46c356d | ||
|
e713abfd75 | ||
|
0caa74c021 | ||
|
30b7a592c5 | ||
|
6c6a047a68 | ||
|
8d34d34517 | ||
|
fa33db8191 | ||
|
dc850fca7d | ||
|
7dd40dfeec | ||
|
2f625873f8 | ||
|
1203d6e8c5 | ||
|
3e84cd9e6c | ||
|
98ceefd296 | ||
|
7bcc18bdc1 | ||
|
676306f793 | ||
|
41f3cd0a61 | ||
|
535f5f2d96 |
335 changed files with 6293 additions and 2528 deletions
160
.github/scripts/playground-comment.js
vendored
Normal file
160
.github/scripts/playground-comment.js
vendored
Normal file
|
@ -0,0 +1,160 @@
|
|||
const generateWordpressPlaygroundBlueprint = (runId, prNumber, artifactName) => {
|
||||
const defaultSchema = {
|
||||
landingPage: '/wp-admin/admin.php?page=wc-settings&tab=advanced§ion=blueprint&activate-multi=true',
|
||||
|
||||
preferredVersions: {
|
||||
php: '8.0',
|
||||
wp: 'latest',
|
||||
},
|
||||
|
||||
phpExtensionBundles: ['kitchen-sink'],
|
||||
|
||||
// Enable networking for API calls and external connections
|
||||
features: {
|
||||
networking: true
|
||||
},
|
||||
|
||||
steps: [
|
||||
// Step 1: Install and activate WooCommerce
|
||||
{
|
||||
step: 'installPlugin',
|
||||
pluginData: {
|
||||
resource: 'wordpress.org/plugins',
|
||||
slug: 'woocommerce'
|
||||
},
|
||||
options: {
|
||||
activate: true
|
||||
}
|
||||
},
|
||||
|
||||
// Step 2: Install PayPal Payments plugin from PR artifact
|
||||
{
|
||||
step: 'installPlugin',
|
||||
pluginZipFile: {
|
||||
resource: 'url',
|
||||
url: `https://playground.wordpress.net/plugin-proxy.php?org=woocommerce&repo=woocommerce-paypal-payments&workflow=PR%20Playground%20Demo&artifact=${artifactName}&pr=${prNumber}`,
|
||||
},
|
||||
options: {
|
||||
activate: true,
|
||||
},
|
||||
},
|
||||
|
||||
// Step 3: Skip WooCommerce onboarding wizard
|
||||
{
|
||||
step: 'setSiteOptions',
|
||||
options: {
|
||||
woocommerce_onboarding_profile: {
|
||||
skipped: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// Step 4: Enable Coming Soon mode
|
||||
{
|
||||
step: 'setSiteOptions',
|
||||
options: {
|
||||
woocommerce_coming_soon: 'yes',
|
||||
},
|
||||
},
|
||||
|
||||
// Step 5: Set up admin user login
|
||||
{
|
||||
step: 'login',
|
||||
username: 'admin',
|
||||
password: 'password',
|
||||
},
|
||||
],
|
||||
|
||||
// Initialize empty plugins array (can be extended later)
|
||||
plugins: [],
|
||||
};
|
||||
|
||||
return defaultSchema;
|
||||
};
|
||||
|
||||
async function run({ github, context, core }) {
|
||||
try {
|
||||
const commentInfo = {
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.issue.number,
|
||||
};
|
||||
|
||||
// Validate required environment variables
|
||||
if (!process.env.PLUGIN_VERSION || !process.env.ARTIFACT_NAME) {
|
||||
core.setFailed('Missing required environment variables: PLUGIN_VERSION or ARTIFACT_NAME');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for existing playground comment to update instead of creating duplicate
|
||||
const comments = await github.rest.issues.listComments(commentInfo);
|
||||
|
||||
const existingComment = comments.data.find(comment =>
|
||||
comment.user.type === 'Bot' &&
|
||||
comment.body.includes('Test using WordPress Playground')
|
||||
);
|
||||
|
||||
const defaultSchema = generateWordpressPlaygroundBlueprint(
|
||||
context.runId,
|
||||
context.issue.number,
|
||||
process.env.ARTIFACT_NAME
|
||||
);
|
||||
|
||||
const url = `https://playground.wordpress.net/#${JSON.stringify(defaultSchema)}`;
|
||||
|
||||
const body = `## Test using WordPress Playground
|
||||
The changes in this pull request can be previewed and tested using a [WordPress Playground](https://developer.wordpress.org/playground/) instance.
|
||||
[WordPress Playground](https://developer.wordpress.org/playground/) is an experimental project that creates a full WordPress instance entirely within the browser.
|
||||
|
||||
**🔗 [Test this pull request with WordPress Playground](${url})**
|
||||
|
||||
### What's included:
|
||||
- ✅ WordPress (latest)
|
||||
- ✅ WooCommerce (latest)
|
||||
- ✅ PayPal Payments plugin v${process.env.PLUGIN_VERSION} (built from this PR)
|
||||
|
||||
### Login credentials:
|
||||
- **Username:** \`admin\`
|
||||
- **Password:** \`password\`
|
||||
|
||||
### Plugin Details:
|
||||
- **Version:** ${process.env.PLUGIN_VERSION}
|
||||
- **Commit:** ${context.payload.pull_request.head.sha}
|
||||
- **Artifact:** ${process.env.ARTIFACT_NAME}
|
||||
|
||||
> 💡 The demo environment resets each time you refresh. Perfect for testing!
|
||||
>
|
||||
> 🔄 This link updates automatically with each new commit to the PR.
|
||||
>
|
||||
> ⚠️ This URL is valid for 30 days from when this comment was last updated.
|
||||
|
||||
---
|
||||
<sub>🤖 Auto-generated for commit ${context.payload.pull_request.head.sha} • Last updated: ${new Date().toISOString()}</sub>`;
|
||||
|
||||
if (existingComment) {
|
||||
// Update existing comment
|
||||
await github.rest.issues.updateComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
comment_id: existingComment.id,
|
||||
body: body
|
||||
});
|
||||
|
||||
core.info(`Successfully updated existing playground comment #${existingComment.id} on PR #${context.issue.number}`);
|
||||
} else {
|
||||
// Create new comment
|
||||
await github.rest.issues.createComment({
|
||||
...commentInfo,
|
||||
body: body
|
||||
});
|
||||
|
||||
core.info(`Successfully created new playground comment on PR #${context.issue.number}`);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
core.setFailed(`Failed to create/update playground comment: ${error.message}`);
|
||||
core.error(`Error details: ${error.stack}`);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { run };
|
163
.github/workflows/pr-playground-demo.yml
vendored
Normal file
163
.github/workflows/pr-playground-demo.yml
vendored
Normal file
|
@ -0,0 +1,163 @@
|
|||
name: PR Playground Demo
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
paths:
|
||||
- "src/**"
|
||||
- "assets/**"
|
||||
- "modules/**"
|
||||
- "package.json"
|
||||
- "composer.json"
|
||||
push:
|
||||
paths:
|
||||
- "src/**"
|
||||
- "assets/**"
|
||||
- "modules/**"
|
||||
- "package.json"
|
||||
- "composer.json"
|
||||
|
||||
# Cancels all previous workflow runs for pull requests that have not completed.
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.sha }}
|
||||
cancel-in-progress: true
|
||||
|
||||
# Disable permissions for all available scopes by default.
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
prepare_version:
|
||||
runs-on: ubuntu-latest
|
||||
# Only run for the main repository, not forks
|
||||
if: github.repository == 'woocommerce/woocommerce-paypal-payments' && github.event_name == 'pull_request'
|
||||
outputs:
|
||||
artifact_name: ${{ steps.version.outputs.artifact_name }}
|
||||
plugin_version: ${{ steps.version.outputs.plugin_version }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set plugin version and artifact name
|
||||
id: version
|
||||
run: |
|
||||
BASE_VERSION=$(sed -nE '/Version:/s/.* ([0-9.]+).*/\1/p' woocommerce-paypal-payments.php)
|
||||
VERSUFFIX="${GITHUB_RUN_ID}-g$(git rev-parse --short HEAD)"
|
||||
PR_VERSION="${BASE_VERSION}-pr${{ github.event.pull_request.number }}-${VERSUFFIX}"
|
||||
ARTIFACT_NAME="woocommerce-paypal-payments-${PR_VERSION}"
|
||||
echo "plugin_version=$PR_VERSION" >> $GITHUB_OUTPUT
|
||||
echo "artifact_name=$ARTIFACT_NAME" >> $GITHUB_OUTPUT
|
||||
|
||||
build_plugin:
|
||||
needs: prepare_version
|
||||
uses: inpsyde/reusable-workflows/.github/workflows/build-plugin-archive.yml@a9af34f34e95cbe18703198c7e972e97ebcd7473
|
||||
with:
|
||||
PHP_VERSION: 7.4
|
||||
NODE_VERSION: 22
|
||||
PLUGIN_MAIN_FILE: ./woocommerce-paypal-payments.php
|
||||
PLUGIN_VERSION: ${{ needs.prepare_version.outputs.plugin_version }}
|
||||
PLUGIN_FOLDER_NAME: woocommerce-paypal-payments
|
||||
ARCHIVE_NAME: ${{ needs.prepare_version.outputs.artifact_name }}
|
||||
COMPILE_ASSETS_ARGS: "-vv --env=root"
|
||||
|
||||
create_archive:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [prepare_version, build_plugin]
|
||||
outputs:
|
||||
artifact_name: ${{ needs.prepare_version.outputs.artifact_name }}
|
||||
plugin_version: ${{ needs.prepare_version.outputs.plugin_version }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Save PR details
|
||||
run: |
|
||||
mkdir -p ./pr
|
||||
echo "${{ github.event.pull_request.number }}" > ./pr/NR
|
||||
echo "${{ needs.prepare_version.outputs.plugin_version }}" > ./pr/VERSION
|
||||
echo "${{ needs.prepare_version.outputs.artifact_name }}" > ./pr/ARTIFACT
|
||||
|
||||
- name: Upload PR number
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pr-details
|
||||
path: pr/
|
||||
|
||||
playground_demo:
|
||||
name: Comment on PR with Playground details
|
||||
runs-on: ubuntu-latest
|
||||
needs: create_archive
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
# Only run for pull requests in the main repository
|
||||
if: github.repository == 'woocommerce/woocommerce-paypal-payments' && github.event_name == 'pull_request'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Download PR details artifact
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const artifacts = await github.rest.actions.listWorkflowRunArtifacts({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
run_id: context.runId,
|
||||
});
|
||||
|
||||
const matchArtifact = artifacts.data.artifacts.filter((artifact) => {
|
||||
return artifact.name === 'pr-details'
|
||||
})[0];
|
||||
|
||||
if (!matchArtifact) {
|
||||
core.setFailed('No pr-details artifact found!');
|
||||
return;
|
||||
}
|
||||
|
||||
const download = await github.rest.actions.downloadArtifact({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
artifact_id: matchArtifact.id,
|
||||
archive_format: 'zip',
|
||||
});
|
||||
|
||||
const fs = require('fs');
|
||||
fs.writeFileSync('${{github.workspace}}/pr-details.zip', Buffer.from(download.data));
|
||||
|
||||
- name: Unzip PR details
|
||||
run: unzip pr-details.zip
|
||||
|
||||
- name: Create or update PR playground comment
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const fs = require('fs');
|
||||
|
||||
const pr_number = fs.readFileSync('./NR', 'utf8').trim();
|
||||
const plugin_version = fs.readFileSync('./VERSION', 'utf8').trim();
|
||||
const artifact_name = fs.readFileSync('./ARTIFACT', 'utf8').trim();
|
||||
|
||||
// Load the comment script
|
||||
const script = require('./.github/scripts/playground-comment.js');
|
||||
|
||||
// Set environment variables for the script
|
||||
process.env.PLUGIN_VERSION = plugin_version;
|
||||
process.env.ARTIFACT_NAME = artifact_name;
|
||||
|
||||
const updatedContext = {
|
||||
repo: {
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo
|
||||
},
|
||||
issue: {
|
||||
number: parseInt(pr_number, 10)
|
||||
},
|
||||
runId: context.runId,
|
||||
payload: {
|
||||
pull_request: {
|
||||
number: parseInt(pr_number, 10),
|
||||
head: {
|
||||
sha: context.sha
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
await script.run({ github, context: updatedContext, core });
|
82
README.md
82
README.md
|
@ -52,26 +52,56 @@ Visit our [official documentation](https://woocommerce.com/document/woocommerce-
|
|||
|
||||
## Development
|
||||
|
||||
### Install dependencies & build
|
||||
### Setup using DDEV (recommended)
|
||||
|
||||
You can install WooCommerce PayPal Payments locally using the dev environment of your preference, or you can use the DDEV setup provided in this repository. Which includes WordPress, WooCommerce and all development tools.
|
||||
|
||||
To set up the DDEV environment, follow these steps:
|
||||
|
||||
0. Install Docker and [DDEV](https://ddev.readthedocs.io/en/stable/).
|
||||
1. Edit the [configuration](https://docs.ddev.com/en/stable/users/configuration/config/#managing-configuration) in the [`.ddev/config.yml`](.ddev/config.yaml) file if needed.
|
||||
2. `$ ddev setup` to setup and orchestrate the plugin, WooCommerce and WordPress
|
||||
3. Open https://woocommerce-paypal-payments.ddev.site
|
||||
|
||||
Use `$ ddev reset` for reinstallation (will destroy all site data).
|
||||
You may also need `$ ddev restart` to apply the config changes.
|
||||
|
||||
#### Running tests and other tasks in the DDEV environment
|
||||
|
||||
Tests and code style:
|
||||
- `$ yarn ddev:unit-tests`
|
||||
- `$ yarn ddev:lint`
|
||||
- `$ yarn ddev:fix-lint`
|
||||
- `$ yarn ddev:lint-js`
|
||||
|
||||
See [package.json](/package.json) for other useful commands.
|
||||
|
||||
For debugging, see [the DDEV docs](https://ddev.readthedocs.io/en/stable/users/step-debugging/).
|
||||
Enable xdebug via `$ ddev xdebug enable`, and press `Start Listening for PHP Debug Connections` in PHPStorm.
|
||||
After creating the server in the PHPStorm dialog, you need to set the local project path for the server plugin path.
|
||||
Check [this article](https://docs.ddev.com/en/stable/users/debugging-profiling/step-debugging/#phpstorm-debugging-setup) for a detailed guide.
|
||||
|
||||
## Setup in other environments
|
||||
|
||||
#### Install dependencies & build
|
||||
|
||||
- `$ composer install`
|
||||
- `$ yarn install`
|
||||
|
||||
Optionally, change the `PAYPAL_INTEGRATION_DATE` constant to `gmdate( 'Y-m-d' )` to run the latest PayPal JavaScript SDK
|
||||
|
||||
### Unit tests and code style
|
||||
#### Unit tests and code style
|
||||
|
||||
1. `$ composer install`
|
||||
2. `$ ./vendor/bin/phpunit`
|
||||
3. `$ ./vendor/bin/phpcs`
|
||||
4. `$ ./vendor/bin/psalm`
|
||||
5. `$ wp-scripts lint-js`
|
||||
6. `$ yarn run test:unit-js` - Ensure node version is `18` or above
|
||||
1. `$ ./vendor/bin/phpunit`
|
||||
2. `$ ./vendor/bin/phpcs`
|
||||
3. `$ ./vendor/bin/psalm`
|
||||
4. `$ yarn run lint-js`
|
||||
5. `$ yarn run test:unit-js` - Ensure node version is `18` or above
|
||||
|
||||
### Building a release package
|
||||
|
||||
If you want to build a release package
|
||||
(that can be used for deploying a new version on wordpress.org or manual installation on a WP website via ZIP uploading),
|
||||
(that can be used for deploying a new version on wordpress.org or manual installation on a WordPress website via ZIP uploading),
|
||||
follow these steps:
|
||||
|
||||
1. Clone the repository and `cd` into it.
|
||||
|
@ -88,38 +118,6 @@ or if using the DDEV setup:
|
|||
$ yarn run ddev:build-package
|
||||
```
|
||||
|
||||
## Setup
|
||||
|
||||
You can install WooCommerce PayPal Payments locally using the dev environment of your preference, or you can use the DDEV setup provided in this repository which includes WP, WC and all developments tools.
|
||||
|
||||
To set up the DDEV environment, follow these steps:
|
||||
|
||||
0. Install Docker and [DDEV](https://ddev.readthedocs.io/en/stable/).
|
||||
1. Edit the configuration in the [`.ddev/config.yml`](.ddev/config.yaml) file if needed.
|
||||
2. `$ ddev start`
|
||||
3. `$ ddev orchestrate` to install WP/WC.
|
||||
4. Open https://wc-pp.ddev.site
|
||||
|
||||
Use `$ ddev orchestrate -f` for reinstallation (will destroy all site data).
|
||||
You may also need `$ ddev restart` to apply the config changes.
|
||||
|
||||
### Running tests and other tasks in the DDEV environment
|
||||
|
||||
Tests and code style:
|
||||
- `$ yarn ddev:test`
|
||||
- `$ yarn ddev:lint`
|
||||
- `$ yarn ddev:fix-lint`
|
||||
- `$ yarn ddev:lint-js`
|
||||
|
||||
See [package.json](/package.json) for other useful commands.
|
||||
|
||||
For debugging, see [the DDEV docs](https://ddev.readthedocs.io/en/stable/users/step-debugging/).
|
||||
Enable xdebug via `$ ddev xdebug`, and press `Start Listening for PHP Debug Connections` in PHPStorm.
|
||||
After creating the server in the PHPStorm dialog, you need to set the local project path for the server plugin path.
|
||||
It should look [like this](https://i.imgur.com/ofsF1Mc.png).
|
||||
|
||||
See [tests/playwright](tests/playwright) for e2e (browser-based) tests.
|
||||
|
||||
## Test account setup
|
||||
|
||||
You will need a PayPal sandbox merchant and customer accounts to configure the plugin and make test purchases with it.
|
||||
|
@ -133,7 +131,7 @@ For testing webhooks locally, follow these steps to set up ngrok:
|
|||
0. Install [ngrok](https://ngrok.com/).
|
||||
|
||||
1.
|
||||
- If using DDEV, run our wrapper Bash script which will start `ddev share` and replace the URLs in the WP database:
|
||||
- If using DDEV, run our wrapper Bash script which will start `ddev share` and replace the URLs in the WordPress database:
|
||||
```
|
||||
$ .ddev/bin/share
|
||||
```
|
||||
|
|
|
@ -17,6 +17,8 @@ use RuntimeException;
|
|||
use WC_Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
||||
use WooCommerce\PayPalCommerce\OrderTracking\Endpoint\OrderTrackingEndpoint;
|
||||
use WooCommerce\PayPalCommerce\OrderTracking\Shipment\ShipmentFactoryInterface;
|
||||
use WooCommerce\PayPalCommerce\PPCP;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\RefundFeesUpdater;
|
||||
|
@ -159,3 +161,53 @@ function ppcp_update_order_refund_fees( WC_Order $wc_order ): void {
|
|||
assert( $updater instanceof RefundFeesUpdater );
|
||||
$updater->update( $wc_order );
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates or updates PayPal order tracking information for a WooCommerce order.
|
||||
*
|
||||
* Retrieves the PayPal capture ID associated with the given WooCommerce order,
|
||||
* creates a shipment instance, and sends it to the PayPal Order Tracking API.
|
||||
* If tracking information for the given tracking number already exists, it will
|
||||
* be updated; otherwise, it will be added as new tracking information.
|
||||
*
|
||||
* @param WC_Order $wc_order WooCommerce order instance to attach tracking to.
|
||||
* @param string $tracking_number Tracking number provided by the carrier.
|
||||
* @param string $carrier Name of the shipping carrier (must be PayPal-approved).
|
||||
* @param string $status Shipment status (must be PayPal-approved). Defaults to 'SHIPPED'.
|
||||
*
|
||||
* @see https://developer.paypal.com/docs/tracking/reference/carriers/ List of PayPal-approved carriers.
|
||||
* @see https://developer.paypal.com/docs/tracking/reference/shipping-status/ List of PayPal-approved shipment statuses.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function ppcp_create_order_tracking( WC_Order $wc_order, string $tracking_number, string $carrier, string $status = 'SHIPPED' ): void {
|
||||
$shipment_factory = PPCP::container()->get( 'order-tracking.shipment.factory' );
|
||||
assert( $shipment_factory instanceof ShipmentFactoryInterface );
|
||||
|
||||
$endpoint = PPCP::container()->get( 'order-tracking.endpoint.controller' );
|
||||
assert( $endpoint instanceof OrderTrackingEndpoint );
|
||||
|
||||
$paypal_order = ppcp_get_paypal_order( $wc_order );
|
||||
$capture_id = $endpoint->get_paypal_order_transaction_id( $paypal_order );
|
||||
if ( is_null( $capture_id ) ) {
|
||||
throw new RuntimeException( 'Could not retrieve transaction ID from PayPal order' );
|
||||
}
|
||||
|
||||
$wc_order_id = $wc_order->get_id();
|
||||
|
||||
$ppcp_shipment = $shipment_factory->create_shipment(
|
||||
$wc_order_id,
|
||||
$capture_id,
|
||||
$tracking_number,
|
||||
$status,
|
||||
'OTHER',
|
||||
$carrier,
|
||||
array()
|
||||
);
|
||||
|
||||
$tracking_information = $endpoint->get_tracking_information( $wc_order_id, $tracking_number );
|
||||
|
||||
$tracking_information
|
||||
? $endpoint->update_tracking_information( $ppcp_shipment, $wc_order_id )
|
||||
: $endpoint->add_tracking_information( $ppcp_shipment, $wc_order_id );
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ return function (
|
|||
$modules = apply_filters( 'woocommerce_paypal_payments_modules', $modules );
|
||||
|
||||
// Initialize plugin.
|
||||
$properties = PluginProperties::new( __FILE__ );
|
||||
$properties = PluginProperties::new( "$root_dir/woocommerce-paypal-payments.php" );
|
||||
$bootstrap = Package::new( $properties );
|
||||
|
||||
foreach ( $modules as $module ) {
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
*** Changelog ***
|
||||
|
||||
= 3.0.9 - 2025-07-31 =
|
||||
* Fix - Payment via "Proceed to PayPal" may result in a redirect loop #3570
|
||||
|
||||
= 3.0.8 - 2025-07-28 =
|
||||
* Enhancement - Migration from Legacy Settings to New Settings as opt-in via banner & button #3491
|
||||
* Enhancement - Replace call to `billing-agreements/agreement-tokens` with checking the capabilities for Reference Transactions #3495
|
||||
|
|
|
@ -20,13 +20,14 @@
|
|||
"container-interop/service-provider": "^0.4.0",
|
||||
"dhii/containers": "^0.1.0-alpha1",
|
||||
"inpsyde/modularity": "^1.7",
|
||||
"woocommerce/woocommerce-sniffs": "^0.1.0",
|
||||
"woocommerce/woocommerce-sniffs": "^1.0.0",
|
||||
"phpunit/phpunit": "^7.0 | ^8.0 | ^9.0",
|
||||
"brain/monkey": "^2.4",
|
||||
"php-stubs/wordpress-stubs": "^5.0@stable",
|
||||
"php-stubs/woocommerce-stubs": "^8.0@stable",
|
||||
"vimeo/psalm": "^4.0",
|
||||
"vlucas/phpdotenv": "^5"
|
||||
"vlucas/phpdotenv": "^5",
|
||||
"coenjacobs/mozart": "^0.7.1"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
|
585
composer.lock
generated
585
composer.lock
generated
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "2fa610ed883c0868838d3008b7127cbf",
|
||||
"content-hash": "fd277e5a82374078694b99b0e6aef07c",
|
||||
"packages": [
|
||||
{
|
||||
"name": "container-interop/service-provider",
|
||||
|
@ -904,6 +904,64 @@
|
|||
},
|
||||
"time": "2024-08-29T20:15:04+00:00"
|
||||
},
|
||||
{
|
||||
"name": "coenjacobs/mozart",
|
||||
"version": "0.7.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/coenjacobs/mozart.git",
|
||||
"reference": "dbcdeb992d20d9c8914eef090f9a0d684bb1102c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/coenjacobs/mozart/zipball/dbcdeb992d20d9c8914eef090f9a0d684bb1102c",
|
||||
"reference": "dbcdeb992d20d9c8914eef090f9a0d684bb1102c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"league/flysystem": "^1.0",
|
||||
"php": "^7.3|^8.0",
|
||||
"symfony/console": "^4|^5",
|
||||
"symfony/finder": "^4|^5"
|
||||
},
|
||||
"require-dev": {
|
||||
"mheap/phpunit-github-actions-printer": "^1.4",
|
||||
"phpunit/phpunit": "^8.5",
|
||||
"squizlabs/php_codesniffer": "^3.5",
|
||||
"vimeo/psalm": "^4.4"
|
||||
},
|
||||
"bin": [
|
||||
"bin/mozart"
|
||||
],
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"CoenJacobs\\Mozart\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Coen Jacobs",
|
||||
"email": "coenjacobs@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Composes all dependencies as a package inside a WordPress plugin",
|
||||
"support": {
|
||||
"issues": "https://github.com/coenjacobs/mozart/issues",
|
||||
"source": "https://github.com/coenjacobs/mozart/tree/0.7.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/coenjacobs",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2021-02-02T21:37:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/package-versions-deprecated",
|
||||
"version": "1.11.99.5",
|
||||
|
@ -1205,35 +1263,38 @@
|
|||
},
|
||||
{
|
||||
"name": "dealerdirect/phpcodesniffer-composer-installer",
|
||||
"version": "v0.7.2",
|
||||
"version": "v1.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer.git",
|
||||
"reference": "1c968e542d8843d7cd71de3c5c9c3ff3ad71a1db"
|
||||
"url": "https://github.com/PHPCSStandards/composer-installer.git",
|
||||
"reference": "e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/1c968e542d8843d7cd71de3c5c9c3ff3ad71a1db",
|
||||
"reference": "1c968e542d8843d7cd71de3c5c9c3ff3ad71a1db",
|
||||
"url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1",
|
||||
"reference": "e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"composer-plugin-api": "^1.0 || ^2.0",
|
||||
"php": ">=5.3",
|
||||
"composer-plugin-api": "^2.2",
|
||||
"php": ">=5.4",
|
||||
"squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"composer/composer": "*",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.3.1",
|
||||
"phpcompatibility/php-compatibility": "^9.0"
|
||||
"composer/composer": "^2.2",
|
||||
"ext-json": "*",
|
||||
"ext-zip": "*",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.4.0",
|
||||
"phpcompatibility/php-compatibility": "^9.0",
|
||||
"yoast/phpunit-polyfills": "^1.0"
|
||||
},
|
||||
"type": "composer-plugin",
|
||||
"extra": {
|
||||
"class": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin"
|
||||
"class": "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/"
|
||||
"PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
|
@ -1243,17 +1304,16 @@
|
|||
"authors": [
|
||||
{
|
||||
"name": "Franck Nijhof",
|
||||
"email": "franck.nijhof@dealerdirect.com",
|
||||
"homepage": "http://www.frenck.nl",
|
||||
"role": "Developer / IT Manager"
|
||||
"email": "opensource@frenck.dev",
|
||||
"homepage": "https://frenck.dev",
|
||||
"role": "Open source developer"
|
||||
},
|
||||
{
|
||||
"name": "Contributors",
|
||||
"homepage": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer/graphs/contributors"
|
||||
"homepage": "https://github.com/PHPCSStandards/composer-installer/graphs/contributors"
|
||||
}
|
||||
],
|
||||
"description": "PHP_CodeSniffer Standards Composer Installer Plugin",
|
||||
"homepage": "http://www.dealerdirect.com",
|
||||
"keywords": [
|
||||
"PHPCodeSniffer",
|
||||
"PHP_CodeSniffer",
|
||||
|
@ -1273,10 +1333,29 @@
|
|||
"tests"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/dealerdirect/phpcodesniffer-composer-installer/issues",
|
||||
"source": "https://github.com/dealerdirect/phpcodesniffer-composer-installer"
|
||||
"issues": "https://github.com/PHPCSStandards/composer-installer/issues",
|
||||
"security": "https://github.com/PHPCSStandards/composer-installer/security/policy",
|
||||
"source": "https://github.com/PHPCSStandards/composer-installer"
|
||||
},
|
||||
"time": "2022-02-04T12:51:07+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"
|
||||
},
|
||||
{
|
||||
"url": "https://thanks.dev/u/gh/phpcsstandards",
|
||||
"type": "thanks_dev"
|
||||
}
|
||||
],
|
||||
"time": "2025-07-17T20:45:56+00:00"
|
||||
},
|
||||
{
|
||||
"name": "dhii/collections-interface",
|
||||
|
@ -1888,6 +1967,156 @@
|
|||
},
|
||||
"time": "2025-05-09T12:13:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/flysystem",
|
||||
"version": "1.1.10",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/flysystem.git",
|
||||
"reference": "3239285c825c152bcc315fe0e87d6b55f5972ed1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/3239285c825c152bcc315fe0e87d6b55f5972ed1",
|
||||
"reference": "3239285c825c152bcc315fe0e87d6b55f5972ed1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-fileinfo": "*",
|
||||
"league/mime-type-detection": "^1.3",
|
||||
"php": "^7.2.5 || ^8.0"
|
||||
},
|
||||
"conflict": {
|
||||
"league/flysystem-sftp": "<1.0.6"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpspec/prophecy": "^1.11.1",
|
||||
"phpunit/phpunit": "^8.5.8"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-ftp": "Allows you to use FTP server storage",
|
||||
"ext-openssl": "Allows you to use FTPS server storage",
|
||||
"league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2",
|
||||
"league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3",
|
||||
"league/flysystem-azure": "Allows you to use Windows Azure Blob storage",
|
||||
"league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching",
|
||||
"league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem",
|
||||
"league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files",
|
||||
"league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib",
|
||||
"league/flysystem-webdav": "Allows you to use WebDAV storage",
|
||||
"league/flysystem-ziparchive": "Allows you to use ZipArchive adapter",
|
||||
"spatie/flysystem-dropbox": "Allows you to use Dropbox storage",
|
||||
"srmklive/flysystem-dropbox-v2": "Allows you to use Dropbox storage for PHP 5 applications"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.1-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"League\\Flysystem\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Frank de Jonge",
|
||||
"email": "info@frenky.net"
|
||||
}
|
||||
],
|
||||
"description": "Filesystem abstraction: Many filesystems, one API.",
|
||||
"keywords": [
|
||||
"Cloud Files",
|
||||
"WebDAV",
|
||||
"abstraction",
|
||||
"aws",
|
||||
"cloud",
|
||||
"copy.com",
|
||||
"dropbox",
|
||||
"file systems",
|
||||
"files",
|
||||
"filesystem",
|
||||
"filesystems",
|
||||
"ftp",
|
||||
"rackspace",
|
||||
"remote",
|
||||
"s3",
|
||||
"sftp",
|
||||
"storage"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/thephpleague/flysystem/issues",
|
||||
"source": "https://github.com/thephpleague/flysystem/tree/1.1.10"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://offset.earth/frankdejonge",
|
||||
"type": "other"
|
||||
}
|
||||
],
|
||||
"time": "2022-10-04T09:16:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/mime-type-detection",
|
||||
"version": "1.16.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/mime-type-detection.git",
|
||||
"reference": "2d6702ff215bf922936ccc1ad31007edc76451b9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/2d6702ff215bf922936ccc1ad31007edc76451b9",
|
||||
"reference": "2d6702ff215bf922936ccc1ad31007edc76451b9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-fileinfo": "*",
|
||||
"php": "^7.4 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^3.2",
|
||||
"phpstan/phpstan": "^0.12.68",
|
||||
"phpunit/phpunit": "^8.5.8 || ^9.3 || ^10.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"League\\MimeTypeDetection\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Frank de Jonge",
|
||||
"email": "info@frankdejonge.nl"
|
||||
}
|
||||
],
|
||||
"description": "Mime-type detection for Flysystem",
|
||||
"support": {
|
||||
"issues": "https://github.com/thephpleague/mime-type-detection/issues",
|
||||
"source": "https://github.com/thephpleague/mime-type-detection/tree/1.16.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/frankdejonge",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/league/flysystem",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-09-21T08:32:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "mockery/mockery",
|
||||
"version": "1.6.12",
|
||||
|
@ -1973,16 +2202,16 @@
|
|||
},
|
||||
{
|
||||
"name": "myclabs/deep-copy",
|
||||
"version": "1.13.1",
|
||||
"version": "1.13.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/myclabs/DeepCopy.git",
|
||||
"reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c"
|
||||
"reference": "faed855a7b5f4d4637717c2b3863e277116beb36"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/1720ddd719e16cf0db4eb1c6eca108031636d46c",
|
||||
"reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c",
|
||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/faed855a7b5f4d4637717c2b3863e277116beb36",
|
||||
"reference": "faed855a7b5f4d4637717c2b3863e277116beb36",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2021,7 +2250,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/myclabs/DeepCopy/issues",
|
||||
"source": "https://github.com/myclabs/DeepCopy/tree/1.13.1"
|
||||
"source": "https://github.com/myclabs/DeepCopy/tree/1.13.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -2029,7 +2258,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-04-29T12:36:36+00:00"
|
||||
"time": "2025-07-05T12:25:42+00:00"
|
||||
},
|
||||
{
|
||||
"name": "netresearch/jsonmapper",
|
||||
|
@ -2609,6 +2838,181 @@
|
|||
],
|
||||
"time": "2025-05-12T16:38:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpcsstandards/phpcsextra",
|
||||
"version": "1.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHPCSStandards/PHPCSExtra.git",
|
||||
"reference": "fa4b8d051e278072928e32d817456a7fdb57b6ca"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHPCSStandards/PHPCSExtra/zipball/fa4b8d051e278072928e32d817456a7fdb57b6ca",
|
||||
"reference": "fa4b8d051e278072928e32d817456a7fdb57b6ca",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.4",
|
||||
"phpcsstandards/phpcsutils": "^1.1.0",
|
||||
"squizlabs/php_codesniffer": "^3.13.0 || ^4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"php-parallel-lint/php-console-highlighter": "^1.0",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.4.0",
|
||||
"phpcsstandards/phpcsdevcs": "^1.1.6",
|
||||
"phpcsstandards/phpcsdevtools": "^1.2.1",
|
||||
"phpunit/phpunit": "^4.5 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4"
|
||||
},
|
||||
"type": "phpcodesniffer-standard",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-stable": "1.x-dev",
|
||||
"dev-develop": "1.x-dev"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"LGPL-3.0-or-later"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Juliette Reinders Folmer",
|
||||
"homepage": "https://github.com/jrfnl",
|
||||
"role": "lead"
|
||||
},
|
||||
{
|
||||
"name": "Contributors",
|
||||
"homepage": "https://github.com/PHPCSStandards/PHPCSExtra/graphs/contributors"
|
||||
}
|
||||
],
|
||||
"description": "A collection of sniffs and standards for use with PHP_CodeSniffer.",
|
||||
"keywords": [
|
||||
"PHP_CodeSniffer",
|
||||
"phpcbf",
|
||||
"phpcodesniffer-standard",
|
||||
"phpcs",
|
||||
"standards",
|
||||
"static analysis"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/PHPCSStandards/PHPCSExtra/issues",
|
||||
"security": "https://github.com/PHPCSStandards/PHPCSExtra/security/policy",
|
||||
"source": "https://github.com/PHPCSStandards/PHPCSExtra"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/PHPCSStandards",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/jrfnl",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://opencollective.com/php_codesniffer",
|
||||
"type": "open_collective"
|
||||
},
|
||||
{
|
||||
"url": "https://thanks.dev/u/gh/phpcsstandards",
|
||||
"type": "thanks_dev"
|
||||
}
|
||||
],
|
||||
"time": "2025-06-14T07:40:39+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpcsstandards/phpcsutils",
|
||||
"version": "1.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHPCSStandards/PHPCSUtils.git",
|
||||
"reference": "f7eb16f2fa4237d5db9e8fed8050239bee17a9bd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHPCSStandards/PHPCSUtils/zipball/f7eb16f2fa4237d5db9e8fed8050239bee17a9bd",
|
||||
"reference": "f7eb16f2fa4237d5db9e8fed8050239bee17a9bd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "^0.4.1 || ^0.5 || ^0.6.2 || ^0.7 || ^1.0",
|
||||
"php": ">=5.4",
|
||||
"squizlabs/php_codesniffer": "^3.13.0 || ^4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-filter": "*",
|
||||
"php-parallel-lint/php-console-highlighter": "^1.0",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.4.0",
|
||||
"phpcsstandards/phpcsdevcs": "^1.1.6",
|
||||
"yoast/phpunit-polyfills": "^1.1.0 || ^2.0.0 || ^3.0.0"
|
||||
},
|
||||
"type": "phpcodesniffer-standard",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-stable": "1.x-dev",
|
||||
"dev-develop": "1.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"PHPCSUtils/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"LGPL-3.0-or-later"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Juliette Reinders Folmer",
|
||||
"homepage": "https://github.com/jrfnl",
|
||||
"role": "lead"
|
||||
},
|
||||
{
|
||||
"name": "Contributors",
|
||||
"homepage": "https://github.com/PHPCSStandards/PHPCSUtils/graphs/contributors"
|
||||
}
|
||||
],
|
||||
"description": "A suite of utility functions for use with PHP_CodeSniffer",
|
||||
"homepage": "https://phpcsutils.com/",
|
||||
"keywords": [
|
||||
"PHP_CodeSniffer",
|
||||
"phpcbf",
|
||||
"phpcodesniffer-standard",
|
||||
"phpcs",
|
||||
"phpcs3",
|
||||
"phpcs4",
|
||||
"standards",
|
||||
"static analysis",
|
||||
"tokens",
|
||||
"utility"
|
||||
],
|
||||
"support": {
|
||||
"docs": "https://phpcsutils.com/",
|
||||
"issues": "https://github.com/PHPCSStandards/PHPCSUtils/issues",
|
||||
"security": "https://github.com/PHPCSStandards/PHPCSUtils/security/policy",
|
||||
"source": "https://github.com/PHPCSStandards/PHPCSUtils"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/PHPCSStandards",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/jrfnl",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://opencollective.com/php_codesniffer",
|
||||
"type": "open_collective"
|
||||
},
|
||||
{
|
||||
"url": "https://thanks.dev/u/gh/phpcsstandards",
|
||||
"type": "thanks_dev"
|
||||
}
|
||||
],
|
||||
"time": "2025-08-10T01:04:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/reflection-common",
|
||||
"version": "2.2.0",
|
||||
|
@ -4549,6 +4953,69 @@
|
|||
],
|
||||
"time": "2024-09-25T14:11:13+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v5.4.45",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
"reference": "63741784cd7b9967975eec610b256eed3ede022b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/63741784cd7b9967975eec610b256eed3ede022b",
|
||||
"reference": "63741784cd7b9967975eec610b256eed3ede022b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2.5",
|
||||
"symfony/deprecation-contracts": "^2.1|^3",
|
||||
"symfony/polyfill-php80": "^1.16"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Finder\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Finds files and directories via an intuitive fluent interface",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/finder/tree/v5.4.45"
|
||||
},
|
||||
"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": "2024-09-28T13:32:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
"version": "v1.32.0",
|
||||
|
@ -5466,74 +5933,77 @@
|
|||
},
|
||||
{
|
||||
"name": "woocommerce/woocommerce-sniffs",
|
||||
"version": "0.1.3",
|
||||
"version": "1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/woocommerce/woocommerce-sniffs.git",
|
||||
"reference": "4576d54595614d689bc4436acff8baaece3c5bb0"
|
||||
"reference": "3a65b917ff5ab5e65609e5dcb7bc62f9455bbef8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/woocommerce/woocommerce-sniffs/zipball/4576d54595614d689bc4436acff8baaece3c5bb0",
|
||||
"reference": "4576d54595614d689bc4436acff8baaece3c5bb0",
|
||||
"url": "https://api.github.com/repos/woocommerce/woocommerce-sniffs/zipball/3a65b917ff5ab5e65609e5dcb7bc62f9455bbef8",
|
||||
"reference": "3a65b917ff5ab5e65609e5dcb7bc62f9455bbef8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "^1.0.0",
|
||||
"php": ">=7.0",
|
||||
"phpcompatibility/phpcompatibility-wp": "^2.1.0",
|
||||
"wp-coding-standards/wpcs": "^2.3.0"
|
||||
"wp-coding-standards/wpcs": "^3.0.0"
|
||||
},
|
||||
"type": "phpcodesniffer-standard",
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Claudio Sanches",
|
||||
"email": "claudio@automattic.com"
|
||||
}
|
||||
],
|
||||
"description": "WooCommerce sniffs",
|
||||
"keywords": [
|
||||
"phpcs",
|
||||
"standards",
|
||||
"static analysis",
|
||||
"woocommerce",
|
||||
"wordpress"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/woocommerce/woocommerce-sniffs/issues",
|
||||
"source": "https://github.com/woocommerce/woocommerce-sniffs/tree/0.1.3"
|
||||
"source": "https://github.com/woocommerce/woocommerce-sniffs/tree/1.0.0"
|
||||
},
|
||||
"time": "2022-02-17T15:34:51+00:00"
|
||||
"time": "2023-09-29T13:52:33+00:00"
|
||||
},
|
||||
{
|
||||
"name": "wp-coding-standards/wpcs",
|
||||
"version": "2.3.0",
|
||||
"version": "3.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/WordPress/WordPress-Coding-Standards.git",
|
||||
"reference": "7da1894633f168fe244afc6de00d141f27517b62"
|
||||
"reference": "d2421de7cec3274ae622c22c744de9a62c7925af"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/7da1894633f168fe244afc6de00d141f27517b62",
|
||||
"reference": "7da1894633f168fe244afc6de00d141f27517b62",
|
||||
"url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/d2421de7cec3274ae622c22c744de9a62c7925af",
|
||||
"reference": "d2421de7cec3274ae622c22c744de9a62c7925af",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-filter": "*",
|
||||
"ext-libxml": "*",
|
||||
"ext-tokenizer": "*",
|
||||
"ext-xmlreader": "*",
|
||||
"php": ">=5.4",
|
||||
"squizlabs/php_codesniffer": "^3.3.1"
|
||||
"phpcsstandards/phpcsextra": "^1.4.0",
|
||||
"phpcsstandards/phpcsutils": "^1.1.0",
|
||||
"squizlabs/php_codesniffer": "^3.13.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "^0.5 || ^0.6",
|
||||
"php-parallel-lint/php-console-highlighter": "^1.0.0",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.4.0",
|
||||
"phpcompatibility/php-compatibility": "^9.0",
|
||||
"phpcsstandards/phpcsdevtools": "^1.0",
|
||||
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
|
||||
"phpcsstandards/phpcsdevtools": "^1.2.0",
|
||||
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0"
|
||||
},
|
||||
"suggest": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "^0.6 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically."
|
||||
"ext-iconv": "For improved results",
|
||||
"ext-mbstring": "For improved results"
|
||||
},
|
||||
"type": "phpcodesniffer-standard",
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
|
@ -5550,6 +6020,7 @@
|
|||
"keywords": [
|
||||
"phpcs",
|
||||
"standards",
|
||||
"static analysis",
|
||||
"wordpress"
|
||||
],
|
||||
"support": {
|
||||
|
@ -5557,14 +6028,20 @@
|
|||
"source": "https://github.com/WordPress/WordPress-Coding-Standards",
|
||||
"wiki": "https://github.com/WordPress/WordPress-Coding-Standards/wiki"
|
||||
},
|
||||
"time": "2020-05-13T23:57:56+00:00"
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://opencollective.com/php_codesniffer",
|
||||
"type": "custom"
|
||||
}
|
||||
],
|
||||
"time": "2025-07-24T20:08:31+00:00"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": {
|
||||
"php-stubs/wordpress-stubs": 0,
|
||||
"php-stubs/woocommerce-stubs": 0
|
||||
"php-stubs/woocommerce-stubs": 0,
|
||||
"php-stubs/wordpress-stubs": 0
|
||||
},
|
||||
"prefer-stable": true,
|
||||
"prefer-lowest": false,
|
||||
|
@ -5572,7 +6049,7 @@
|
|||
"php": "^7.4 | ^8.0",
|
||||
"ext-json": "*"
|
||||
},
|
||||
"platform-dev": [],
|
||||
"platform-dev": {},
|
||||
"platform-overrides": {
|
||||
"php": "7.4"
|
||||
},
|
||||
|
|
|
@ -64,6 +64,8 @@ class AliasingContainer implements ContainerInterface
|
|||
*/
|
||||
public function has($key)
|
||||
{
|
||||
$key = (string) $key;
|
||||
|
||||
return $this->inner->has($this->getInnerKey($key));
|
||||
}
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ class CachingContainer implements ContainerInterface
|
|||
throw new NotFoundException($this->__('Key "%1$s" not found in inner container', [$key]), 0, $e);
|
||||
} catch (Exception $e) {
|
||||
throw new ContainerException(
|
||||
$this->__('Could not retrieve value for key "%1$s from inner container', [$key]),
|
||||
$this->__('Could not retrieve value for key "%1$s" from inner container', [$key]),
|
||||
0,
|
||||
$e
|
||||
);
|
||||
|
|
|
@ -38,7 +38,8 @@ class CompositeCachingServiceProvider implements ServiceProviderInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @inheritDoc
|
||||
*
|
||||
* @psalm-suppress InvalidNullableReturnType
|
||||
* It isn't actually going to return null ever, because $factories will be filled during indexing.
|
||||
*/
|
||||
|
@ -56,7 +57,8 @@ class CompositeCachingServiceProvider implements ServiceProviderInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @inheritDoc
|
||||
*
|
||||
* @psalm-suppress InvalidNullableReturnType
|
||||
* It isn't actually going to return null ever, because $factories will be filled during indexing.
|
||||
*/
|
||||
|
@ -78,7 +80,7 @@ class CompositeCachingServiceProvider implements ServiceProviderInterface
|
|||
*
|
||||
* Caches them internally.
|
||||
*
|
||||
* @param iterable|ServiceProviderInterface[] $providers The providers to index.
|
||||
* @param iterable<ServiceProviderInterface> $providers The providers to index.
|
||||
*/
|
||||
protected function indexProviderDefinitions(iterable $providers): void
|
||||
{
|
||||
|
|
|
@ -89,6 +89,7 @@ class DelegatingContainer implements ContainerInterface
|
|||
public function has($id)
|
||||
{
|
||||
$services = $this->provider->getFactories();
|
||||
$id = (string) $id;
|
||||
|
||||
return array_key_exists($id, $services);
|
||||
}
|
||||
|
|
|
@ -84,7 +84,10 @@ class DeprefixingContainer implements ContainerInterface
|
|||
*/
|
||||
public function has($key)
|
||||
{
|
||||
return $this->inner->has($this->getInnerKey($key)) || (!$this->strict && $this->inner->has($key));
|
||||
$key = (string) $key;
|
||||
$realKey = $this->getInnerKey($key);
|
||||
|
||||
return $this->inner->has($realKey) || (!$this->strict && $this->inner->has($key));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,13 +5,13 @@ declare(strict_types=1);
|
|||
namespace WooCommerce\PayPalCommerce\Vendor\Dhii\Container;
|
||||
|
||||
use ArrayIterator;
|
||||
use Traversable;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Collection\WritableContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Collection\WritableMapInterface;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Container\Exception\NotFoundException;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Container\Util\StringTranslatingTrait;
|
||||
use IteratorAggregate;
|
||||
use RangeException;
|
||||
use Traversable;
|
||||
|
||||
/**
|
||||
* A simple mutable dictionary, i.e. an enumerable key-value map.
|
||||
|
@ -54,6 +54,8 @@ class Dictionary implements
|
|||
*/
|
||||
public function has($key)
|
||||
{
|
||||
$key = (string) $key;
|
||||
|
||||
$isHas = array_key_exists($key, $this->data);
|
||||
|
||||
return $isHas;
|
||||
|
|
|
@ -61,6 +61,8 @@ class FlashContainer implements
|
|||
*/
|
||||
public function has($key)
|
||||
{
|
||||
$key = (string) $key;
|
||||
|
||||
return array_key_exists($key, $this->flashData);
|
||||
}
|
||||
|
||||
|
|
|
@ -88,6 +88,8 @@ class HierarchyContainer implements ContainerInterface
|
|||
*/
|
||||
public function has($key)
|
||||
{
|
||||
$key = (string) $key;
|
||||
|
||||
return array_key_exists($key, $this->data);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,6 +85,8 @@ class MappingContainer implements ContainerInterface
|
|||
*/
|
||||
public function has($key)
|
||||
{
|
||||
$key = (string) $key;
|
||||
|
||||
return $this->inner->has($key);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,6 +80,8 @@ class MaskingContainer implements ContainerInterface
|
|||
*/
|
||||
public function has($key)
|
||||
{
|
||||
$key = (string) $key;
|
||||
|
||||
return $this->isExposed($key) && $this->inner->has($key);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ use WooCommerce\PayPalCommerce\Vendor\Dhii\Collection\WritableMapInterface;
|
|||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Container\Exception\ContainerException;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Container\Exception\NotFoundException;
|
||||
use IteratorAggregate;
|
||||
use Traversable;
|
||||
|
||||
/**
|
||||
* A container that does nothing.
|
||||
|
@ -92,7 +93,7 @@ class NoOpContainer implements
|
|||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getIterator()
|
||||
public function getIterator(): Traversable
|
||||
{
|
||||
return new ArrayIterator([]);
|
||||
}
|
||||
|
|
|
@ -127,6 +127,8 @@ class PathContainer implements ContainerInterface
|
|||
*/
|
||||
public function has($key)
|
||||
{
|
||||
$key = (string) $key;
|
||||
|
||||
/**
|
||||
* @psalm-suppress InvalidCatch
|
||||
* The base interface does not extend Throwable, but in fact everything that is possible
|
||||
|
|
|
@ -5,9 +5,12 @@ declare(strict_types=1);
|
|||
namespace WooCommerce\PayPalCommerce\Vendor\Dhii\Container;
|
||||
|
||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Collection\ContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Container\Exception\ContainerException;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Container\Exception\NotFoundException;
|
||||
use Exception;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface as PsrContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\NotFoundExceptionInterface;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* A container implementation that wraps around an inner container and prefixes its keys, requiring consumers to
|
||||
|
@ -89,11 +92,18 @@ class PrefixingContainer implements ContainerInterface
|
|||
*/
|
||||
public function has($key)
|
||||
{
|
||||
$key = (string) $key;
|
||||
if (!$this->isPrefixed($key) && $this->strict) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->inner->has($this->unprefix($key)) || (!$this->strict && $this->inner->has($key));
|
||||
try {
|
||||
$realKey = $this->unprefix($key);
|
||||
} catch (Exception $e) {
|
||||
throw new ContainerException(sprintf('Could not unprefix key "%1$s"', $key), 0, $e);
|
||||
}
|
||||
|
||||
return $this->inner->has($realKey) || (!$this->strict && $this->inner->has($key));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -108,7 +118,7 @@ class PrefixingContainer implements ContainerInterface
|
|||
protected function unprefix(string $key): string
|
||||
{
|
||||
return $this->isPrefixed($key)
|
||||
? substr($key, strlen($this->prefix))
|
||||
? $this->substring($key, strlen($this->prefix))
|
||||
: $key;
|
||||
}
|
||||
|
||||
|
@ -125,4 +135,35 @@ class PrefixingContainer implements ContainerInterface
|
|||
{
|
||||
return strlen($this->prefix) > 0 && strpos($key, $this->prefix) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts a substring from the specified string.
|
||||
*
|
||||
* @see substr()
|
||||
*
|
||||
* @param string $string The string to extract from.
|
||||
* @param int $offset The char position, at which to start extraction.
|
||||
* @param int|null $length The char position, at which to end extraction; unlimited if `null`.
|
||||
*
|
||||
* @return string The extracted substring.
|
||||
*
|
||||
* @throws RuntimeException If unable to extract.
|
||||
*/
|
||||
protected function substring(string $string, int $offset = 0, ?int $length = null): string
|
||||
{
|
||||
$length = $length ?? strlen($string) - $offset;
|
||||
$substring = substr($string, $offset, $length);
|
||||
if ($substring === false) {
|
||||
throw new RuntimeException(
|
||||
sprintf(
|
||||
'Could not extract substring starting at %1$d of length %2$s from string "%3$s"',
|
||||
$offset,
|
||||
$length ?: 'null',
|
||||
$string
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $substring;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -114,6 +114,8 @@ class SegmentingContainer implements ContainerInterface
|
|||
*/
|
||||
public function has($key)
|
||||
{
|
||||
$key = (string) $key;
|
||||
|
||||
return $this->inner->has($key);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,22 +5,22 @@ declare(strict_types=1);
|
|||
namespace WooCommerce\PayPalCommerce\Vendor\Dhii\Container;
|
||||
|
||||
use WooCommerce\PayPalCommerce\Vendor\Interop\Container\ServiceProviderInterface;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
|
||||
/**
|
||||
* A value object capable of providing services.
|
||||
*
|
||||
* @package Dhii\Di
|
||||
* @psalm-type Factory = callable(ContainerInterface): mixed
|
||||
* @psalm-type Extension = callable(ContainerInterface, mixed): mixed
|
||||
*/
|
||||
class ServiceProvider implements ServiceProviderInterface
|
||||
{
|
||||
/** @var callable[] */
|
||||
protected array $factories;
|
||||
/**
|
||||
* @var callable[]
|
||||
*/
|
||||
protected $factories;
|
||||
/**
|
||||
* @var callable[]
|
||||
*/
|
||||
protected $extensions;
|
||||
protected array $extensions;
|
||||
|
||||
/**
|
||||
* @param callable[] $factories A map of service name to service factory.
|
||||
|
|
|
@ -55,6 +55,7 @@ class SimpleCacheContainer implements
|
|||
*/
|
||||
public function has($id)
|
||||
{
|
||||
$id = (string) $id;
|
||||
$storage = $this->storage;
|
||||
|
||||
try {
|
||||
|
@ -77,7 +78,11 @@ class SimpleCacheContainer implements
|
|||
try {
|
||||
$storage->set($key, $value, $ttl);
|
||||
} catch (Exception $e) {
|
||||
throw new ContainerException(sprintf('Could not set key "%1$s" with value "%2$s"', $key, $value), 0, $e);
|
||||
throw new ContainerException(
|
||||
sprintf('Could not set key "%1$s" with value "%2$s"', $key, (string) $value),
|
||||
0,
|
||||
$e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,7 +110,7 @@ class SimpleCacheContainer implements
|
|||
try {
|
||||
$storage->clear();
|
||||
} catch (Exception $e) {
|
||||
throw new ContainerException(sprintf('Could not clear container'), 0, $e);
|
||||
throw new ContainerException('Could not clear container', 0, $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
121
lib/packages/Dhii/Container/TaggingServiceProvider.php
Normal file
121
lib/packages/Dhii/Container/TaggingServiceProvider.php
Normal file
|
@ -0,0 +1,121 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Vendor\Dhii\Container;
|
||||
|
||||
use WooCommerce\PayPalCommerce\Vendor\Interop\Container\ServiceProviderInterface;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use ReflectionException;
|
||||
use ReflectionFunction;
|
||||
use ReflectionObject;
|
||||
|
||||
/**
|
||||
* A service provider that detects tags in factory docBlocks, and exposes them as services.
|
||||
*
|
||||
* A service may have a docBlock. The docBlock may contain various docBlock tags, such as `@param` or `@return`.
|
||||
* This class will detect `@tag {tagname}` tags in service docBlocks. `tagname` may be anything that a service
|
||||
* key may be - they exist in the same namespace. In fact, a `tagname` corresponds to a service
|
||||
* that returns a list of tagged services. To retrieve them, just resolve the tagname as a service.
|
||||
*
|
||||
* For each unique `tagname` in factory docBlocks, this service provider will create an extension with
|
||||
* an identical name. This extension at resolution time will resolve each tagged service by key,
|
||||
* and add resulting services to the list it is extending. To ensure there's always a list to extend,
|
||||
* this service provider will also add a service with an identical name, which resolves to an empty list.
|
||||
* All such "tag" services are empty list in the beginning of their resolution, so it doesn't matter
|
||||
* if it gets overwritten by another module's identical empty list.
|
||||
*
|
||||
* @psalm-import-type Factory from ServiceProvider
|
||||
* @psalm-import-type Extension from ServiceProvider
|
||||
*/
|
||||
class TaggingServiceProvider implements ServiceProviderInterface
|
||||
{
|
||||
/** @var array<Factory> */
|
||||
protected array $factories;
|
||||
/** @var array<Extension> */
|
||||
protected array $extensions;
|
||||
|
||||
public function __construct(ServiceProviderInterface $inner)
|
||||
{
|
||||
$this->factories = $inner->getFactories();
|
||||
$this->extensions = $inner->getExtensions();
|
||||
$this->indexTags();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getFactories()
|
||||
{
|
||||
return $this->factories;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getExtensions()
|
||||
{
|
||||
return $this->extensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indexes tagged factories, and creates factories and extensions for tags.
|
||||
*
|
||||
* @throws ReflectionException If problem obtaining factory reflection.
|
||||
*/
|
||||
protected function indexTags(): void
|
||||
{
|
||||
$tags = [];
|
||||
|
||||
foreach ($this->factories as $serviceName => $factory) {
|
||||
if (is_string($factory)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$reflection = is_object($factory) && get_class($factory) === 'Closure'
|
||||
? new ReflectionFunction($factory)
|
||||
: new ReflectionObject($factory);
|
||||
$docBlock = $reflection->getDocComment();
|
||||
|
||||
// No docblock
|
||||
if ($docBlock === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$factoryTags = $this->getTagsFromDocBlock($docBlock);
|
||||
foreach ($factoryTags as $tag) {
|
||||
if (!isset($tags[$tag]) || !is_array($tags[$tag])) {
|
||||
$tags[$tag] = [];
|
||||
}
|
||||
$tags[$tag][] = $serviceName;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($tags as $tag => $taggedServiceNames) {
|
||||
$this->factories[$tag] = fn (): array => [];
|
||||
$this->extensions[$tag] = function (ContainerInterface $c, array $prev) use ($taggedServiceNames): array {
|
||||
return array_merge(
|
||||
$prev,
|
||||
array_map(fn (string $serviceName) => $c->get($serviceName), $taggedServiceNames)
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves tags names that are part of a docBlock.
|
||||
*
|
||||
* @link https://www.php.net/manual/en/reflectionclass.getdoccomment.php#118606
|
||||
*
|
||||
* @param string $docBlock The docBlock.
|
||||
*
|
||||
* @return array<string> A list of tag names.
|
||||
*/
|
||||
protected function getTagsFromDocBlock(string $docBlock): array
|
||||
{
|
||||
$regex = '#^\s*/?\**\s*(@tag\s*(?P<tags>[^\s]+))#m';
|
||||
preg_match_all($regex, $docBlock, $matches);
|
||||
|
||||
return $matches['tags'];
|
||||
}
|
||||
}
|
|
@ -27,6 +27,7 @@ trait StringTranslatingTrait
|
|||
*/
|
||||
protected function __(string $string, array $args = array(), $context = null): string
|
||||
{
|
||||
$context = (string) $context;
|
||||
$string = $this->_translate($string, $context);
|
||||
array_unshift($args, $string);
|
||||
return call_user_func_array('sprintf', $args);
|
||||
|
|
|
@ -1,52 +1,38 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Container;
|
||||
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerExceptionInterface;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
|
||||
/**
|
||||
* @phpstan-import-type Service from \WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ServiceModule
|
||||
* @phpstan-import-type ExtendingService from \WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ExtendingModule
|
||||
*/
|
||||
class ContainerConfigurator
|
||||
{
|
||||
/**
|
||||
* @var array<string, callable(ContainerInterface $container):mixed>
|
||||
*/
|
||||
private $services = [];
|
||||
/** @var array<string, Service> */
|
||||
private array $services = [];
|
||||
/** @var array<string, bool> */
|
||||
private array $factoryIds = [];
|
||||
private ServiceExtensions $extensions;
|
||||
private ?ContainerInterface $compiledContainer = null;
|
||||
/** @var ContainerInterface[] */
|
||||
private array $containers = [];
|
||||
|
||||
/**
|
||||
* @var array<string, bool>
|
||||
*/
|
||||
private $factoryIds = [];
|
||||
|
||||
/**
|
||||
* @var array<string, array<callable(mixed $service, ContainerInterface $container):mixed>>
|
||||
*/
|
||||
private $extensions = [];
|
||||
|
||||
/**
|
||||
* @var ContainerInterface[]
|
||||
*/
|
||||
private $containers = [];
|
||||
|
||||
/**
|
||||
* @var null|ContainerInterface
|
||||
*/
|
||||
private $compiledContainer;
|
||||
|
||||
/**
|
||||
* ContainerConfigurator constructor.
|
||||
*
|
||||
* @param ContainerInterface[] $containers
|
||||
*/
|
||||
public function __construct(array $containers = [])
|
||||
public function __construct(array $containers = [], ?ServiceExtensions $extensions = null)
|
||||
{
|
||||
array_map([$this, 'addContainer'], $containers);
|
||||
$this->extensions = $extensions ?? new ServiceExtensions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allowing to add child containers.
|
||||
*
|
||||
* @param ContainerInterface $container
|
||||
* @return void
|
||||
*/
|
||||
public function addContainer(ContainerInterface $container): void
|
||||
{
|
||||
|
@ -55,7 +41,7 @@ class ContainerConfigurator
|
|||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param callable(ContainerInterface $container):mixed $factory
|
||||
* @param Service $factory
|
||||
*/
|
||||
public function addFactory(string $id, callable $factory): void
|
||||
{
|
||||
|
@ -67,8 +53,7 @@ class ContainerConfigurator
|
|||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param callable(ContainerInterface $container):mixed $service
|
||||
*
|
||||
* @param Service $service
|
||||
* @return void
|
||||
*/
|
||||
public function addService(string $id, callable $service): void
|
||||
|
@ -89,7 +74,6 @@ class ContainerConfigurator
|
|||
|
||||
/**
|
||||
* @param string $id
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasService(string $id): bool
|
||||
|
@ -109,37 +93,31 @@ class ContainerConfigurator
|
|||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param callable(mixed $service, ContainerInterface $container):mixed $extender
|
||||
*
|
||||
* @param ExtendingService $extender
|
||||
* @return void
|
||||
*/
|
||||
public function addExtension(string $id, callable $extender): void
|
||||
{
|
||||
if (!isset($this->extensions[$id])) {
|
||||
$this->extensions[$id] = [];
|
||||
}
|
||||
|
||||
$this->extensions[$id][] = $extender;
|
||||
$this->extensions->add($id, $extender);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasExtension(string $id): bool
|
||||
{
|
||||
return isset($this->extensions[$id]);
|
||||
return $this->extensions->has($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a read only version of this Container.
|
||||
*
|
||||
* @return ContainerInterface
|
||||
*
|
||||
* @phpstan-assert ContainerInterface $this->compiledContainer
|
||||
*/
|
||||
public function createReadOnlyContainer(): ContainerInterface
|
||||
{
|
||||
if (!$this->compiledContainer) {
|
||||
if ($this->compiledContainer === null) {
|
||||
$this->compiledContainer = new ReadOnlyContainer(
|
||||
$this->services,
|
||||
$this->factoryIds,
|
||||
|
|
|
@ -10,15 +10,8 @@ use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
|||
|
||||
class PackageProxyContainer implements ContainerInterface
|
||||
{
|
||||
/**
|
||||
* @var Package
|
||||
*/
|
||||
private $package;
|
||||
|
||||
/**
|
||||
* @var ContainerInterface|null
|
||||
*/
|
||||
private $container;
|
||||
private Package $package;
|
||||
private ?ContainerInterface $container = null;
|
||||
|
||||
/**
|
||||
* @param Package $package
|
||||
|
@ -31,8 +24,6 @@ class PackageProxyContainer implements ContainerInterface
|
|||
/**
|
||||
* @param string $id
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function get(string $id)
|
||||
{
|
||||
|
@ -44,8 +35,6 @@ class PackageProxyContainer implements ContainerInterface
|
|||
/**
|
||||
* @param string $id
|
||||
* @return bool
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function has(string $id): bool
|
||||
{
|
||||
|
@ -55,33 +44,30 @@ class PackageProxyContainer implements ContainerInterface
|
|||
/**
|
||||
* @return bool
|
||||
*
|
||||
* @throws \Exception
|
||||
* @psalm-assert-if-true ContainerInterface $this->container
|
||||
* @phpstan-assert-if-true ContainerInterface $this->container
|
||||
* @phpstan-assert-if-false null $this->container
|
||||
*/
|
||||
private function tryContainer(): bool
|
||||
{
|
||||
if ($this->container) {
|
||||
if ($this->container !== null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** TODO: We need a better way to deal with status checking besides equality */
|
||||
if (
|
||||
$this->package->statusIs(Package::STATUS_READY)
|
||||
|| $this->package->statusIs(Package::STATUS_BOOTED)
|
||||
$this->package->hasContainer()
|
||||
|| $this->package->hasReachedStatus(Package::STATUS_INITIALIZED)
|
||||
) {
|
||||
$this->container = $this->package->container();
|
||||
}
|
||||
|
||||
return (bool)$this->container;
|
||||
return $this->container !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @return void
|
||||
*
|
||||
* @throws \Exception
|
||||
*
|
||||
* @psalm-assert ContainerInterface $this->container
|
||||
* @phpstan-assert ContainerInterface $this->container
|
||||
*/
|
||||
private function assertPackageBooted(string $id): void
|
||||
{
|
||||
|
@ -90,13 +76,11 @@ class PackageProxyContainer implements ContainerInterface
|
|||
}
|
||||
|
||||
$name = $this->package->name();
|
||||
$status = $this->package->statusIs(Package::STATUS_FAILED)
|
||||
? 'is errored'
|
||||
: 'is not ready yet';
|
||||
$status = $this->package->hasFailed() ? 'is errored' : 'is not ready yet';
|
||||
|
||||
throw new class ("Error retrieving service {$id} because package {$name} {$status}.")
|
||||
extends \Exception
|
||||
implements ContainerExceptionInterface {
|
||||
$error = "Error retrieving service {$id} because package {$name} {$status}.";
|
||||
throw new class (esc_html($error)) extends \Exception implements ContainerExceptionInterface
|
||||
{
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,58 +7,43 @@ namespace WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Container;
|
|||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\NotFoundExceptionInterface;
|
||||
|
||||
/**
|
||||
* @phpstan-import-type Service from \WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ServiceModule
|
||||
* @phpstan-import-type ExtendingService from \WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ExtendingModule
|
||||
*/
|
||||
class ReadOnlyContainer implements ContainerInterface
|
||||
{
|
||||
/**
|
||||
* @var array<string, callable(\WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface $container):mixed>
|
||||
*/
|
||||
private $services;
|
||||
/** @var array<string, Service> */
|
||||
private array $services;
|
||||
/** @var array<string, bool> */
|
||||
private array $factoryIds;
|
||||
private ServiceExtensions $extensions;
|
||||
/** @var ContainerInterface[] */
|
||||
private array $containers;
|
||||
/** @var array<string, mixed> */
|
||||
private array $resolvedServices = [];
|
||||
|
||||
/**
|
||||
* @var array<string, bool>
|
||||
*/
|
||||
private $factoryIds;
|
||||
|
||||
/**
|
||||
* @var array<string, array<callable(mixed, ContainerInterface $container):mixed>>
|
||||
*/
|
||||
private $extensions;
|
||||
|
||||
/**
|
||||
* Resolved factories.
|
||||
*
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
private $resolvedServices = [];
|
||||
|
||||
/**
|
||||
* @var ContainerInterface[]
|
||||
*/
|
||||
private $containers;
|
||||
|
||||
/**
|
||||
* ReadOnlyContainer constructor.
|
||||
*
|
||||
* @param array<string, callable(ContainerInterface $container):mixed> $services
|
||||
* @param array<string, Service> $services
|
||||
* @param array<string, bool> $factoryIds
|
||||
* @param array<string, array<callable(mixed, ContainerInterface $container):mixed>> $extensions
|
||||
* @param ServiceExtensions|array<string, ExtendingService> $extensions
|
||||
* @param ContainerInterface[] $containers
|
||||
*/
|
||||
public function __construct(
|
||||
array $services,
|
||||
array $factoryIds,
|
||||
array $extensions,
|
||||
$extensions,
|
||||
array $containers
|
||||
) {
|
||||
|
||||
$this->services = $services;
|
||||
$this->factoryIds = $factoryIds;
|
||||
$this->extensions = $extensions;
|
||||
$this->extensions = $this->configureServiceExtensions($extensions);
|
||||
$this->containers = $containers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get(string $id)
|
||||
|
@ -69,7 +54,7 @@ class ReadOnlyContainer implements ContainerInterface
|
|||
|
||||
if (array_key_exists($id, $this->services)) {
|
||||
$service = $this->services[$id]($this);
|
||||
$resolved = $this->resolveExtensions($id, $service);
|
||||
$resolved = $this->extensions->resolve($service, $id, $this);
|
||||
|
||||
if (!isset($this->factoryIds[$id])) {
|
||||
$this->resolvedServices[$id] = $resolved;
|
||||
|
@ -83,19 +68,18 @@ class ReadOnlyContainer implements ContainerInterface
|
|||
if ($container->has($id)) {
|
||||
$service = $container->get($id);
|
||||
|
||||
return $this->resolveExtensions($id, $service);
|
||||
return $this->extensions->resolve($service, $id, $this);
|
||||
}
|
||||
}
|
||||
|
||||
throw new class ("Service with ID {$id} not found.")
|
||||
extends \Exception
|
||||
implements NotFoundExceptionInterface {
|
||||
$error = "Service with ID {$id} not found.";
|
||||
throw new class (esc_html($error)) extends \Exception implements NotFoundExceptionInterface
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has(string $id): bool
|
||||
|
@ -118,21 +102,43 @@ class ReadOnlyContainer implements ContainerInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param mixed $service
|
||||
* Support extensions as array or ServiceExtensions instance for backward compatibility.
|
||||
*
|
||||
* @return mixed
|
||||
* With PHP 8+ we could use an actual union type, but when we bump to PHP 8 as min supported
|
||||
* version, we will probably bump major version as well, so we can just get rid of support
|
||||
* for array.
|
||||
*
|
||||
* @param mixed $extensions
|
||||
* @return ServiceExtensions
|
||||
*/
|
||||
private function resolveExtensions(string $id, $service)
|
||||
private function configureServiceExtensions($extensions): ServiceExtensions
|
||||
{
|
||||
if (!isset($this->extensions[$id])) {
|
||||
return $service;
|
||||
if ($extensions instanceof ServiceExtensions) {
|
||||
return $extensions;
|
||||
}
|
||||
|
||||
foreach ($this->extensions[$id] as $extender) {
|
||||
$service = $extender($service, $this);
|
||||
if (!is_array($extensions)) {
|
||||
$type = is_object($extensions) ? get_class($extensions) : gettype($extensions);
|
||||
throw new \TypeError(
|
||||
sprintf(
|
||||
'%s::%s(): Argument #3 ($extensions) must be of type %s|array, %s given',
|
||||
__CLASS__,
|
||||
'__construct',
|
||||
ServiceExtensions::class,
|
||||
esc_html($type)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $service;
|
||||
$servicesExtensions = new ServiceExtensions();
|
||||
foreach ($extensions as $id => $callback) {
|
||||
/**
|
||||
* @var string $id
|
||||
* @var ExtendingService $callback
|
||||
*/
|
||||
$servicesExtensions->add($id, $callback);
|
||||
}
|
||||
|
||||
return $servicesExtensions;
|
||||
}
|
||||
}
|
||||
|
|
194
lib/packages/Inpsyde/Modularity/Container/ServiceExtensions.php
Normal file
194
lib/packages/Inpsyde/Modularity/Container/ServiceExtensions.php
Normal file
|
@ -0,0 +1,194 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Container;
|
||||
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface as Container;
|
||||
|
||||
/**
|
||||
* @phpstan-import-type ExtendingService from \WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ExtendingModule
|
||||
*/
|
||||
class ServiceExtensions
|
||||
{
|
||||
private const SERVICE_TYPE_NOT_CHANGED = 1;
|
||||
private const SERVICE_TYPE_CHANGED = 2;
|
||||
private const SERVICE_TYPE_NOT_OBJECT = 0;
|
||||
|
||||
/** @var array<string, list<ExtendingService>> */
|
||||
protected array $extensions = [];
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
final public static function typeId(string $type): string
|
||||
{
|
||||
return "@instanceof<{$type}>";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $extensionId
|
||||
* @param ExtendingService $extender
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function add(string $extensionId, callable $extender): ServiceExtensions
|
||||
{
|
||||
if (!isset($this->extensions[$extensionId])) {
|
||||
$this->extensions[$extensionId] = [];
|
||||
}
|
||||
$this->extensions[$extensionId][] = $extender;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $extensionId
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has(string $extensionId): bool
|
||||
{
|
||||
return isset($this->extensions[$extensionId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $service
|
||||
* @param string $id
|
||||
* @param Container $container
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
final public function resolve($service, string $id, Container $container)
|
||||
{
|
||||
$service = $this->resolveById($id, $service, $container);
|
||||
|
||||
return is_object($service)
|
||||
? $this->resolveByType(get_class($service), $service, $container)
|
||||
: $service;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param mixed $service
|
||||
* @param Container $container
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function resolveById(string $id, $service, Container $container)
|
||||
{
|
||||
foreach ($this->extensions[$id] ?? [] as $extender) {
|
||||
$service = $extender($service, $container);
|
||||
}
|
||||
|
||||
return $service;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $className
|
||||
* @param object $service
|
||||
* @param Container $container
|
||||
* @param string[] $extendedClasses
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* phpcs:disable SlevomatCodingStandard.Complexity.Cognitive.ComplexityTooHigh
|
||||
* phpcs:disable Syde.Functions.ReturnTypeDeclaration.NoReturnType
|
||||
*/
|
||||
protected function resolveByType(
|
||||
string $className,
|
||||
object $service,
|
||||
Container $container,
|
||||
array $extendedClasses = []
|
||||
) {
|
||||
// phpcs:enable SlevomatCodingStandard.Complexity.Cognitive.ComplexityTooHigh
|
||||
// phpcs:enable Syde.Functions.ReturnTypeDeclaration.NoReturnType
|
||||
|
||||
$extendedClasses[] = $className;
|
||||
|
||||
/** @var array<class-string, list<ExtendingService>> $allCallbacks */
|
||||
$allCallbacks = [];
|
||||
|
||||
// 1st group of extensions: targeting exact class
|
||||
$byClass = $this->extensions[self::typeId($className)] ?? null;
|
||||
if (($byClass !== null) && ($byClass !== [])) {
|
||||
$allCallbacks[$className] = $byClass;
|
||||
}
|
||||
|
||||
// 2nd group of extensions: targeting parent classes
|
||||
$parents = class_parents($service, false) ?: [];
|
||||
foreach ($parents as $parentName) {
|
||||
$byParent = $this->extensions[self::typeId($parentName)] ?? null;
|
||||
if (($byParent !== null) && ($byParent !== [])) {
|
||||
$allCallbacks[$parentName] = $byParent;
|
||||
}
|
||||
}
|
||||
|
||||
// 3rd group of extensions: targeting implemented interfaces
|
||||
$interfaces = class_implements($service, false) ?: [];
|
||||
foreach ($interfaces as $interfaceName) {
|
||||
$byInterface = $this->extensions[self::typeId($interfaceName)] ?? null;
|
||||
if (($byInterface !== null) && ($byInterface !== [])) {
|
||||
$allCallbacks[$interfaceName] = $byInterface;
|
||||
}
|
||||
}
|
||||
|
||||
$resultType = self::SERVICE_TYPE_NOT_CHANGED;
|
||||
/** @var class-string $type */
|
||||
foreach ($allCallbacks as $type => $extenders) {
|
||||
// When the previous group of callbacks resulted in a type change, we need to check
|
||||
// type before processing next group.
|
||||
if (($resultType === self::SERVICE_TYPE_CHANGED) && !is_a($service, $type)) {
|
||||
continue;
|
||||
}
|
||||
/** @var object $service */
|
||||
[$service, $resultType] = $this->extendByType($type, $service, $container, $extenders);
|
||||
if ($resultType === self::SERVICE_TYPE_NOT_OBJECT) {
|
||||
// Service is not an object anymore, let's return it.
|
||||
return $service;
|
||||
}
|
||||
}
|
||||
|
||||
// If type changed since beginning, let's start over.
|
||||
// We check if class was already extended to avoid infinite recursion. E.g. instead of:
|
||||
// `-> extend(A): B -> extend(B): A -> *loop* ->`
|
||||
// we have:
|
||||
// `-> extend(A): B -> extend(B): A -> return A`.
|
||||
$newClassName = get_class($service);
|
||||
if (!in_array($newClassName, $extendedClasses, true)) {
|
||||
return $this->resolveByType($newClassName, $service, $container, $extendedClasses);
|
||||
}
|
||||
|
||||
return $service;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string $type
|
||||
* @param object $service
|
||||
* @param Container $container
|
||||
* @param list<ExtendingService> $extenders
|
||||
*
|
||||
* @return list{mixed, int}
|
||||
*/
|
||||
private function extendByType(
|
||||
string $type,
|
||||
object $service,
|
||||
Container $container,
|
||||
array $extenders
|
||||
): array {
|
||||
|
||||
foreach ($extenders as $extender) {
|
||||
$service = $extender($service, $container);
|
||||
if (!is_object($service)) {
|
||||
return [$service, self::SERVICE_TYPE_NOT_OBJECT];
|
||||
}
|
||||
if (!is_a($service, $type)) {
|
||||
return [$service, self::SERVICE_TYPE_CHANGED];
|
||||
}
|
||||
}
|
||||
|
||||
return [$service, self::SERVICE_TYPE_NOT_CHANGED];
|
||||
}
|
||||
}
|
|
@ -8,7 +8,6 @@ use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
|||
|
||||
interface ExecutableModule extends Module
|
||||
{
|
||||
|
||||
/**
|
||||
* Perform actions with objects retrieved from the container. Usually, adding WordPress hooks.
|
||||
* Return true to signal a success, false to signal a failure.
|
||||
|
|
|
@ -4,9 +4,13 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module;
|
||||
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
|
||||
/**
|
||||
* @phpstan-type ExtendingService callable(mixed $service, ContainerInterface $container): mixed
|
||||
*/
|
||||
interface ExtendingModule extends Module
|
||||
{
|
||||
|
||||
/**
|
||||
* Return application services' extensions.
|
||||
*
|
||||
|
@ -18,7 +22,7 @@ interface ExtendingModule extends Module
|
|||
* That is done by using as ID (array key in the `extensions` method) the target module ID
|
||||
* and the service ID.
|
||||
*
|
||||
* @return array<string, callable(mixed $service, \WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface $container):mixed>
|
||||
* @return array<string, ExtendingService>
|
||||
*/
|
||||
public function extensions(): array;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,9 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module;
|
||||
|
||||
/**
|
||||
* @phpstan-import-type Service from ServiceModule
|
||||
*/
|
||||
interface FactoryModule extends Module
|
||||
{
|
||||
/**
|
||||
|
@ -12,7 +15,7 @@ interface FactoryModule extends Module
|
|||
* Similar to `services`, but object created by given factories are not "cached", but a *new*
|
||||
* instance is returned everytime `get()` is called in the container.
|
||||
*
|
||||
* @return array<string, callable(\WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface $container):mixed>
|
||||
* @return array<string, Service>
|
||||
*/
|
||||
public function factories(): array;
|
||||
}
|
||||
|
|
|
@ -9,12 +9,10 @@ namespace WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module;
|
|||
*/
|
||||
interface Module
|
||||
{
|
||||
|
||||
/**
|
||||
* Unique identifier for your Module.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function id(): string;
|
||||
|
||||
}
|
||||
|
|
|
@ -4,16 +4,11 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module;
|
||||
|
||||
/**
|
||||
* Trait ModuleClassNameIdTrait
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module
|
||||
*/
|
||||
trait ModuleClassNameIdTrait
|
||||
{
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
* @see Module::id()
|
||||
*/
|
||||
public function id(): string
|
||||
|
|
|
@ -4,9 +4,13 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module;
|
||||
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
|
||||
/**
|
||||
* @phpstan-type Service callable(ContainerInterface $container): mixed
|
||||
*/
|
||||
interface ServiceModule extends Module
|
||||
{
|
||||
|
||||
/**
|
||||
* Return application services' factories.
|
||||
*
|
||||
|
@ -15,7 +19,7 @@ interface ServiceModule extends Module
|
|||
* Services are "cached", so the given factory is called once the first time `get()` is called
|
||||
* in the container, and on subsequent `get()` the same instance is returned again and again.
|
||||
*
|
||||
* @return array<string, callable(\WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface $container):mixed>
|
||||
* @return array<string, Service>
|
||||
*/
|
||||
public function services(): array;
|
||||
}
|
||||
|
|
|
@ -6,19 +6,22 @@ namespace WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity;
|
|||
|
||||
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Container\ContainerConfigurator;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Container\PackageProxyContainer;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ExtendingModule;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ExecutableModule;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ExtendingModule;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\FactoryModule;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\Module;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ServiceModule;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Properties\Properties;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
|
||||
/**
|
||||
* @phpstan-import-type Service from \WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ServiceModule
|
||||
* @phpstan-import-type ExtendingService from \WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ExtendingModule
|
||||
*/
|
||||
class Package
|
||||
{
|
||||
/**
|
||||
* All the hooks fired in this class use this prefix.
|
||||
* @var string
|
||||
*/
|
||||
private const HOOK_PREFIX = 'inpsyde.modularity.';
|
||||
|
||||
|
@ -34,14 +37,13 @@ class Package
|
|||
* $container->has(Package::PROPERTIES);
|
||||
* $container->get(Package::PROPERTIES);
|
||||
* </code>
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public const PROPERTIES = 'properties';
|
||||
|
||||
/**
|
||||
* Custom action to be used to add Modules to the package.
|
||||
* Custom action to be used to add modules and connect other packages.
|
||||
* It might also be used to access package properties.
|
||||
* Access container is not possible at this stage.
|
||||
*
|
||||
* @example
|
||||
* <code>
|
||||
|
@ -49,67 +51,64 @@ class Package
|
|||
*
|
||||
* add_action(
|
||||
* $package->hookName(Package::ACTION_INIT),
|
||||
* $callback
|
||||
* fn (Package $package) => // do something,
|
||||
* );
|
||||
* </code>
|
||||
*/
|
||||
public const ACTION_INIT = 'init';
|
||||
|
||||
/**
|
||||
* Custom action which is triggered after the application
|
||||
* is booted to access container and properties.
|
||||
* Very similar to `ACTION_INIT`, but it is static, so not dependent on package name.
|
||||
* It passes package name as first argument.
|
||||
*
|
||||
* @example
|
||||
* <code>
|
||||
* $package = Package::new();
|
||||
*
|
||||
* add_action(
|
||||
* $package->hookName(Package::ACTION_READY),
|
||||
* $callback
|
||||
* );
|
||||
* </code>
|
||||
* <code>
|
||||
* add_action(
|
||||
* Package::ACTION_MODULARITY_INIT,
|
||||
* fn (string $packageName, Package $package) => // do something,
|
||||
* 10,
|
||||
* 2
|
||||
* );
|
||||
* </code>
|
||||
*/
|
||||
public const ACTION_READY = 'ready';
|
||||
public const ACTION_MODULARITY_INIT = self::HOOK_PREFIX . self::ACTION_INIT;
|
||||
|
||||
/**
|
||||
* Custom action which is triggered when a failure happens during the building stage.
|
||||
*
|
||||
* @example
|
||||
* <code>
|
||||
* $package = Package::new();
|
||||
*
|
||||
* add_action(
|
||||
* $package->hookName(Package::ACTION_FAILED_BUILD),
|
||||
* $callback
|
||||
* );
|
||||
* </code>
|
||||
* Action fired when it is safe to access container.
|
||||
* Add more modules is not anymore possible at this stage.
|
||||
*/
|
||||
public const ACTION_INITIALIZED = 'initialized';
|
||||
|
||||
/**
|
||||
* Action fired when plugin finished its bootstrapping process, all its hooks are added.
|
||||
* Add more modules is not anymore possible at this stage.
|
||||
*/
|
||||
public const ACTION_BOOTED = 'ready';
|
||||
|
||||
/**
|
||||
* Action fired when anything went wrong during the "build" procedure.
|
||||
*/
|
||||
public const ACTION_FAILED_BUILD = 'failed-build';
|
||||
|
||||
/**
|
||||
* Custom action which is triggered when a failure happens during the booting stage.
|
||||
*
|
||||
* @example
|
||||
* <code>
|
||||
* $package = Package::new();
|
||||
*
|
||||
* add_action(
|
||||
* $package->hookName(Package::ACTION_FAILED_BOOT),
|
||||
* $callback
|
||||
* );
|
||||
* </code>
|
||||
* Action fired when anything went wrong during the "boot" procedure.
|
||||
*/
|
||||
public const ACTION_FAILED_BOOT = 'failed-boot';
|
||||
|
||||
/**
|
||||
* Custom action which is triggered when a package is connected.
|
||||
* Action fired when adding a module failed.
|
||||
*/
|
||||
public const ACTION_PACKAGE_CONNECTED = 'package-connected';
|
||||
public const ACTION_FAILED_ADD_MODULE = 'failed-add-module';
|
||||
|
||||
/**
|
||||
* Custom action which is triggered when a package cannot be connected.
|
||||
* Action fired when a package connection failed.
|
||||
*/
|
||||
public const ACTION_FAILED_CONNECTION = 'failed-connection';
|
||||
public const ACTION_FAILED_CONNECT = 'failed-connection';
|
||||
|
||||
/**
|
||||
* Action fired when a package is connected successfully.
|
||||
*/
|
||||
public const ACTION_PACKAGE_CONNECTED = 'package-connected';
|
||||
|
||||
/**
|
||||
* Module states can be used to get information about your module.
|
||||
|
@ -118,7 +117,7 @@ class Package
|
|||
* <code>
|
||||
* $package = Package::new();
|
||||
* $package->moduleIs(SomeModule::class, Package::MODULE_ADDED); // false
|
||||
* $package->boot(new SomeModule());
|
||||
* $package->addModule(new SomeModule());
|
||||
* $package->moduleIs(SomeModule::class, Package::MODULE_ADDED); // true
|
||||
* </code>
|
||||
*/
|
||||
|
@ -137,90 +136,81 @@ class Package
|
|||
* @example
|
||||
* <code>
|
||||
* $package = Package::new();
|
||||
* $package->statusIs(Package::IDLE); // true
|
||||
* $package->statusIs(Package::STATUS_IDLE); // true
|
||||
* $package->build();
|
||||
* $package->statusIs(Package::STATUS_INITIALIZED); // true
|
||||
* $package->boot();
|
||||
* $package->statusIs(Package::BOOTED); // true
|
||||
* $package->statusIs(Package::STATUS_DONE); // true
|
||||
* </code>
|
||||
*/
|
||||
public const STATUS_IDLE = 2;
|
||||
public const STATUS_INITIALIZING = 3;
|
||||
public const STATUS_INITIALIZED = 4;
|
||||
public const STATUS_MODULES_ADDED = 5;
|
||||
public const STATUS_READY = 7;
|
||||
public const STATUS_BOOTED = 8;
|
||||
public const STATUS_BOOTING = 5;
|
||||
public const STATUS_BOOTED = 7;
|
||||
public const STATUS_DONE = 8;
|
||||
public const STATUS_FAILED = -8;
|
||||
|
||||
/**
|
||||
* Current state of the application.
|
||||
*
|
||||
* @see Package::STATUS_*
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $status = self::STATUS_IDLE;
|
||||
// Deprecated flags
|
||||
/** @deprecated */
|
||||
public const STATUS_MODULES_ADDED = self::STATUS_BOOTING;
|
||||
/** @deprecated */
|
||||
public const ACTION_READY = self::ACTION_BOOTED;
|
||||
/** @deprecated */
|
||||
public const ACTION_FAILED_CONNECTION = self::ACTION_FAILED_CONNECT;
|
||||
|
||||
/**
|
||||
* Contains the progress of all modules.
|
||||
*
|
||||
* @see Package::moduleProgress()
|
||||
*
|
||||
* @var array<string, list<string>>
|
||||
*/
|
||||
private $moduleStatus = [self::MODULES_ALL => []];
|
||||
// Map of status to package-specific and global hook, both optional (i..e, null).
|
||||
private const STATUSES_ACTIONS_MAP = [
|
||||
self::STATUS_INITIALIZING => [self::ACTION_INIT, self::ACTION_MODULARITY_INIT],
|
||||
self::STATUS_INITIALIZED => [self::ACTION_INITIALIZED, null],
|
||||
self::STATUS_BOOTED => [self::ACTION_BOOTED, null],
|
||||
];
|
||||
|
||||
/**
|
||||
* Hashmap of where keys are names of connected packages, and values are boolean, true
|
||||
* if connection was successful.
|
||||
*
|
||||
* @see Package::connect()
|
||||
*
|
||||
* @var array<string, bool>
|
||||
*/
|
||||
private $connectedPackages = [];
|
||||
private const SUCCESS_STATUSES = [
|
||||
self::STATUS_IDLE => self::STATUS_IDLE,
|
||||
self::STATUS_INITIALIZING => self::STATUS_INITIALIZING,
|
||||
self::STATUS_INITIALIZED => self::STATUS_INITIALIZED,
|
||||
self::STATUS_BOOTING => self::STATUS_BOOTING,
|
||||
self::STATUS_BOOTED => self::STATUS_BOOTED,
|
||||
self::STATUS_DONE => self::STATUS_DONE,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var list<ExecutableModule>
|
||||
*/
|
||||
private $executables = [];
|
||||
private const OPERATORS = [
|
||||
'<' => '<',
|
||||
'<=' => '<=',
|
||||
'>' => '>',
|
||||
'>=' => '>=',
|
||||
'==' => '==',
|
||||
'!=' => '!=',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var Properties
|
||||
*/
|
||||
private $properties;
|
||||
|
||||
/**
|
||||
* @var ContainerConfigurator
|
||||
*/
|
||||
private $containerConfigurator;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $built = false;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $hasContainer = false;
|
||||
|
||||
/**
|
||||
* @var \Throwable|null
|
||||
*/
|
||||
private $lastError = null;
|
||||
/** @var Package::STATUS_* */
|
||||
private int $status = self::STATUS_IDLE;
|
||||
/** @var array<string, list<string>> */
|
||||
private array $moduleStatus = [self::MODULES_ALL => []];
|
||||
/** @var array<string, bool> */
|
||||
private array $connectedPackages = [];
|
||||
/** @var list<ExecutableModule> */
|
||||
private array $executables = [];
|
||||
private Properties $properties;
|
||||
private ContainerConfigurator $containerConfigurator;
|
||||
private bool $built = false;
|
||||
private bool $hasContainer = false;
|
||||
private ?\Throwable $lastError = null;
|
||||
|
||||
/**
|
||||
* @param Properties $properties
|
||||
* @param ContainerInterface[] $containers
|
||||
*
|
||||
* @param ContainerInterface ...$containers
|
||||
* @return Package
|
||||
*/
|
||||
public static function new(Properties $properties, ContainerInterface ...$containers): Package
|
||||
public static function new(Properties $properties, ContainerInterface ...$containers): Package
|
||||
{
|
||||
return new self($properties, ...$containers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Properties $properties
|
||||
* @param ContainerInterface[] $containers
|
||||
* @param ContainerInterface ...$containers
|
||||
*/
|
||||
private function __construct(Properties $properties, ContainerInterface ...$containers)
|
||||
{
|
||||
|
@ -229,7 +219,7 @@ class Package
|
|||
$this->containerConfigurator = new ContainerConfigurator($containers);
|
||||
$this->containerConfigurator->addService(
|
||||
self::PROPERTIES,
|
||||
static function () use ($properties) {
|
||||
static function () use ($properties): Properties {
|
||||
return $properties;
|
||||
}
|
||||
);
|
||||
|
@ -237,14 +227,14 @@ class Package
|
|||
|
||||
/**
|
||||
* @param Module $module
|
||||
*
|
||||
* @return static
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function addModule(Module $module): Package
|
||||
{
|
||||
try {
|
||||
$this->assertStatus(self::STATUS_IDLE, sprintf('add module %s', $module->id()));
|
||||
$reason = sprintf('add module %s', $module->id());
|
||||
$this->assertStatus(self::STATUS_FAILED, $reason, '!=');
|
||||
$this->assertStatus(self::STATUS_INITIALIZING, $reason, '<=');
|
||||
|
||||
$registeredServices = $this->addModuleServices(
|
||||
$module,
|
||||
|
@ -271,7 +261,7 @@ class Package
|
|||
$status = $added ? self::MODULE_ADDED : self::MODULE_NOT_ADDED;
|
||||
$this->moduleProgress($module->id(), $status);
|
||||
} catch (\Throwable $throwable) {
|
||||
$this->handleFailure($throwable, self::ACTION_FAILED_BUILD);
|
||||
$this->handleFailure($throwable, self::ACTION_FAILED_ADD_MODULE);
|
||||
}
|
||||
|
||||
return $this;
|
||||
|
@ -280,7 +270,6 @@ class Package
|
|||
/**
|
||||
* @param Package $package
|
||||
* @return bool
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function connect(Package $package): bool
|
||||
{
|
||||
|
@ -290,33 +279,17 @@ class Package
|
|||
}
|
||||
|
||||
$packageName = $package->name();
|
||||
$errorData = ['package' => $packageName, 'status' => $this->status];
|
||||
$errorMessage = "Failed connecting package {$packageName}";
|
||||
|
||||
// Don't connect, if already connected
|
||||
if (array_key_exists($packageName, $this->connectedPackages)) {
|
||||
$error = "{$errorMessage} because it was already connected.";
|
||||
do_action(
|
||||
$this->hookName(self::ACTION_FAILED_CONNECTION),
|
||||
$packageName,
|
||||
new \WP_Error('already_connected', $error, $errorData)
|
||||
);
|
||||
|
||||
throw new \Exception($error, 0, $this->lastError);
|
||||
return $this->handleConnectionFailure($packageName, 'already connected', false);
|
||||
}
|
||||
|
||||
// Don't connect, if already booted or boot failed
|
||||
$failed = $this->statusIs(self::STATUS_FAILED);
|
||||
if ($failed || $this->statusIs(self::STATUS_BOOTED)) {
|
||||
$status = $failed ? 'errored' : 'booted';
|
||||
$error = "{$errorMessage} to a {$status} package.";
|
||||
do_action(
|
||||
$this->hookName(self::ACTION_FAILED_CONNECTION),
|
||||
$packageName,
|
||||
new \WP_Error("no_connect_on_{$status}", $error, $errorData)
|
||||
);
|
||||
|
||||
throw new \Exception($error, 0, $this->lastError);
|
||||
$failed = $this->hasFailed();
|
||||
if ($failed || $this->hasReachedStatus(self::STATUS_INITIALIZED)) {
|
||||
$reason = $failed ? 'is errored' : 'has a built container already';
|
||||
$this->handleConnectionFailure($packageName, "current package {$reason}", true);
|
||||
}
|
||||
|
||||
$this->connectedPackages[$packageName] = true;
|
||||
|
@ -330,9 +303,10 @@ class Package
|
|||
}
|
||||
);
|
||||
|
||||
// If the other package is booted, we can obtain a container, otherwise
|
||||
// we build a proxy container
|
||||
$container = $package->statusIs(self::STATUS_BOOTED)
|
||||
// If we can obtain a container we do, otherwise we build a proxy container
|
||||
$packageHasContainer = $package->hasReachedStatus(self::STATUS_INITIALIZED)
|
||||
|| $package->hasContainer();
|
||||
$container = $packageHasContainer
|
||||
? $package->container()
|
||||
: new PackageProxyContainer($package);
|
||||
|
||||
|
@ -347,7 +321,10 @@ class Package
|
|||
|
||||
return true;
|
||||
} catch (\Throwable $throwable) {
|
||||
if (isset($packageName)) {
|
||||
if (
|
||||
isset($packageName)
|
||||
&& (($this->connectedPackages[$packageName] ?? false) !== true)
|
||||
) {
|
||||
$this->connectedPackages[$packageName] = false;
|
||||
}
|
||||
$this->handleFailure($throwable, self::ACTION_FAILED_BUILD);
|
||||
|
@ -362,17 +339,26 @@ class Package
|
|||
public function build(): Package
|
||||
{
|
||||
try {
|
||||
// Don't allow building the application multiple times.
|
||||
// Be tolerant about things like `$package->build()->build()`.
|
||||
// Sometimes, from the extern, we might want to call `build()` to ensure the container
|
||||
// is ready before accessing a service. And in that case we don't want to throw an
|
||||
// exception if the container is already built.
|
||||
if ($this->built && $this->statusIs(self::STATUS_INITIALIZED)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
// We expect `build` to be called only after `addModule()` or `connect()` which do
|
||||
// not change the status, so we expect status to be still "IDLE".
|
||||
// This will prevent invalid things like calling `build()` from inside something
|
||||
// hooking ACTION_INIT OR ACTION_INITIALIZED.
|
||||
$this->assertStatus(self::STATUS_IDLE, 'build package');
|
||||
|
||||
do_action(
|
||||
$this->hookName(self::ACTION_INIT),
|
||||
$this
|
||||
);
|
||||
// Changing the status here ensures we can not call this method again, and also we can not
|
||||
// add new modules, because both this and `addModule()` methods check for idle status.
|
||||
// For backward compatibility, adding new modules via `boot()` will still be possible, even
|
||||
// if deprecated, at the condition that the container was not yet accessed at that point.
|
||||
// This will change the status to "INITIALIZING" then fire the action that allow other
|
||||
// packages to add modules or connect packages.
|
||||
$this->progress(self::STATUS_INITIALIZING);
|
||||
|
||||
// This will change the status to "INITIALIZED" then fire an action when it is safe to
|
||||
// access the container, because from this moment on, container is locked from change.
|
||||
$this->progress(self::STATUS_INITIALIZED);
|
||||
} catch (\Throwable $throwable) {
|
||||
$this->handleFailure($throwable, self::ACTION_FAILED_BUILD);
|
||||
|
@ -386,37 +372,47 @@ class Package
|
|||
/**
|
||||
* @param Module ...$defaultModules Deprecated, use `addModule()` to add default modules.
|
||||
* @return bool
|
||||
*
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function boot(Module ...$defaultModules): bool
|
||||
{
|
||||
try {
|
||||
// When package is done, nothing should happen to it calling boot again, but we call
|
||||
// false to signal something is off.
|
||||
if ($this->statusIs(self::STATUS_DONE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Call build() if not called yet, and ensure any new module passed here is added
|
||||
// as well, throwing if the container was already built.
|
||||
$this->doBuild(...$defaultModules);
|
||||
|
||||
// Don't allow booting the application multiple times.
|
||||
$this->assertStatus(self::STATUS_MODULES_ADDED, 'boot application', '<');
|
||||
$this->assertStatus(self::STATUS_FAILED, 'boot application', '!=');
|
||||
// Make sure we call boot() on a non-failed instance, and also make a sanity check
|
||||
// on the status flow, e.g. prevent calling boot() from an action hook.
|
||||
$this->assertStatus(self::STATUS_INITIALIZED, 'boot application');
|
||||
|
||||
$this->progress(self::STATUS_MODULES_ADDED);
|
||||
// This will change status to STATUS_BOOTING "locking" subsequent call to `boot()`, but
|
||||
// no hook is fired here, because at this point we can not do anything more or less than
|
||||
// what can be done on the ACTION_INITIALIZED hook, so that hook is sufficient.
|
||||
$this->progress(self::STATUS_BOOTING);
|
||||
|
||||
$this->doExecute();
|
||||
|
||||
$this->progress(self::STATUS_READY);
|
||||
|
||||
do_action(
|
||||
$this->hookName(self::ACTION_READY),
|
||||
$this
|
||||
);
|
||||
// This will change status to STATUS_BOOTED and then fire an action that make it
|
||||
// possible to hook on a package that has finished its bootstrapping process, so all its
|
||||
// "executable" modules have been executed.
|
||||
$this->progress(self::STATUS_BOOTED);
|
||||
} catch (\Throwable $throwable) {
|
||||
$this->handleFailure($throwable, self::ACTION_FAILED_BOOT);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->progress(self::STATUS_BOOTED);
|
||||
// This will change the status to DONE and will not fire any action.
|
||||
// This is a status that proves that everything went well, not only the Package itself,
|
||||
// but also anything hooking Package's hooks.
|
||||
// The only way to move out of this status is a failure that might only happen directly
|
||||
// calling `addModule()`, `connect()` or `build()`.
|
||||
$this->progress(self::STATUS_DONE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -439,39 +435,67 @@ class Package
|
|||
);
|
||||
}
|
||||
|
||||
// We expect `boot()` to be called either:
|
||||
// 1. Directly after `addModule()`/`connect()`, without any `build()` call in between, so
|
||||
// status is IDLE and `$this->built` is `false`.
|
||||
// 2. After `build()` is called, so status is INITIALIZED and `$this->built` is `true`.
|
||||
// Any other usage is not allowed (e.g. calling `boot()` from an hook callback) and in that
|
||||
// case we return here, giving back control to `boot()` which will throw.
|
||||
$validFlows = (!$this->built && $this->statusIs(self::STATUS_IDLE))
|
||||
|| ($this->built && $this->statusIs(self::STATUS_INITIALIZED));
|
||||
|
||||
if (!$validFlows) {
|
||||
// If none of the two supported flows happened, we just return handling control back
|
||||
// to `boot()`, that will throw.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$this->built) {
|
||||
array_map([$this, 'addModule'], $defaultModules);
|
||||
// First valid flow: `boot()` was called directly after `addModule()`/`connect()`
|
||||
// without any call to `build()`. We can call `build()` and return, handing control
|
||||
// back to `boot()`. Before returning, if we had default modules passed to `boot()` we
|
||||
// already have fired a deprecation, so here we just add them dealing with back-compat.
|
||||
foreach ($defaultModules as $defaultModule) {
|
||||
$this->addModule($defaultModule);
|
||||
}
|
||||
$this->build();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
!$defaultModules
|
||||
|| ($this->status >= self::STATUS_MODULES_ADDED)
|
||||
|| ($this->statusIs(self::STATUS_FAILED))
|
||||
) {
|
||||
// if we don't have default modules, there's nothing to do, and if the status is beyond
|
||||
// "modules added" or is failed, we do nothing as well and let `boot()` throw.
|
||||
// Second valid flow: we have called `boot()` after `build()`. If we did it correctly,
|
||||
// without default modules passed to `boot()`, we can just return handing control back
|
||||
// to `boot()`.
|
||||
if (!$defaultModules) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If here, we have done something like: `$package->build()->boot($module1, $module2)`.
|
||||
// Passing modules to `boot()` was deprecated when `build()` was introduced, so whoever
|
||||
// added `build()` should have removed modules passed to `boot()`.
|
||||
// But we want to keep 100% backward compatibility so we still support this behavior
|
||||
// until the next major is released. To do that, we simulate IDLE status to prevent
|
||||
// `addModule()` from throwing when adding default modules.
|
||||
// But we can do that only if we don't have a compiled container yet.
|
||||
// If anything hooking ACTION_INIT called `container()` we have a compiled container
|
||||
// already, and we can't add modules, so we not going to simulate INIT status, which mean
|
||||
// the `$this->addModule()` call below will throw.
|
||||
$backup = $this->status;
|
||||
|
||||
try {
|
||||
// simulate idle status to prevent `addModule()` from throwing
|
||||
// only if we don't have a container yet
|
||||
$this->hasContainer or $this->status = self::STATUS_IDLE;
|
||||
|
||||
if (!$this->hasContainer()) {
|
||||
$this->status = self::STATUS_IDLE;
|
||||
}
|
||||
foreach ($defaultModules as $defaultModule) {
|
||||
// If a module was added by `build()` or `addModule()` we can skip it, a
|
||||
// deprecation was trigger to make it noticeable without breakage
|
||||
// If a module was already added via `addModule()` we can skip it, reducing the
|
||||
// chances of throwing an exception if not needed.
|
||||
if (!$this->moduleIs($defaultModule->id(), self::MODULE_ADDED)) {
|
||||
$this->addModule($defaultModule);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
$this->status = $backup;
|
||||
if (!$this->hasFailed()) {
|
||||
$this->status = $backup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -482,7 +506,9 @@ class Package
|
|||
*/
|
||||
private function addModuleServices(Module $module, string $status): bool
|
||||
{
|
||||
/** @var null|array<string, Service|ExtendingService> $services */
|
||||
$services = null;
|
||||
/** @var null|callable(string, Service|ExtendingService): void $addCallback */
|
||||
$addCallback = null;
|
||||
switch ($status) {
|
||||
case self::MODULE_REGISTERED:
|
||||
|
@ -499,21 +525,16 @@ class Package
|
|||
break;
|
||||
}
|
||||
|
||||
if (!$services) {
|
||||
if (($services === null) || ($services === []) || ($addCallback === null)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$ids = [];
|
||||
array_walk(
|
||||
$services,
|
||||
static function (callable $service, string $id) use ($addCallback, &$ids) {
|
||||
/** @var callable(string, callable) $addCallback */
|
||||
$addCallback($id, $service);
|
||||
/** @var list<string> $ids */
|
||||
$ids[] = $id;
|
||||
}
|
||||
);
|
||||
/** @var list<string> $ids */
|
||||
foreach ($services as $id => $service) {
|
||||
$addCallback($id, $service);
|
||||
$ids[] = $id;
|
||||
}
|
||||
|
||||
$this->moduleProgress($module->id(), $status, $ids);
|
||||
|
||||
return true;
|
||||
|
@ -521,8 +542,6 @@ class Package
|
|||
|
||||
/**
|
||||
* @return void
|
||||
*
|
||||
* @throws \Throwable
|
||||
*/
|
||||
private function doExecute(): void
|
||||
{
|
||||
|
@ -530,9 +549,7 @@ class Package
|
|||
$success = $executable->run($this->container());
|
||||
$this->moduleProgress(
|
||||
$executable->id(),
|
||||
$success
|
||||
? self::MODULE_EXECUTED
|
||||
: self::MODULE_EXECUTION_FAILED
|
||||
$success ? self::MODULE_EXECUTED : self::MODULE_EXECUTION_FAILED,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -541,15 +558,20 @@ class Package
|
|||
* @param string $moduleId
|
||||
* @param string $status
|
||||
* @param list<string>|null $serviceIds
|
||||
*
|
||||
* @return void
|
||||
* @return void
|
||||
*/
|
||||
private function moduleProgress(string $moduleId, string $status, ?array $serviceIds = null)
|
||||
{
|
||||
isset($this->moduleStatus[$status]) or $this->moduleStatus[$status] = [];
|
||||
private function moduleProgress(
|
||||
string $moduleId,
|
||||
string $status,
|
||||
?array $serviceIds = null
|
||||
): void {
|
||||
|
||||
if (!isset($this->moduleStatus[$status])) {
|
||||
$this->moduleStatus[$status] = [];
|
||||
}
|
||||
$this->moduleStatus[$status][] = $moduleId;
|
||||
|
||||
if (!$serviceIds || !$this->properties->isDebug()) {
|
||||
if (($serviceIds === null) || ($serviceIds === []) || !$this->properties->isDebug()) {
|
||||
$this->moduleStatus[self::MODULES_ALL][] = "{$moduleId} {$status}";
|
||||
|
||||
return;
|
||||
|
@ -605,10 +627,9 @@ class Package
|
|||
* `inpsyde.modularity.my-plugin` anyway, so the file name is not relevant.
|
||||
*
|
||||
* @param string $suffix
|
||||
*
|
||||
* @return string
|
||||
* @see Package::name()
|
||||
*
|
||||
* @see Package::name()
|
||||
*/
|
||||
public function hookName(string $suffix = ''): string
|
||||
{
|
||||
|
@ -631,8 +652,6 @@ class Package
|
|||
|
||||
/**
|
||||
* @return ContainerInterface
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function container(): ContainerInterface
|
||||
{
|
||||
|
@ -642,6 +661,14 @@ class Package
|
|||
return $this->containerConfigurator->createReadOnlyContainer();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function hasContainer(): bool
|
||||
{
|
||||
return $this->hasContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
|
@ -652,27 +679,94 @@ class Package
|
|||
|
||||
/**
|
||||
* @param int $status
|
||||
*/
|
||||
private function progress(int $status): void
|
||||
{
|
||||
$this->status = $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $status
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function statusIs(int $status): bool
|
||||
{
|
||||
return $this->status === $status;
|
||||
return $this->checkStatus($status);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function hasFailed(): bool
|
||||
{
|
||||
return $this->status === self::STATUS_FAILED;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $status
|
||||
* @return bool
|
||||
*/
|
||||
public function hasReachedStatus(int $status): bool
|
||||
{
|
||||
if ($this->hasFailed()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isset(self::SUCCESS_STATUSES[$status]) && $this->checkStatus($status, '>=');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $status
|
||||
* @param value-of<Package::OPERATORS> $operator
|
||||
* @return bool
|
||||
*/
|
||||
private function checkStatus(int $status, string $operator = '=='): bool
|
||||
{
|
||||
assert(isset(self::OPERATORS[$operator]));
|
||||
|
||||
return version_compare((string) $this->status, (string) $status, $operator);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Package::STATUS_* $status
|
||||
*/
|
||||
private function progress(int $status): void
|
||||
{
|
||||
$this->status = $status;
|
||||
|
||||
[$packageHookSuffix, $globalHook] = self::STATUSES_ACTIONS_MAP[$status] ?? [null, null];
|
||||
if ($packageHookSuffix !== null) {
|
||||
do_action($this->hookName($packageHookSuffix), $this);
|
||||
}
|
||||
if ($globalHook !== null) {
|
||||
do_action($globalHook, $this->name(), $this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @param string $reason
|
||||
* @param bool $throw
|
||||
* @return bool
|
||||
*/
|
||||
private function handleConnectionFailure(string $packageName, string $reason, bool $throw): bool
|
||||
{
|
||||
$errorData = ['package' => $packageName, 'status' => $this->status];
|
||||
$message = "Failed connecting package {$packageName} because {$reason}.";
|
||||
|
||||
do_action(
|
||||
$this->hookName(self::ACTION_FAILED_CONNECT),
|
||||
$packageName,
|
||||
new \WP_Error('failed_connection', $message, $errorData)
|
||||
);
|
||||
|
||||
if ($throw) {
|
||||
throw new \Exception(
|
||||
esc_html($message),
|
||||
0,
|
||||
$this->lastError // phpcs:ignore WordPress.Security.EscapeOutput
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Throwable $throwable
|
||||
* @param Package::ACTION_FAILED_* $action
|
||||
* @return void
|
||||
* @throws \Throwable
|
||||
*/
|
||||
private function handleFailure(\Throwable $throwable, string $action): void
|
||||
{
|
||||
|
@ -690,18 +784,15 @@ class Package
|
|||
/**
|
||||
* @param int $status
|
||||
* @param string $action
|
||||
* @param string $operator
|
||||
*
|
||||
* @throws \Exception
|
||||
* @psalm-suppress ArgumentTypeCoercion
|
||||
* @param value-of<Package::OPERATORS> $operator
|
||||
*/
|
||||
private function assertStatus(int $status, string $action, string $operator = '=='): void
|
||||
{
|
||||
if (!version_compare((string) $this->status, (string) $status, $operator)) {
|
||||
if (!$this->checkStatus($status, $operator)) {
|
||||
throw new \Exception(
|
||||
sprintf("Can't %s at this point of application.", $action),
|
||||
sprintf("Can't %s at this point of application.", esc_html($action)),
|
||||
0,
|
||||
$this->lastError
|
||||
$this->lastError // phpcs:ignore WordPress.Security.EscapeOutput
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -713,7 +804,6 @@ class Package
|
|||
* @param string $message
|
||||
* @param string $function
|
||||
* @param string $version
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function deprecatedArgument(string $message, string $function, string $version): void
|
||||
|
@ -721,7 +811,9 @@ class Package
|
|||
do_action('deprecated_argument_run', $function, $message, $version);
|
||||
|
||||
if (apply_filters('deprecated_argument_trigger_error', true)) {
|
||||
trigger_error($message, \E_USER_DEPRECATED);
|
||||
do_action('wp_trigger_error_run', $function, $message, \E_USER_DEPRECATED);
|
||||
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
|
||||
trigger_error(esc_html($message), \E_USER_DEPRECATED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,47 +6,30 @@ namespace WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Properties;
|
|||
|
||||
class BaseProperties implements Properties
|
||||
{
|
||||
/**
|
||||
* @var null|bool
|
||||
*/
|
||||
protected $isDebug = null;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $baseName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $basePath;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
protected $baseUrl;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $properties;
|
||||
protected ?bool $isDebug = null;
|
||||
protected string $baseName;
|
||||
protected string $basePath;
|
||||
protected ?string $baseUrl;
|
||||
/** @var array<string, mixed> */
|
||||
protected array $properties;
|
||||
|
||||
/**
|
||||
* @param string $baseName
|
||||
* @param string $basePath
|
||||
* @param string|null $baseUrl
|
||||
* @param array $properties
|
||||
* @param array<string, mixed> $properties
|
||||
*/
|
||||
protected function __construct(
|
||||
string $baseName,
|
||||
string $basePath,
|
||||
string $baseUrl = null,
|
||||
?string $baseUrl = null,
|
||||
array $properties = []
|
||||
) {
|
||||
|
||||
$baseName = $this->sanitizeBaseName($baseName);
|
||||
$basePath = (string) trailingslashit($basePath);
|
||||
if ($baseUrl) {
|
||||
$baseUrl = (string) trailingslashit($baseUrl);
|
||||
$basePath = trailingslashit($basePath);
|
||||
if ($baseUrl !== null) {
|
||||
$baseUrl = trailingslashit($baseUrl);
|
||||
}
|
||||
|
||||
$this->baseName = $baseName;
|
||||
|
@ -58,11 +41,13 @@ class BaseProperties implements Properties
|
|||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return string
|
||||
* @return lowercase-string
|
||||
*/
|
||||
protected function sanitizeBaseName(string $name): string
|
||||
{
|
||||
substr_count($name, '/') and $name = dirname($name);
|
||||
if (substr_count($name, '/')) {
|
||||
$name = dirname($name);
|
||||
}
|
||||
|
||||
return strtolower(pathinfo($name, PATHINFO_FILENAME));
|
||||
}
|
||||
|
@ -162,7 +147,9 @@ class BaseProperties implements Properties
|
|||
{
|
||||
$value = $this->get(self::PROP_REQUIRES_WP);
|
||||
|
||||
return $value && is_string($value) ? $value : null;
|
||||
return (($value !== '') && is_string($value))
|
||||
? $value
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -172,11 +159,13 @@ class BaseProperties implements Properties
|
|||
{
|
||||
$value = $this->get(self::PROP_REQUIRES_PHP);
|
||||
|
||||
return $value && is_string($value) ? $value : null;
|
||||
return (($value !== '') && is_string($value))
|
||||
? $value
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @return string[]
|
||||
*/
|
||||
public function tags(): array
|
||||
{
|
||||
|
@ -185,7 +174,8 @@ class BaseProperties implements Properties
|
|||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param null $default
|
||||
* @param mixed $default
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get(string $key, $default = null)
|
||||
|
@ -195,6 +185,7 @@ class BaseProperties implements Properties
|
|||
|
||||
/**
|
||||
* @param string $key
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has(string $key): bool
|
||||
|
|
|
@ -5,17 +5,26 @@ declare(strict_types=1);
|
|||
namespace WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Properties;
|
||||
|
||||
/**
|
||||
* Class LibraryProperties
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Properties
|
||||
* @phpstan-type ComposerAuthor array{
|
||||
* name: string,
|
||||
* email?: string,
|
||||
* homepage?: string,
|
||||
* role?: string,
|
||||
* }
|
||||
* @phpstan-type ComposerData array{
|
||||
* name: string,
|
||||
* version?: string,
|
||||
* require?: array<string, string>,
|
||||
* require-dev?: array<string, string>,
|
||||
* description?: string,
|
||||
* keywords?: string[],
|
||||
* authors?: ComposerAuthor[],
|
||||
* extra?: array{modularity?: array<string, string>},
|
||||
* }
|
||||
*/
|
||||
class LibraryProperties extends BaseProperties
|
||||
{
|
||||
/**
|
||||
* Allowed configuration in composer.json "extra.modularity".
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
/** Allowed configuration in composer.json "extra.modularity" */
|
||||
public const EXTRA_KEYS = [
|
||||
self::PROP_DOMAIN_PATH,
|
||||
self::PROP_NAME,
|
||||
|
@ -31,32 +40,33 @@ class LibraryProperties extends BaseProperties
|
|||
*
|
||||
* @return LibraryProperties
|
||||
*
|
||||
* @throws \Exception
|
||||
* @psalm-suppress MixedArrayAccess
|
||||
* phpcs:disable SlevomatCodingStandard.Complexity
|
||||
*/
|
||||
public static function new(string $composerJsonFile, ?string $baseUrl = null): LibraryProperties
|
||||
{
|
||||
if (!\is_file($composerJsonFile) || !\is_readable($composerJsonFile)) {
|
||||
throw new \Exception("File {$composerJsonFile} does not exist or is not readable.");
|
||||
}
|
||||
// phpcs:enable SlevomatCodingStandard.Complexity
|
||||
|
||||
$content = (string) file_get_contents($composerJsonFile);
|
||||
/** @var array $composerJsonData */
|
||||
$composerJsonData = json_decode($content, true);
|
||||
$composerJsonData = self::readComposerJsonData($composerJsonFile);
|
||||
|
||||
$properties = Properties::DEFAULT_PROPERTIES;
|
||||
$properties[self::PROP_DESCRIPTION] = $composerJsonData['description'] ?? '';
|
||||
$properties[self::PROP_TAGS] = $composerJsonData['keywords'] ?? [];
|
||||
|
||||
$authors = $composerJsonData['authors'] ?? [];
|
||||
if (!is_array($authors)) {
|
||||
$authors = [];
|
||||
}
|
||||
$names = [];
|
||||
foreach ((array) $authors as $author) {
|
||||
$name = $author['name'] ?? null;
|
||||
if ($name && is_string($name)) {
|
||||
foreach ($authors as $author) {
|
||||
if (!is_array($author)) {
|
||||
continue;
|
||||
}
|
||||
$name = $author['name'] ?? '';
|
||||
if (($name !== '') && is_string($name)) {
|
||||
$names[] = $name;
|
||||
}
|
||||
$url = $author['homepage'] ?? null;
|
||||
if ($url && !$properties['authorUri'] && is_string($url)) {
|
||||
$url = $author['homepage'] ?? '';
|
||||
if (($url !== '') && ($properties[self::PROP_AUTHOR_URI] === '') && is_string($url)) {
|
||||
$properties[self::PROP_AUTHOR_URI] = $url;
|
||||
}
|
||||
}
|
||||
|
@ -66,6 +76,9 @@ class LibraryProperties extends BaseProperties
|
|||
|
||||
// Custom settings which can be stored in composer.json "extra.modularity"
|
||||
$extra = $composerJsonData['extra']['modularity'] ?? [];
|
||||
if (!is_array($extra)) {
|
||||
$extra = [];
|
||||
}
|
||||
foreach (self::EXTRA_KEYS as $key) {
|
||||
$properties[$key] = $extra[$key] ?? '';
|
||||
}
|
||||
|
@ -74,39 +87,50 @@ class LibraryProperties extends BaseProperties
|
|||
$properties[self::PROP_REQUIRES_PHP] = self::extractPhpVersion($composerJsonData);
|
||||
|
||||
// composer.json might have "version" in root
|
||||
$version = $composerJsonData['version'] ?? null;
|
||||
if ($version && is_string($version)) {
|
||||
$version = $composerJsonData['version'] ?? '';
|
||||
if (($version !== '') && is_string($version)) {
|
||||
$properties[self::PROP_VERSION] = $version;
|
||||
}
|
||||
|
||||
[$baseName, $name] = static::buildNames($composerJsonData);
|
||||
$basePath = dirname($composerJsonFile);
|
||||
if (empty($properties[self::PROP_NAME])) {
|
||||
if (($properties[self::PROP_NAME] === '') || !is_string($properties[self::PROP_NAME])) {
|
||||
$properties[self::PROP_NAME] = $name;
|
||||
}
|
||||
|
||||
return new self(
|
||||
$baseName,
|
||||
$basePath,
|
||||
$baseUrl,
|
||||
$properties
|
||||
);
|
||||
return new self($baseName, $basePath, $baseUrl, $properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $composerJsonData
|
||||
* @param string $url
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function withBaseUrl(string $url): LibraryProperties
|
||||
{
|
||||
if ($this->baseUrl !== null) {
|
||||
throw new \Exception(sprintf('%s::$baseUrl property is not overridable.', __CLASS__));
|
||||
}
|
||||
|
||||
$this->baseUrl = trailingslashit($url);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ComposerData $composerJsonData
|
||||
*
|
||||
* @return array{string, string}
|
||||
*/
|
||||
private static function buildNames(array $composerJsonData): array
|
||||
protected static function buildNames(array $composerJsonData): array
|
||||
{
|
||||
$composerName = (string) ($composerJsonData['name'] ?? '');
|
||||
$packageNamePieces = explode('/', $composerName, 2);
|
||||
$basename = implode('-', $packageNamePieces);
|
||||
// "inpsyde/foo-bar-baz" => "Inpsyde Foo Bar Baz"
|
||||
// From "syde/foo-bar-baz" to "Syde Foo Bar Baz"
|
||||
$name = mb_convert_case(
|
||||
str_replace(['-', '_', '.'], ' ', implode(' ', $packageNamePieces)),
|
||||
MB_CASE_TITLE
|
||||
MB_CASE_TITLE,
|
||||
);
|
||||
|
||||
return [$basename, $name];
|
||||
|
@ -122,88 +146,111 @@ class LibraryProperties extends BaseProperties
|
|||
* `5.6 || >= 7.1` returns `5.6`
|
||||
* `>= 7.1 < 8` returns `7.1`
|
||||
*
|
||||
* @param array $composerData
|
||||
* @param ComposerData $composerData
|
||||
* @param string $key
|
||||
*
|
||||
* @return string|null
|
||||
* @return string
|
||||
*/
|
||||
private static function extractPhpVersion(array $composerData, string $key = 'require'): ?string
|
||||
{
|
||||
protected static function extractPhpVersion(
|
||||
array $composerData,
|
||||
string $key = 'require'
|
||||
): string {
|
||||
|
||||
$nextKey = ($key === 'require')
|
||||
? 'require-dev'
|
||||
: null;
|
||||
$base = (array) ($composerData[$key] ?? []);
|
||||
$requirement = $base['php'] ?? null;
|
||||
$version = ($requirement && is_string($requirement))
|
||||
$base = $composerData[$key] ?? null;
|
||||
$requirement = is_array($base)
|
||||
? ($base['php'] ?? '')
|
||||
: '';
|
||||
$version = (($requirement !== '') && is_string($requirement))
|
||||
? trim($requirement)
|
||||
: null;
|
||||
if (!$version) {
|
||||
return $nextKey
|
||||
: '';
|
||||
if ($version === '') {
|
||||
return ($nextKey !== null)
|
||||
? static::extractPhpVersion($composerData, $nextKey)
|
||||
: null;
|
||||
: '';
|
||||
}
|
||||
|
||||
static $matcher;
|
||||
$matcher or $matcher = static function (string $version): ?string {
|
||||
$version = trim($version);
|
||||
if (!$version) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// versions range like `>= 7.2.4 < 8`
|
||||
if (preg_match('{>=?([\s0-9\.]+)<}', $version, $matches)) {
|
||||
return trim($matches[1], " \t\n\r\0\x0B.");
|
||||
}
|
||||
|
||||
// aliases like `dev-src#abcde as 7.4`
|
||||
if (preg_match('{as\s*([\s0-9\.]+)}', $version, $matches)) {
|
||||
return trim($matches[1], " \t\n\r\0\x0B.");
|
||||
}
|
||||
|
||||
// Basic requirements like 7.2, >=7.2, ^7.2, ~7.2
|
||||
if (preg_match('{^(?:[>=\s~\^]+)?([0-9\.]+)}', $version, $matches)) {
|
||||
return trim($matches[1], " \t\n\r\0\x0B.");
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
// support for simpler requirements like `7.3`, `>=7.4` or alternative like `5.6 || >=7`
|
||||
|
||||
$alternatives = explode('||', $version);
|
||||
/** @var non-empty-string|null $found */
|
||||
$found = null;
|
||||
foreach ($alternatives as $alternative) {
|
||||
/** @var callable(string):?string $matcher */
|
||||
$itemFound = $matcher($alternative);
|
||||
if ($itemFound && (!$found || version_compare($itemFound, $found, '<'))) {
|
||||
$itemFound = static::parseVersion($alternative);
|
||||
if (
|
||||
($itemFound !== '')
|
||||
&& (($found === null) || version_compare($itemFound, $found, '<'))
|
||||
) {
|
||||
$found = $itemFound;
|
||||
}
|
||||
}
|
||||
|
||||
if ($found) {
|
||||
if ($found !== null) {
|
||||
return $found;
|
||||
}
|
||||
|
||||
return $nextKey
|
||||
return ($nextKey !== null)
|
||||
? static::extractPhpVersion($composerData, $nextKey)
|
||||
: null;
|
||||
: '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @param string $version
|
||||
*
|
||||
* @return static
|
||||
*
|
||||
* @throws \Exception
|
||||
* @return string
|
||||
*/
|
||||
public function withBaseUrl(string $url): LibraryProperties
|
||||
protected static function parseVersion(string $version): string
|
||||
{
|
||||
if ($this->baseUrl !== null) {
|
||||
throw new \Exception(sprintf('%s::$baseUrl property is not overridable.', __CLASS__));
|
||||
$version = trim($version);
|
||||
if ($version === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
$this->baseUrl = trailingslashit($url);
|
||||
// versions range like `>= 7.2.4 < 8`
|
||||
if (preg_match('{>=?([\s0-9\.]+)<}', $version, $matches)) {
|
||||
return trim($matches[1], " \t\n\r\0\x0B.");
|
||||
}
|
||||
|
||||
return $this;
|
||||
// aliases like `dev-src#abcde as 7.4`
|
||||
if (preg_match('{as\s*([\s0-9\.]+)}', $version, $matches)) {
|
||||
return trim($matches[1], " \t\n\r\0\x0B.");
|
||||
}
|
||||
|
||||
// Basic requirements like 7.2, >=7.2, ^7.2, ~7.2
|
||||
if (preg_match('{^(?:[>=\s~\^]+)?([0-9\.]+)}', $version, $matches)) {
|
||||
return trim($matches[1], " \t\n\r\0\x0B.");
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $composerJsonFile
|
||||
*
|
||||
* @return ComposerData
|
||||
* @throws \Exception
|
||||
*/
|
||||
private static function readComposerJsonData(string $composerJsonFile): array
|
||||
{
|
||||
if (!\is_file($composerJsonFile) || !\is_readable($composerJsonFile)) {
|
||||
throw new \Exception(
|
||||
esc_html("File {$composerJsonFile} does not exist or is not readable."),
|
||||
);
|
||||
}
|
||||
|
||||
$content = (string) file_get_contents($composerJsonFile);
|
||||
|
||||
/** @var ComposerData $composerJsonData */
|
||||
$composerJsonData = json_decode($content, true);
|
||||
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
throw new \Exception(
|
||||
esc_html("Error reading file {$composerJsonFile}: " . json_last_error_msg()),
|
||||
);
|
||||
}
|
||||
|
||||
return $composerJsonData;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,24 +4,14 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Properties;
|
||||
|
||||
/**
|
||||
* Class PluginProperties
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Properties
|
||||
*
|
||||
* @psalm-suppress PossiblyFalseArgument, InvalidArgument
|
||||
*/
|
||||
class PluginProperties extends BaseProperties
|
||||
{
|
||||
/**
|
||||
* Custom properties for Plugins.
|
||||
*/
|
||||
// Custom properties for Plugins
|
||||
public const PROP_NETWORK = 'network';
|
||||
public const PROP_REQUIRES_PLUGINS = 'requiresPlugins';
|
||||
|
||||
/**
|
||||
* Available methods of Properties::__call()
|
||||
* from plugin headers.
|
||||
*
|
||||
* @link https://developer.wordpress.org/reference/functions/get_plugin_data/
|
||||
* @see https://developer.wordpress.org/reference/functions/get_plugin_data/
|
||||
*/
|
||||
protected const HEADERS = [
|
||||
self::PROP_AUTHOR => 'Author',
|
||||
|
@ -37,36 +27,17 @@ class PluginProperties extends BaseProperties
|
|||
|
||||
// additional headers
|
||||
self::PROP_NETWORK => 'Network',
|
||||
self::PROP_REQUIRES_PLUGINS => 'RequiresPlugins',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $pluginMainFile;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $pluginBaseName;
|
||||
|
||||
/**
|
||||
* @var bool|null
|
||||
*/
|
||||
protected $isMu;
|
||||
|
||||
/**
|
||||
* @var bool|null
|
||||
*/
|
||||
protected $isActive;
|
||||
|
||||
/**
|
||||
* @var bool|null
|
||||
*/
|
||||
protected $isNetworkActive;
|
||||
private string $pluginMainFile;
|
||||
private string $pluginBaseName;
|
||||
protected ?bool $isMu = null;
|
||||
protected ?bool $isActive = null;
|
||||
protected ?bool $isNetworkActive = null;
|
||||
|
||||
/**
|
||||
* @param string $pluginMainFile
|
||||
*
|
||||
* @return PluginProperties
|
||||
*/
|
||||
public static function new(string $pluginMainFile): PluginProperties
|
||||
|
@ -75,8 +46,6 @@ class PluginProperties extends BaseProperties
|
|||
}
|
||||
|
||||
/**
|
||||
* PluginProperties constructor.
|
||||
*
|
||||
* @param string $pluginMainFile
|
||||
*/
|
||||
protected function __construct(string $pluginMainFile)
|
||||
|
@ -85,7 +54,11 @@ class PluginProperties extends BaseProperties
|
|||
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
||||
}
|
||||
|
||||
$pluginData = get_plugin_data($pluginMainFile);
|
||||
// $markup = false, to avoid an incorrect early wptexturize call.
|
||||
// $translate = false, to avoid loading translations too early
|
||||
// @see https://core.trac.wordpress.org/ticket/49965
|
||||
// @see https://core.trac.wordpress.org/ticket/34114
|
||||
$pluginData = (array) get_plugin_data($pluginMainFile, false, false);
|
||||
$properties = Properties::DEFAULT_PROPERTIES;
|
||||
|
||||
// Map pluginData to internal structure.
|
||||
|
@ -93,6 +66,7 @@ class PluginProperties extends BaseProperties
|
|||
$properties[$key] = $pluginData[$pluginDataKey] ?? '';
|
||||
unset($pluginData[$pluginDataKey]);
|
||||
}
|
||||
/** @var array<string, mixed> $properties */
|
||||
$properties = array_merge($properties, $pluginData);
|
||||
|
||||
$this->pluginMainFile = wp_normalize_path($pluginMainFile);
|
||||
|
@ -119,14 +93,22 @@ class PluginProperties extends BaseProperties
|
|||
|
||||
/**
|
||||
* @return bool
|
||||
*
|
||||
* @psalm-suppress PossiblyFalseArgument
|
||||
*/
|
||||
public function network(): bool
|
||||
{
|
||||
return (bool) $this->get(self::PROP_NETWORK, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function requiresPlugins(): array
|
||||
{
|
||||
$value = $this->get(self::PROP_REQUIRES_PLUGINS);
|
||||
|
||||
return $value && is_string($value) ? explode(',', $value) : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
|
@ -163,10 +145,6 @@ class PluginProperties extends BaseProperties
|
|||
public function isMuPlugin(): bool
|
||||
{
|
||||
if ($this->isMu === null) {
|
||||
/**
|
||||
* @psalm-suppress UndefinedConstant
|
||||
* @psalm-suppress MixedArgument
|
||||
*/
|
||||
$muPluginDir = wp_normalize_path(WPMU_PLUGIN_DIR);
|
||||
$this->isMu = strpos($this->pluginMainFile, $muPluginDir) === 0;
|
||||
}
|
||||
|
|
|
@ -17,9 +17,7 @@ interface Properties
|
|||
public const PROP_REQUIRES_WP = 'requiresWp';
|
||||
public const PROP_REQUIRES_PHP = 'requiresPhp';
|
||||
public const PROP_TAGS = 'tags';
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
|
||||
public const DEFAULT_PROPERTIES = [
|
||||
self::PROP_AUTHOR => '',
|
||||
self::PROP_AUTHOR_URI => '',
|
||||
|
@ -36,15 +34,13 @@ interface Properties
|
|||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param null $default
|
||||
*
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
*/
|
||||
public function get(string $key, $default = null);
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has(string $key): bool;
|
||||
|
@ -103,6 +99,7 @@ interface Properties
|
|||
|
||||
/**
|
||||
* The home page of the plugin, theme or library.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function uri(): string;
|
||||
|
@ -122,7 +119,7 @@ interface Properties
|
|||
/**
|
||||
* Optional. Specify the minimum required PHP version.
|
||||
*
|
||||
* @return string
|
||||
* @return string|null
|
||||
*/
|
||||
public function requiresPhp(): ?string;
|
||||
|
||||
|
@ -130,10 +127,10 @@ interface Properties
|
|||
* Optional. Currently, only available for Theme and Library.
|
||||
* Plugins do not have support for "tags"/"keywords" in header.
|
||||
*
|
||||
* @link https://developer.wordpress.org/reference/classes/wp_theme/#properties
|
||||
* @link https://getcomposer.org/doc/04-schema.md#keywords
|
||||
* @return string[]
|
||||
*
|
||||
* @return array
|
||||
* @see https://developer.wordpress.org/reference/classes/wp_theme/#properties
|
||||
* @see https://getcomposer.org/doc/04-schema.md#keywords
|
||||
*/
|
||||
public function tags(): array;
|
||||
}
|
||||
|
|
|
@ -4,26 +4,12 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Properties;
|
||||
|
||||
/**
|
||||
* Class ThemeProperties
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Properties
|
||||
*
|
||||
* @psalm-suppress PossiblyFalseArgument, InvalidArgument
|
||||
*/
|
||||
class ThemeProperties extends BaseProperties
|
||||
{
|
||||
/**
|
||||
* Additional properties specific for themes.
|
||||
*/
|
||||
public const PROP_STATUS = 'status';
|
||||
public const PROP_TEMPLATE = 'template';
|
||||
/**
|
||||
* Available methods of Properties::__call()
|
||||
* from theme headers.
|
||||
*
|
||||
* @link https://developer.wordpress.org/reference/classes/wp_theme/
|
||||
*/
|
||||
|
||||
/** @see https://developer.wordpress.org/reference/classes/wp_theme/ */
|
||||
protected const HEADERS = [
|
||||
self::PROP_AUTHOR => 'Author',
|
||||
self::PROP_AUTHOR_URI => 'AuthorURI',
|
||||
|
@ -53,8 +39,6 @@ class ThemeProperties extends BaseProperties
|
|||
}
|
||||
|
||||
/**
|
||||
* ThemeProperties constructor.
|
||||
*
|
||||
* @param string $themeDirectory
|
||||
*/
|
||||
protected function __construct(string $themeDirectory)
|
||||
|
@ -67,13 +51,15 @@ class ThemeProperties extends BaseProperties
|
|||
$properties = Properties::DEFAULT_PROPERTIES;
|
||||
|
||||
foreach (self::HEADERS as $key => $themeKey) {
|
||||
/** @psalm-suppress DocblockTypeContradiction */
|
||||
$properties[$key] = $theme->get($themeKey) ?? '';
|
||||
$property = $theme->get($themeKey);
|
||||
if (is_string($property) || is_array($property)) {
|
||||
$properties[$key] = $property;
|
||||
}
|
||||
}
|
||||
|
||||
$baseName = $theme->get_stylesheet();
|
||||
$basePath = $theme->get_stylesheet_directory();
|
||||
$baseUrl = (string) trailingslashit($theme->get_stylesheet_directory_uri());
|
||||
$baseUrl = trailingslashit($theme->get_stylesheet_directory_uri());
|
||||
|
||||
parent::__construct(
|
||||
$baseName,
|
||||
|
@ -84,8 +70,6 @@ class ThemeProperties extends BaseProperties
|
|||
}
|
||||
|
||||
/**
|
||||
* If the theme is published.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function status(): string
|
||||
|
@ -93,6 +77,9 @@ class ThemeProperties extends BaseProperties
|
|||
return (string) $this->get(self::PROP_STATUS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function template(): string
|
||||
{
|
||||
return (string) $this->get(self::PROP_TEMPLATE);
|
||||
|
@ -120,7 +107,7 @@ class ThemeProperties extends BaseProperties
|
|||
public function parentThemeProperties(): ?ThemeProperties
|
||||
{
|
||||
$template = $this->template();
|
||||
if (!$template) {
|
||||
if ($template === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,9 +2,11 @@
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\Vendor\Psr\Container;
|
||||
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Base interface representing a generic exception in a container.
|
||||
*/
|
||||
interface ContainerExceptionInterface
|
||||
interface ContainerExceptionInterface extends Throwable
|
||||
{
|
||||
}
|
||||
|
|
|
@ -18,14 +18,7 @@ use WooCommerce\PayPalCommerce\AdminNotices\Endpoint\MuteMessageEndpoint;
|
|||
|
||||
return array(
|
||||
'admin-notices.url' => static function ( ContainerInterface $container ): string {
|
||||
$path = realpath( __FILE__ );
|
||||
if ( false === $path ) {
|
||||
return '';
|
||||
}
|
||||
return plugins_url(
|
||||
'/modules/ppcp-admin-notices/',
|
||||
dirname( $path, 3 ) . '/woocommerce-paypal-payments.php'
|
||||
);
|
||||
return plugins_url( '/modules/ppcp-admin-notices/', $container->get( 'ppcp.path-to-plugin-main-file' ) );
|
||||
},
|
||||
'admin-notices.renderer' => static function ( ContainerInterface $container ): RendererInterface {
|
||||
return new Renderer(
|
||||
|
|
|
@ -49,7 +49,7 @@ class AdminNotices implements ServiceModule, ExtendingModule, ExecutableModule {
|
|||
|
||||
add_action(
|
||||
'admin_notices',
|
||||
function() use ( $renderer ) {
|
||||
function () use ( $renderer ) {
|
||||
$renderer->render();
|
||||
}
|
||||
);
|
||||
|
@ -113,11 +113,10 @@ class AdminNotices implements ServiceModule, ExtendingModule, ExecutableModule {
|
|||
|
||||
add_action(
|
||||
'woocommerce_init',
|
||||
function() {
|
||||
function () {
|
||||
if ( is_admin() && is_callable( array( WC(), 'is_wc_admin_active' ) ) && WC()->is_wc_admin_active() && class_exists( 'Automattic\WooCommerce\Admin\Notes\Notes' ) ) {
|
||||
MexicoInstallmentsNote::init();
|
||||
}
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ class MuteMessageEndpoint {
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function nonce() : string {
|
||||
public static function nonce(): string {
|
||||
return self::ENDPOINT;
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,7 @@ class MuteMessageEndpoint {
|
|||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle_request() : void {
|
||||
public function handle_request(): void {
|
||||
try {
|
||||
$data = $this->request_data->read_request( $this->nonce() );
|
||||
} catch ( RuntimeException $ex ) {
|
||||
|
|
|
@ -62,7 +62,7 @@ class Message {
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function message() : string {
|
||||
public function message(): string {
|
||||
return $this->message;
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,7 @@ class Message {
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function type() : string {
|
||||
public function type(): string {
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
|
@ -80,7 +80,7 @@ class Message {
|
|||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_dismissible() : bool {
|
||||
public function is_dismissible(): bool {
|
||||
return $this->dismissible;
|
||||
}
|
||||
|
||||
|
@ -89,7 +89,7 @@ class Message {
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function wrapper() : string {
|
||||
public function wrapper(): string {
|
||||
return $this->wrapper;
|
||||
}
|
||||
|
||||
|
@ -98,7 +98,7 @@ class Message {
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function to_array() : array {
|
||||
public function to_array(): array {
|
||||
return array(
|
||||
'type' => $this->type,
|
||||
'message' => $this->message,
|
||||
|
@ -114,7 +114,7 @@ class Message {
|
|||
*
|
||||
* @return Message
|
||||
*/
|
||||
public static function from_array( array $data ) : Message {
|
||||
public static function from_array( array $data ): Message {
|
||||
return new Message(
|
||||
(string) ( $data['message'] ?? '' ),
|
||||
(string) ( $data['type'] ?? '' ),
|
||||
|
|
|
@ -47,7 +47,7 @@ class PersistentMessage extends Message {
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function id( bool $with_db_prefix = false ) : string {
|
||||
public function id( bool $with_db_prefix = false ): string {
|
||||
if ( ! $this->message_id ) {
|
||||
return '';
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ class PersistentMessage extends Message {
|
|||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function to_array() : array {
|
||||
public function to_array(): array {
|
||||
$data = parent::to_array();
|
||||
$data['id'] = $this->message_id;
|
||||
|
||||
|
@ -70,7 +70,7 @@ class PersistentMessage extends Message {
|
|||
*
|
||||
* @return PersistentMessage
|
||||
*/
|
||||
public static function from_array( array $data ) : Message {
|
||||
public static function from_array( array $data ): Message {
|
||||
return new PersistentMessage(
|
||||
(string) ( $data['id'] ?? '' ),
|
||||
(string) ( $data['message'] ?? '' ),
|
||||
|
@ -84,7 +84,7 @@ class PersistentMessage extends Message {
|
|||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_muted() : bool {
|
||||
public function is_muted(): bool {
|
||||
$user_id = get_current_user_id();
|
||||
|
||||
if ( ! $this->message_id || ! $user_id ) {
|
||||
|
@ -99,7 +99,7 @@ class PersistentMessage extends Message {
|
|||
*
|
||||
* @return void
|
||||
*/
|
||||
public function mute() : void {
|
||||
public function mute(): void {
|
||||
$user_id = get_current_user_id();
|
||||
|
||||
if ( $this->message_id && $user_id && ! $this->is_muted() ) {
|
||||
|
@ -112,7 +112,7 @@ class PersistentMessage extends Message {
|
|||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function clear_all() : void {
|
||||
public static function clear_all(): void {
|
||||
global $wpdb;
|
||||
|
||||
$wpdb->query(
|
||||
|
|
|
@ -95,7 +95,7 @@ class Renderer implements RendererInterface {
|
|||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function enqueue_admin() : void {
|
||||
public function enqueue_admin(): void {
|
||||
if ( ! $this->can_mute_message ) {
|
||||
return;
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ class Renderer implements RendererInterface {
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function script_data_for_admin() : array {
|
||||
protected function script_data_for_admin(): array {
|
||||
$ajax_url = admin_url( 'admin-ajax.php' );
|
||||
|
||||
return array(
|
||||
|
|
|
@ -26,5 +26,5 @@ interface RendererInterface {
|
|||
*
|
||||
* @return void
|
||||
*/
|
||||
public function enqueue_admin() : void;
|
||||
public function enqueue_admin(): void;
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ class Repository implements RepositoryInterface {
|
|||
*
|
||||
* @return Message[]
|
||||
*/
|
||||
public function current_message() : array {
|
||||
public function current_message(): array {
|
||||
return array_filter(
|
||||
/**
|
||||
* Returns the list of admin messages.
|
||||
|
@ -34,7 +34,7 @@ class Repository implements RepositoryInterface {
|
|||
self::NOTICES_FILTER,
|
||||
array()
|
||||
),
|
||||
function ( $element ) : bool {
|
||||
function ( $element ): bool {
|
||||
if ( $element instanceof PersistentMessage ) {
|
||||
return ! $element->is_muted();
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ class Repository implements RepositoryInterface {
|
|||
*
|
||||
* @return void
|
||||
*/
|
||||
public function persist( Message $message ) : void {
|
||||
public function persist( Message $message ): void {
|
||||
$persisted_notices = get_option( self::PERSISTED_NOTICES_OPTION ) ?: array();
|
||||
|
||||
$persisted_notices[] = $message->to_array();
|
||||
|
@ -64,7 +64,7 @@ class Repository implements RepositoryInterface {
|
|||
*
|
||||
* @return array|Message[]
|
||||
*/
|
||||
public function get_persisted_and_clear() : array {
|
||||
public function get_persisted_and_clear(): array {
|
||||
$notices = array();
|
||||
|
||||
$persisted_data = get_option( self::PERSISTED_NOTICES_OPTION ) ?: array();
|
||||
|
|
|
@ -86,7 +86,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Helper\EnvironmentConfig;
|
|||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
||||
return array(
|
||||
'api.host' => static function( ContainerInterface $container ) : string {
|
||||
'api.host' => static function ( ContainerInterface $container ): string {
|
||||
$environment = $container->get( 'settings.environment' );
|
||||
assert( $environment instanceof Environment );
|
||||
|
||||
|
@ -96,25 +96,25 @@ return array(
|
|||
|
||||
return (string) $container->get( 'api.production-host' );
|
||||
},
|
||||
'api.paypal-host' => function( ContainerInterface $container ) : string {
|
||||
'api.paypal-host' => function ( ContainerInterface $container ): string {
|
||||
return PAYPAL_API_URL;
|
||||
},
|
||||
// It seems this 'api.paypal-website-url' key is always overridden in ppcp-onboarding/services.php.
|
||||
'api.paypal-website-url' => function( ContainerInterface $container ) : string {
|
||||
'api.paypal-website-url' => function ( ContainerInterface $container ): string {
|
||||
return PAYPAL_URL;
|
||||
},
|
||||
'api.factory.paypal-checkout-url' => function( ContainerInterface $container ) : callable {
|
||||
'api.factory.paypal-checkout-url' => function ( ContainerInterface $container ): callable {
|
||||
return function ( string $id ) use ( $container ): string {
|
||||
return $container->get( 'api.paypal-website-url' ) . '/checkoutnow?token=' . $id;
|
||||
};
|
||||
},
|
||||
'api.partner_merchant_id' => static function () : string {
|
||||
'api.partner_merchant_id' => static function (): string {
|
||||
return '';
|
||||
},
|
||||
'api.merchant_email' => function () : string {
|
||||
'api.merchant_email' => function (): string {
|
||||
return '';
|
||||
},
|
||||
'api.merchant_id' => function () : string {
|
||||
'api.merchant_id' => function (): string {
|
||||
return '';
|
||||
},
|
||||
'api.key' => static function (): string {
|
||||
|
@ -142,7 +142,7 @@ return array(
|
|||
$container->get( 'wcgateway.settings' )
|
||||
);
|
||||
},
|
||||
'api.endpoint.partners' => static function ( ContainerInterface $container ) : PartnersEndpoint {
|
||||
'api.endpoint.partners' => static function ( ContainerInterface $container ): PartnersEndpoint {
|
||||
return new PartnersEndpoint(
|
||||
$container->get( 'api.host' ),
|
||||
$container->get( 'api.bearer' ),
|
||||
|
@ -153,10 +153,10 @@ return array(
|
|||
$container->get( 'api.helper.failure-registry' )
|
||||
);
|
||||
},
|
||||
'api.factory.sellerstatus' => static function ( ContainerInterface $container ) : SellerStatusFactory {
|
||||
'api.factory.sellerstatus' => static function ( ContainerInterface $container ): SellerStatusFactory {
|
||||
return new SellerStatusFactory();
|
||||
},
|
||||
'api.endpoint.payment-token' => static function ( ContainerInterface $container ) : PaymentTokenEndpoint {
|
||||
'api.endpoint.payment-token' => static function ( ContainerInterface $container ): PaymentTokenEndpoint {
|
||||
return new PaymentTokenEndpoint(
|
||||
$container->get( 'api.host' ),
|
||||
$container->get( 'api.bearer' ),
|
||||
|
@ -166,14 +166,14 @@ return array(
|
|||
$container->get( 'api.repository.customer' )
|
||||
);
|
||||
},
|
||||
'api.endpoint.payment-tokens' => static function( ContainerInterface $container ) : PaymentTokensEndpoint {
|
||||
'api.endpoint.payment-tokens' => static function ( ContainerInterface $container ): PaymentTokensEndpoint {
|
||||
return new PaymentTokensEndpoint(
|
||||
$container->get( 'api.host' ),
|
||||
$container->get( 'api.bearer' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'api.endpoint.webhook' => static function ( ContainerInterface $container ) : WebhookEndpoint {
|
||||
'api.endpoint.webhook' => static function ( ContainerInterface $container ): WebhookEndpoint {
|
||||
|
||||
return new WebhookEndpoint(
|
||||
$container->get( 'api.host' ),
|
||||
|
@ -183,7 +183,7 @@ return array(
|
|||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'api.endpoint.partner-referrals' => static function ( ContainerInterface $container ) : PartnerReferrals {
|
||||
'api.endpoint.partner-referrals' => static function ( ContainerInterface $container ): PartnerReferrals {
|
||||
|
||||
return new PartnerReferrals(
|
||||
$container->get( 'api.host' ),
|
||||
|
@ -191,7 +191,7 @@ return array(
|
|||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'api.endpoint.partner-referrals-sandbox' => static function ( ContainerInterface $container ) : PartnerReferrals {
|
||||
'api.endpoint.partner-referrals-sandbox' => static function ( ContainerInterface $container ): PartnerReferrals {
|
||||
|
||||
return new PartnerReferrals(
|
||||
CONNECT_WOO_SANDBOX_URL,
|
||||
|
@ -199,7 +199,7 @@ return array(
|
|||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'api.endpoint.partner-referrals-production' => static function ( ContainerInterface $container ) : PartnerReferrals {
|
||||
'api.endpoint.partner-referrals-production' => static function ( ContainerInterface $container ): PartnerReferrals {
|
||||
|
||||
return new PartnerReferrals(
|
||||
CONNECT_WOO_URL,
|
||||
|
@ -207,7 +207,7 @@ return array(
|
|||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'api.endpoint.identity-token' => static function ( ContainerInterface $container ) : IdentityToken {
|
||||
'api.endpoint.identity-token' => static function ( ContainerInterface $container ): IdentityToken {
|
||||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
$customer_repository = $container->get( 'api.repository.customer' );
|
||||
|
@ -232,7 +232,7 @@ return array(
|
|||
$logger
|
||||
);
|
||||
},
|
||||
'api.endpoint.login-seller' => static function ( ContainerInterface $container ) : LoginSeller {
|
||||
'api.endpoint.login-seller' => static function ( ContainerInterface $container ): LoginSeller {
|
||||
|
||||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||
return new LoginSeller(
|
||||
|
@ -287,7 +287,7 @@ return array(
|
|||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'api.endpoint.billing-plans' => static function( ContainerInterface $container ): BillingPlans {
|
||||
'api.endpoint.billing-plans' => static function ( ContainerInterface $container ): BillingPlans {
|
||||
return new BillingPlans(
|
||||
$container->get( 'api.host' ),
|
||||
$container->get( 'api.bearer' ),
|
||||
|
@ -296,21 +296,21 @@ return array(
|
|||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'api.endpoint.billing-subscriptions' => static function( ContainerInterface $container ): BillingSubscriptions {
|
||||
'api.endpoint.billing-subscriptions' => static function ( ContainerInterface $container ): BillingSubscriptions {
|
||||
return new BillingSubscriptions(
|
||||
$container->get( 'api.host' ),
|
||||
$container->get( 'api.bearer' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'api.endpoint.payment-method-tokens' => static function( ContainerInterface $container ): PaymentMethodTokensEndpoint {
|
||||
'api.endpoint.payment-method-tokens' => static function ( ContainerInterface $container ): PaymentMethodTokensEndpoint {
|
||||
return new PaymentMethodTokensEndpoint(
|
||||
$container->get( 'api.host' ),
|
||||
$container->get( 'api.bearer' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'api.repository.partner-referrals-data' => static function ( ContainerInterface $container ) : PartnerReferralsData {
|
||||
'api.repository.partner-referrals-data' => static function ( ContainerInterface $container ): PartnerReferralsData {
|
||||
|
||||
$dcc_applies = $container->get( 'api.helpers.dccapplies' );
|
||||
return new PartnerReferralsData( $dcc_applies );
|
||||
|
@ -320,11 +320,11 @@ return array(
|
|||
$merchant_id = $container->get( 'api.merchant_id' );
|
||||
return new PayeeRepository( $merchant_email, $merchant_id );
|
||||
},
|
||||
'api.repository.customer' => static function( ContainerInterface $container ): CustomerRepository {
|
||||
'api.repository.customer' => static function ( ContainerInterface $container ): CustomerRepository {
|
||||
$prefix = $container->get( 'api.prefix' );
|
||||
return new CustomerRepository( $prefix );
|
||||
},
|
||||
'api.repository.order' => static function( ContainerInterface $container ): OrderRepository {
|
||||
'api.repository.order' => static function ( ContainerInterface $container ): OrderRepository {
|
||||
return new OrderRepository(
|
||||
$container->get( 'api.endpoint.order' )
|
||||
);
|
||||
|
@ -345,10 +345,10 @@ return array(
|
|||
$container->get( 'settings.merchant-details' )
|
||||
);
|
||||
},
|
||||
'api.factory.payment-token' => static function ( ContainerInterface $container ) : PaymentTokenFactory {
|
||||
'api.factory.payment-token' => static function ( ContainerInterface $container ): PaymentTokenFactory {
|
||||
return new PaymentTokenFactory();
|
||||
},
|
||||
'api.factory.payment-token-action-links' => static function ( ContainerInterface $container ) : PaymentTokenActionLinksFactory {
|
||||
'api.factory.payment-token-action-links' => static function ( ContainerInterface $container ): PaymentTokenActionLinksFactory {
|
||||
return new PaymentTokenActionLinksFactory();
|
||||
},
|
||||
'api.factory.webhook' => static function ( ContainerInterface $container ): WebhookFactory {
|
||||
|
@ -485,25 +485,25 @@ return array(
|
|||
'api.factory.fraud-processor-response' => static function ( ContainerInterface $container ): FraudProcessorResponseFactory {
|
||||
return new FraudProcessorResponseFactory();
|
||||
},
|
||||
'api.factory.product' => static function( ContainerInterface $container ): ProductFactory {
|
||||
'api.factory.product' => static function ( ContainerInterface $container ): ProductFactory {
|
||||
return new ProductFactory();
|
||||
},
|
||||
'api.factory.billing-cycle' => static function( ContainerInterface $container ): BillingCycleFactory {
|
||||
'api.factory.billing-cycle' => static function ( ContainerInterface $container ): BillingCycleFactory {
|
||||
return new BillingCycleFactory( $container->get( 'api.shop.currency.getter' ) );
|
||||
},
|
||||
'api.factory.payment-preferences' => static function( ContainerInterface $container ):PaymentPreferencesFactory {
|
||||
'api.factory.payment-preferences' => static function ( ContainerInterface $container ): PaymentPreferencesFactory {
|
||||
return new PaymentPreferencesFactory( $container->get( 'api.shop.currency.getter' ) );
|
||||
},
|
||||
'api.factory.plan' => static function( ContainerInterface $container ): PlanFactory {
|
||||
'api.factory.plan' => static function ( ContainerInterface $container ): PlanFactory {
|
||||
return new PlanFactory(
|
||||
$container->get( 'api.factory.billing-cycle' ),
|
||||
$container->get( 'api.factory.payment-preferences' )
|
||||
);
|
||||
},
|
||||
'api.factory.card-authentication-result-factory' => static function( ContainerInterface $container ): CardAuthenticationResultFactory {
|
||||
'api.factory.card-authentication-result-factory' => static function ( ContainerInterface $container ): CardAuthenticationResultFactory {
|
||||
return new CardAuthenticationResultFactory();
|
||||
},
|
||||
'api.helpers.dccapplies' => static function ( ContainerInterface $container ) : DccApplies {
|
||||
'api.helpers.dccapplies' => static function ( ContainerInterface $container ): DccApplies {
|
||||
return new DccApplies(
|
||||
$container->get( 'api.dcc-supported-country-currency-matrix' ),
|
||||
$container->get( 'api.dcc-supported-country-card-matrix' ),
|
||||
|
@ -512,21 +512,21 @@ return array(
|
|||
);
|
||||
},
|
||||
|
||||
'api.shop.currency.getter' => static function ( ContainerInterface $container ) : CurrencyGetter {
|
||||
'api.shop.currency.getter' => static function ( ContainerInterface $container ): CurrencyGetter {
|
||||
return new CurrencyGetter();
|
||||
},
|
||||
'api.shop.country' => static function ( ContainerInterface $container ) : string {
|
||||
'api.shop.country' => static function ( ContainerInterface $container ): string {
|
||||
$location = wc_get_base_location();
|
||||
return $location['country'];
|
||||
},
|
||||
'api.shop.is-psd2-country' => static function ( ContainerInterface $container ) : bool {
|
||||
'api.shop.is-psd2-country' => static function ( ContainerInterface $container ): bool {
|
||||
return in_array(
|
||||
$container->get( 'api.shop.country' ),
|
||||
$container->get( 'api.psd2-countries' ),
|
||||
true
|
||||
);
|
||||
},
|
||||
'api.shop.is-currency-supported' => static function ( ContainerInterface $container ) : bool {
|
||||
'api.shop.is-currency-supported' => static function ( ContainerInterface $container ): bool {
|
||||
return in_array(
|
||||
$container->get( 'api.shop.currency.getter' )->get(),
|
||||
$container->get( 'api.supported-currencies' ),
|
||||
|
@ -593,7 +593,7 @@ return array(
|
|||
*
|
||||
* From https://developer.paypal.com/docs/reports/reference/paypal-supported-currencies/
|
||||
*/
|
||||
'api.supported-currencies' => static function ( ContainerInterface $container ) : array {
|
||||
'api.supported-currencies' => static function ( ContainerInterface $container ): array {
|
||||
return array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
|
@ -626,7 +626,7 @@ return array(
|
|||
/**
|
||||
* The matrix which countries and currency combinations can be used for DCC.
|
||||
*/
|
||||
'api.dcc-supported-country-currency-matrix' => static function ( ContainerInterface $container ) : array {
|
||||
'api.dcc-supported-country-currency-matrix' => static function ( ContainerInterface $container ): array {
|
||||
$default_currencies = apply_filters(
|
||||
'woocommerce_paypal_payments_supported_currencies',
|
||||
array(
|
||||
|
@ -712,7 +712,7 @@ return array(
|
|||
/**
|
||||
* Which countries support which credit cards. Empty credit card arrays mean no restriction on currency.
|
||||
*/
|
||||
'api.dcc-supported-country-card-matrix' => static function ( ContainerInterface $container ) : array {
|
||||
'api.dcc-supported-country-card-matrix' => static function ( ContainerInterface $container ): array {
|
||||
$mastercard_visa_amex = array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
|
@ -793,7 +793,7 @@ return array(
|
|||
);
|
||||
},
|
||||
|
||||
'api.psd2-countries' => static function ( ContainerInterface $container ) : array {
|
||||
'api.psd2-countries' => static function ( ContainerInterface $container ): array {
|
||||
return array(
|
||||
'AT',
|
||||
'BE',
|
||||
|
@ -826,7 +826,7 @@ return array(
|
|||
);
|
||||
},
|
||||
|
||||
'api.paylater-countries' => static function ( ContainerInterface $container ) : array {
|
||||
'api.paylater-countries' => static function ( ContainerInterface $container ): array {
|
||||
return apply_filters(
|
||||
'woocommerce_paypal_payments_supported_paylater_countries',
|
||||
array(
|
||||
|
@ -840,20 +840,20 @@ return array(
|
|||
)
|
||||
);
|
||||
},
|
||||
'api.order-helper' => static function( ContainerInterface $container ): OrderHelper {
|
||||
'api.order-helper' => static function ( ContainerInterface $container ): OrderHelper {
|
||||
return new OrderHelper();
|
||||
},
|
||||
'api.helper.order-transient' => static function( ContainerInterface $container ): OrderTransient {
|
||||
'api.helper.order-transient' => static function ( ContainerInterface $container ): OrderTransient {
|
||||
$cache = $container->get( 'api.paypal-bearer-cache' );
|
||||
$purchase_unit_sanitizer = $container->get( 'api.helper.purchase-unit-sanitizer' );
|
||||
return new OrderTransient( $cache, $purchase_unit_sanitizer );
|
||||
},
|
||||
'api.helper.failure-registry' => static function( ContainerInterface $container ): FailureRegistry {
|
||||
'api.helper.failure-registry' => static function ( ContainerInterface $container ): FailureRegistry {
|
||||
$cache = new Cache( 'ppcp-paypal-api-status-cache' );
|
||||
return new FailureRegistry( $cache );
|
||||
},
|
||||
'api.helper.purchase-unit-sanitizer' => SingletonDecorator::make(
|
||||
static function( ContainerInterface $container ): PurchaseUnitSanitizer {
|
||||
static function ( ContainerInterface $container ): PurchaseUnitSanitizer {
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
assert( $settings instanceof Settings );
|
||||
|
||||
|
@ -862,24 +862,24 @@ return array(
|
|||
return new PurchaseUnitSanitizer( $behavior, $line_name );
|
||||
}
|
||||
),
|
||||
'api.client-credentials' => static function( ContainerInterface $container ): ClientCredentials {
|
||||
'api.client-credentials' => static function ( ContainerInterface $container ): ClientCredentials {
|
||||
return new ClientCredentials(
|
||||
$container->get( 'wcgateway.settings' )
|
||||
);
|
||||
},
|
||||
'api.paypal-bearer-cache' => static function( ContainerInterface $container ): Cache {
|
||||
'api.paypal-bearer-cache' => static function ( ContainerInterface $container ): Cache {
|
||||
return new Cache( 'ppcp-paypal-bearer' );
|
||||
},
|
||||
'api.client-credentials-cache' => static function( ContainerInterface $container ): Cache {
|
||||
'api.client-credentials-cache' => static function ( ContainerInterface $container ): Cache {
|
||||
return new Cache( 'ppcp-client-credentials-cache' );
|
||||
},
|
||||
'api.user-id-token-cache' => static function( ContainerInterface $container ): Cache {
|
||||
'api.user-id-token-cache' => static function ( ContainerInterface $container ): Cache {
|
||||
return new Cache( 'ppcp-id-token-cache' );
|
||||
},
|
||||
'api.reference-transaction-status-cache' => static function( ContainerInterface $container ): Cache {
|
||||
'api.reference-transaction-status-cache' => static function ( ContainerInterface $container ): Cache {
|
||||
return new Cache( 'ppcp-reference-transaction-status-cache' );
|
||||
},
|
||||
'api.user-id-token' => static function( ContainerInterface $container ): UserIdToken {
|
||||
'api.user-id-token' => static function ( ContainerInterface $container ): UserIdToken {
|
||||
return new UserIdToken(
|
||||
$container->get( 'api.host' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' ),
|
||||
|
@ -887,7 +887,7 @@ return array(
|
|||
$container->get( 'api.user-id-token-cache' )
|
||||
);
|
||||
},
|
||||
'api.sdk-client-token' => static function( ContainerInterface $container ): SdkClientToken {
|
||||
'api.sdk-client-token' => static function ( ContainerInterface $container ): SdkClientToken {
|
||||
return new SdkClientToken(
|
||||
$container->get( 'api.host' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' ),
|
||||
|
@ -895,39 +895,39 @@ return array(
|
|||
$container->get( 'api.client-credentials-cache' )
|
||||
);
|
||||
},
|
||||
'api.paypal-host-production' => static function( ContainerInterface $container ) : string {
|
||||
'api.paypal-host-production' => static function ( ContainerInterface $container ): string {
|
||||
return PAYPAL_API_URL;
|
||||
},
|
||||
'api.paypal-host-sandbox' => static function( ContainerInterface $container ) : string {
|
||||
'api.paypal-host-sandbox' => static function ( ContainerInterface $container ): string {
|
||||
return PAYPAL_SANDBOX_API_URL;
|
||||
},
|
||||
'api.paypal-website-url-production' => static function( ContainerInterface $container ) : string {
|
||||
'api.paypal-website-url-production' => static function ( ContainerInterface $container ): string {
|
||||
return PAYPAL_URL;
|
||||
},
|
||||
'api.paypal-website-url-sandbox' => static function( ContainerInterface $container ) : string {
|
||||
'api.paypal-website-url-sandbox' => static function ( ContainerInterface $container ): string {
|
||||
return PAYPAL_SANDBOX_URL;
|
||||
},
|
||||
'api.partner_merchant_id-production' => static function( ContainerInterface $container ) : string {
|
||||
'api.partner_merchant_id-production' => static function ( ContainerInterface $container ): string {
|
||||
return CONNECT_WOO_MERCHANT_ID;
|
||||
},
|
||||
'api.partner_merchant_id-sandbox' => static function( ContainerInterface $container ) : string {
|
||||
'api.partner_merchant_id-sandbox' => static function ( ContainerInterface $container ): string {
|
||||
return CONNECT_WOO_SANDBOX_MERCHANT_ID;
|
||||
},
|
||||
'api.endpoint.login-seller-production' => static function ( ContainerInterface $container ) : LoginSeller {
|
||||
'api.endpoint.login-seller-production' => static function ( ContainerInterface $container ): LoginSeller {
|
||||
return new LoginSeller(
|
||||
$container->get( 'api.paypal-host-production' ),
|
||||
$container->get( 'api.partner_merchant_id-production' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'api.endpoint.login-seller-sandbox' => static function ( ContainerInterface $container ) : LoginSeller {
|
||||
'api.endpoint.login-seller-sandbox' => static function ( ContainerInterface $container ): LoginSeller {
|
||||
return new LoginSeller(
|
||||
$container->get( 'api.paypal-host-sandbox' ),
|
||||
$container->get( 'api.partner_merchant_id-sandbox' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'api.env.paypal-host' => static function ( ContainerInterface $container ) : EnvironmentConfig {
|
||||
'api.env.paypal-host' => static function ( ContainerInterface $container ): EnvironmentConfig {
|
||||
/**
|
||||
* Environment specific API host names.
|
||||
*
|
||||
|
@ -939,7 +939,7 @@ return array(
|
|||
$container->get( 'api.paypal-host-sandbox' )
|
||||
);
|
||||
},
|
||||
'api.env.endpoint.login-seller' => static function ( ContainerInterface $container ) : EnvironmentConfig {
|
||||
'api.env.endpoint.login-seller' => static function ( ContainerInterface $container ): EnvironmentConfig {
|
||||
/**
|
||||
* Environment specific LoginSeller API instances.
|
||||
*
|
||||
|
@ -951,7 +951,7 @@ return array(
|
|||
$container->get( 'api.endpoint.login-seller-sandbox' )
|
||||
);
|
||||
},
|
||||
'api.env.endpoint.partner-referrals' => static function ( ContainerInterface $container ) : EnvironmentConfig {
|
||||
'api.env.endpoint.partner-referrals' => static function ( ContainerInterface $container ): EnvironmentConfig {
|
||||
/**
|
||||
* Environment specific PartnerReferrals API instances.
|
||||
*
|
||||
|
@ -981,7 +981,7 @@ return array(
|
|||
|
||||
return CONNECT_WOO_URL;
|
||||
},
|
||||
'api.helper.partner-attribution' => static function ( ContainerInterface $container ) : PartnerAttribution {
|
||||
'api.helper.partner-attribution' => static function ( ContainerInterface $container ): PartnerAttribution {
|
||||
return new PartnerAttribution(
|
||||
'ppcp_bn_code',
|
||||
array(
|
||||
|
|
|
@ -66,7 +66,7 @@ class ApiModule implements ServiceModule, FactoryModule, ExtendingModule, Execut
|
|||
);
|
||||
add_filter(
|
||||
'ppcp_create_order_request_body_data',
|
||||
function( array $data ) use ( $c ) {
|
||||
function ( array $data ) use ( $c ) {
|
||||
|
||||
foreach ( ( $data['purchase_units'] ?? array() ) as $purchase_unit_index => $purchase_unit ) {
|
||||
foreach ( ( $purchase_unit['items'] ?? array() ) as $item_index => $item ) {
|
||||
|
|
|
@ -100,7 +100,7 @@ class PayPalBearer implements Bearer {
|
|||
* @throws RuntimeException When request fails.
|
||||
* @return Token
|
||||
*/
|
||||
public function bearer() : Token {
|
||||
public function bearer(): Token {
|
||||
try {
|
||||
$bearer = Token::from_json( (string) $this->cache->get( self::CACHE_KEY ) );
|
||||
|
||||
|
@ -115,7 +115,7 @@ class PayPalBearer implements Bearer {
|
|||
*
|
||||
* @return string The client ID from settings, or the key defined via constructor.
|
||||
*/
|
||||
private function get_key() : string {
|
||||
private function get_key(): string {
|
||||
if (
|
||||
$this->settings
|
||||
&& $this->settings->has( 'client_id' )
|
||||
|
@ -132,7 +132,7 @@ class PayPalBearer implements Bearer {
|
|||
*
|
||||
* @return string The client secret from settings, or the value defined via constructor.
|
||||
*/
|
||||
private function get_secret() : string {
|
||||
private function get_secret(): string {
|
||||
if (
|
||||
$this->settings
|
||||
&& $this->settings->has( 'client_secret' )
|
||||
|
@ -150,7 +150,7 @@ class PayPalBearer implements Bearer {
|
|||
* @throws RuntimeException When request fails.
|
||||
* @return Token
|
||||
*/
|
||||
private function newBearer() : Token {
|
||||
private function newBearer(): Token {
|
||||
$key = $this->get_key();
|
||||
$secret = $this->get_secret();
|
||||
$url = trailingslashit( $this->host ) . 'v1/oauth2/token?grant_type=client_credentials';
|
||||
|
|
|
@ -65,7 +65,7 @@ class BillingSubscriptions {
|
|||
* @throws RuntimeException If the request fails.
|
||||
* @throws PayPalApiException If the request fails.
|
||||
*/
|
||||
public function suspend( string $id ):void {
|
||||
public function suspend( string $id ): void {
|
||||
$data = array(
|
||||
'reason' => sprintf( 'Suspended by %s.', is_admin() ? 'merchant' : 'customer' ),
|
||||
);
|
||||
|
@ -214,6 +214,4 @@ class BillingSubscriptions {
|
|||
|
||||
return $json;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -108,7 +108,7 @@ class PartnersEndpoint {
|
|||
* @return SellerStatus
|
||||
* @throws RuntimeException When request could not be fulfilled.
|
||||
*/
|
||||
public function seller_status() : SellerStatus {
|
||||
public function seller_status(): SellerStatus {
|
||||
$url = trailingslashit( $this->host ) . 'v1/customer/partners/' . $this->partner_id . '/merchant-integrations/' . $this->merchant_id;
|
||||
$bearer = $this->bearer->bearer();
|
||||
$args = array(
|
||||
|
|
|
@ -203,7 +203,7 @@ class PaymentsEndpoint {
|
|||
* @throws RuntimeException If the request fails.
|
||||
* @throws PayPalApiException If the request fails.
|
||||
*/
|
||||
public function reauthorize( string $authorization_id, ?Money $amount = null ) : string {
|
||||
public function reauthorize( string $authorization_id, ?Money $amount = null ): string {
|
||||
$bearer = $this->bearer->bearer();
|
||||
$url = trailingslashit( $this->host ) . 'v2/payments/authorizations/' . $authorization_id . '/reauthorize';
|
||||
|
||||
|
@ -249,7 +249,7 @@ class PaymentsEndpoint {
|
|||
* @throws RuntimeException If the request fails.
|
||||
* @throws PayPalApiException If the request fails.
|
||||
*/
|
||||
public function refund( RefundCapture $refund ) : string {
|
||||
public function refund( RefundCapture $refund ): string {
|
||||
$bearer = $this->bearer->bearer();
|
||||
$url = trailingslashit( $this->host ) . 'v2/payments/captures/' . $refund->for_capture()->id() . '/refund';
|
||||
$args = array(
|
||||
|
@ -289,7 +289,7 @@ class PaymentsEndpoint {
|
|||
* @throws RuntimeException If the request fails.
|
||||
* @throws PayPalApiException If the request fails.
|
||||
*/
|
||||
public function void( Authorization $authorization ) : void {
|
||||
public function void( Authorization $authorization ): void {
|
||||
$bearer = $this->bearer->bearer();
|
||||
$url = trailingslashit( $this->host ) . 'v2/payments/authorizations/' . $authorization->id() . '/void';
|
||||
$args = array(
|
||||
|
|
|
@ -348,7 +348,7 @@ class WebhookEndpoint {
|
|||
if ( isset( $expected_headers[ $key ] ) ) {
|
||||
$expected_headers[ $key ] = $header;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
foreach ( $expected_headers as $key => $value ) {
|
||||
if ( ! empty( $value ) ) {
|
||||
|
|
|
@ -86,7 +86,7 @@ class Authorization {
|
|||
*
|
||||
* @return FraudProcessorResponse|null
|
||||
*/
|
||||
public function fraud_processor_response() : ?FraudProcessorResponse {
|
||||
public function fraud_processor_response(): ?FraudProcessorResponse {
|
||||
return $this->fraud_processor_response;
|
||||
}
|
||||
|
||||
|
|
|
@ -120,7 +120,7 @@ class Capture {
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function id() : string {
|
||||
public function id(): string {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
|
@ -129,7 +129,7 @@ class Capture {
|
|||
*
|
||||
* @return CaptureStatus
|
||||
*/
|
||||
public function status() : CaptureStatus {
|
||||
public function status(): CaptureStatus {
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
|
@ -138,7 +138,7 @@ class Capture {
|
|||
*
|
||||
* @return Amount
|
||||
*/
|
||||
public function amount() : Amount {
|
||||
public function amount(): Amount {
|
||||
return $this->amount;
|
||||
}
|
||||
|
||||
|
@ -147,7 +147,7 @@ class Capture {
|
|||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function final_capture() : bool {
|
||||
public function final_capture(): bool {
|
||||
return $this->final_capture;
|
||||
}
|
||||
|
||||
|
@ -165,7 +165,7 @@ class Capture {
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function invoice_id() : string {
|
||||
public function invoice_id(): string {
|
||||
return $this->invoice_id;
|
||||
}
|
||||
|
||||
|
@ -174,7 +174,7 @@ class Capture {
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function custom_id() : string {
|
||||
public function custom_id(): string {
|
||||
return $this->custom_id;
|
||||
}
|
||||
|
||||
|
@ -183,7 +183,7 @@ class Capture {
|
|||
*
|
||||
* @return SellerReceivableBreakdown|null
|
||||
*/
|
||||
public function seller_receivable_breakdown() : ?SellerReceivableBreakdown {
|
||||
public function seller_receivable_breakdown(): ?SellerReceivableBreakdown {
|
||||
return $this->seller_receivable_breakdown;
|
||||
}
|
||||
|
||||
|
@ -192,7 +192,7 @@ class Capture {
|
|||
*
|
||||
* @return FraudProcessorResponse|null
|
||||
*/
|
||||
public function fraud_processor_response() : ?FraudProcessorResponse {
|
||||
public function fraud_processor_response(): ?FraudProcessorResponse {
|
||||
return $this->fraud_processor_response;
|
||||
}
|
||||
|
||||
|
@ -201,7 +201,7 @@ class Capture {
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function to_array() : array {
|
||||
public function to_array(): array {
|
||||
$data = array(
|
||||
'id' => $this->id(),
|
||||
'status' => $this->status()->name(),
|
||||
|
|
|
@ -204,7 +204,7 @@ class Item {
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function url():string {
|
||||
public function url(): string {
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
|
@ -213,7 +213,7 @@ class Item {
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function image_url():string {
|
||||
public function image_url(): string {
|
||||
return $this->validate_image_url() ? $this->image_url : '';
|
||||
}
|
||||
|
||||
|
@ -222,7 +222,7 @@ class Item {
|
|||
*
|
||||
* @return float
|
||||
*/
|
||||
public function tax_rate():float {
|
||||
public function tax_rate(): float {
|
||||
return round( (float) $this->tax_rate, 2 );
|
||||
}
|
||||
|
||||
|
@ -231,7 +231,7 @@ class Item {
|
|||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function cart_item_key():?string {
|
||||
public function cart_item_key(): ?string {
|
||||
return $this->cart_item_key;
|
||||
}
|
||||
|
||||
|
|
|
@ -104,7 +104,7 @@ class PaymentPreferences {
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function to_array():array {
|
||||
public function to_array(): array {
|
||||
return array(
|
||||
'setup_fee' => $this->setup_fee(),
|
||||
'auto_bill_outstanding' => $this->auto_bill_outstanding(),
|
||||
|
|
|
@ -124,5 +124,4 @@ class PaymentToken {
|
|||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -141,7 +141,7 @@ class Plan {
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function to_array():array {
|
||||
public function to_array(): array {
|
||||
return array(
|
||||
'id' => $this->id(),
|
||||
'name' => $this->name(),
|
||||
|
|
|
@ -119,7 +119,7 @@ class Refund {
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function id() : string {
|
||||
public function id(): string {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
|
@ -128,7 +128,7 @@ class Refund {
|
|||
*
|
||||
* @return RefundStatus
|
||||
*/
|
||||
public function status() : RefundStatus {
|
||||
public function status(): RefundStatus {
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
|
@ -137,7 +137,7 @@ class Refund {
|
|||
*
|
||||
* @return Amount
|
||||
*/
|
||||
public function amount() : Amount {
|
||||
public function amount(): Amount {
|
||||
return $this->amount;
|
||||
}
|
||||
|
||||
|
@ -146,7 +146,7 @@ class Refund {
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function invoice_id() : string {
|
||||
public function invoice_id(): string {
|
||||
return $this->invoice_id;
|
||||
}
|
||||
|
||||
|
@ -155,7 +155,7 @@ class Refund {
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function custom_id() : string {
|
||||
public function custom_id(): string {
|
||||
return $this->custom_id;
|
||||
}
|
||||
|
||||
|
@ -164,7 +164,7 @@ class Refund {
|
|||
*
|
||||
* @return SellerPayableBreakdown|null
|
||||
*/
|
||||
public function seller_payable_breakdown() : ?SellerPayableBreakdown {
|
||||
public function seller_payable_breakdown(): ?SellerPayableBreakdown {
|
||||
return $this->seller_payable_breakdown;
|
||||
}
|
||||
|
||||
|
@ -173,7 +173,7 @@ class Refund {
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function acquirer_reference_number() : string {
|
||||
public function acquirer_reference_number(): string {
|
||||
return $this->acquirer_reference_number;
|
||||
}
|
||||
|
||||
|
@ -182,7 +182,7 @@ class Refund {
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function note_to_payer() : string {
|
||||
public function note_to_payer(): string {
|
||||
return $this->note_to_payer;
|
||||
}
|
||||
|
||||
|
@ -191,7 +191,7 @@ class Refund {
|
|||
*
|
||||
* @return RefundPayer|null
|
||||
*/
|
||||
public function payer() : ?RefundPayer {
|
||||
public function payer(): ?RefundPayer {
|
||||
return $this->payer;
|
||||
}
|
||||
|
||||
|
@ -200,7 +200,7 @@ class Refund {
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function to_array() : array {
|
||||
public function to_array(): array {
|
||||
$data = array(
|
||||
'id' => $this->id(),
|
||||
'status' => $this->status()->name(),
|
||||
|
|
|
@ -67,7 +67,7 @@ class RefundCapture {
|
|||
*
|
||||
* @return Capture
|
||||
*/
|
||||
public function for_capture() : Capture {
|
||||
public function for_capture(): Capture {
|
||||
return $this->capture;
|
||||
}
|
||||
|
||||
|
@ -76,7 +76,7 @@ class RefundCapture {
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function invoice_id() : string {
|
||||
public function invoice_id(): string {
|
||||
return $this->invoice_id;
|
||||
}
|
||||
|
||||
|
@ -85,7 +85,7 @@ class RefundCapture {
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function note_to_payer() : string {
|
||||
public function note_to_payer(): string {
|
||||
return $this->note_to_payer;
|
||||
}
|
||||
|
||||
|
@ -103,7 +103,7 @@ class RefundCapture {
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function to_array() : array {
|
||||
public function to_array(): array {
|
||||
$data = array(
|
||||
'invoice_id' => $this->invoice_id(),
|
||||
);
|
||||
|
|
|
@ -68,7 +68,7 @@ class SellerStatus {
|
|||
*
|
||||
* @return SellerStatusProduct[]
|
||||
*/
|
||||
public function products() : array {
|
||||
public function products(): array {
|
||||
return $this->products;
|
||||
}
|
||||
|
||||
|
@ -77,7 +77,7 @@ class SellerStatus {
|
|||
*
|
||||
* @return SellerStatusCapability[]
|
||||
*/
|
||||
public function capabilities() : array {
|
||||
public function capabilities(): array {
|
||||
return $this->capabilities;
|
||||
}
|
||||
|
||||
|
@ -86,7 +86,7 @@ class SellerStatus {
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function country() : string {
|
||||
public function country(): string {
|
||||
return $this->country;
|
||||
}
|
||||
|
||||
|
@ -95,16 +95,16 @@ class SellerStatus {
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function to_array() : array {
|
||||
public function to_array(): array {
|
||||
$products = array_map(
|
||||
function( SellerStatusProduct $product ) : array {
|
||||
function ( SellerStatusProduct $product ): array {
|
||||
return $product->to_array();
|
||||
},
|
||||
$this->products()
|
||||
);
|
||||
|
||||
$capabilities = array_map(
|
||||
function( SellerStatusCapability $capability ) : array {
|
||||
function ( SellerStatusCapability $capability ): array {
|
||||
return $capability->to_array();
|
||||
},
|
||||
$this->capabilities()
|
||||
|
|
|
@ -49,7 +49,7 @@ class SellerStatusCapability {
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function name() : string {
|
||||
public function name(): string {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,7 @@ class SellerStatusCapability {
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function status() : string {
|
||||
public function status(): string {
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
|
@ -67,11 +67,10 @@ class SellerStatusCapability {
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function to_array() : array {
|
||||
public function to_array(): array {
|
||||
return array(
|
||||
'name' => $this->name(),
|
||||
'status' => $this->status(),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ class SellerStatusProduct {
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function name() : string {
|
||||
public function name(): string {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
|
@ -78,7 +78,7 @@ class SellerStatusProduct {
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function vetting_status() : string {
|
||||
public function vetting_status(): string {
|
||||
return $this->vetting_status;
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,7 @@ class SellerStatusProduct {
|
|||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function capabilities() : array {
|
||||
public function capabilities(): array {
|
||||
return $this->capabilities;
|
||||
}
|
||||
|
||||
|
@ -96,13 +96,11 @@ class SellerStatusProduct {
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function to_array() : array {
|
||||
public function to_array(): array {
|
||||
return array(
|
||||
'name' => $this->name(),
|
||||
'vetting_status' => $this->vetting_status(),
|
||||
'capabilities' => $this->capabilities(),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -17,46 +17,46 @@ class Shipping {
|
|||
/**
|
||||
* The name.
|
||||
*
|
||||
* @var string
|
||||
* @var string|null
|
||||
*/
|
||||
private $name;
|
||||
private ?string $name;
|
||||
|
||||
/**
|
||||
* The address.
|
||||
*
|
||||
* @var Address
|
||||
* @var Address|null
|
||||
*/
|
||||
private $address;
|
||||
private ?Address $address;
|
||||
|
||||
/**
|
||||
* Custom contact email address, usually added via the Contact Module.
|
||||
*/
|
||||
private ?string $email_address = null;
|
||||
private ?string $email_address;
|
||||
|
||||
/**
|
||||
* Custom contact phone number, usually added via the Contact Module.
|
||||
*/
|
||||
private ?Phone $phone_number = null;
|
||||
private ?Phone $phone_number;
|
||||
|
||||
/**
|
||||
* Shipping methods.
|
||||
*
|
||||
* @var ShippingOption[]
|
||||
*/
|
||||
private $options;
|
||||
private array $options;
|
||||
|
||||
/**
|
||||
* Shipping constructor.
|
||||
*
|
||||
* @param string $name The name.
|
||||
* @param Address $address The address.
|
||||
* @param string|null $name The name.
|
||||
* @param Address|null $address The address.
|
||||
* @param string|null $email_address Contact email.
|
||||
* @param Phone|null $phone_number Contact phone.
|
||||
* @param ShippingOption[] $options Shipping methods.
|
||||
*/
|
||||
public function __construct(
|
||||
string $name,
|
||||
Address $address,
|
||||
?string $name = null,
|
||||
?Address $address = null,
|
||||
?string $email_address = null,
|
||||
?Phone $phone_number = null,
|
||||
array $options = array()
|
||||
|
@ -71,18 +71,18 @@ class Shipping {
|
|||
/**
|
||||
* Returns the name.
|
||||
*
|
||||
* @return string
|
||||
* @return null|string
|
||||
*/
|
||||
public function name(): string {
|
||||
public function name(): ?string {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the shipping address.
|
||||
*
|
||||
* @return Address
|
||||
* @return null|Address
|
||||
*/
|
||||
public function address(): Address {
|
||||
public function address(): ?Address {
|
||||
return $this->address;
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,7 @@ class Shipping {
|
|||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function email_address() : ?string {
|
||||
public function email_address(): ?string {
|
||||
return $this->email_address;
|
||||
}
|
||||
|
||||
|
@ -100,7 +100,7 @@ class Shipping {
|
|||
*
|
||||
* @return null|Phone
|
||||
*/
|
||||
public function phone_number() : ?Phone {
|
||||
public function phone_number(): ?Phone {
|
||||
return $this->phone_number;
|
||||
}
|
||||
|
||||
|
@ -119,19 +119,26 @@ class Shipping {
|
|||
* @return array
|
||||
*/
|
||||
public function to_array(): array {
|
||||
$result = array(
|
||||
'name' => array(
|
||||
'full_name' => $this->name(),
|
||||
),
|
||||
'address' => $this->address()->to_array(),
|
||||
);
|
||||
$result = array();
|
||||
|
||||
$name = $this->name();
|
||||
if ( $name ) {
|
||||
$result['name'] = array(
|
||||
'full_name' => $name,
|
||||
);
|
||||
}
|
||||
|
||||
$address = $this->address();
|
||||
if ( $address ) {
|
||||
$result['address'] = $address->to_array();
|
||||
}
|
||||
|
||||
$contact_email = $this->email_address();
|
||||
$contact_phone = $this->phone_number();
|
||||
|
||||
if ( $contact_email ) {
|
||||
$result['email_address'] = $contact_email;
|
||||
}
|
||||
|
||||
$contact_phone = $this->phone_number();
|
||||
if ( $contact_phone ) {
|
||||
$result['phone_number'] = $contact_phone->to_array();
|
||||
}
|
||||
|
@ -144,6 +151,7 @@ class Shipping {
|
|||
$this->options
|
||||
);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ class CaptureFactory {
|
|||
* @return Capture
|
||||
* @throws RuntimeException When capture amount data is invalid.
|
||||
*/
|
||||
public function from_paypal_response( \stdClass $data ) : Capture {
|
||||
public function from_paypal_response( \stdClass $data ): Capture {
|
||||
$reason = $data->status_details->reason ?? null;
|
||||
$seller_receivable_breakdown = isset( $data->seller_receivable_breakdown ) ?
|
||||
$this->seller_receivable_breakdown_factory->from_paypal_response( $data->seller_receivable_breakdown )
|
||||
|
|
|
@ -48,7 +48,7 @@ class ContactPreferenceFactory {
|
|||
* @param string $payment_source_key Name of the payment_source.
|
||||
* @return string|null
|
||||
*/
|
||||
public function from_state( string $payment_source_key ) : ?string {
|
||||
public function from_state( string $payment_source_key ): ?string {
|
||||
$payment_sources_with_contact = array( 'paypal', 'venmo' );
|
||||
|
||||
/**
|
||||
|
|
|
@ -214,7 +214,7 @@ class ExperienceContextBuilder {
|
|||
*
|
||||
* @param string|null $preference The new preference to apply.
|
||||
*/
|
||||
public function with_contact_preference( ?string $preference = null ) : ExperienceContextBuilder {
|
||||
public function with_contact_preference( ?string $preference = null ): ExperienceContextBuilder {
|
||||
$builder = clone $this;
|
||||
|
||||
$builder->experience_context = $builder->experience_context
|
||||
|
|
|
@ -53,7 +53,7 @@ class PatchCollectionFactory {
|
|||
$from,
|
||||
static function ( PurchaseUnit $unit ) use ( $purchase_unit_to ): bool {
|
||||
// Loose comparison needed to compare two objects.
|
||||
// phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
|
||||
// phpcs:ignore Universal.Operators.StrictComparisons.LooseEqual
|
||||
return $unit == $purchase_unit_to;
|
||||
}
|
||||
)
|
||||
|
|
|
@ -41,7 +41,7 @@ class PaymentPreferencesFactory {
|
|||
* @param WC_Product $product WC product.
|
||||
* @return PaymentPreferences
|
||||
*/
|
||||
public function from_wc_product( WC_Product $product ):PaymentPreferences {
|
||||
public function from_wc_product( WC_Product $product ): PaymentPreferences {
|
||||
return new PaymentPreferences(
|
||||
array(
|
||||
'value' => $product->get_meta( '_subscription_sign_up_fee' ) ?: '0',
|
||||
|
|
|
@ -15,6 +15,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\PurchaseUnitSanitizer;
|
||||
use WooCommerce\PayPalCommerce\Webhooks\CustomIds;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Address;
|
||||
|
||||
/**
|
||||
* Class PurchaseUnitFactory
|
||||
|
@ -108,21 +109,20 @@ class PurchaseUnitFactory {
|
|||
* @return PurchaseUnit
|
||||
*/
|
||||
public function from_wc_order( \WC_Order $order ): PurchaseUnit {
|
||||
$amount = $this->amount_factory->from_wc_order( $order );
|
||||
$items = array_filter(
|
||||
$amount = $this->amount_factory->from_wc_order( $order );
|
||||
$items = array_filter(
|
||||
$this->item_factory->from_wc_order( $order ),
|
||||
function ( Item $item ): bool {
|
||||
return $item->unit_amount()->value() >= 0;
|
||||
}
|
||||
);
|
||||
$shipping = $this->shipping_factory->from_wc_order( $order );
|
||||
if (
|
||||
! $this->shipping_needed( ... array_values( $items ) ) ||
|
||||
empty( $shipping->address()->country_code() ) ||
|
||||
( ! $shipping->address()->postal_code() && ! $this->country_without_postal_code( $shipping->address()->country_code() ) )
|
||||
) {
|
||||
|
||||
$shipping = $this->shipping_factory->from_wc_order( $order );
|
||||
$shipping_address = $shipping->address();
|
||||
if ( $this->should_disable_shipping( $items, $shipping_address ) ) {
|
||||
$shipping = null;
|
||||
}
|
||||
|
||||
$reference_id = 'default';
|
||||
$description = '';
|
||||
$custom_id = (string) $order->get_id();
|
||||
|
@ -175,11 +175,14 @@ class PurchaseUnitFactory {
|
|||
|
||||
$shipping = null;
|
||||
$customer = \WC()->customer;
|
||||
if ( $this->shipping_needed( ... array_values( $items ) ) && is_a( $customer, \WC_Customer::class ) ) {
|
||||
$shipping = $this->shipping_factory->from_wc_customer( \WC()->customer, $with_shipping_options );
|
||||
/** @psalm-suppress RedundantConditionGivenDocblockType False positive. Ignored because $customer can be null as well. */
|
||||
if ( $this->shipping_needed( ...array_values( $items ) ) && is_a( $customer, \WC_Customer::class ) ) {
|
||||
$shipping = $this->shipping_factory->from_wc_customer( \WC()->customer, $with_shipping_options );
|
||||
$shipping_address = $shipping->address();
|
||||
if (
|
||||
2 !== strlen( $shipping->address()->country_code() ) ||
|
||||
( ! $shipping->address()->postal_code() && ! $this->country_without_postal_code( $shipping->address()->country_code() ) )
|
||||
! $shipping_address ||
|
||||
2 !== strlen( $shipping_address->country_code() ) ||
|
||||
( ! $shipping_address->postal_code() && ! $this->country_without_postal_code( $shipping_address->country_code() ) )
|
||||
) {
|
||||
$shipping = null;
|
||||
}
|
||||
|
@ -248,11 +251,11 @@ class PurchaseUnitFactory {
|
|||
}
|
||||
$shipping = null;
|
||||
try {
|
||||
if ( isset( $data->shipping ) ) {
|
||||
if ( isset( $data->shipping ) && ! empty( (array) $data->shipping ) ) {
|
||||
$shipping = $this->shipping_factory->from_paypal_response( $data->shipping );
|
||||
}
|
||||
} catch ( RuntimeException $error ) {
|
||||
;
|
||||
$shipping = null;
|
||||
}
|
||||
$payments = null;
|
||||
try {
|
||||
|
@ -260,7 +263,7 @@ class PurchaseUnitFactory {
|
|||
$payments = $this->payments_factory->from_paypal_response( $data->payments );
|
||||
}
|
||||
} catch ( RuntimeException $error ) {
|
||||
;
|
||||
$payments = null;
|
||||
}
|
||||
|
||||
$purchase_unit = new PurchaseUnit(
|
||||
|
@ -331,10 +334,25 @@ class PurchaseUnitFactory {
|
|||
*
|
||||
* @return string The sanitized soft descriptor.
|
||||
*/
|
||||
private function sanitize_soft_descriptor( string $soft_descriptor ) : string {
|
||||
private function sanitize_soft_descriptor( string $soft_descriptor ): string {
|
||||
$decoded = html_entity_decode( $soft_descriptor, ENT_QUOTES, 'UTF-8' );
|
||||
$sanitized = preg_replace( '/[^a-zA-Z0-9 *\-.]/', '', $decoded ) ?: '';
|
||||
|
||||
return substr( $sanitized, 0, 22 ) ?: '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether shipping should be disabled for a purchase unit.
|
||||
*
|
||||
* @param array $items Purchase unit items.
|
||||
* @param Address|null $shipping_address The shipping address to validate.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function should_disable_shipping( array $items, ?Address $shipping_address ): bool {
|
||||
return ! $this->shipping_needed( ...array_values( $items ) ) ||
|
||||
! $shipping_address ||
|
||||
empty( $shipping_address->country_code() ) ||
|
||||
( ! $shipping_address->postal_code() && ! $this->country_without_postal_code( $shipping_address->country_code() ) );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ class RefundFactory {
|
|||
* @return Refund
|
||||
* @throws RuntimeException When refund amount data is invalid.
|
||||
*/
|
||||
public function from_paypal_response( \stdClass $data ) : Refund {
|
||||
public function from_paypal_response( \stdClass $data ): Refund {
|
||||
$reason = $data->status_details->reason ?? null;
|
||||
$seller_payable_breakdown = isset( $data->seller_payable_breakdown ) ?
|
||||
$this->seller_payable_breakdown_factory->from_paypal_response( $data->seller_payable_breakdown )
|
||||
|
|
|
@ -25,9 +25,9 @@ class SellerStatusFactory {
|
|||
*
|
||||
* @return SellerStatus
|
||||
*/
|
||||
public function from_paypal_response( \stdClass $json ) : SellerStatus {
|
||||
public function from_paypal_response( \stdClass $json ): SellerStatus {
|
||||
$products = array_map(
|
||||
function( $json ) : SellerStatusProduct {
|
||||
function ( $json ): SellerStatusProduct {
|
||||
$product = new SellerStatusProduct(
|
||||
isset( $json->name ) ? (string) $json->name : '',
|
||||
isset( $json->vetting_status ) ? (string) $json->vetting_status : '',
|
||||
|
@ -39,7 +39,7 @@ class SellerStatusFactory {
|
|||
);
|
||||
|
||||
$capabilities = array_map(
|
||||
function( $json ) : SellerStatusCapability {
|
||||
function ( $json ): SellerStatusCapability {
|
||||
$capability = new SellerStatusCapability(
|
||||
isset( $json->name ) ? (string) $json->name : '',
|
||||
isset( $json->status ) ? (string) $json->status : ''
|
||||
|
|
|
@ -96,30 +96,25 @@ class ShippingFactory {
|
|||
* @throws RuntimeException When JSON object is malformed.
|
||||
*/
|
||||
public function from_paypal_response( \stdClass $data ): Shipping {
|
||||
if ( ! isset( $data->name->full_name ) ) {
|
||||
throw new RuntimeException( 'No name was given for shipping.' );
|
||||
}
|
||||
if ( ! isset( $data->address ) ) {
|
||||
throw new RuntimeException( 'No address was given for shipping.' );
|
||||
}
|
||||
$contact_phone = null;
|
||||
$contact_email = null;
|
||||
$address = $this->address_factory->from_paypal_response( $data->address );
|
||||
$name = $data->name->full_name ?? null;
|
||||
|
||||
$address = isset( $data->address )
|
||||
? $this->address_factory->from_paypal_response( $data->address )
|
||||
: null;
|
||||
|
||||
$contact_email = $data->email_address ?? null;
|
||||
|
||||
$contact_phone = isset( $data->phone_number->national_number )
|
||||
? new Phone( $data->phone_number->national_number )
|
||||
: null;
|
||||
|
||||
$options = array_map(
|
||||
array( $this->shipping_option_factory, 'from_paypal_response' ),
|
||||
$data->options ?? array()
|
||||
);
|
||||
|
||||
if ( isset( $data->phone_number->national_number ) ) {
|
||||
$contact_phone = new Phone( $data->phone_number->national_number );
|
||||
}
|
||||
if ( isset( $data->email_address ) ) {
|
||||
$contact_email = $data->email_address;
|
||||
}
|
||||
|
||||
return new Shipping(
|
||||
$data->name->full_name,
|
||||
$name,
|
||||
$address,
|
||||
$contact_email,
|
||||
$contact_phone,
|
||||
|
|
|
@ -48,7 +48,7 @@ class Cache {
|
|||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has( string $key ) : bool {
|
||||
public function has( string $key ): bool {
|
||||
$value = $this->get( $key );
|
||||
|
||||
return false !== $value;
|
||||
|
@ -59,7 +59,7 @@ class Cache {
|
|||
*
|
||||
* @param string $key The key.
|
||||
*/
|
||||
public function delete( string $key ) : void {
|
||||
public function delete( string $key ): void {
|
||||
delete_transient( $this->prefix . $key );
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ class Cache {
|
|||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function set( string $key, $value, int $expiration = 0 ) : bool {
|
||||
public function set( string $key, $value, int $expiration = 0 ): bool {
|
||||
return (bool) set_transient( $this->prefix . $key, $value, $expiration );
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ class Cache {
|
|||
*
|
||||
* @return void
|
||||
*/
|
||||
public function flush() : void {
|
||||
public function flush(): void {
|
||||
global $wpdb;
|
||||
|
||||
// Get a list of all transients with the relevant "group prefix" from the DB.
|
||||
|
|
|
@ -94,7 +94,7 @@ class DccApplies {
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function valid_cards() : array {
|
||||
public function valid_cards(): array {
|
||||
$cards = array();
|
||||
if ( ! isset( $this->country_card_matrix[ $this->country ] ) ) {
|
||||
return $cards;
|
||||
|
@ -122,7 +122,7 @@ class DccApplies {
|
|||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function can_process_card( string $card ) : bool {
|
||||
public function can_process_card( string $card ): bool {
|
||||
if ( ! isset( $this->country_card_matrix[ $this->country ] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -90,5 +90,4 @@ class FailureRegistry {
|
|||
private function cache_key( string $key ): string {
|
||||
return implode( '_', array( self::CACHE_KEY, $key ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -156,5 +156,4 @@ class OrderTransient {
|
|||
}
|
||||
return implode( '_', array( self::CACHE_KEY . $order->id() ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ class PartnerAttribution {
|
|||
* @param string $installation_path The installation path used to determine the BN Code.
|
||||
* @param bool $force_update Whether to force an update of the BN code if it already exists.
|
||||
*/
|
||||
public function initialize_bn_code( string $installation_path, bool $force_update = false ) : void {
|
||||
public function initialize_bn_code( string $installation_path, bool $force_update = false ): void {
|
||||
$selected_bn_code = $this->bn_codes[ $installation_path ] ?? '';
|
||||
if ( ! $selected_bn_code ) {
|
||||
return;
|
||||
|
@ -82,7 +82,7 @@ class PartnerAttribution {
|
|||
*
|
||||
* @return string The stored BN Code, or the default value if no path is detected.
|
||||
*/
|
||||
public function get_bn_code() : string {
|
||||
public function get_bn_code(): string {
|
||||
$bn_code = (string) ( get_option( $this->bn_code_option_name, $this->default_bn_code ) ?? $this->default_bn_code );
|
||||
|
||||
if ( ! in_array( $bn_code, $this->bn_codes, true ) ) {
|
||||
|
|
|
@ -93,7 +93,7 @@ abstract class ProductStatus {
|
|||
* @throws RuntimeException When the check failed.
|
||||
* @throws NotFoundException When a relevant service or setting was not found.
|
||||
*/
|
||||
abstract protected function check_local_state() : ?bool;
|
||||
abstract protected function check_local_state(): ?bool;
|
||||
|
||||
/**
|
||||
* Inspects the API response of the SellerStatus to determine feature eligibility.
|
||||
|
@ -105,7 +105,7 @@ abstract class ProductStatus {
|
|||
* @return bool
|
||||
* @throws RuntimeException When the check failed.
|
||||
*/
|
||||
abstract protected function check_active_state( SellerStatus $seller_status ) : bool;
|
||||
abstract protected function check_active_state( SellerStatus $seller_status ): bool;
|
||||
|
||||
/**
|
||||
* Clears the eligibility status from the local cache/DB to enforce a new
|
||||
|
@ -114,14 +114,14 @@ abstract class ProductStatus {
|
|||
* @param Settings|null $settings See description in {@see self::clear()}.
|
||||
* @return void
|
||||
*/
|
||||
abstract protected function clear_state( ?Settings $settings = null ) : void;
|
||||
abstract protected function clear_state( ?Settings $settings = null ): void;
|
||||
|
||||
/**
|
||||
* Whether the merchant has access to the feature.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_active() : bool {
|
||||
public function is_active(): bool {
|
||||
if ( null !== $this->is_eligible ) {
|
||||
return $this->is_eligible;
|
||||
}
|
||||
|
@ -158,7 +158,7 @@ abstract class ProductStatus {
|
|||
* @return SellerStatus
|
||||
* @throws RuntimeException When the check failed.
|
||||
*/
|
||||
protected function get_seller_status_object() : SellerStatus {
|
||||
protected function get_seller_status_object(): SellerStatus {
|
||||
if ( null === self::$seller_status ) {
|
||||
// Check API failure registry to prevent multiple failed API requests.
|
||||
if ( $this->api_failure_registry->has_failure_in_timeframe( FailureRegistry::SELLER_STATUS_KEY, MINUTE_IN_SECONDS ) ) {
|
||||
|
@ -177,7 +177,7 @@ abstract class ProductStatus {
|
|||
*
|
||||
* @return bool True, if we can use the merchant API endpoints.
|
||||
*/
|
||||
public function is_onboarded() : bool {
|
||||
public function is_onboarded(): bool {
|
||||
return $this->is_connected;
|
||||
}
|
||||
|
||||
|
@ -186,7 +186,7 @@ abstract class ProductStatus {
|
|||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has_request_failure() : bool {
|
||||
public function has_request_failure(): bool {
|
||||
return $this->has_request_failure;
|
||||
}
|
||||
|
||||
|
@ -199,7 +199,7 @@ abstract class ProductStatus {
|
|||
* @param Settings|null $settings The settings object.
|
||||
* @return void
|
||||
*/
|
||||
public function clear( ?Settings $settings = null ) : void {
|
||||
public function clear( ?Settings $settings = null ): void {
|
||||
$this->is_eligible = null;
|
||||
$this->has_request_failure = false;
|
||||
|
||||
|
|
|
@ -393,5 +393,4 @@ class PurchaseUnitSanitizer {
|
|||
public function set_last_message( string $message ): void {
|
||||
$this->last_message = $message;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ class PartnerReferralsData {
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function nonce() : string {
|
||||
public function nonce(): string {
|
||||
return 'a1233wtergfsdt4365tzrshgfbaewa36AGa1233wtergfsdt4365tzrshgfbaewa36AG';
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,7 @@ class PartnerReferralsData {
|
|||
string $onboarding_token = '',
|
||||
?bool $use_subscriptions = null,
|
||||
bool $use_card_payments = true
|
||||
) : array {
|
||||
): array {
|
||||
$in_acdc_country = $this->dcc_applies->for_country_currency();
|
||||
|
||||
if ( ! $products ) {
|
||||
|
|
|
@ -334,12 +334,22 @@ class ApplePayButton extends PaymentButton {
|
|||
this.checkEligibility();
|
||||
}
|
||||
|
||||
reinit() {
|
||||
async reinit() {
|
||||
// Missing (invalid) configuration indicates, that the first `init()` call did not happen yet.
|
||||
if ( ! this.validateConfiguration( true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensures transaction info is updated when cart or checkout update events are triggered.
|
||||
await this.contextHandler
|
||||
.transactionInfo()
|
||||
.then( ( transactionInfo ) => {
|
||||
this.transactionInfo = transactionInfo;
|
||||
} )
|
||||
.catch( ( error ) => {
|
||||
console.error( 'Failed to get transaction info:', error );
|
||||
} );
|
||||
|
||||
super.reinit();
|
||||
|
||||
this.init();
|
||||
|
|
|
@ -94,20 +94,23 @@ if (
|
|||
features.push( 'subscriptions' );
|
||||
}
|
||||
|
||||
registerExpressPaymentMethod( {
|
||||
name: buttonData.id,
|
||||
title: `PayPal - ${ buttonData.title }`,
|
||||
description: __(
|
||||
'Eligible users will see the PayPal button.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
label: <div dangerouslySetInnerHTML={ { __html: buttonData.title } } />,
|
||||
content: <ApplePayComponent isEditing={ false } />,
|
||||
edit: <ApplePayComponent isEditing={ true } />,
|
||||
ariaLabel: buttonData.title,
|
||||
canMakePayment: () => buttonData.enabled,
|
||||
supports: {
|
||||
features,
|
||||
style: [ 'height', 'borderRadius' ],
|
||||
},
|
||||
} );
|
||||
if ( buttonConfig?.is_enabled ) {
|
||||
registerExpressPaymentMethod( {
|
||||
name: buttonData.id,
|
||||
title: `PayPal - ${ buttonData.title }`,
|
||||
description: __(
|
||||
'Eligible users will see the PayPal button.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
label: <div dangerouslySetInnerHTML={ { __html: buttonData.title } } />,
|
||||
content: <ApplePayComponent isEditing={ false } />,
|
||||
edit: <ApplePayComponent isEditing={ true } />,
|
||||
ariaLabel: buttonData.title,
|
||||
canMakePayment: () =>
|
||||
buttonData.enabled && window.ApplePaySession?.canMakePayments(),
|
||||
supports: {
|
||||
features,
|
||||
style: [ 'height', 'borderRadius' ],
|
||||
},
|
||||
} );
|
||||
}
|
||||
|
|
|
@ -33,11 +33,11 @@ return array(
|
|||
$apm_applies = $container->get( 'applepay.helpers.apm-applies' );
|
||||
assert( $apm_applies instanceof ApmApplies );
|
||||
|
||||
return static function () use ( $apm_applies ) : bool {
|
||||
return static function () use ( $apm_applies ): bool {
|
||||
return $apm_applies->for_country() && $apm_applies->for_currency() && $apm_applies->for_merchant();
|
||||
};
|
||||
},
|
||||
'applepay.helpers.apm-applies' => static function ( ContainerInterface $container ) : ApmApplies {
|
||||
'applepay.helpers.apm-applies' => static function ( ContainerInterface $container ): ApmApplies {
|
||||
return new ApmApplies(
|
||||
$container->get( 'applepay.supported-countries' ),
|
||||
$container->get( 'applepay.supported-currencies' ),
|
||||
|
@ -45,7 +45,7 @@ return array(
|
|||
$container->get( 'api.shop.country' )
|
||||
);
|
||||
},
|
||||
'applepay.status-cache' => static function( ContainerInterface $container ): Cache {
|
||||
'applepay.status-cache' => static function ( ContainerInterface $container ): Cache {
|
||||
return new Cache( 'ppcp-paypal-apple-status-cache' );
|
||||
},
|
||||
|
||||
|
@ -82,7 +82,7 @@ return array(
|
|||
},
|
||||
|
||||
'applepay.apple-product-status' => SingletonDecorator::make(
|
||||
static function( ContainerInterface $container ): AppleProductStatus {
|
||||
static function ( ContainerInterface $container ): AppleProductStatus {
|
||||
return new AppleProductStatus(
|
||||
$container->get( 'wcgateway.settings' ),
|
||||
$container->get( 'api.endpoint.partners' ),
|
||||
|
@ -136,14 +136,7 @@ return array(
|
|||
return false;
|
||||
},
|
||||
'applepay.url' => static function ( ContainerInterface $container ): string {
|
||||
$path = realpath( __FILE__ );
|
||||
if ( false === $path ) {
|
||||
return '';
|
||||
}
|
||||
return plugins_url(
|
||||
'/modules/ppcp-applepay/',
|
||||
dirname( $path, 3 ) . '/woocommerce-paypal-payments.php'
|
||||
);
|
||||
return plugins_url( '/modules/ppcp-applepay/', $container->get( 'ppcp.path-to-plugin-main-file' ) );
|
||||
},
|
||||
'applepay.sdk_script_url' => static function ( ContainerInterface $container ): string {
|
||||
return 'https://applepay.cdn-apple.com/jsapi/v1/apple-pay-sdk.js';
|
||||
|
@ -176,7 +169,7 @@ return array(
|
|||
/**
|
||||
* The list of which countries can be used for ApplePay.
|
||||
*/
|
||||
'applepay.supported-countries' => static function ( ContainerInterface $container ) : array {
|
||||
'applepay.supported-countries' => static function ( ContainerInterface $container ): array {
|
||||
/**
|
||||
* Returns which countries can be used for ApplePay.
|
||||
*/
|
||||
|
@ -232,7 +225,7 @@ return array(
|
|||
/**
|
||||
* The list of which currencies can be used for ApplePay.
|
||||
*/
|
||||
'applepay.supported-currencies' => static function ( ContainerInterface $container ) : array {
|
||||
'applepay.supported-currencies' => static function ( ContainerInterface $container ): array {
|
||||
/**
|
||||
* Returns which currencies can be used for ApplePay.
|
||||
*/
|
||||
|
|
|
@ -171,7 +171,7 @@ class ApplePayGateway extends WC_Payment_Gateway {
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function process_payment( $order_id ) : array {
|
||||
public function process_payment( $order_id ): array {
|
||||
$wc_order = wc_get_order( $order_id );
|
||||
if ( ! is_a( $wc_order, WC_Order::class ) ) {
|
||||
return $this->handle_payment_failure(
|
||||
|
@ -234,7 +234,7 @@ class ApplePayGateway extends WC_Payment_Gateway {
|
|||
*
|
||||
* @return boolean True or false based on success, or a WP_Error object.
|
||||
*/
|
||||
public function process_refund( $order_id, $amount = null, $reason = '' ) : bool {
|
||||
public function process_refund( $order_id, $amount = null, $reason = '' ): bool {
|
||||
$order = wc_get_order( $order_id );
|
||||
if ( ! is_a( $order, WC_Order::class ) ) {
|
||||
return false;
|
||||
|
@ -250,7 +250,7 @@ class ApplePayGateway extends WC_Payment_Gateway {
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_transaction_url( $order ) : string {
|
||||
public function get_transaction_url( $order ): string {
|
||||
$this->view_transaction_url = $this->transaction_url_provider->get_transaction_url_base( $order );
|
||||
|
||||
return parent::get_transaction_url( $order );
|
||||
|
|
|
@ -18,6 +18,7 @@ use WooCommerce\PayPalCommerce\Applepay\Assets\PropertiesDictionary;
|
|||
use WooCommerce\PayPalCommerce\Button\Assets\ButtonInterface;
|
||||
use WooCommerce\PayPalCommerce\Button\Assets\SmartButtonInterface;
|
||||
use WooCommerce\PayPalCommerce\Applepay\Helper\AvailabilityNotice;
|
||||
use WooCommerce\PayPalCommerce\Settings\SettingsModule;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ExecutableModule;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ExtendingModule;
|
||||
|
@ -55,7 +56,7 @@ class ApplepayModule implements ServiceModule, ExtendingModule, ExecutableModule
|
|||
// Clears product status when appropriate.
|
||||
add_action(
|
||||
'woocommerce_paypal_payments_clear_apm_product_status',
|
||||
function( ?Settings $settings = null ) use ( $c ): void {
|
||||
function ( ?Settings $settings = null ) use ( $c ): void {
|
||||
$apm_status = $c->get( 'applepay.apple-product-status' );
|
||||
assert( $apm_status instanceof AppleProductStatus );
|
||||
$apm_status->clear( $settings );
|
||||
|
@ -93,15 +94,17 @@ class ApplepayModule implements ServiceModule, ExtendingModule, ExecutableModule
|
|||
return;
|
||||
}
|
||||
|
||||
if ( $apple_payment_method->is_enabled() ) {
|
||||
$module->load_assets( $c, $apple_payment_method );
|
||||
$module->handle_validation_file( $c, $apple_payment_method );
|
||||
$module->render_buttons( $c, $apple_payment_method );
|
||||
$apple_payment_method->bootstrap_ajax_request();
|
||||
}
|
||||
|
||||
$module->load_admin_assets( $c, $apple_payment_method );
|
||||
$module->load_block_editor_assets( $c, $apple_payment_method );
|
||||
|
||||
if ( SettingsModule::should_use_the_old_ui() && ! $apple_payment_method->is_enabled() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$module->load_assets( $c, $apple_payment_method );
|
||||
$module->handle_validation_file( $c, $apple_payment_method );
|
||||
$module->render_buttons( $c, $apple_payment_method );
|
||||
$apple_payment_method->bootstrap_ajax_request();
|
||||
},
|
||||
1
|
||||
);
|
||||
|
@ -171,7 +174,7 @@ class ApplepayModule implements ServiceModule, ExtendingModule, ExecutableModule
|
|||
|
||||
add_filter(
|
||||
'woocommerce_paypal_payments_selected_button_locations',
|
||||
function( array $locations, string $setting_name ): array {
|
||||
function ( array $locations, string $setting_name ): array {
|
||||
$gateway = WC()->payment_gateways()->payment_gateways()[ ApplePayGateway::ID ] ?? '';
|
||||
if ( $gateway && $gateway->enabled === 'yes' && $setting_name === 'smart_button_locations' ) {
|
||||
$locations[] = 'checkout';
|
||||
|
@ -185,7 +188,7 @@ class ApplepayModule implements ServiceModule, ExtendingModule, ExecutableModule
|
|||
|
||||
add_filter(
|
||||
'woocommerce_paypal_payments_rest_common_merchant_features',
|
||||
function( array $features ) use ( $c ): array {
|
||||
function ( array $features ) use ( $c ): array {
|
||||
$product_status = $c->get( 'applepay.apple-product-status' );
|
||||
assert( $product_status instanceof AppleProductStatus );
|
||||
|
||||
|
@ -201,7 +204,7 @@ class ApplepayModule implements ServiceModule, ExtendingModule, ExecutableModule
|
|||
|
||||
add_filter(
|
||||
'ppcp_create_order_request_body_data',
|
||||
static function ( array $data, string $payment_method, array $request ) use ( $c ) : array {
|
||||
static function ( array $data, string $payment_method, array $request ) use ( $c ): array {
|
||||
|
||||
if ( $payment_method !== ApplePayGateway::ID ) {
|
||||
return $data;
|
||||
|
@ -255,13 +258,13 @@ class ApplepayModule implements ServiceModule, ExtendingModule, ExecutableModule
|
|||
* @return void
|
||||
*/
|
||||
public function load_assets( ContainerInterface $c, ApplePayButton $button ): void {
|
||||
if ( ! $button->is_enabled() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_action(
|
||||
'wp_enqueue_scripts',
|
||||
function () use ( $c, $button ) {
|
||||
if ( ! $button->is_enabled() ) {
|
||||
return;
|
||||
}
|
||||
$smart_button = $c->get( 'button.smart-button' );
|
||||
assert( $smart_button instanceof SmartButtonInterface );
|
||||
if ( $smart_button->should_load_ppcp_script() ) {
|
||||
|
@ -282,13 +285,16 @@ class ApplepayModule implements ServiceModule, ExtendingModule, ExecutableModule
|
|||
add_action(
|
||||
'enqueue_block_editor_assets',
|
||||
function () use ( $c, $button ) {
|
||||
if ( ! $button->is_enabled() ) {
|
||||
return;
|
||||
}
|
||||
$button->enqueue_admin_styles();
|
||||
}
|
||||
);
|
||||
|
||||
add_action(
|
||||
'woocommerce_blocks_payment_method_type_registration',
|
||||
function( PaymentMethodRegistry $payment_method_registry ) use ( $c ): void {
|
||||
function ( PaymentMethodRegistry $payment_method_registry ) use ( $c ): void {
|
||||
$payment_method_registry->register( $c->get( 'applepay.blocks-payment-method' ) );
|
||||
}
|
||||
);
|
||||
|
@ -323,7 +329,7 @@ class ApplepayModule implements ServiceModule, ExtendingModule, ExecutableModule
|
|||
// Adds ApplePay component to the backend button preview settings.
|
||||
add_action(
|
||||
'woocommerce_paypal_payments_admin_gateway_settings',
|
||||
function( array $settings ) use ( $c ): array {
|
||||
function ( array $settings ) use ( $c ): array {
|
||||
if ( is_array( $settings['components'] ) ) {
|
||||
$settings['components'][] = 'applepay';
|
||||
}
|
||||
|
@ -362,9 +368,6 @@ class ApplepayModule implements ServiceModule, ExtendingModule, ExecutableModule
|
|||
* @return void
|
||||
*/
|
||||
public function render_buttons( ContainerInterface $c, ApplePayButton $button ): void {
|
||||
if ( ! $button->is_enabled() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_action(
|
||||
'wp',
|
||||
|
@ -372,8 +375,13 @@ class ApplepayModule implements ServiceModule, ExtendingModule, ExecutableModule
|
|||
if ( is_admin() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$button = $c->get( 'applepay.button' );
|
||||
|
||||
if ( ! $button->is_enabled() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Button.
|
||||
*
|
||||
|
@ -392,9 +400,6 @@ class ApplepayModule implements ServiceModule, ExtendingModule, ExecutableModule
|
|||
* @return void
|
||||
*/
|
||||
public function handle_validation_file( ContainerInterface $c, ApplePayButton $button ): void {
|
||||
if ( ! $button->is_enabled() ) {
|
||||
return;
|
||||
}
|
||||
$env = $c->get( 'settings.environment' );
|
||||
assert( $env instanceof Environment );
|
||||
$is_sandbox = $env->current_environment_is( Environment::SANDBOX );
|
||||
|
@ -407,7 +412,7 @@ class ApplepayModule implements ServiceModule, ExtendingModule, ExecutableModule
|
|||
* @param bool $is_sandbox The environment for this merchant.
|
||||
* @return string
|
||||
*/
|
||||
public function validation_string( bool $is_sandbox ) : string {
|
||||
public function validation_string( bool $is_sandbox ): string {
|
||||
$sandbox_string = $this->sandbox_validation_string();
|
||||
$live_string = $this->live_validation_string();
|
||||
return $is_sandbox ? $sandbox_string : $live_string;
|
||||
|
|
|
@ -26,7 +26,8 @@ use WooCommerce\PayPalCommerce\Button\Helper\ContextTrait;
|
|||
* Class ApplePayButton
|
||||
*/
|
||||
class ApplePayButton implements ButtonInterface {
|
||||
use RequestHandlerTrait, ContextTrait;
|
||||
use RequestHandlerTrait;
|
||||
use ContextTrait;
|
||||
|
||||
/**
|
||||
* The settings.
|
||||
|
@ -222,7 +223,6 @@ class ApplePayButton implements ButtonInterface {
|
|||
return $options . '<li><label><input type="checkbox" id="ppcp-onboarding-apple" ' . $checked . ' data-onboarding-option="ppcp-onboarding-apple"> ' .
|
||||
__( 'Onboard with ApplePay', 'woocommerce-paypal-payments' ) . '
|
||||
</label></li>';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -445,7 +445,7 @@ class ApplePayButton implements ButtonInterface {
|
|||
} else {
|
||||
add_filter(
|
||||
'woocommerce_payment_successful_result',
|
||||
function ( array $result ) use ( $cart, $cart_item_key ) : array {
|
||||
function ( array $result ) use ( $cart, $cart_item_key ): array {
|
||||
$this->clear_current_cart( $cart, $cart_item_key );
|
||||
$this->reload_cart( $cart );
|
||||
return $result;
|
||||
|
@ -917,7 +917,7 @@ class ApplePayButton implements ButtonInterface {
|
|||
|
||||
add_filter(
|
||||
'woocommerce_paypal_payments_sdk_components_hook',
|
||||
function( array $components ) {
|
||||
function ( array $components ) {
|
||||
$components[] = 'applepay';
|
||||
return $components;
|
||||
}
|
||||
|
|
|
@ -361,7 +361,6 @@ class ApplePayDataObjectHttp {
|
|||
}
|
||||
$this->$key = $value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -509,7 +508,7 @@ class ApplePayDataObjectHttp {
|
|||
* @param array $data The data.
|
||||
* @return void
|
||||
*/
|
||||
protected function update_simplified_contact( array $data ) : void {
|
||||
protected function update_simplified_contact( array $data ): void {
|
||||
$simplified_contact_info = array_map( 'sanitize_text_field', $data );
|
||||
$this->simplified_contact = $this->simplified_address(
|
||||
$simplified_contact_info
|
||||
|
@ -727,7 +726,7 @@ class ApplePayDataObjectHttp {
|
|||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_nonce_valid():bool {
|
||||
public function is_nonce_valid(): bool {
|
||||
$nonce = filter_input( INPUT_POST, 'woocommerce-process-checkout-nonce', FILTER_SANITIZE_SPECIAL_CHARS );
|
||||
if ( ! $nonce ) {
|
||||
return false;
|
||||
|
|
|
@ -54,7 +54,7 @@ class AppleProductStatus extends ProductStatus {
|
|||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected function check_local_state() : ?bool {
|
||||
protected function check_local_state(): ?bool {
|
||||
$status_override = apply_filters( 'woocommerce_paypal_payments_apple_pay_product_status', null );
|
||||
if ( null !== $status_override ) {
|
||||
return $status_override;
|
||||
|
@ -68,7 +68,7 @@ class AppleProductStatus extends ProductStatus {
|
|||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected function check_active_state( SellerStatus $seller_status ) : bool {
|
||||
protected function check_active_state( SellerStatus $seller_status ): bool {
|
||||
// Check the seller status for the intended capability.
|
||||
$has_capability = false;
|
||||
foreach ( $seller_status->products() as $product ) {
|
||||
|
@ -101,7 +101,7 @@ class AppleProductStatus extends ProductStatus {
|
|||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected function clear_state( ?Settings $settings = null ) : void {
|
||||
protected function clear_state( ?Settings $settings = null ): void {
|
||||
if ( null === $settings ) {
|
||||
$settings = $this->settings;
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ class DataToAppleButtonScripts {
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function apple_pay_script_data() : array {
|
||||
public function apple_pay_script_data(): array {
|
||||
if ( is_product() ) {
|
||||
return $this->data_for_product_page();
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ class DataToAppleButtonScripts {
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function apple_pay_script_data_for_admin() : array {
|
||||
public function apple_pay_script_data_for_admin(): array {
|
||||
return $this->data_for_admin_page();
|
||||
}
|
||||
|
||||
|
@ -73,7 +73,7 @@ class DataToAppleButtonScripts {
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_apple_pay_data( array $product = array() ) : array {
|
||||
private function get_apple_pay_data( array $product = array() ): array {
|
||||
// true: Use Apple Pay as distinct gateway.
|
||||
// false: integrate it with the smart buttons.
|
||||
$available_gateways = WC()->payment_gateways->get_available_payment_gateways();
|
||||
|
@ -132,7 +132,7 @@ class DataToAppleButtonScripts {
|
|||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function check_if_need_shipping( WC_Product $product ) : bool {
|
||||
protected function check_if_need_shipping( WC_Product $product ): bool {
|
||||
if (
|
||||
! wc_shipping_enabled()
|
||||
|| 0 === wc_get_shipping_method_count(
|
||||
|
@ -154,7 +154,7 @@ class DataToAppleButtonScripts {
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function data_for_product_page() : array {
|
||||
protected function data_for_product_page(): array {
|
||||
$product = wc_get_product( get_the_id() );
|
||||
if ( ! $product ) {
|
||||
return array();
|
||||
|
@ -185,7 +185,7 @@ class DataToAppleButtonScripts {
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function data_for_cart_page() : array {
|
||||
protected function data_for_cart_page(): array {
|
||||
$cart = WC()->cart;
|
||||
if ( ! $cart ) {
|
||||
return array();
|
||||
|
@ -206,7 +206,7 @@ class DataToAppleButtonScripts {
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function data_for_admin_page() : array {
|
||||
protected function data_for_admin_page(): array {
|
||||
$data = $this->get_apple_pay_data(
|
||||
array(
|
||||
'needShipping' => false,
|
||||
|
|
|
@ -89,7 +89,7 @@ class ApmApplies {
|
|||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function for_merchant() : bool {
|
||||
public function for_merchant(): bool {
|
||||
return apply_filters(
|
||||
'woocommerce_paypal_payments_is_eligible_for_applepay',
|
||||
true
|
||||
|
|
|
@ -141,7 +141,6 @@ class AvailabilityNotice {
|
|||
if ( ! $this->is_merchant_validated ) {
|
||||
$this->add_merchant_not_validated_notice();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -287,5 +286,4 @@ class AvailabilityNotice {
|
|||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,6 +9,6 @@ declare( strict_types = 1 );
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\AxoBlock;
|
||||
|
||||
return static function () : AxoBlockModule {
|
||||
return static function (): AxoBlockModule {
|
||||
return new AxoBlockModule();
|
||||
};
|
||||
|
|
|
@ -42,40 +42,56 @@ $fast-transition-duration: 0.5s;
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
max-width: 300px;
|
||||
max-width: 340px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&__content {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
aspect-ratio: 1.586;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
border: 1px solid $border-color;
|
||||
font-size: 0.875em;
|
||||
font-family: monospace;
|
||||
padding: 1em;
|
||||
margin: 1em 0;
|
||||
border-radius: 4px;
|
||||
border-radius: 10px;
|
||||
width: 100%;
|
||||
box-shadow: 0 3px 10px -3px rgba(0, 0, 0, .2666666667);
|
||||
background-image: linear-gradient(60deg, rgba(0, 0, 0, 0.0666666667), rgba(204, 204, 204, 0.0666666667) 65%, rgba(255, 255, 255, 0.4) 68%, rgba(255, 255, 255, 0));
|
||||
border: 2px solid #ccc;
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
|
||||
&__meta {
|
||||
@include flex-space-between;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
|
||||
&-digits {
|
||||
letter-spacing: 2px;
|
||||
margin-top: 76px;
|
||||
font-size: 24px;
|
||||
text-shadow: 0 -1px 1px #fff, 0 1px 1px rgba(0, 0, 0, .2666666667);
|
||||
color: #666;
|
||||
text-align: center;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
align-self: flex-end;
|
||||
&-logo {
|
||||
position: absolute;
|
||||
right: 32px;
|
||||
top: 32px;
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
&__watermark {
|
||||
align-self: flex-end;
|
||||
&-expiry {
|
||||
text-align: right;
|
||||
font-size: 14px;
|
||||
padding-right: 32px;
|
||||
}
|
||||
|
||||
&-name {
|
||||
text-transform: uppercase;
|
||||
position: absolute;
|
||||
left: 24px;
|
||||
bottom: 20px;
|
||||
line-height: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
&__edit {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue