mirror of
https://github.com/SuiteCRM/SuiteCRM-Core.git
synced 2025-08-29 08:17:18 +08:00
Squashed 'public/legacy/' content from commit 817a12dc0
git-subtree-dir: public/legacy git-subtree-split: 817a12dc0c30c189f56d5cb1f7dc37a9631bdbe3
This commit is contained in:
commit
8e4cc94994
9769 changed files with 1617695 additions and 0 deletions
62
.codecov.yml
Normal file
62
.codecov.yml
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
codecov:
|
||||||
|
notify:
|
||||||
|
require_ci_to_pass: yes
|
||||||
|
|
||||||
|
coverage:
|
||||||
|
precision: 2
|
||||||
|
round: down
|
||||||
|
range: "70...100"
|
||||||
|
|
||||||
|
status:
|
||||||
|
project:
|
||||||
|
default:
|
||||||
|
target: 0%
|
||||||
|
threshold: 5%
|
||||||
|
base: parent
|
||||||
|
branches: null
|
||||||
|
if_no_uploads: error
|
||||||
|
if_not_found: success
|
||||||
|
if_ci_failed: error
|
||||||
|
only_pulls: false
|
||||||
|
flags: null
|
||||||
|
paths: null
|
||||||
|
patch: no
|
||||||
|
changes: no
|
||||||
|
|
||||||
|
parsers:
|
||||||
|
gcov:
|
||||||
|
branch_detection:
|
||||||
|
conditional: yes
|
||||||
|
loop: yes
|
||||||
|
method: no
|
||||||
|
macro: no
|
||||||
|
|
||||||
|
comment:
|
||||||
|
layout: "header, diff"
|
||||||
|
behavior: default
|
||||||
|
require_changes: false
|
||||||
|
|
||||||
|
ignore:
|
||||||
|
- "include/timezone/.*"
|
||||||
|
- "include/SuiteGraphs/.*"
|
||||||
|
- "include/social/.*"
|
||||||
|
- "include/Smarty/.*"
|
||||||
|
- "include/reCaptcha/.*"
|
||||||
|
- "include/phpmailer/.*"
|
||||||
|
- "include/Pear/.*"
|
||||||
|
- "include/pclzip/.*"
|
||||||
|
- "include/nusoap/.*"
|
||||||
|
- "include/HTTP_WebDAV_Server/.*"
|
||||||
|
- "include/HTMLPurifier/.*"
|
||||||
|
- "include/ytree/.*"
|
||||||
|
- "include/php-sql-parser.php"
|
||||||
|
- "include/parsecsv.lib.php"
|
||||||
|
- "modules/AOS_PDF_Templates/PDF_Lib/.*"
|
||||||
|
- "Zend/.*"
|
||||||
|
- "modules/AOD_Index/Lib/.*"
|
||||||
|
- "modules/Users/authentication/SAML2Authenticate/lib/.*"
|
||||||
|
- "install/demoData.en_us.php"
|
||||||
|
- "include/tcpdf/.*"
|
||||||
|
- "modules/AOR_Charts/lib/.*"
|
||||||
|
# The old lowercase v8 API is deprecated/unsupported and the CI doesn't run the tests for it. The new API uses an upper-case V.
|
||||||
|
- "lib/API/.*"
|
52
.env.dist
Normal file
52
.env.dist
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
# This is a template dotenv file. You should copy it and then modify it to fit
|
||||||
|
# your setup. These environment variables won't do anything unless copied into
|
||||||
|
# a file called `.env.test`. There, they'll be used to determine information
|
||||||
|
# about the test environment.
|
||||||
|
#
|
||||||
|
# This is useful because we want the test environment to have a different
|
||||||
|
# configuration from the development environment. That way, we can run
|
||||||
|
# the automated test suites without worrying about their impact on the database
|
||||||
|
# we use for development.
|
||||||
|
#
|
||||||
|
# For more information, see the Automated Testing Documentation.
|
||||||
|
# https://docs.suitecrm.com/developer/automatedtesting/
|
||||||
|
|
||||||
|
|
||||||
|
#== Install Test Suite:
|
||||||
|
|
||||||
|
# MYSQL or MSSQL
|
||||||
|
DATABASE_DRIVER=MYSQL
|
||||||
|
|
||||||
|
# Path to database server
|
||||||
|
DATABASE_HOST=localhost
|
||||||
|
|
||||||
|
# Name of the database
|
||||||
|
DATABASE_NAME=automated_tests
|
||||||
|
|
||||||
|
# Database user
|
||||||
|
DATABASE_USER=automated_tests
|
||||||
|
|
||||||
|
# Database password
|
||||||
|
DATABASE_PASSWORD=automated_tests
|
||||||
|
|
||||||
|
|
||||||
|
#== Acceptance, API, and Install Test Suites:
|
||||||
|
|
||||||
|
# URL of the SuiteCRM instance which the tester needs to access
|
||||||
|
INSTANCE_URL=http://localhost:8000
|
||||||
|
|
||||||
|
# Admin username for SuiteCRM instance
|
||||||
|
INSTANCE_ADMIN_USER=admin
|
||||||
|
|
||||||
|
# Admin password for SuiteCRM instance
|
||||||
|
INSTANCE_ADMIN_PASSWORD=password
|
||||||
|
|
||||||
|
|
||||||
|
#== API Test Suite:
|
||||||
|
|
||||||
|
# API Client ID
|
||||||
|
INSTANCE_CLIENT_ID=suitecrm_client
|
||||||
|
|
||||||
|
# API Client Secret
|
||||||
|
INSTANCE_CLIENT_SECRET=secret
|
||||||
|
|
196
.gitattributes
vendored
Normal file
196
.gitattributes
vendored
Normal file
|
@ -0,0 +1,196 @@
|
||||||
|
# Auto detect and handle line endings for all text eol=lf files while leaving binary files untouched.
|
||||||
|
# This will handle all files NOT defined below.
|
||||||
|
* text=auto
|
||||||
|
|
||||||
|
# Linux specific
|
||||||
|
*.sh text eol=lf
|
||||||
|
*.so binary
|
||||||
|
|
||||||
|
# Windows specific
|
||||||
|
*.bat text eol=crlf
|
||||||
|
*.exe binary
|
||||||
|
*.dll binary
|
||||||
|
|
||||||
|
# Sources
|
||||||
|
*.coffee text eol=lf
|
||||||
|
*.css text eol=lf
|
||||||
|
*.htm text eol=lf
|
||||||
|
*.html text eol=lf
|
||||||
|
*.inc text eol=lf
|
||||||
|
*.ini text eol=lf
|
||||||
|
*.js text eol=lf
|
||||||
|
*.json text eol=lf
|
||||||
|
*.jsx text eol=lf
|
||||||
|
*.less text eol=lf
|
||||||
|
*.od text eol=lf
|
||||||
|
*.onlydata text eol=lf
|
||||||
|
*.php text eol=lf
|
||||||
|
*.pl text eol=lf
|
||||||
|
*.py text eol=lf
|
||||||
|
*.rb text eol=lf
|
||||||
|
*.sass text eol=lf
|
||||||
|
*.scm text eol=lf
|
||||||
|
*.scss text eol=lf
|
||||||
|
*.sql text eol=lf
|
||||||
|
*.styl text eol=lf
|
||||||
|
*.tag text eol=lf
|
||||||
|
*.ts text eol=lf
|
||||||
|
*.tsx text eol=lf
|
||||||
|
*.xml text eol=lf
|
||||||
|
*.xhtml text eol=lf
|
||||||
|
*.lock text eol=lf
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
*.markdown text eol=lf
|
||||||
|
*.md text eol=lf
|
||||||
|
*.mdwn text eol=lf
|
||||||
|
*.mdown text eol=lf
|
||||||
|
*.mkd text eol=lf
|
||||||
|
*.mkdn text eol=lf
|
||||||
|
*.mdtxt text eol=lf
|
||||||
|
*.mdtext text eol=lf
|
||||||
|
*.txt text eol=lf
|
||||||
|
AUTHORS text eol=lf
|
||||||
|
CHANGELOG text eol=lf
|
||||||
|
CHANGES text eol=lf
|
||||||
|
CONTRIBUTING text eol=lf
|
||||||
|
COPYING text eol=lf
|
||||||
|
copyright text eol=lf
|
||||||
|
*COPYRIGHT* text eol=lf
|
||||||
|
INSTALL text eol=lf
|
||||||
|
license text eol=lf
|
||||||
|
LICENSE text eol=lf
|
||||||
|
NEWS text eol=lf
|
||||||
|
readme text eol=lf
|
||||||
|
*README* text eol=lf
|
||||||
|
TODO text eol=lf
|
||||||
|
|
||||||
|
# Templates
|
||||||
|
*.dot text eol=lf
|
||||||
|
*.ejs text eol=lf
|
||||||
|
*.haml text eol=lf
|
||||||
|
*.handlebars text eol=lf
|
||||||
|
*.hbs text eol=lf
|
||||||
|
*.hbt text eol=lf
|
||||||
|
*.jade text eol=lf
|
||||||
|
*.latte text eol=lf
|
||||||
|
*.mustache text eol=lf
|
||||||
|
*.njk text eol=lf
|
||||||
|
*.phtml text eol=lf
|
||||||
|
*.phpt text eol=lf
|
||||||
|
*.tmpl text eol=lf
|
||||||
|
*.tpl text eol=lf
|
||||||
|
*.twig text eol=lf
|
||||||
|
|
||||||
|
# Configs
|
||||||
|
*.cnf text eol=lf
|
||||||
|
*.conf text eol=lf
|
||||||
|
*.config text eol=lf
|
||||||
|
.browserslistrc text eol=lf
|
||||||
|
.editorconfig text eol=lf
|
||||||
|
.htaccess text eol=lf
|
||||||
|
*.npmignore text eol=lf
|
||||||
|
*.yaml text eol=lf
|
||||||
|
*.yml text eol=lf
|
||||||
|
browserslist text eol=lf
|
||||||
|
Makefile text eol=lf
|
||||||
|
makefile text eol=lf
|
||||||
|
|
||||||
|
# Git
|
||||||
|
.gitattributes text eol=lf
|
||||||
|
.gitignore text eol=lf
|
||||||
|
.gitconfig text eol=lf
|
||||||
|
.gitmodules text eol=lf
|
||||||
|
|
||||||
|
# Docker
|
||||||
|
*.dockerignore text eol=lf
|
||||||
|
Dockerfile text eol=lf
|
||||||
|
|
||||||
|
# Graphics
|
||||||
|
*.ai binary
|
||||||
|
*.bmp binary
|
||||||
|
*.eps binary
|
||||||
|
*.gif binary
|
||||||
|
*.ico binary
|
||||||
|
*.jng binary
|
||||||
|
*.jp2 binary
|
||||||
|
*.jpg binary
|
||||||
|
*.jpeg binary
|
||||||
|
*.jpx binary
|
||||||
|
*.jxr binary
|
||||||
|
*.pdf binary
|
||||||
|
*.png binary
|
||||||
|
*.psb binary
|
||||||
|
*.psd binary
|
||||||
|
*.svg text eol=lf
|
||||||
|
*.svgz binary
|
||||||
|
*.tif binary
|
||||||
|
*.tiff binary
|
||||||
|
*.wbmp binary
|
||||||
|
*.webp binary
|
||||||
|
|
||||||
|
# Audio
|
||||||
|
*.kar binary
|
||||||
|
*.m4a binary
|
||||||
|
*.mid binary
|
||||||
|
*.midi binary
|
||||||
|
*.mp3 binary
|
||||||
|
*.ogg binary
|
||||||
|
*.ra binary
|
||||||
|
|
||||||
|
# Video
|
||||||
|
*.3gpp binary
|
||||||
|
*.3gp binary
|
||||||
|
*.as binary
|
||||||
|
*.asf binary
|
||||||
|
*.asx binary
|
||||||
|
*.fla binary
|
||||||
|
*.flv binary
|
||||||
|
*.m4v binary
|
||||||
|
*.mng binary
|
||||||
|
*.mov binary
|
||||||
|
*.mp4 binary
|
||||||
|
*.mpeg binary
|
||||||
|
*.mpg binary
|
||||||
|
*.ogv binary
|
||||||
|
*.swc binary
|
||||||
|
*.swf binary
|
||||||
|
*.webm binary
|
||||||
|
|
||||||
|
# Archives
|
||||||
|
*.7z binary
|
||||||
|
*.gz binary
|
||||||
|
*.jar binary
|
||||||
|
*.rar binary
|
||||||
|
*.tar binary
|
||||||
|
*.zip binary
|
||||||
|
|
||||||
|
# Fonts
|
||||||
|
*.ttf binary
|
||||||
|
*.eot binary
|
||||||
|
*.otf binary
|
||||||
|
*.woff binary
|
||||||
|
*.woff2 binary
|
||||||
|
|
||||||
|
# Executables
|
||||||
|
*.phar binary
|
||||||
|
|
||||||
|
# Directories to exclude when creating an archive
|
||||||
|
/tests export-ignore
|
||||||
|
/build export-ignore
|
||||||
|
/.github export-ignore
|
||||||
|
|
||||||
|
# Files to exclude when creating an archive
|
||||||
|
/.gitmodules export-ignore
|
||||||
|
/.gitignore export-ignore
|
||||||
|
/php_cs.xml export-ignore
|
||||||
|
/codacy.yml export-ignore
|
||||||
|
/codeception.dist.yml export-ignore
|
||||||
|
/.codecov.yml export-ignore
|
||||||
|
/.php_cs.dist export-ignore
|
||||||
|
/.travis.yml export-ignore
|
||||||
|
travis.php.ini export-ignore
|
||||||
|
/.phpcs.xml export-ignore
|
||||||
|
/.gitattributes export-ignore
|
||||||
|
/custom/modules/unified_search_modules_display.php export-ignore
|
||||||
|
/.env.dist export-ignore
|
35
.github/CODE_OF_CONDUCT.md
vendored
Normal file
35
.github/CODE_OF_CONDUCT.md
vendored
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
# Code of Conduct #
|
||||||
|
|
||||||
|
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||||
|
|
||||||
|
Examples of behaviour that contributes to creating a positive environment
|
||||||
|
include:
|
||||||
|
|
||||||
|
* Using welcoming and inclusive language
|
||||||
|
* Being respectful of differing viewpoints and experiences
|
||||||
|
* Gracefully accepting constructive criticism
|
||||||
|
* Focusing on what is best for the community in a professional manner
|
||||||
|
* Showing empathy towards other community members
|
||||||
|
|
||||||
|
Examples of unacceptable behaviour by participants include:
|
||||||
|
|
||||||
|
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||||
|
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||||
|
* Public or private harassment
|
||||||
|
* Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||||
|
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||||
|
|
||||||
|
The SuiteCRM project maintainers are responsible for clarifying the standards of acceptable behaviour and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behaviour. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team.
|
||||||
|
|
||||||
|
The SuiteCRM project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviours that they deem inappropriate, threatening, offensive, or harmful.
|
||||||
|
|
||||||
|
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, within project forums, posting via an official social media account, or acting as an appointed representative at an online or offline event.
|
||||||
|
|
||||||
|
Instances of abusive, harassing, or otherwise unacceptable behaviour may be reported by contacting the project team at [community@suitecrm.com][community_email]. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||||
|
|
||||||
|
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||||
|
available at [http://contributor-covenant.org/version/1/4][version]
|
||||||
|
|
||||||
|
[community_email]: mailto:community@suitecrm.com
|
||||||
|
[homepage]: http://contributor-covenant.org
|
||||||
|
[version]: http://contributor-covenant.org/version/1/4/
|
183
.github/CONTRIBUTING.md
vendored
Normal file
183
.github/CONTRIBUTING.md
vendored
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
## How to contribute to SuiteCRM
|
||||||
|
|
||||||
|
|
||||||
|
### **Code of Conduct**
|
||||||
|
|
||||||
|
This project and all community members are expected to uphold the [SuiteCRM Code of Conduct.](https://github.com/salesagility/SuiteCRM/blob/master/CODE_OF_CONDUCT.md)
|
||||||
|
|
||||||
|
#### **Bug Reporting**
|
||||||
|
|
||||||
|
* **Please do not open a GitHub issue if the bug is a security vulnerability**, and instead email us at security@suitecrm.com. This will be delivered to the product team who handle security issues. Please don't disclose security bugs publicly until they have been handled by the security team.
|
||||||
|
|
||||||
|
* Your email will be acknowledged within 24 hours during the business week (Mon - Fri), and you’ll receive a more detailed response to your email within 72 hours during the business week (Mon - Fri) indicating the next steps in handling your report.
|
||||||
|
|
||||||
|
* **Ensure the bug was not already reported** by searching on GitHub under [Issues.](https://github.com/salesagility/SuiteCRM/issues)
|
||||||
|
|
||||||
|
* If you're unable to find an open issue that relates to your problem, [open a new one.](https://github.com/salesagility/SuiteCRM/issues/new) Please be sure to follow the issue template as much as possible.
|
||||||
|
|
||||||
|
* **Ensure that the bug you are reporting is a core SuiteCRM issue** and not specific to your individual setup. For these types of issues please use the [Community Forum.](https://community.suitecrm.com/)
|
||||||
|
|
||||||
|
#### **Did you fix a bug?**
|
||||||
|
|
||||||
|
* To provide a code contribution for an issue you will need to set up your own fork of the SuiteCRM repository, make your code changes, commit the changes and make a Pull Request to the appropriate branch on the SuiteCM repository. See our [Quick Guide to Fork SuiteCRM.](https://suitecrm.com/wiki/index.php/Contributing_to_SuiteCRM#Quick_Guide_to_Fork_SuiteCRM) Once you have set up your forked repository you can begin making commits to the project.
|
||||||
|
|
||||||
|
* Determine which base branch your bug fix should use. If your bug is present in both hotfix and hotfix-7.10.x then you will need to make a separate pull request for each branch.
|
||||||
|
|
||||||
|
* Separate each fix into a new branch in your repository and name it with the issue ID e.g. bugfix_3062 or issue-1234.
|
||||||
|
|
||||||
|
* When committing to your individual bugfix branch, please try and use the following as your commit message
|
||||||
|
```Fixed #1234 - <the subject of the issue>```. E.g. ```Fixed #1436 - Reports with nested Parentheses are removing parameters```. By using this format we can easily include all bug fixes within major and minor release notes on our [Wiki](https://suitecrm.com/wiki/index.php/Main_Page).
|
||||||
|
|
||||||
|
* If you are new to Writing Commit Messages in git, follow the guide [here.](http://chris.beams.io/posts/git-commit/#seven-rules)
|
||||||
|
|
||||||
|
* After you have made your commits and pushed them up to your forked repository you then create a [Pull Request](https://help.github.com/articles/about-pull-requests/) to be reviewed and merged into the SuiteCRM repository. Make a new Pull Request for each issue you fix – do not combine multiple bugfixes into one Pull Request.
|
||||||
|
Ensure that your Pull Request fork is salesagility/SuiteCRM, base branch is either hotfix or hotfix-7.8.x, the head fork is your repository, and the base branch is your unique bugfix branch e.g. bugfix_1234.
|
||||||
|
We will automatically reject any Pull Requests made to the wrong branch!
|
||||||
|
|
||||||
|
* If you have not signed our CLA [Contributor License Agreement](https://www.clahub.com/agreements/salesagility/SuiteCRM) then your pull request will fail a check and we will be unable to merge it into the project. You will only be required to sign this once.
|
||||||
|
|
||||||
|
* When a new Pull Request is opened, Travis CI will test the merging of the origin and upstream branch and update the Pull Request. If this check fails you can review the test results and resolve accordingly. To test prior to making a Pull Request install PHPUnit via composer into your develop environment then cd into the tests directory and run: ```$ sh runtests.sh```
|
||||||
|
|
||||||
|
* Ensure that you follow the pull request [template](https://github.com/salesagility/SuiteCRM/blob/master/.github/PULL_REQUEST_TEMPLATE.md) as much as possible.
|
||||||
|
|
||||||
|
#### **Did you create a new feature or enhancement?**
|
||||||
|
|
||||||
|
* Changes that can be considered a new feature or enhancement should be made to the develop branch instead of the hotfix or hotfix-7.8.x. branch.
|
||||||
|
|
||||||
|
* To contribute a feature to SuiteCRM, similar to providing a Bug Fix, you must create a forked repository of SuiteCRM and set up your git and development environment.
|
||||||
|
Once done, create a new branch from **hotfix-7.10.x** (Issues effecting 7.10 & 7.11) or **hotfix** (Issues effecting 7.11 only) and name it relevant to the feature's purpose e.g campaign-wizard-ui. Following our [Code Standards,](https://suitecrm.com/wiki/index.php/Coding_Standards) develop the new feature and ensure your forked repository is kept up to date with minor/major releases. See our [Quick Guide to Fork SuiteCRM](https://suitecrm.com/wiki/index.php/Contributing_to_SuiteCRM#Quick_Guide_to_Fork_SuiteCRM) to update your repository.
|
||||||
|
Make sure your commit messages are relevant and descriptive. When ready to submit for review, make a Pull Request detailing your feature's functionality.
|
||||||
|
Ensure that your Pull Requests base fork is **salesagility/SuiteCRM**, the base branch is **hotfix-7.10.x** (Issues effecting 7.10 & 7.11) or **hotfix** (Issues effecting 7.11 only), the head fork is your repository, and the base branch is your feature branch.
|
||||||
|
Add any new PHPUnit tests to the new feature branch if required e.g new modules or classes.
|
||||||
|
|
||||||
|
### Issue and Pull Request Labels
|
||||||
|
|
||||||
|
* This section lists the labels we use to help us track and manage issues and pull requests across the SuiteCRM repositories.
|
||||||
|
|
||||||
|
* By using [GitHub search](https://help.github.com/articles/searching-issues/) you can use labels to help find issues and pull requests that you are interested in. If for example, you are interested in which PR's will be included in the next release of SuiteCRM, you can use the [open issues "Resolved: Next Release"](https://github.com/salesagility/SuiteCRM/issues?q=is%3Aopen+is%3Aissue+label%3A%22Resolved%3A+Next+Release%22) label.
|
||||||
|
|
||||||
|
* We encourage users who feel an issue should be raised as a higher priority for a next release that they should make a comment to that affect. This also applies to incorrect labelling.
|
||||||
|
|
||||||
|
#### General Labels
|
||||||
|
|
||||||
|
| Label name | `salesagility/SuiteCRM` | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `Bug` | [search][search-suitecrm-label-Bug] | Bugs within the core SuiteCRM codebase |
|
||||||
|
| `Community Contribution` | [search][search-suitecrm-label-Community-Contribution] | These are contribution made by the community |
|
||||||
|
| `Deprecated` | [search][search-suitecrm-label-Deprecated] | Issues & PRs related to an unsupported version of SuiteCRM |
|
||||||
|
| `Enhancement` | [search][search-suitecrm-label-Enhancement] | Pull requests that provide more functionality. Associated Issues are called suggestions |
|
||||||
|
| `Fix Proposed` | [search][search-suitecrm-label-Fix-Proposed] | A issue that has a PR related to it that provides a possible resolution |
|
||||||
|
| `Good First Issue` | [search][search-suitecrm-label-Good-First-Issue] | A good issue for someone new to SuiteCRM or web development |
|
||||||
|
| `Help Wanted` | [search][search-suitecrm-label-Help-Wanted] | Requesting help from the community to achieve a solution |
|
||||||
|
| `High Priority` | [search][search-suitecrm-label-High-Priority] | Issues & PRs that are critical; broken core functionality; fatal errors; there are no workarounds |
|
||||||
|
| `Medium Priority` | [search][search-suitecrm-label-Medium-Priority] | Issues & PRs that are important; broken functions; errors; there are workarounds |
|
||||||
|
| `Low Priority` | [search][search-suitecrm-label-Low-Priority] | Issues & PRs that are minor; broken styling; warns; there are practical workarounds |
|
||||||
|
| `Resolved: Next Release` | [search][search-suitecrm-label-Resolved-Next-Release] | Issues that have been resolved in a hotfix branch and scheduled to be in the next release |
|
||||||
|
| `Suggestion` | [search][search-suitecrm-label-Suggestion] | Issue containing a suggestion of functionality, process or UI. Associated PRs are called enhancement |
|
||||||
|
| `Question` | [search][search-suitecrm-label-Question] | This is a question raised about the functionality of SuiteCRM |
|
||||||
|
|
||||||
|
#### Description Labels
|
||||||
|
|
||||||
|
| Label name | `salesagility/SuiteCRM` | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `API` | [search][search-suitecrm-label-API] | Issues & PRs related to all things regarding the API |
|
||||||
|
| `Campaigns` | [search][search-suitecrm-label-Campaigns] | Issues & PRs related to all things regarding campaigns |
|
||||||
|
| `Cases` | [search][search-suitecrm-label-Cases] | Issues & PRs related to all things regarding cases |
|
||||||
|
| `Clean Up` | [search][search-suitecrm-label-Clean-Up] | Issues & PRs related to all things regarding to technical debt and log files |
|
||||||
|
| `Databases` | [search][search-suitecrm-label-Databases] | Issues & PRs related to all things regarding databases |
|
||||||
|
| `Dependencies` | [search][search-suitecrm-label-Dependencies] | Pull Requests that update a core dependency |
|
||||||
|
| `Developer Tools` | [search][search-suitecrm-label-Developer-Tools] | Issues & PRs related to all things regarding development tools like Robo, Travis, etc |
|
||||||
|
| `Discussion` | [search][search-suitecrm-label-Discussion] | Issues & PRs related to ongoing discussions |
|
||||||
|
| `Elasticsearch` | [search][search-suitecrm-label-Elasticsearch] | Issues & PRs related to all things regarding Elasticsearch |
|
||||||
|
| `Emails:Campaigns` | [search][search-suitecrm-label-Emails:Campaigns] | Issues & PRs related to email campaigns |
|
||||||
|
| `Emails:Cases` | [search][search-suitecrm-label-Emails:Cases] | Issues & PRs related to email cases & AOP |
|
||||||
|
| `Emails:Compose` | [search][search-suitecrm-label-Emails:Compose] | Issues & PRs related to email compose |
|
||||||
|
| `Emails:Config` | [search][search-suitecrm-label-Emails:Config] | Issues & PRs related to email configuration |
|
||||||
|
| `Emails:Templates` | [search][search-suitecrm-label-Emails:Templates] | Issues & PRs related to email templates |
|
||||||
|
| `Emails` | [search][search-suitecrm-label-Emails] | Issues & PRs related to all things regarding emails & email module |
|
||||||
|
| `Enviroment` | [search][search-suitecrm-label-Enviroment] | Issues & PRs related to the application environment |
|
||||||
|
| `Installation` | [search][search-suitecrm-label-Installation] | Issues & PRs related to the installation of the application |
|
||||||
|
| `Language` | [search][search-suitecrm-label-Language] | Issues & PRs that are confirmed as issues with language & translation within the core |
|
||||||
|
| `Module` | [search][search-suitecrm-label-Module] | Issues & PRs related to modules that do not have specific label |
|
||||||
|
| `Reports` | [search][search-suitecrm-label-Reports] | Issues & PRs related to all things regarding reports |
|
||||||
|
| `Upgrading` | [search][search-suitecrm-label-Upgrading] | Issues & PRs related to all things regarding upgrading & UpgradeWizard |
|
||||||
|
| `Workflow` | [search][search-suitecrm-label-Workflow] | Issues & PRs related to all things regarding workflow |
|
||||||
|
| `Studio` | [search][search-suitecrm-label-Studio] | Issues & PRs related to all things regarding studio & module builder |
|
||||||
|
| `Styling` | [search][search-suitecrm-label-Styling] | Issues & PRs related to all things regarding styling |
|
||||||
|
|
||||||
|
#### Status Labels
|
||||||
|
|
||||||
|
| Label name | `salesagility/SuiteCRM` | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `Assessed` | [search][search-suitecrm-label-Assessed] | PRs that have been tested and confirmed to resolve an issue by a core team member |
|
||||||
|
| `Community Assessed` | [search][search-suitecrm-label-Community-Assessed] | PRs that have been tested and confirmed to resolve an issue by at least 2 community members |
|
||||||
|
| `In Review` | [search][search-suitecrm-label-In-Review] | Pull Requests that are activity being reviewed by the core team |
|
||||||
|
| `Wrong Branch` | [search][search-suitecrm-label-Wrong-Branch] | Pull requests that point towards a restricted branch such as master |
|
||||||
|
| `Needs Review` | [search][search-suitecrm-label-Needs-Review] | Needs the core team to code review |
|
||||||
|
| `Needs Assessed` | [search][search-suitecrm-label-Needs-Assessed] | Needs the core team to assess |
|
||||||
|
| `Invalid` | [search][search-suitecrm-label-Invalid] | Issues & PRs which are a duplicate of an existing issue/PR |
|
||||||
|
| `Duplicate` | [search][search-suitecrm-label-Duplicate] | Issues & PRs which are a duplicate of an existing issue/PR |
|
||||||
|
| `Requires Tests` | [search][search-suitecrm-label-Requires-Tests] | Suggestion to OP to provide automated testing (unit, or acceptance) |
|
||||||
|
| `Requires Updates` | [search][search-suitecrm-label-Requires-Updates] | Issues & PRs which requires input or update from the author |
|
||||||
|
| `Needs Documentation` | [search][search-suitecrm-label-Needs-Documentation] | Requires adding documentation |
|
||||||
|
| `Needs Duplicated: Latest` | [search][search-suitecrm-label-Needs-Duplicated-Latest] | Pull Requests that require being duplicated to the "latest" branches i.e. Hotfix |
|
||||||
|
| `Needs Duplicated: LTS` | [search][search-suitecrm-label-Needs-Duplicated-LTS] | Pull Requests that require being duplicated to the LTS branches i.e. hotfix-7.x.x |
|
||||||
|
| `Work In Progress` | [search][search-suitecrm-label-Work-In-Progress] | Pull Requests that are not yet ready to be assessed |
|
||||||
|
|
||||||
|
[search-suitecrm-label-Bug]: https://github.com/salesagility/SuiteCRM/labels/Bug
|
||||||
|
[search-suitecrm-label-Community-Contribution]: https://github.com/salesagility/SuiteCRM/labels/Community%20Contribution
|
||||||
|
[search-suitecrm-label-Deprecated]: https://github.com/salesagility/SuiteCRM/labels/Deprecated
|
||||||
|
[search-suitecrm-label-Enhancement]: https://github.com/salesagility/SuiteCRM/labels/Enhancement
|
||||||
|
[search-suitecrm-label-Fix-Proposed]: https://github.com/salesagility/SuiteCRM/labels/Fix%20Proposed
|
||||||
|
[search-suitecrm-label-Good-First-Issue]: https://github.com/salesagility/SuiteCRM/labels/Good%20First%20Issue
|
||||||
|
[search-suitecrm-label-Help-Wanted]: https://github.com/salesagility/SuiteCRM/labels/Help%20Wanted
|
||||||
|
[search-suitecrm-label-High-Priority]: https://github.com/salesagility/SuiteCRM/labels/High%20Priority
|
||||||
|
[search-suitecrm-label-Medium-Priority]: https://github.com/salesagility/SuiteCRM/labels/Medium%20Priority
|
||||||
|
[search-suitecrm-label-Low-Priority]: https://github.com/salesagility/SuiteCRM/labels/Low%20Priority
|
||||||
|
[search-suitecrm-label-Resolved-Next-Release]: https://github.com/salesagility/SuiteCRM/labels/Resolved%3A%20Next%20Release
|
||||||
|
[search-suitecrm-label-Suggestion]: https://github.com/salesagility/SuiteCRM/labels/Suggestion
|
||||||
|
[search-suitecrm-label-Question]: https://github.com/salesagility/SuiteCRM/labels/Question
|
||||||
|
|
||||||
|
[search-suitecrm-label-API]: https://github.com/salesagility/SuiteCRM/labels/API
|
||||||
|
[search-suitecrm-label-Campaigns]: https://github.com/salesagility/SuiteCRM/labels/Campaigns
|
||||||
|
[search-suitecrm-label-Cases]: https://github.com/salesagility/SuiteCRM/labels/Cases
|
||||||
|
[search-suitecrm-label-Clean-Up]: https://github.com/salesagility/SuiteCRM/labels/Clean%20Up
|
||||||
|
[search-suitecrm-label-Databases]: https://github.com/salesagility/SuiteCRM/labels/Databases
|
||||||
|
[search-suitecrm-label-Dependencies]: https://github.com/salesagility/SuiteCRM/labels/Dependencies
|
||||||
|
[search-suitecrm-label-Developer-Tools]: https://github.com/salesagility/SuiteCRM/labels/Developer%20Tools
|
||||||
|
[search-suitecrm-label-Discussion]: https://github.com/salesagility/SuiteCRM/labels/Discussion
|
||||||
|
[search-suitecrm-label-Elasticsearch]: https://github.com/salesagility/SuiteCRM/labels/Elasticsearch
|
||||||
|
[search-suitecrm-label-Emails:Campaigns]: https://github.com/salesagility/SuiteCRM/labels/Emails%3ACampaigns
|
||||||
|
[search-suitecrm-label-Emails:Cases]: https://github.com/salesagility/SuiteCRM/labels/Emails%3ACases
|
||||||
|
[search-suitecrm-label-Emails:Compose]: https://github.com/salesagility/SuiteCRM/labels/Emails%3ACompose
|
||||||
|
[search-suitecrm-label-Emails:Config]: https://github.com/salesagility/SuiteCRM/labels/Emails%3AConfig
|
||||||
|
[search-suitecrm-label-Emails:Templates]: https://github.com/salesagility/SuiteCRM/labels/Emails%3ATemplates
|
||||||
|
[search-suitecrm-label-Emails]: https://github.com/salesagility/SuiteCRM/labels/Emails
|
||||||
|
[search-suitecrm-label-Enviroment]: https://github.com/salesagility/SuiteCRM/labels/Environment
|
||||||
|
[search-suitecrm-label-Installation]: https://github.com/salesagility/SuiteCRM/labels/Installation
|
||||||
|
[search-suitecrm-label-Language]: https://github.com/salesagility/SuiteCRM/labels/Language
|
||||||
|
[search-suitecrm-label-Module]: https://github.com/salesagility/SuiteCRM/labels/Module
|
||||||
|
[search-suitecrm-label-Reports]: https://github.com/salesagility/SuiteCRM/labels/Reports
|
||||||
|
[search-suitecrm-label-Studio]: https://github.com/salesagility/SuiteCRM/labels/Studio
|
||||||
|
[search-suitecrm-label-Styling]: https://github.com/salesagility/SuiteCRM/labels/Styling
|
||||||
|
[search-suitecrm-label-Upgrading]: https://github.com/salesagility/SuiteCRM/labels/Upgrading
|
||||||
|
[search-suitecrm-label-Workflow]: https://github.com/salesagility/SuiteCRM/labels/Workflow
|
||||||
|
|
||||||
|
[search-suitecrm-label-Duplicate]: https://github.com/salesagility/SuiteCRM/labels/Duplicate
|
||||||
|
[search-suitecrm-label-Assessed]: https://github.com/salesagility/SuiteCRM/labels/Assessed
|
||||||
|
[search-suitecrm-label-Community-Assessed]: https://github.com/salesagility/SuiteCRM/labels/Community%20Assessed
|
||||||
|
[search-suitecrm-label-In-Review]: https://github.com/salesagility/SuiteCRM/labels/In%20Review
|
||||||
|
[search-suitecrm-label-Invalid]: https://github.com/salesagility/SuiteCRM/labels/Invalid
|
||||||
|
[search-suitecrm-label-Needs-Assessed]: https://github.com/salesagility/SuiteCRM/labels/Needs%20Assessed
|
||||||
|
[search-suitecrm-label-Needs-Documentation]: https://github.com/salesagility/SuiteCRM/labels/Needs%20Documentation
|
||||||
|
[search-suitecrm-label-Needs-Duplicated-Latest]: https://github.com/salesagility/SuiteCRM/labels/Needs%20Duplicated%3A%20Latest
|
||||||
|
[search-suitecrm-label-Needs-Duplicated-LTS]: https://github.com/salesagility/SuiteCRM/labels/Needs%20Duplicated%3A%20LTS
|
||||||
|
[search-suitecrm-label-Needs-Review]: https://github.com/salesagility/SuiteCRM/labels/Needs%20Review
|
||||||
|
[search-suitecrm-label-Requires-Tests]: https://github.com/salesagility/SuiteCRM/labels/Requires%20Tests
|
||||||
|
[search-suitecrm-label-Requires-Updates]: https://github.com/salesagility/SuiteCRM/labels/Requires%20Updates
|
||||||
|
[search-suitecrm-label-Work-In-Progress]: https://github.com/salesagility/SuiteCRM/labels/Work%20In%20Progress
|
||||||
|
[search-suitecrm-label-Wrong-Branch]: https://github.com/salesagility/SuiteCRM/labels/Wrong%20Branch
|
||||||
|
|
||||||
|
Thanks!
|
||||||
|
|
||||||
|
SuiteCRM Team
|
12
.github/FUNDING.yml
vendored
Normal file
12
.github/FUNDING.yml
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||||
|
patreon: # Replace with a single Patreon username
|
||||||
|
open_collective: suitecrm
|
||||||
|
ko_fi: # Replace with a single Ko-fi username
|
||||||
|
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||||
|
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||||
|
liberapay: # Replace with a single Liberapay username
|
||||||
|
issuehunt: # Replace with a single IssueHunt username
|
||||||
|
otechie: # Replace with a single Otechie username
|
||||||
|
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
37
.github/ISSUE_TEMPLATE.md
vendored
Normal file
37
.github/ISSUE_TEMPLATE.md
vendored
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
<!--- Provide a general summary of the issue in the **Title** above -->
|
||||||
|
<!--- Before you open an issue, please check if a similar issue already exists or has been closed before. --->
|
||||||
|
<!--- If you have discovered a security risk please report it by emailing security@suitecrm.com. This will be delivered to the product team who handle security issues. Please don't disclose security bugs publicly until they have been handled by the security team. --->
|
||||||
|
|
||||||
|
#### Issue
|
||||||
|
<!--- Provide a more detailed introduction to the issue itself, and why you consider it to be a bug -->
|
||||||
|
<!--- Ensure that all code ``` is surrounded ``` by triple back quotes. This can also be done over multiple lines -->
|
||||||
|
|
||||||
|
#### Expected Behavior
|
||||||
|
<!--- Tell us what should happen -->
|
||||||
|
|
||||||
|
#### Actual Behavior
|
||||||
|
<!--- Tell us what happens instead -->
|
||||||
|
<!--- Also please check relevant logs (suitecrm.log, php error.log etc.) -->
|
||||||
|
|
||||||
|
#### Possible Fix
|
||||||
|
<!--- Not obligatory, but suggest a fix or reason for the bug -->
|
||||||
|
|
||||||
|
#### Steps to Reproduce
|
||||||
|
<!--- Provide a link to a live example, or an unambiguous set of steps to -->
|
||||||
|
<!--- reproduce this bug include code to reproduce, if relevant -->
|
||||||
|
1.
|
||||||
|
2.
|
||||||
|
3.
|
||||||
|
4.
|
||||||
|
|
||||||
|
#### Context
|
||||||
|
<!--- How has this bug affected you? What were you trying to accomplish? -->
|
||||||
|
<!--- If you feel this should be a low/medium/high priority then please state so -->
|
||||||
|
|
||||||
|
#### Your Environment
|
||||||
|
<!--- Include as many relevant details about the environment you experienced the bug in -->
|
||||||
|
* SuiteCRM Version used:
|
||||||
|
* Browser name and version (e.g. Chrome Version 51.0.2704.63 (64-bit)):
|
||||||
|
* Environment name and version (e.g. MySQL, PHP 7):
|
||||||
|
* Operating System and version (e.g Ubuntu 16.04):
|
||||||
|
|
30
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
30
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<!--- Provide a general summary of your changes in the Title above -->
|
||||||
|
|
||||||
|
## Description
|
||||||
|
<!--- Describe your changes in detail -->
|
||||||
|
<!--- If fixing a bug, there should be an issue describing it with steps to reproduce -->
|
||||||
|
<!--- Please link to the issue here unless your commit contains the issue number -->
|
||||||
|
<!--- Ensure that all code ``` is surrounded ``` by triple back quotes. This can also be done over multiple lines -->
|
||||||
|
|
||||||
|
## Motivation and Context
|
||||||
|
<!--- Why is this change required? What problem does it solve? -->
|
||||||
|
|
||||||
|
## How To Test This
|
||||||
|
<!--- Please describe in detail how to test your changes. -->
|
||||||
|
|
||||||
|
## Types of changes
|
||||||
|
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
|
||||||
|
- [ ] Bug fix (non-breaking change which fixes an issue)
|
||||||
|
- [ ] New feature (non-breaking change which adds functionality)
|
||||||
|
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
|
||||||
|
|
||||||
|
### Final checklist
|
||||||
|
<!--- Go over all the following points and check all the boxes that apply. --->
|
||||||
|
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! --->
|
||||||
|
- [ ] My code follows the code style of this project found [here](https://docs.suitecrm.com/community/contributing-code/coding-standards/).
|
||||||
|
- [ ] My change requires a change to the documentation.
|
||||||
|
- [ ] I have read the [**How to Contribute**](https://docs.suitecrm.com/community/contributing-code/) guidelines.
|
||||||
|
|
||||||
|
<!--- Your pull request will be tested via Travis CI to automatically indicate that your changes do not prevent compilation. --->
|
||||||
|
|
||||||
|
<!--- If it reports back that there are problems, you can log into the Travis system and check the log report for your pull request to see what the problem was. --->
|
21
.github/SECURITY.md
vendored
Normal file
21
.github/SECURITY.md
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Supported Versions
|
||||||
|
|
||||||
|
For a complete compatibility matrix, please see the documentation [here](https://docs.suitecrm.com/admin/compatibility-matrix/).
|
||||||
|
|
||||||
|
| Version | Supported |
|
||||||
|
| ------- | ------------------ |
|
||||||
|
| 7.11.x | :heavy_check_mark: |
|
||||||
|
| 7.10.x | :heavy_check_mark: |
|
||||||
|
| ≤7.8.x | :x: |
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
We take Security seriously here at SuiteCRM so if you have discovered a security risk report it by
|
||||||
|
emailing [security@suitecrm.com](mailto:security@suitecrm.com). This will be delivered to the product team who handle security issues.
|
||||||
|
Please don't disclose security bugs publicly until they have been handled by the security team.
|
||||||
|
|
||||||
|
Your email will be acknowledged within 24 hours during the business week (Mon - Fri), and you’ll receive a more
|
||||||
|
detailed response to your email within 72 hours during the business week (Mon - Fri) indicating the next steps in
|
||||||
|
handling your report.
|
94
.github/config.yml
vendored
Normal file
94
.github/config.yml
vendored
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
owner:
|
||||||
|
- salesagility
|
||||||
|
|
||||||
|
repo:
|
||||||
|
- SuiteCRM
|
||||||
|
|
||||||
|
members:
|
||||||
|
- cameronblaikie
|
||||||
|
- CamoMacdonald
|
||||||
|
- code-ph0y
|
||||||
|
- craigpanton
|
||||||
|
- Dillon-Brown
|
||||||
|
- e-reeley
|
||||||
|
- g-fantini
|
||||||
|
- gregsoper
|
||||||
|
- gymad
|
||||||
|
- jack7anderson7
|
||||||
|
- JackBuchanan
|
||||||
|
- Jason-Dang
|
||||||
|
- JimMackin
|
||||||
|
- johnM2401
|
||||||
|
- Mac-Rae
|
||||||
|
- mattlorimer
|
||||||
|
- MikeyJC
|
||||||
|
- murdal
|
||||||
|
- PedroErnst
|
||||||
|
- pgorod
|
||||||
|
- samus-aran
|
||||||
|
- SuiteBot
|
||||||
|
- willrennie
|
||||||
|
|
||||||
|
eolBranches:
|
||||||
|
- 7.9.x,
|
||||||
|
- 7.8.x,
|
||||||
|
- hotfix-7.8.x
|
||||||
|
|
||||||
|
invalidBranches:
|
||||||
|
- master
|
||||||
|
- 7.10.x
|
||||||
|
|
||||||
|
invalid: >
|
||||||
|
Hello and thanks for the contribution! would you be able to rebase this pull request to the hotfix-7.10.x branch?
|
||||||
|
we currently don't accept pull requests directly to this branch
|
||||||
|
(See [SuiteDocs](https://docs.suitecrm.com/community/contributing-code/bugs) for more information).
|
||||||
|
eol: >
|
||||||
|
Hello and thanks for the contribution! unfortunately this branch is EOL
|
||||||
|
(See our [blog post](https://suitecrm.com/7-8-x-end-of-life/) for more information).
|
||||||
|
invalidIssueTemplate: >
|
||||||
|
Hello and thanks for raising this issue! I notice you don't seem to be following the standard issue template. If this is a bug report, would you be able to go back and edit this issue while following the template and including exact replication steps?
|
||||||
|
|
||||||
|
|
||||||
|
Thanks.
|
||||||
|
sprintPlanning: >
|
||||||
|
Hello Everyone! :wave:
|
||||||
|
|
||||||
|
|
||||||
|
We are 1 week away from commencing our Sprint. So we would like to take this opportunity to ask for your nominated issues here in this thread so we can assess, refine and coordinate with ourselves (the Core Team) and the community contributors on the upcoming priorities.
|
||||||
|
|
||||||
|
|
||||||
|
If you are new to this sprint planning then essentially we are asking you, as the users, to post your issues (by referencing the GitHub hash/ID) that you would like to see being tackled. We, the Core Team, will review and select the achievable ones within the sprint and allocate them among ourselves. The others we may label them as Help Wanted which would make them up for grabs by our community code contributors. This process will help encourage ownership of these bugs and their bug fixes. [Find out more of the sprint concept here](https://docs.suitecrm.com/community/nominating-issues-in-sprint-planning) :point_left:
|
||||||
|
|
||||||
|
|
||||||
|
Sprints are every 2 weeks with the aim to deliver a release every 2 Sprints (monthly).
|
||||||
|
|
||||||
|
|
||||||
|
Just to re-iterate from previous posts, that the core team do have other tasks that may not be identified in the above sprints and these are usually from our own internal backlog i.e. improving the release process, CI/CD tools, security patches etc so that accounts for some ‘slack’ visible in the public sprints.
|
||||||
|
|
||||||
|
|
||||||
|
Look forward to your nominations! :writing_hand:
|
||||||
|
sprintRetrospective: >
|
||||||
|
Hello Everyone!
|
||||||
|
|
||||||
|
|
||||||
|
Welcome to the sprint retrospective, lets break down the previous sprint.
|
||||||
|
|
||||||
|
|
||||||
|
To Do | In Progress | In Review | Done
|
||||||
|
|
||||||
|
------------ | ------------- | ------------- | -------------
|
||||||
|
|
||||||
|
SPRINTMETRICS
|
||||||
|
|
||||||
|
|
||||||
|
Again, to note, that we also tackle a lot of other issues that are high priorities, security patches and internal roadmap tasks
|
||||||
|
|
||||||
|
|
||||||
|
List of the currently open "Help Wanted" issues:
|
||||||
|
|
||||||
|
HELPWANTED
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Thanks everyone and comment below to start a discussion to improve the open sprint processes & gain feedback +1
|
||||||
|
We are planning to open the next Sprint for nominations next week.
|
133
.gitignore
vendored
Executable file
133
.gitignore
vendored
Executable file
|
@ -0,0 +1,133 @@
|
||||||
|
## First part from https://github.com/github/gitignore/blob/master/SugarCRM.gitignore
|
||||||
|
# Ignore custom .htaccess stuff.
|
||||||
|
/.htaccess
|
||||||
|
# Ignore large parts of the annoying cache directory without breaking things.
|
||||||
|
cache/*
|
||||||
|
upload/*
|
||||||
|
!upload/index.html
|
||||||
|
# Ignore some files and directories from the custom directory.
|
||||||
|
custom/
|
||||||
|
custom/history/*
|
||||||
|
custom/blowfish/*
|
||||||
|
custom/modulebuilder/*
|
||||||
|
custom/working/*
|
||||||
|
custom/modules/*/Ext/
|
||||||
|
custom/modules/unified_search_modules_display.php
|
||||||
|
# Ignore AOD indexes
|
||||||
|
modules/AOD_Index/Index/*
|
||||||
|
install/status.json
|
||||||
|
# Configuration files should be ignored.
|
||||||
|
/config.php
|
||||||
|
/config_override.php
|
||||||
|
/config_si.php
|
||||||
|
|
||||||
|
#Ignore Sass Generated files in SuiteP
|
||||||
|
themes/suite8/css/*.map
|
||||||
|
themes/suite8/css/*/*.map
|
||||||
|
themes/suite8/css/*/*.css
|
||||||
|
|
||||||
|
tests/_output/*
|
||||||
|
tests/config.test.php
|
||||||
|
# Connector configuration should also be ignored.
|
||||||
|
custom/modules/Connectors/connectors/sources/ext/*/*/config.php
|
||||||
|
# Logs files can safely be ignored.
|
||||||
|
*.log
|
||||||
|
## IDE specific items
|
||||||
|
# Eclipse
|
||||||
|
*.pydevproject
|
||||||
|
.project
|
||||||
|
.metadata
|
||||||
|
bin/**
|
||||||
|
tmp/**
|
||||||
|
tmp/**/*
|
||||||
|
*.tmp
|
||||||
|
*.bak
|
||||||
|
*.swp
|
||||||
|
*~.nib
|
||||||
|
local.properties
|
||||||
|
.classpath
|
||||||
|
.settings/
|
||||||
|
.loadpath
|
||||||
|
# Emacs
|
||||||
|
*~
|
||||||
|
\#*\#
|
||||||
|
/.emacs.desktop
|
||||||
|
/.emacs.desktop.lock
|
||||||
|
.elc
|
||||||
|
auto-save-list
|
||||||
|
tramp
|
||||||
|
# IntelliJ Idea
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
.idea/
|
||||||
|
.phpstorm.meta.php
|
||||||
|
# NetBeans
|
||||||
|
nbproject/
|
||||||
|
# Vim
|
||||||
|
.*.sw[a-z]
|
||||||
|
*.un~
|
||||||
|
Session.vim
|
||||||
|
tags
|
||||||
|
# Windows
|
||||||
|
Thumbs.db
|
||||||
|
Desktop.ini
|
||||||
|
.DS_Store
|
||||||
|
.DS_Store?
|
||||||
|
# Microsoft Visual Studio
|
||||||
|
*.sln
|
||||||
|
*.suo
|
||||||
|
*.phpproj
|
||||||
|
# Microsoft Visual Studio Code
|
||||||
|
.vscode
|
||||||
|
# Disytel
|
||||||
|
lang_cmp.php
|
||||||
|
.kdev4/
|
||||||
|
SuiteCRM.kdev4
|
||||||
|
|
||||||
|
#Ignore composer vendor folder
|
||||||
|
vendor/
|
||||||
|
public/
|
||||||
|
|
||||||
|
.php_cs.cache
|
||||||
|
|
||||||
|
|
||||||
|
#Ignore bower_components
|
||||||
|
bower_components/
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
|
||||||
|
#Ignore Sass Generated files in SuiteP
|
||||||
|
themes/SuiteP/css/*.map
|
||||||
|
themes/SuiteP/css/*/*.map
|
||||||
|
themes/SuiteP/css/*/color-palette.css
|
||||||
|
themes/SuiteP/css/*/variables.css
|
||||||
|
tests/_output/*
|
||||||
|
|
||||||
|
|
||||||
|
#Ignore browserstack
|
||||||
|
BrowserStackLocal
|
||||||
|
browserstack.err
|
||||||
|
cache/
|
||||||
|
custom/**/
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Ignore testing environment
|
||||||
|
build/tmp/
|
||||||
|
|
||||||
|
# IMAP testing
|
||||||
|
fakeImapResource
|
||||||
|
include/Imap/ImapTestSettings.txt
|
||||||
|
|
||||||
|
# Ignore php-cs-fixer cache
|
||||||
|
.php_cs.cache
|
||||||
|
|
||||||
|
# Ignore custom codeception environments so they won't be committed.
|
||||||
|
tests/_envs/custom.yml
|
||||||
|
codeception.yml
|
||||||
|
|
||||||
|
# Ignore dotenv files so they don't get commited to git.
|
||||||
|
# Only .env.dist should be committed.
|
||||||
|
.env
|
||||||
|
.env.test
|
||||||
|
.env.dev
|
43
.php_cs.dist
Normal file
43
.php_cs.dist
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use SuiteCRM\Utility\Paths;
|
||||||
|
|
||||||
|
$paths = new Paths();
|
||||||
|
|
||||||
|
$finder = PhpCsFixer\Finder::create()
|
||||||
|
->exclude('cache')
|
||||||
|
->exclude('service')
|
||||||
|
->exclude('build')
|
||||||
|
->exclude('vendor')
|
||||||
|
->exclude('themes')
|
||||||
|
->exclude('upload')
|
||||||
|
->exclude('XTemplate')
|
||||||
|
->exclude('Zend')
|
||||||
|
->exclude('include/timezone')
|
||||||
|
->exclude('include/SuiteGraphs')
|
||||||
|
->exclude('include/social')
|
||||||
|
->exclude('include/Smarty')
|
||||||
|
->exclude('include/reCaptcha')
|
||||||
|
->exclude('include/phpmailer')
|
||||||
|
->exclude('include/Pear')
|
||||||
|
->exclude('include/pclzip')
|
||||||
|
->exclude('include/nusoap')
|
||||||
|
->exclude('include/HTTP_WebDAV_Server')
|
||||||
|
->exclude('include/HTMLPurifier')
|
||||||
|
->exclude('include/ytree')
|
||||||
|
->exclude('include/tcpdf')
|
||||||
|
->exclude('include/php-sql-parser.php')
|
||||||
|
->exclude('include/parsecsv.lib.php')
|
||||||
|
->exclude('modules/AOS_PDF_Templates/PDF_Lib')
|
||||||
|
->exclude('modules/AOD_Index/Lib')
|
||||||
|
->exclude('modules/Users/authentication/SAML2Authenticate/lib')
|
||||||
|
->exclude('modules/AOR_Charts/lib')
|
||||||
|
->exclude('install/demoData.en_us.php')
|
||||||
|
->exclude('include/SugarObjects/templates')
|
||||||
|
->in($paths->getProjectPath());
|
||||||
|
|
||||||
|
return PhpCsFixer\Config::create()
|
||||||
|
->setRules([
|
||||||
|
'@PSR2' => true,
|
||||||
|
])
|
||||||
|
->setFinder($finder);
|
117
.travis.yml
Normal file
117
.travis.yml
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
language: php
|
||||||
|
os: linux
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
fast_finish: true
|
||||||
|
include:
|
||||||
|
- name: "PHP 7.2 / MySQL 5.7"
|
||||||
|
php: "7.2"
|
||||||
|
dist: xenial
|
||||||
|
- name: "PHP 7.4 / MySQL 5.7"
|
||||||
|
php: "7.4"
|
||||||
|
dist: xenial
|
||||||
|
# Run composer validate to make sure the composer.json and composer.lock are in sync.
|
||||||
|
- name: "composer validate"
|
||||||
|
php: "7.2"
|
||||||
|
dist: xenial
|
||||||
|
before_script: composer install
|
||||||
|
script: composer validate
|
||||||
|
- name: "code coverage"
|
||||||
|
php: "7.3"
|
||||||
|
dist: xenial
|
||||||
|
script: ./vendor/bin/codecept run install --env travis-ci-hub -f --ext DotReporter; ./vendor/bin/robo code:coverage --ci; cat codeception.dist.yml; bash <(curl -s https://codecov.io/bash) -f tests/_output/coverage.xml
|
||||||
|
|
||||||
|
services:
|
||||||
|
- mysql
|
||||||
|
- elasticsearch
|
||||||
|
addons:
|
||||||
|
chrome: stable
|
||||||
|
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- $HOME/.composer/cache/files
|
||||||
|
|
||||||
|
env:
|
||||||
|
- INSTANCE_URL=http://localhost DATABASE_DRIVER=MYSQL DATABASE_NAME=automated_tests DATABASE_HOST=localhost DATABASE_USER=automated_tests DATABASE_PASSWORD=automated_tests INSTANCE_ADMIN_USER=admin INSTANCE_ADMIN_PASSWORD=admin1 COMPOSER_MEMORY_LIMIT=-1
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
# Install chrome driver#
|
||||||
|
- whereis google-chrome-stable
|
||||||
|
- wget https://chromedriver.storage.googleapis.com/2.36/chromedriver_linux64.zip
|
||||||
|
- unzip -o chromedriver_linux64.zip
|
||||||
|
- ./chromedriver --url-base=/wd/hub &
|
||||||
|
# Lint PHP
|
||||||
|
- for file in $(git diff --name-status HEAD~1 HEAD | egrep "^[ACMR].*\.php$" | cut -c 3-); do php -l $file; done
|
||||||
|
|
||||||
|
install:
|
||||||
|
- phpenv config-add travis.php.ini
|
||||||
|
- composer self-update --1 && composer --version
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
# Set up MySQL
|
||||||
|
- mysql -e "CREATE DATABASE automated_tests CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;"
|
||||||
|
- mysql -u root -e "CREATE USER 'automated_tests'@'localhost' IDENTIFIED BY 'automated_tests';"
|
||||||
|
- mysql -u root -e "GRANT ALL PRIVILEGES ON automated_tests.* TO 'automated_tests'@'localhost';"
|
||||||
|
# Install apache - images with PHP 7 or above
|
||||||
|
- sudo apt-get update
|
||||||
|
- sudo apt-get install apache2 libapache2-mod-fastcgi
|
||||||
|
# Enable php-fpm - images with PHP 7 or above
|
||||||
|
- sudo cp ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.d/www.conf.default ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.d/www.conf 2>/dev/null || true
|
||||||
|
- sudo cp ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.conf.default ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.conf
|
||||||
|
- sudo a2enmod rewrite actions fastcgi alias
|
||||||
|
- echo "cgi.fix_pathinfo = 1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
|
||||||
|
- sudo sed -i -e "s,www-data,travis,g" /etc/apache2/envvars
|
||||||
|
- sudo chown -R travis:travis /var/lib/apache2/fastcgi
|
||||||
|
- ~/.phpenv/versions/$(phpenv version-name)/sbin/php-fpm
|
||||||
|
# Configure apache virtual hosts - images with PHP 7 or above
|
||||||
|
- sudo cp -f build/travis-ci-apache /etc/apache2/sites-available/000-default.conf
|
||||||
|
- sudo sed -e "s?%TRAVIS_BUILD_DIR%?$(pwd)?g" --in-place /etc/apache2/sites-available/000-default.conf
|
||||||
|
# Additional PHP config
|
||||||
|
- phpenv config-add travis.php.ini
|
||||||
|
- sudo service apache2 restart
|
||||||
|
# Install composer
|
||||||
|
- composer install
|
||||||
|
- ./vendor/bin/codecept build
|
||||||
|
|
||||||
|
script:
|
||||||
|
# Run the wizard installer
|
||||||
|
- echo "using install wizard"
|
||||||
|
- ./vendor/bin/codecept run install --env travis-ci-hub -f --ext DotReporter
|
||||||
|
- ./build/push_output.sh
|
||||||
|
|
||||||
|
# Run the unit tests
|
||||||
|
- sudo chmod -R 777 .
|
||||||
|
- ./vendor/bin/phpunit --stop-on-failure --stop-on-error --colors --configuration ./tests/phpunit.xml.dist ./tests/unit/phpunit
|
||||||
|
# Install OAuth2 demo data
|
||||||
|
- mysql -u root -D automated_tests -v -e "source tests/_data/api_data.sql"
|
||||||
|
# Install demo user data
|
||||||
|
- mysql -u root -D automated_tests -v -e "source tests/_data/demo_users.sql"
|
||||||
|
# set the log level to error
|
||||||
|
- echo "\$sugar_config['logger']['level'] = 'error';" >> config_override.php
|
||||||
|
# add keys
|
||||||
|
- sudo chmod -R 777 .
|
||||||
|
- openssl genrsa -out Api/V8/OAuth2/private.key 2048
|
||||||
|
- openssl rsa -in Api/V8/OAuth2/private.key -pubout -out Api/V8/OAuth2/public.key
|
||||||
|
- sudo chmod 600 Api/V8/OAuth2/p*.key
|
||||||
|
# - sudo chown www-data:www-data Api/V8/OAuth2/p*.key
|
||||||
|
# Run API functional tests
|
||||||
|
- ./vendor/bin/codecept run tests/api/V8/ -f --ext DotReporter
|
||||||
|
# RUN Basic Acceptance test
|
||||||
|
- echo "\$sugar_config['imap_test'] = true;" >> config_override.php
|
||||||
|
- ./vendor/bin/codecept run acceptance --env travis-ci-hub -f --ext DotReporter
|
||||||
|
|
||||||
|
after_script:
|
||||||
|
- ./build/push_output.sh
|
||||||
|
# ElasticSearch Indexing logs
|
||||||
|
- cat search_index.log
|
||||||
|
- sudo cat /var/log/apache2/error.log
|
||||||
|
- echo $TRAVIS_COMMIT_RANGE
|
||||||
|
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
- develop
|
||||||
|
- /hotfix.*/
|
||||||
|
- /feature.*/
|
||||||
|
- /fix.*/
|
||||||
|
- /staging.*/
|
60
Api/Core/Config/ApiConfig.php
Normal file
60
Api/Core/Config/ApiConfig.php
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\Core\Config;
|
||||||
|
|
||||||
|
class ApiConfig
|
||||||
|
{
|
||||||
|
// we still support 5.5.9
|
||||||
|
private static $slimSettings = [
|
||||||
|
'Api/Core/Config/slim.php',
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $containers = [
|
||||||
|
'Api/V8/Config/services.php',
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $routes = [
|
||||||
|
'Api/V8/Config/routes.php',
|
||||||
|
];
|
||||||
|
|
||||||
|
const OAUTH2_PRIVATE_KEY = 'Api/V8/OAuth2/private.key';
|
||||||
|
const OAUTH2_PUBLIC_KEY = 'Api/V8/OAuth2/public.key';
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
private static $debugExceptions = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public static function getDebugExceptions()
|
||||||
|
{
|
||||||
|
return self::$debugExceptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function getSlimSettings()
|
||||||
|
{
|
||||||
|
return self::$slimSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function getContainers()
|
||||||
|
{
|
||||||
|
return self::$containers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function getRoutes()
|
||||||
|
{
|
||||||
|
return self::$routes;
|
||||||
|
}
|
||||||
|
}
|
12
Api/Core/Config/slim.php
Normal file
12
Api/Core/Config/slim.php
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Api\Core\Loader\CustomLoader;
|
||||||
|
|
||||||
|
return CustomLoader::mergeCustomArray([
|
||||||
|
'settings' => [
|
||||||
|
/** Additional information about exceptions are displayed by the default error handler. */
|
||||||
|
'displayErrorDetails' => true,
|
||||||
|
/** Routes are accessible in middleware. */
|
||||||
|
'determineRouteBeforeAppMiddleware' => true,
|
||||||
|
]
|
||||||
|
], basename(__FILE__));
|
29
Api/Core/Loader/ContainerLoader.php
Normal file
29
Api/Core/Loader/ContainerLoader.php
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\Core\Loader;
|
||||||
|
|
||||||
|
use Api\Core\Config\ApiConfig;
|
||||||
|
use Api\Core\Resolver\ConfigResolver;
|
||||||
|
use Psr\Container\ContainerInterface;
|
||||||
|
use Slim\Container;
|
||||||
|
|
||||||
|
class ContainerLoader
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Load all service containers and add slim settings
|
||||||
|
*
|
||||||
|
* @return ContainerInterface
|
||||||
|
*/
|
||||||
|
public static function configure()
|
||||||
|
{
|
||||||
|
$slimSettings = ConfigResolver::loadFiles(ApiConfig::getSlimSettings());
|
||||||
|
// if we want to use this without DI, should create an instance for it
|
||||||
|
$container = new Container($slimSettings);
|
||||||
|
|
||||||
|
$services = ConfigResolver::loadFiles(ApiConfig::getContainers());
|
||||||
|
foreach ($services as $service => $closure) {
|
||||||
|
$container[$service] = $closure;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $container;
|
||||||
|
}
|
||||||
|
}
|
161
Api/Core/Loader/CustomLoader.php
Normal file
161
Api/Core/Loader/CustomLoader.php
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* SugarCRM Community Edition is a customer relationship management program developed by
|
||||||
|
* SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
|
||||||
|
*
|
||||||
|
* SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd.
|
||||||
|
* Copyright (C) 2011 - 2018 SalesAgility Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU Affero General Public License version 3 as published by the
|
||||||
|
* Free Software Foundation with the addition of the following permission added
|
||||||
|
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
||||||
|
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
||||||
|
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License along with
|
||||||
|
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
||||||
|
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
||||||
|
*
|
||||||
|
* The interactive user interfaces in modified source and object code versions
|
||||||
|
* of this program must display Appropriate Legal Notices, as required under
|
||||||
|
* Section 5 of the GNU Affero General Public License version 3.
|
||||||
|
*
|
||||||
|
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||||
|
* these Appropriate Legal Notices must retain the display of the "Powered by
|
||||||
|
* SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
|
||||||
|
* reasonably feasible for technical reasons, the Appropriate Legal Notices must
|
||||||
|
* display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM".
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Api\Core\Loader;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use LoggerManager;
|
||||||
|
use Slim\App;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CustomLoader
|
||||||
|
*
|
||||||
|
* @author gyula
|
||||||
|
*/
|
||||||
|
class CustomLoader
|
||||||
|
{
|
||||||
|
const ERR_NO_ERROR = 0;
|
||||||
|
const ERR_FILE_NOT_FOUND = 1;
|
||||||
|
const ERR_ROUTE_FILE_NOT_FOUND = 2;
|
||||||
|
const ERR_WRONG_CUSTOM_FORMAT = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected static $lastError = self::ERR_NO_ERROR;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected static $customPath = 'custom/application/Ext/Api/V8/';
|
||||||
|
|
||||||
|
public static function setCustomPath($customPath = 'custom/application/Ext/Api/V8/')
|
||||||
|
{
|
||||||
|
self::$customPath = $customPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getCustomPath()
|
||||||
|
{
|
||||||
|
return self::$customPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public static function getLastError()
|
||||||
|
{
|
||||||
|
$ret = self::$lastError;
|
||||||
|
self::$lastError = self::ERR_NO_ERROR;
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* merge multidimensional arrays
|
||||||
|
*
|
||||||
|
* @param array $arrays
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function arrayMerge($arrays)
|
||||||
|
{
|
||||||
|
$result = [];
|
||||||
|
foreach ((array)$arrays as $array) {
|
||||||
|
foreach ($array as $key => $value) {
|
||||||
|
if (is_int($key)) {
|
||||||
|
// is indexed?
|
||||||
|
$result[] = $value;
|
||||||
|
} elseif (isset($result[$key]) && is_array($value) && is_array($result[$key])) {
|
||||||
|
// is associative?
|
||||||
|
$result[$key] = self::arrayMerge([$result[$key], $value]);
|
||||||
|
} else {
|
||||||
|
$result[$key] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* include and merge custom arrays (custom file should return an array)
|
||||||
|
*
|
||||||
|
* @param array $array
|
||||||
|
* @param string $customFile
|
||||||
|
* @return array
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static function mergeCustomArray($array, $customFile)
|
||||||
|
{
|
||||||
|
self::getLastError();
|
||||||
|
$customFile = self::$customPath . $customFile;
|
||||||
|
if (!file_exists($customFile)) {
|
||||||
|
self::$lastError = self::ERR_FILE_NOT_FOUND;
|
||||||
|
LoggerManager::getLogger()->debug('Custom file is not exists: ' . $customFile);
|
||||||
|
} else {
|
||||||
|
$customs = include $customFile;
|
||||||
|
if (!is_array($customs)) {
|
||||||
|
throw new Exception('Custom file should return an array.', self::ERR_WRONG_CUSTOM_FORMAT);
|
||||||
|
}
|
||||||
|
$array = self::arrayMerge([$array, $customs]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $array;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param App $app
|
||||||
|
* @return App
|
||||||
|
*/
|
||||||
|
public static function loadCustomRoutes(App $app, $customRoutesFile = 'Config/routes.php')
|
||||||
|
{
|
||||||
|
self::getLastError();
|
||||||
|
$customRoutesFile = self::$customPath . $customRoutesFile;
|
||||||
|
if (!file_exists($customRoutesFile)) {
|
||||||
|
self::$lastError = self::ERR_ROUTE_FILE_NOT_FOUND;
|
||||||
|
LoggerManager::getLogger()->debug('Custom routes file is not exists: ' . $customRoutesFile);
|
||||||
|
} else {
|
||||||
|
include $customRoutesFile;
|
||||||
|
}
|
||||||
|
return $app;
|
||||||
|
}
|
||||||
|
}
|
25
Api/Core/Loader/RouteLoader.php
Normal file
25
Api/Core/Loader/RouteLoader.php
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\Core\Loader;
|
||||||
|
|
||||||
|
use Api\Core\Config\ApiConfig;
|
||||||
|
use Api\Core\Resolver\ConfigResolver;
|
||||||
|
use Slim\App;
|
||||||
|
|
||||||
|
class RouteLoader
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Load all app routes
|
||||||
|
*
|
||||||
|
* @param App $app
|
||||||
|
*/
|
||||||
|
public function configureRoutes(App $app)
|
||||||
|
{
|
||||||
|
$routes = ApiConfig::getRoutes();
|
||||||
|
|
||||||
|
foreach ($routes as $route) {
|
||||||
|
if (ConfigResolver::isFileExist($route)) {
|
||||||
|
require $route;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
51
Api/Core/Resolver/ConfigResolver.php
Normal file
51
Api/Core/Resolver/ConfigResolver.php
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\Core\Resolver;
|
||||||
|
|
||||||
|
class ConfigResolver
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Loading and merge files which are arrays.
|
||||||
|
*
|
||||||
|
* @param array $files
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* @throws \InvalidArgumentException When config file does not contain an array.
|
||||||
|
*/
|
||||||
|
public static function loadFiles(array $files)
|
||||||
|
{
|
||||||
|
$configs = [];
|
||||||
|
|
||||||
|
foreach ($files as $file) {
|
||||||
|
// base dir must exist in entryPoint.php
|
||||||
|
$file = sprintf('%s/%s', $GLOBALS['BASE_DIR'], $file);
|
||||||
|
|
||||||
|
if (self::isFileExist($file)) {
|
||||||
|
$config = require $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_array($config)) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('File %s is invalid', $file));
|
||||||
|
}
|
||||||
|
|
||||||
|
$configs[] = $config;
|
||||||
|
}
|
||||||
|
|
||||||
|
// since we support 5.5.9, we can't use splat op here
|
||||||
|
return !$configs ? $configs : array_reduce($configs, 'array_merge', []);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $file
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
* @throws \RuntimeException When config file is not readable.
|
||||||
|
*/
|
||||||
|
public static function isFileExist($file)
|
||||||
|
{
|
||||||
|
if (!file_exists($file) || !is_readable($file)) {
|
||||||
|
throw new \RuntimeException(sprintf('File %s is not readable', $file));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
26
Api/Core/app.php
Normal file
26
Api/Core/app.php
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
// Swagger needs this, but should remove - CORS
|
||||||
|
header("Access-Control-Allow-Origin: *");
|
||||||
|
header('Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE');
|
||||||
|
header('Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With');
|
||||||
|
|
||||||
|
// @codingStandardsIgnoreStart
|
||||||
|
if (!defined('sugarEntry')) {
|
||||||
|
define('sugarEntry', true);
|
||||||
|
}
|
||||||
|
// @codingStandardsIgnoreEnd
|
||||||
|
|
||||||
|
// For php-fpm we pass the "Authorization" header through HTTP_AUTHORIZATION
|
||||||
|
// using .htaccess rewrite rules. The rewrite rules result in apache prefixing
|
||||||
|
// the env var which gives us REDIRECT_HTTP_AUTHORIZATION.
|
||||||
|
if (!isset($_SERVER['HTTP_AUTHORIZATION']) && isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) {
|
||||||
|
$_SERVER['HTTP_AUTHORIZATION'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION'];
|
||||||
|
}
|
||||||
|
|
||||||
|
chdir(__DIR__ . '/../../');
|
||||||
|
require_once __DIR__ . '/../../include/entryPoint.php';
|
||||||
|
|
||||||
|
$app = new \Slim\App(\Api\Core\Loader\ContainerLoader::configure());
|
||||||
|
// closure shouldn't be created in static context under PHP7
|
||||||
|
$routeLoader = new \Api\Core\Loader\RouteLoader();
|
||||||
|
$routeLoader->configureRoutes($app);
|
171
Api/V8/BeanDecorator/BeanListRequest.php
Normal file
171
Api/V8/BeanDecorator/BeanListRequest.php
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\BeanDecorator;
|
||||||
|
|
||||||
|
class BeanListRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var \SugarBean
|
||||||
|
*/
|
||||||
|
protected $bean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $orderBy = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $where = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $offset = BeanManager::DEFAULT_OFFSET;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $limit = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $max = BeanManager::DEFAULT_ALL_RECORDS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $deleted = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
protected $singleSelect = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fields = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \SugarBean $bean
|
||||||
|
*/
|
||||||
|
public function __construct(\SugarBean $bean)
|
||||||
|
{
|
||||||
|
$this->bean = $bean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $orderBy
|
||||||
|
*
|
||||||
|
* @return BeanListRequest
|
||||||
|
*/
|
||||||
|
public function orderBy($orderBy)
|
||||||
|
{
|
||||||
|
$this->orderBy = $orderBy;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $where
|
||||||
|
*
|
||||||
|
* @return BeanListRequest
|
||||||
|
*/
|
||||||
|
public function where($where)
|
||||||
|
{
|
||||||
|
$this->where = $where;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param integer $offset
|
||||||
|
*
|
||||||
|
* @return BeanListRequest
|
||||||
|
*/
|
||||||
|
public function offset($offset)
|
||||||
|
{
|
||||||
|
$this->offset = $offset;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param integer $limit
|
||||||
|
*
|
||||||
|
* @return BeanListRequest
|
||||||
|
*/
|
||||||
|
public function limit($limit)
|
||||||
|
{
|
||||||
|
$this->limit = $limit;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param integer $max
|
||||||
|
*
|
||||||
|
* @return BeanListRequest
|
||||||
|
*/
|
||||||
|
public function max($max)
|
||||||
|
{
|
||||||
|
$this->max = $max;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param integer $deleted
|
||||||
|
*
|
||||||
|
* @return BeanListRequest
|
||||||
|
*/
|
||||||
|
public function deleted($deleted)
|
||||||
|
{
|
||||||
|
$this->deleted = $deleted;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param boolean $singleSelect
|
||||||
|
*
|
||||||
|
* @return BeanListRequest
|
||||||
|
*/
|
||||||
|
public function singleSelect($singleSelect)
|
||||||
|
{
|
||||||
|
$this->singleSelect = $singleSelect;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $fields
|
||||||
|
*
|
||||||
|
* @return BeanListRequest
|
||||||
|
*/
|
||||||
|
public function fields(array $fields)
|
||||||
|
{
|
||||||
|
$this->fields = $fields;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return BeanListResponse
|
||||||
|
*/
|
||||||
|
public function fetch()
|
||||||
|
{
|
||||||
|
return new BeanListResponse($this->bean->get_list(
|
||||||
|
$this->orderBy,
|
||||||
|
$this->where,
|
||||||
|
$this->offset,
|
||||||
|
$this->limit,
|
||||||
|
$this->max,
|
||||||
|
$this->deleted,
|
||||||
|
$this->singleSelect,
|
||||||
|
$this->fields
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
40
Api/V8/BeanDecorator/BeanListResponse.php
Normal file
40
Api/V8/BeanDecorator/BeanListResponse.php
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\BeanDecorator;
|
||||||
|
|
||||||
|
class BeanListResponse
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var \SugarBean[]|[]
|
||||||
|
*/
|
||||||
|
protected $beans;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $rowCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $result
|
||||||
|
*/
|
||||||
|
public function __construct(array $result = [])
|
||||||
|
{
|
||||||
|
$this->beans = isset($result['list']) ? $result['list'] : [];
|
||||||
|
$this->rowCount = isset($result['row_count']) ? (int)$result['row_count'] : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \SugarBean[]|[]
|
||||||
|
*/
|
||||||
|
public function getBeans()
|
||||||
|
{
|
||||||
|
return $this->beans;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
|
public function getRowCount()
|
||||||
|
{
|
||||||
|
return $this->rowCount;
|
||||||
|
}
|
||||||
|
}
|
265
Api/V8/BeanDecorator/BeanManager.php
Normal file
265
Api/V8/BeanDecorator/BeanManager.php
Normal file
|
@ -0,0 +1,265 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\BeanDecorator;
|
||||||
|
|
||||||
|
use \SugarBean;
|
||||||
|
use \Person;
|
||||||
|
|
||||||
|
class BeanManager
|
||||||
|
{
|
||||||
|
const DEFAULT_OFFSET = 0;
|
||||||
|
const DEFAULT_LIMIT = -1;
|
||||||
|
const DEFAULT_ALL_RECORDS = -99;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \DBManager
|
||||||
|
*/
|
||||||
|
protected $db;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $beanAliases;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \DBManager $db
|
||||||
|
* @param array $beanAliases
|
||||||
|
*/
|
||||||
|
public function __construct(\DBManager $db, array $beanAliases)
|
||||||
|
{
|
||||||
|
$this->db = $db;
|
||||||
|
$this->beanAliases = $beanAliases;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $module
|
||||||
|
*
|
||||||
|
* @return \SugarBean
|
||||||
|
* @throws \InvalidArgumentException When the module is invalid.
|
||||||
|
*/
|
||||||
|
public function newBeanSafe($module)
|
||||||
|
{
|
||||||
|
if (array_key_exists($module, $this->beanAliases)) {
|
||||||
|
$module = $this->beanAliases[$module];
|
||||||
|
}
|
||||||
|
|
||||||
|
$bean = \BeanFactory::newBean($module);
|
||||||
|
|
||||||
|
if (!$bean instanceof \SugarBean) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('Module %s does not exist', $module));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $bean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $module
|
||||||
|
* @param string|null $id
|
||||||
|
* @param array $params
|
||||||
|
* @param boolean $deleted
|
||||||
|
*
|
||||||
|
* @return \SugarBean|boolean
|
||||||
|
*/
|
||||||
|
public function getBean($module, $id = null, array $params = [], $deleted = true)
|
||||||
|
{
|
||||||
|
return \BeanFactory::getBean($module, $id, $params, $deleted);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $module
|
||||||
|
* @param string $id
|
||||||
|
* @param array $params
|
||||||
|
* @param boolean $deleted
|
||||||
|
*
|
||||||
|
* @return \SugarBean
|
||||||
|
* @throws \DomainException When bean id is empty or bean is not found by name.
|
||||||
|
* @throws \InvalidArgumentException When bean is not found with the given id.
|
||||||
|
*/
|
||||||
|
public function getBeanSafe(
|
||||||
|
$module,
|
||||||
|
$id,
|
||||||
|
array $params = [],
|
||||||
|
$deleted = true
|
||||||
|
) {
|
||||||
|
if (empty($id)) {
|
||||||
|
throw new \DomainException('Module id is empty when trying to get ' . $module);
|
||||||
|
}
|
||||||
|
|
||||||
|
$objectName = \BeanFactory::getObjectName($module);
|
||||||
|
if (!$objectName && array_key_exists($module, $this->beanAliases)) {
|
||||||
|
$objectName = \BeanFactory::getObjectName($this->beanAliases[$module]);
|
||||||
|
$module = $this->beanAliases[$module];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$objectName) {
|
||||||
|
throw new \DomainException(sprintf('Module with name %s is not found', $module));
|
||||||
|
}
|
||||||
|
|
||||||
|
$bean = $this->getBean($module, $id, $params, $deleted);
|
||||||
|
if ($bean === false) {
|
||||||
|
throw new \InvalidArgumentException(
|
||||||
|
sprintf('%s module with id %s is not found', $module, $id)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $bean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $module
|
||||||
|
*
|
||||||
|
* @return BeanListRequest
|
||||||
|
*/
|
||||||
|
public function getList($module)
|
||||||
|
{
|
||||||
|
return new BeanListRequest($this->newBeanSafe($module));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \SugarBean $sourceBean
|
||||||
|
* @param \SugarBean $relatedBean
|
||||||
|
* @param string $relationship
|
||||||
|
*
|
||||||
|
* @throws \RuntimeException If relationship cannot be loaded or created between beans.
|
||||||
|
*/
|
||||||
|
public function createRelationshipSafe(\SugarBean $sourceBean, \SugarBean $relatedBean, $relationship)
|
||||||
|
{
|
||||||
|
if (!$sourceBean->load_relationship($relationship)) {
|
||||||
|
throw new \RuntimeException(
|
||||||
|
sprintf('Cannot load relationship %s for module %s', $relationship, $sourceBean->getObjectName())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $sourceBean->{$relationship}->add($relatedBean);
|
||||||
|
|
||||||
|
if (!$result) {
|
||||||
|
throw new \RuntimeException(
|
||||||
|
sprintf(
|
||||||
|
'Cannot create relationship %s between module %s and %s',
|
||||||
|
$relationship,
|
||||||
|
$sourceBean->getObjectName(),
|
||||||
|
$relatedBean->getObjectName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \SugarBean $sourceBean
|
||||||
|
* @param \SugarBean $relatedBean
|
||||||
|
* @param string $relationship
|
||||||
|
*
|
||||||
|
* @throws \RuntimeException If relationship cannot be loaded or deleted between beans.
|
||||||
|
*/
|
||||||
|
public function deleteRelationshipSafe(\SugarBean $sourceBean, \SugarBean $relatedBean, $relationship)
|
||||||
|
{
|
||||||
|
if (!$sourceBean->load_relationship($relationship)) {
|
||||||
|
throw new \RuntimeException(
|
||||||
|
sprintf('Cannot load relationship %s for module %s', $relationship, $sourceBean->getObjectName())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $sourceBean->{$relationship}->delete($sourceBean->id, $relatedBean->id);
|
||||||
|
|
||||||
|
if (!$result) {
|
||||||
|
throw new \RuntimeException(
|
||||||
|
sprintf(
|
||||||
|
'Cannot delete relationship %s between module %s and %s',
|
||||||
|
$relationship,
|
||||||
|
$sourceBean->getObjectName(),
|
||||||
|
$relatedBean->getObjectName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \SugarBean $sourceBean
|
||||||
|
* @param \SugarBean $relatedBean
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
* @throws \DomainException In case link field is not found.
|
||||||
|
*/
|
||||||
|
public function getLinkedFieldName(\SugarBean $sourceBean, \SugarBean $relatedBean)
|
||||||
|
{
|
||||||
|
$linkedFields = $sourceBean->get_linked_fields();
|
||||||
|
$relationship = \Relationship::retrieve_by_modules(
|
||||||
|
$sourceBean->module_name,
|
||||||
|
$relatedBean->module_name,
|
||||||
|
$sourceBean->db
|
||||||
|
);
|
||||||
|
|
||||||
|
$linkFieldName = '';
|
||||||
|
foreach ($linkedFields as $linkedField) {
|
||||||
|
if ($linkedField['relationship'] === $relationship) {
|
||||||
|
$linkFieldName = $linkedField['name'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$linkFieldName) {
|
||||||
|
throw new \DomainException(
|
||||||
|
sprintf(
|
||||||
|
'Link field has not found in %s to determine relationship for %s',
|
||||||
|
$sourceBean->getObjectName(),
|
||||||
|
$relatedBean->getObjectName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $linkFieldName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $module
|
||||||
|
* @param string $where
|
||||||
|
*
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
|
public function countRecords($module, $where)
|
||||||
|
{
|
||||||
|
$rowCount = $this->db->fetchRow(
|
||||||
|
$this->db->query(
|
||||||
|
sprintf(
|
||||||
|
"SELECT COUNT(*) AS cnt FROM %s %s",
|
||||||
|
$this->newBeanSafe($module)->getTableName(),
|
||||||
|
$where === '' ? '' : 'WHERE ' . $where
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)["cnt"];
|
||||||
|
|
||||||
|
return (int)$rowCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param SugarBean $bean
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getDefaultFields(SugarBean $bean)
|
||||||
|
{
|
||||||
|
return array_column($bean->field_defs, 'name');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param SugarBean $bean
|
||||||
|
* @param array $fields
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function filterAcceptanceFields(SugarBean $bean, array $fields)
|
||||||
|
{
|
||||||
|
if (!$bean instanceof Person) {
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_filter(
|
||||||
|
$fields,
|
||||||
|
static function ($field) use ($bean) {
|
||||||
|
return (
|
||||||
|
in_array($field, array_column($bean->field_defs, 'name'), true)
|
||||||
|
&& (
|
||||||
|
empty($bean->field_defs[$field]['link_type'])
|
||||||
|
|| $bean->field_defs[$field]['link_type'] !== 'relationship_info'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
132
Api/V8/Config/routes.php
Normal file
132
Api/V8/Config/routes.php
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Api\V8\Controller\LogoutController;
|
||||||
|
use Api\V8\Factory\ParamsMiddlewareFactory;
|
||||||
|
use Api\V8\Param;
|
||||||
|
use League\OAuth2\Server\AuthorizationServer;
|
||||||
|
use League\OAuth2\Server\Middleware\AuthorizationServerMiddleware;
|
||||||
|
use League\OAuth2\Server\Middleware\ResourceServerMiddleware;
|
||||||
|
use League\OAuth2\Server\ResourceServer;
|
||||||
|
use Api\Core\Loader\CustomLoader;
|
||||||
|
|
||||||
|
$app->group('', function () use ($app) {
|
||||||
|
/**
|
||||||
|
* OAuth2 access token
|
||||||
|
*/
|
||||||
|
$app->post('/access_token', function () {
|
||||||
|
})->add(new AuthorizationServerMiddleware($app->getContainer()->get(AuthorizationServer::class)));
|
||||||
|
|
||||||
|
$app->group('/V8', function () use ($app) {
|
||||||
|
/** @var ParamsMiddlewareFactory $paramsMiddlewareFactory */
|
||||||
|
$paramsMiddlewareFactory = $app->getContainer()->get(ParamsMiddlewareFactory::class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logout
|
||||||
|
*/
|
||||||
|
$app->post('/logout', LogoutController::class);
|
||||||
|
|
||||||
|
$app
|
||||||
|
->get('/search-defs/module/{moduleName}', 'Api\V8\Controller\ListViewSearchController:getModuleSearchDefs')
|
||||||
|
->add($paramsMiddlewareFactory->bind(Param\ListViewSearchParams::class));
|
||||||
|
|
||||||
|
$app
|
||||||
|
->get('/listview/columns/{moduleName}', 'Api\V8\Controller\ListViewController:getListViewColumns')
|
||||||
|
->add($paramsMiddlewareFactory->bind(Param\ListViewColumnsParams::class));
|
||||||
|
|
||||||
|
$app->get('/current-user', 'Api\V8\Controller\UserController:getCurrentUser');
|
||||||
|
|
||||||
|
$app->get('/meta/modules', 'Api\V8\Controller\MetaController:getModuleList');
|
||||||
|
|
||||||
|
$app->get('/meta/fields/{moduleName}', 'Api\V8\Controller\MetaController:getFieldList')
|
||||||
|
->add($paramsMiddlewareFactory->bind(Param\GetFieldListParams::class));
|
||||||
|
|
||||||
|
$app
|
||||||
|
->get('/user-preferences/{id}', 'Api\V8\Controller\UserPreferencesController:getUserPreferences')
|
||||||
|
->add($paramsMiddlewareFactory->bind(Param\GetUserPreferencesParams::class));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get swagger schema
|
||||||
|
*/
|
||||||
|
$app->get('/meta/swagger.json', 'Api\V8\Controller\MetaController:getSwaggerSchema');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get module records
|
||||||
|
*/
|
||||||
|
$app
|
||||||
|
->get('/module/{moduleName}', 'Api\V8\Controller\ModuleController:getModuleRecords')
|
||||||
|
->add($paramsMiddlewareFactory->bind(Param\GetModulesParams::class));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a module record
|
||||||
|
*/
|
||||||
|
$app
|
||||||
|
->get('/module/{moduleName}/{id}', 'Api\V8\Controller\ModuleController:getModuleRecord')
|
||||||
|
->add($paramsMiddlewareFactory->bind(Param\GetModuleParams::class));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a module record
|
||||||
|
*/
|
||||||
|
$app
|
||||||
|
->post('/module', 'Api\V8\Controller\ModuleController:createModuleRecord')
|
||||||
|
->add($paramsMiddlewareFactory->bind(Param\CreateModuleParams::class));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update a module record
|
||||||
|
*/
|
||||||
|
$app
|
||||||
|
->patch('/module', 'Api\V8\Controller\ModuleController:updateModuleRecord')
|
||||||
|
->add($paramsMiddlewareFactory->bind(Param\UpdateModuleParams::class));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a module record
|
||||||
|
*/
|
||||||
|
$app
|
||||||
|
->delete('/module/{moduleName}/{id}', 'Api\V8\Controller\ModuleController:deleteModuleRecord')
|
||||||
|
->add($paramsMiddlewareFactory->bind(Param\DeleteModuleParams::class));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get relationships
|
||||||
|
*/
|
||||||
|
$app
|
||||||
|
->get(
|
||||||
|
'/module/{moduleName}/{id}/relationships/{linkFieldName}',
|
||||||
|
'Api\V8\Controller\RelationshipController:getRelationship'
|
||||||
|
)
|
||||||
|
->add($paramsMiddlewareFactory->bind(Param\GetRelationshipParams::class));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create relationship
|
||||||
|
*/
|
||||||
|
$app
|
||||||
|
->post(
|
||||||
|
'/module/{moduleName}/{id}/relationships',
|
||||||
|
'Api\V8\Controller\RelationshipController:createRelationship'
|
||||||
|
)
|
||||||
|
->add($paramsMiddlewareFactory->bind(Param\CreateRelationshipParams::class));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create relationship by link
|
||||||
|
*/
|
||||||
|
$app
|
||||||
|
->post(
|
||||||
|
'/module/{moduleName}/{id}/relationships/{linkFieldName}',
|
||||||
|
'Api\V8\Controller\RelationshipController:createRelationshipByLink'
|
||||||
|
)
|
||||||
|
->add($paramsMiddlewareFactory->bind(Param\CreateRelationshipByLinkParams::class));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete relationship
|
||||||
|
*/
|
||||||
|
$app
|
||||||
|
->delete(
|
||||||
|
'/module/{moduleName}/{id}/relationships/{linkFieldName}/{relatedBeanId}',
|
||||||
|
'Api\V8\Controller\RelationshipController:deleteRelationship'
|
||||||
|
)
|
||||||
|
->add($paramsMiddlewareFactory->bind(Param\DeleteRelationshipParams::class));
|
||||||
|
|
||||||
|
// add custom routes
|
||||||
|
$app->group('/custom', function () use ($app) {
|
||||||
|
$app = CustomLoader::loadCustomRoutes($app);
|
||||||
|
});
|
||||||
|
})->add(new ResourceServerMiddleware($app->getContainer()->get(ResourceServer::class)));
|
||||||
|
});
|
28
Api/V8/Config/services.php
Normal file
28
Api/V8/Config/services.php
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Api\V8\BeanDecorator\BeanManager;
|
||||||
|
use Api\V8\Controller\InvocationStrategy\SuiteInvocationStrategy;
|
||||||
|
use Psr\Container\ContainerInterface as Container;
|
||||||
|
use Api\Core\Loader\CustomLoader;
|
||||||
|
|
||||||
|
return CustomLoader::mergeCustomArray([
|
||||||
|
/** overwrite slim's foundHandler */
|
||||||
|
'foundHandler' => function () {
|
||||||
|
return new SuiteInvocationStrategy();
|
||||||
|
},
|
||||||
|
BeanManager::class => function (Container $container) {
|
||||||
|
return new BeanManager(
|
||||||
|
$container->get(DBManager::class),
|
||||||
|
$container->get('beanAliases')
|
||||||
|
);
|
||||||
|
},
|
||||||
|
] +
|
||||||
|
(require __DIR__ . '/services/beanAliases.php') +
|
||||||
|
(require __DIR__ . '/services/controllers.php') +
|
||||||
|
(require __DIR__ . '/services/factories.php') +
|
||||||
|
(require __DIR__ . '/services/globals.php') +
|
||||||
|
(require __DIR__ . '/services/helpers.php') +
|
||||||
|
(require __DIR__ . '/services/middlewares.php') +
|
||||||
|
(require __DIR__ . '/services/params.php') +
|
||||||
|
(require __DIR__ . '/services/services.php') +
|
||||||
|
(require __DIR__ . '/services/validators.php'), basename(__FILE__));
|
62
Api/V8/Config/services/beanAliases.php
Normal file
62
Api/V8/Config/services/beanAliases.php
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Api\Core\Loader\CustomLoader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aliases for core modules
|
||||||
|
*/
|
||||||
|
return [
|
||||||
|
'beanAliases' => function () {
|
||||||
|
return CustomLoader::mergeCustomArray([
|
||||||
|
Account::class => 'Accounts',
|
||||||
|
ACLAction::class => 'ACLActions',
|
||||||
|
ACLRole::class => 'ACLRoles',
|
||||||
|
Alert::class => 'Alerts',
|
||||||
|
AOR_Chart::class => 'AOR_Charts',
|
||||||
|
AOR_Condition::class => 'AOR_Conditions',
|
||||||
|
AOR_Field::class => 'AOR_Fields',
|
||||||
|
AOR_Report::class => 'AOR_Reports',
|
||||||
|
AOW_Action::class => 'AOW_Actions',
|
||||||
|
AOW_Condition::class => 'AOW_Conditions',
|
||||||
|
Call::class => 'Calls',
|
||||||
|
Campaign::class => 'Campaigns',
|
||||||
|
CampaignTracker::class => 'CampaignTrackers',
|
||||||
|
aCase::class => 'Cases',
|
||||||
|
'Case' => 'Cases',
|
||||||
|
ConnectorRecord::class => 'Connector',
|
||||||
|
Contact::class => 'Contacts',
|
||||||
|
Currency::class => 'Currencies',
|
||||||
|
DocumentRevision::class => 'DocumentRevisions',
|
||||||
|
Document::class => 'Documents',
|
||||||
|
FieldsMetaData::class => 'DynamicFields',
|
||||||
|
Email::class => 'Emails',
|
||||||
|
EmailAddress::class => 'EmailAddresses',
|
||||||
|
EmailTemplate::class => 'EmailTemplates',
|
||||||
|
Employee::class => 'Employees',
|
||||||
|
UsersLastImport::class => 'Import',
|
||||||
|
Lead::class => 'Leads',
|
||||||
|
Meeting::class => 'Meetings',
|
||||||
|
MergeRecord::class => 'MergeRecords',
|
||||||
|
Note::class => 'Notes',
|
||||||
|
OAuthKey::class => 'OAuthKeys',
|
||||||
|
OAuthToken::class => 'OAuthTokens',
|
||||||
|
Opportunity::class => 'Opportunities',
|
||||||
|
ProspectList::class => 'ProspectLists',
|
||||||
|
Prospect::class => 'Prospects',
|
||||||
|
Relationship::class => 'Relationships',
|
||||||
|
Reminder::class => 'Reminders',
|
||||||
|
Reminder_Invitee::class => 'Reminders_Invitees',
|
||||||
|
Role::class => 'Roles',
|
||||||
|
SecurityGroup::class => 'SecurityGroups',
|
||||||
|
Task::class => 'Tasks',
|
||||||
|
Tracker::class => 'Trackers',
|
||||||
|
User::class => 'Users',
|
||||||
|
UserPreference::class => 'UserPreferences',
|
||||||
|
vCal::class => 'vCals',
|
||||||
|
'Contracts' => AOS_Contracts::class,
|
||||||
|
'Invoices' => AOS_Invoices::class,
|
||||||
|
'ProductQuotes' => AOS_Products_Quotes::class,
|
||||||
|
'Quotes' => AOS_Quotes::class,
|
||||||
|
], basename(__FILE__));
|
||||||
|
}
|
||||||
|
];
|
59
Api/V8/Config/services/controllers.php
Normal file
59
Api/V8/Config/services/controllers.php
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Api\V8\Controller;
|
||||||
|
use Api\V8\Service\ListViewSearchService;
|
||||||
|
use Api\V8\Service\ListViewService;
|
||||||
|
use Api\V8\Service\LogoutService;
|
||||||
|
use Api\V8\Service\MetaService;
|
||||||
|
use Api\V8\Service\ModuleService;
|
||||||
|
use Api\V8\Service\RelationshipService;
|
||||||
|
use Api\V8\Service\UserPreferencesService;
|
||||||
|
use Api\V8\Service\UserService;
|
||||||
|
use Psr\Container\ContainerInterface as Container;
|
||||||
|
use League\OAuth2\Server\ResourceServer;
|
||||||
|
|
||||||
|
use Api\Core\Loader\CustomLoader;
|
||||||
|
|
||||||
|
return CustomLoader::mergeCustomArray([
|
||||||
|
Controller\ListViewSearchController::class => function (Container $container) {
|
||||||
|
return new Controller\ListViewSearchController(
|
||||||
|
$container->get(ListViewSearchService::class)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Controller\UserPreferencesController::class => function (Container $container) {
|
||||||
|
return new Controller\UserPreferencesController(
|
||||||
|
$container->get(UserPreferencesService::class)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Controller\UserController::class => function (Container $container) {
|
||||||
|
return new Controller\UserController(
|
||||||
|
$container->get(UserService::class)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Controller\MetaController::class => function (Container $container) {
|
||||||
|
return new Controller\MetaController(
|
||||||
|
$container->get(MetaService::class)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Controller\ListViewController::class => function (Container $container) {
|
||||||
|
return new Controller\ListViewController(
|
||||||
|
$container->get(ListViewService::class)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Controller\ModuleController::class => function (Container $container) {
|
||||||
|
return new Controller\ModuleController(
|
||||||
|
$container->get(ModuleService::class)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Controller\LogoutController::class => function (Container $container) {
|
||||||
|
return new Controller\LogoutController(
|
||||||
|
$container->get(LogoutService::class),
|
||||||
|
$container->get(ResourceServer::class)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Controller\RelationshipController::class => function (Container $container) {
|
||||||
|
return new Controller\RelationshipController(
|
||||||
|
$container->get(RelationshipService::class)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
], basename(__FILE__));
|
14
Api/V8/Config/services/factories.php
Normal file
14
Api/V8/Config/services/factories.php
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Api\V8\Factory;
|
||||||
|
use Psr\Container\ContainerInterface as Container;
|
||||||
|
use Api\Core\Loader\CustomLoader;
|
||||||
|
|
||||||
|
return CustomLoader::mergeCustomArray([
|
||||||
|
Factory\ParamsMiddlewareFactory::class => function (Container $container) {
|
||||||
|
return new Factory\ParamsMiddlewareFactory($container);
|
||||||
|
},
|
||||||
|
Factory\ValidatorFactory::class => function (Container $container) {
|
||||||
|
return new Factory\ValidatorFactory($container->get('Validation'));
|
||||||
|
},
|
||||||
|
], basename(__FILE__));
|
13
Api/V8/Config/services/globals.php
Normal file
13
Api/V8/Config/services/globals.php
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Api\Core\Loader\CustomLoader;
|
||||||
|
|
||||||
|
return CustomLoader::mergeCustomArray([
|
||||||
|
'suiteConfig' => function () {
|
||||||
|
global $sugar_config;
|
||||||
|
return $sugar_config;
|
||||||
|
},
|
||||||
|
DBManager::class => function () {
|
||||||
|
return DBManagerFactory::getInstance();
|
||||||
|
},
|
||||||
|
], basename(__FILE__));
|
30
Api/V8/Config/services/helpers.php
Normal file
30
Api/V8/Config/services/helpers.php
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Api\V8\BeanDecorator\BeanManager;
|
||||||
|
use Api\V8\Helper;
|
||||||
|
use Api\V8\JsonApi\Helper as ApiHelper;
|
||||||
|
use Psr\Container\ContainerInterface as Container;
|
||||||
|
|
||||||
|
use Api\Core\Loader\CustomLoader;
|
||||||
|
|
||||||
|
return CustomLoader::mergeCustomArray([
|
||||||
|
Helper\VarDefHelper::class => function () {
|
||||||
|
return new Helper\VarDefHelper();
|
||||||
|
},
|
||||||
|
ApiHelper\AttributeObjectHelper::class => function (Container $container) {
|
||||||
|
return new ApiHelper\AttributeObjectHelper(
|
||||||
|
$container->get(BeanManager::class)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
ApiHelper\RelationshipObjectHelper::class => function (Container $container) {
|
||||||
|
return new ApiHelper\RelationshipObjectHelper(
|
||||||
|
$container->get(Helper\VarDefHelper::class)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
ApiHelper\PaginationObjectHelper::class => function (Container $container) {
|
||||||
|
return new ApiHelper\PaginationObjectHelper();
|
||||||
|
},
|
||||||
|
Helper\ModuleListProvider::class => function (Container $container) {
|
||||||
|
return new Helper\ModuleListProvider();
|
||||||
|
},
|
||||||
|
], basename(__FILE__));
|
88
Api/V8/Config/services/middlewares.php
Normal file
88
Api/V8/Config/services/middlewares.php
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Api\Core\Config\ApiConfig;
|
||||||
|
use Api\V8\BeanDecorator\BeanManager;
|
||||||
|
use Api\V8\OAuth2\Entity\AccessTokenEntity;
|
||||||
|
use Api\V8\OAuth2\Entity\ClientEntity;
|
||||||
|
use Api\V8\OAuth2\Repository\AccessTokenRepository;
|
||||||
|
use Api\V8\OAuth2\Repository\ClientRepository;
|
||||||
|
use Api\V8\OAuth2\Repository\RefreshTokenRepository;
|
||||||
|
use Api\V8\OAuth2\Repository\ScopeRepository;
|
||||||
|
use Api\V8\OAuth2\Repository\UserRepository;
|
||||||
|
use Psr\Container\ContainerInterface as Container;
|
||||||
|
use League\OAuth2\Server\AuthorizationServer;
|
||||||
|
use League\OAuth2\Server\Grant\PasswordGrant;
|
||||||
|
use League\OAuth2\Server\Grant\RefreshTokenGrant;
|
||||||
|
use League\OAuth2\Server\ResourceServer;
|
||||||
|
use Api\Core\Loader\CustomLoader;
|
||||||
|
|
||||||
|
return CustomLoader::mergeCustomArray([
|
||||||
|
AuthorizationServer::class => function (Container $container) {
|
||||||
|
// base dir must exist in entryPoint.php
|
||||||
|
$baseDir = $GLOBALS['BASE_DIR'];
|
||||||
|
|
||||||
|
$server = new AuthorizationServer(
|
||||||
|
new ClientRepository(
|
||||||
|
new ClientEntity(),
|
||||||
|
$container->get(BeanManager::class)
|
||||||
|
),
|
||||||
|
new AccessTokenRepository(
|
||||||
|
new AccessTokenEntity(),
|
||||||
|
$container->get(BeanManager::class)
|
||||||
|
),
|
||||||
|
new ScopeRepository(),
|
||||||
|
sprintf('file://%s/%s', $baseDir, ApiConfig::OAUTH2_PRIVATE_KEY),
|
||||||
|
sprintf('file://%s/%s', $baseDir, ApiConfig::OAUTH2_PUBLIC_KEY)
|
||||||
|
);
|
||||||
|
|
||||||
|
$oauth2EncKey = isset($GLOBALS['sugar_config']['oauth2_encryption_key'])
|
||||||
|
? $GLOBALS['sugar_config']['oauth2_encryption_key'] : '';
|
||||||
|
if (empty($oauth2EncKey)) {
|
||||||
|
$oauth2EncKey = 'SCRM-DEFK';
|
||||||
|
if (isset($GLOBALS['log'])) {
|
||||||
|
$GLOBALS['log']->fatal('WARNING: `oauth2_encryption_key` not set in config.php');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$server->setEncryptionKey($oauth2EncKey);
|
||||||
|
|
||||||
|
// Client credentials grant
|
||||||
|
$server->enableGrantType(
|
||||||
|
new \League\OAuth2\Server\Grant\ClientCredentialsGrant(),
|
||||||
|
new \DateInterval('PT1H')
|
||||||
|
);
|
||||||
|
|
||||||
|
// Password credentials grant
|
||||||
|
$server->enableGrantType(
|
||||||
|
new PasswordGrant(
|
||||||
|
new UserRepository($container->get(BeanManager::class)),
|
||||||
|
new RefreshTokenRepository($container->get(BeanManager::class))
|
||||||
|
),
|
||||||
|
new \DateInterval('PT1H')
|
||||||
|
);
|
||||||
|
|
||||||
|
$refreshGrant = new RefreshTokenGrant(
|
||||||
|
new RefreshTokenRepository($container->get(BeanManager::class))
|
||||||
|
);
|
||||||
|
|
||||||
|
$refreshGrant->setRefreshTokenTTL(new \DateInterval('P1M'));
|
||||||
|
|
||||||
|
$server->enableGrantType(
|
||||||
|
$refreshGrant,
|
||||||
|
new \DateInterval('PT1H')
|
||||||
|
);
|
||||||
|
|
||||||
|
return $server;
|
||||||
|
},
|
||||||
|
ResourceServer::class => function (Container $container) {
|
||||||
|
$baseDir = $GLOBALS['BASE_DIR'];
|
||||||
|
|
||||||
|
return new ResourceServer(
|
||||||
|
new AccessTokenRepository(
|
||||||
|
new AccessTokenEntity(),
|
||||||
|
$container->get(BeanManager::class)
|
||||||
|
),
|
||||||
|
sprintf('file://%s/%s', $baseDir, ApiConfig::OAUTH2_PUBLIC_KEY)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
], basename(__FILE__));
|
88
Api/V8/Config/services/params.php
Normal file
88
Api/V8/Config/services/params.php
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Api\V8\BeanDecorator\BeanManager;
|
||||||
|
use Api\V8\Factory\ValidatorFactory;
|
||||||
|
use Api\V8\Param;
|
||||||
|
use Psr\Container\ContainerInterface as Container;
|
||||||
|
use Api\Core\Loader\CustomLoader;
|
||||||
|
|
||||||
|
return CustomLoader::mergeCustomArray([
|
||||||
|
Param\ListViewSearchParams::class => function (Container $container) {
|
||||||
|
return new Param\ListViewSearchParams(
|
||||||
|
$container->get(ValidatorFactory::class),
|
||||||
|
$container->get(BeanManager::class)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Param\GetUserPreferencesParams::class => function (Container $container) {
|
||||||
|
return new Param\GetUserPreferencesParams(
|
||||||
|
$container->get(ValidatorFactory::class),
|
||||||
|
$container->get(BeanManager::class)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Param\ListViewColumnsParams::class => function (Container $container) {
|
||||||
|
return new Param\ListViewColumnsParams(
|
||||||
|
$container->get(ValidatorFactory::class),
|
||||||
|
$container->get(BeanManager::class)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Param\GetModuleParams::class => function (Container $container) {
|
||||||
|
return new Param\GetModuleParams(
|
||||||
|
$container->get(ValidatorFactory::class),
|
||||||
|
$container->get(BeanManager::class)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Param\GetModulesParams::class => function (Container $container) {
|
||||||
|
return new Param\GetModulesParams(
|
||||||
|
$container->get(ValidatorFactory::class),
|
||||||
|
$container->get(BeanManager::class)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Param\CreateModuleParams::class => function (Container $container) {
|
||||||
|
return new Param\CreateModuleParams(
|
||||||
|
$container->get(ValidatorFactory::class),
|
||||||
|
$container->get(BeanManager::class)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Param\UpdateModuleParams::class => function (Container $container) {
|
||||||
|
return new Param\UpdateModuleParams(
|
||||||
|
$container->get(ValidatorFactory::class),
|
||||||
|
$container->get(BeanManager::class)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Param\DeleteModuleParams::class => function (Container $container) {
|
||||||
|
return new Param\DeleteModuleParams(
|
||||||
|
$container->get(ValidatorFactory::class),
|
||||||
|
$container->get(BeanManager::class)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Param\GetRelationshipParams::class => function (Container $container) {
|
||||||
|
return new Param\GetRelationshipParams(
|
||||||
|
$container->get(ValidatorFactory::class),
|
||||||
|
$container->get(BeanManager::class)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Param\CreateRelationshipParams::class => function (Container $container) {
|
||||||
|
return new Param\CreateRelationshipParams(
|
||||||
|
$container->get(ValidatorFactory::class),
|
||||||
|
$container->get(BeanManager::class)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Param\CreateRelationshipByLinkParams::class => function (Container $container) {
|
||||||
|
return new Param\CreateRelationshipByLinkParams(
|
||||||
|
$container->get(ValidatorFactory::class),
|
||||||
|
$container->get(BeanManager::class)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Param\DeleteRelationshipParams::class => function (Container $container) {
|
||||||
|
return new Param\DeleteRelationshipParams(
|
||||||
|
$container->get(ValidatorFactory::class),
|
||||||
|
$container->get(BeanManager::class)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Param\GetFieldListParams::class => function (Container $container) {
|
||||||
|
return new Param\GetFieldListParams(
|
||||||
|
$container->get(ValidatorFactory::class),
|
||||||
|
$container->get(BeanManager::class)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
], basename(__FILE__));
|
63
Api/V8/Config/services/services.php
Normal file
63
Api/V8/Config/services/services.php
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Api\V8\BeanDecorator\BeanManager;
|
||||||
|
use Api\V8\Helper\ModuleListProvider;
|
||||||
|
use Api\V8\JsonApi\Helper\AttributeObjectHelper;
|
||||||
|
use Api\V8\JsonApi\Helper\PaginationObjectHelper;
|
||||||
|
use Api\V8\JsonApi\Helper\RelationshipObjectHelper;
|
||||||
|
use Api\V8\Service;
|
||||||
|
use Psr\Container\ContainerInterface as Container;
|
||||||
|
use Api\Core\Loader\CustomLoader;
|
||||||
|
|
||||||
|
return CustomLoader::mergeCustomArray([
|
||||||
|
Service\ListViewSearchService::class => function (Container $container) {
|
||||||
|
return new Service\ListViewSearchService(
|
||||||
|
$container->get(BeanManager::class)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Service\UserPreferencesService::class => function (Container $container) {
|
||||||
|
return new Service\UserPreferencesService(
|
||||||
|
$container->get(BeanManager::class)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Service\UserService::class => function (Container $container) {
|
||||||
|
return new Service\UserService(
|
||||||
|
$container->get(BeanManager::class),
|
||||||
|
$container->get(AttributeObjectHelper::class),
|
||||||
|
$container->get(RelationshipObjectHelper::class)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Service\MetaService::class => function (Container $container) {
|
||||||
|
return new Service\MetaService(
|
||||||
|
$container->get(BeanManager::class),
|
||||||
|
$container->get(ModuleListProvider::class)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Service\ListViewService::class => function (Container $container) {
|
||||||
|
return new Service\ListViewService(
|
||||||
|
$container->get(BeanManager::class),
|
||||||
|
$container->get(AttributeObjectHelper::class),
|
||||||
|
$container->get(RelationshipObjectHelper::class),
|
||||||
|
$container->get(PaginationObjectHelper::class)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Service\ModuleService::class => function (Container $container) {
|
||||||
|
return new Service\ModuleService(
|
||||||
|
$container->get(BeanManager::class),
|
||||||
|
$container->get(AttributeObjectHelper::class),
|
||||||
|
$container->get(RelationshipObjectHelper::class),
|
||||||
|
$container->get(PaginationObjectHelper::class)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Service\LogoutService::class => function (Container $container) {
|
||||||
|
return new Service\LogoutService(
|
||||||
|
$container->get(BeanManager::class)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Service\RelationshipService::class => function (Container $container) {
|
||||||
|
return new Service\RelationshipService(
|
||||||
|
$container->get(BeanManager::class),
|
||||||
|
$container->get(AttributeObjectHelper::class)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
], basename(__FILE__));
|
11
Api/V8/Config/services/validators.php
Normal file
11
Api/V8/Config/services/validators.php
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Api\Core\Loader\CustomLoader;
|
||||||
|
|
||||||
|
include_once __DIR__ . '/../../../../vendor/symfony/validator/ValidatorBuilder.php';
|
||||||
|
|
||||||
|
return CustomLoader::mergeCustomArray([
|
||||||
|
'Validation' => function () {
|
||||||
|
return (new Symfony\Component\Validator\ValidatorBuilder())->getValidator();
|
||||||
|
},
|
||||||
|
], basename(__FILE__));
|
51
Api/V8/Controller/BaseController.php
Normal file
51
Api/V8/Controller/BaseController.php
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\Controller;
|
||||||
|
|
||||||
|
use Api\V8\JsonApi\Response\ErrorResponse;
|
||||||
|
use Slim\Http\Response as HttpResponse;
|
||||||
|
|
||||||
|
abstract class BaseController
|
||||||
|
{
|
||||||
|
const MEDIA_TYPE = 'application/vnd.api+json';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param HttpResponse $httpResponse
|
||||||
|
* @param mixed $response
|
||||||
|
* @param integer $status
|
||||||
|
*
|
||||||
|
* @return HttpResponse
|
||||||
|
*/
|
||||||
|
public function generateResponse(
|
||||||
|
HttpResponse $httpResponse,
|
||||||
|
$response,
|
||||||
|
$status
|
||||||
|
) {
|
||||||
|
return $httpResponse
|
||||||
|
->withStatus($status)
|
||||||
|
->withHeader('Accept', static::MEDIA_TYPE)
|
||||||
|
->withHeader('Content-type', static::MEDIA_TYPE)
|
||||||
|
->write(
|
||||||
|
json_encode(
|
||||||
|
$response,
|
||||||
|
JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param HttpResponse $httpResponse
|
||||||
|
* @param \Exception $exception
|
||||||
|
* @param integer $status
|
||||||
|
*
|
||||||
|
* @return HttpResponse
|
||||||
|
*/
|
||||||
|
public function generateErrorResponse(HttpResponse $httpResponse, \Exception $exception, $status)
|
||||||
|
{
|
||||||
|
$response = new ErrorResponse();
|
||||||
|
$response->setStatus($status);
|
||||||
|
$response->setDetail($exception->getMessage());
|
||||||
|
$response->setException($exception);
|
||||||
|
|
||||||
|
return $this->generateResponse($httpResponse, $response, $status);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\Controller\InvocationStrategy;
|
||||||
|
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
use Slim\Interfaces\InvocationStrategyInterface;
|
||||||
|
|
||||||
|
class SuiteInvocationStrategy implements InvocationStrategyInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function __invoke(
|
||||||
|
callable $callable,
|
||||||
|
ServerRequestInterface $request,
|
||||||
|
ResponseInterface $response,
|
||||||
|
array $routeArguments
|
||||||
|
) {
|
||||||
|
foreach ($routeArguments as $attribute => $value) {
|
||||||
|
$request = $request->withAttribute($attribute, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// since we support 5.5.9, we can't use splat op here
|
||||||
|
return $callable(
|
||||||
|
$request,
|
||||||
|
$response,
|
||||||
|
$routeArguments,
|
||||||
|
$request->getAttribute('params') ? $request->getAttribute('params') : null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
94
Api/V8/Controller/ListViewController.php
Normal file
94
Api/V8/Controller/ListViewController.php
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* SugarCRM Community Edition is a customer relationship management program developed by
|
||||||
|
* SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
|
||||||
|
*
|
||||||
|
* SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd.
|
||||||
|
* Copyright (C) 2011 - 2018 SalesAgility Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU Affero General Public License version 3 as published by the
|
||||||
|
* Free Software Foundation with the addition of the following permission added
|
||||||
|
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
||||||
|
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
||||||
|
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License along with
|
||||||
|
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
||||||
|
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
||||||
|
*
|
||||||
|
* The interactive user interfaces in modified source and object code versions
|
||||||
|
* of this program must display Appropriate Legal Notices, as required under
|
||||||
|
* Section 5 of the GNU Affero General Public License version 3.
|
||||||
|
*
|
||||||
|
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||||
|
* these Appropriate Legal Notices must retain the display of the "Powered by
|
||||||
|
* SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
|
||||||
|
* reasonably feasible for technical reasons, the Appropriate Legal Notices must
|
||||||
|
* display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM".
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Api\V8\Controller;
|
||||||
|
|
||||||
|
if (!defined('sugarEntry') || !sugarEntry) {
|
||||||
|
die('Not A Valid Entry Point');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
use Api\V8\Param\ListViewColumnsParams;
|
||||||
|
use Api\V8\Service\ListViewService;
|
||||||
|
use Exception;
|
||||||
|
use Slim\Http\Request;
|
||||||
|
use Slim\Http\Response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ListViewController
|
||||||
|
*
|
||||||
|
* @author gyula
|
||||||
|
*/
|
||||||
|
class ListViewController extends BaseController
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ListViewService
|
||||||
|
*/
|
||||||
|
protected $listViewService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ListViewService $listViewService
|
||||||
|
*/
|
||||||
|
public function __construct(ListViewService $listViewService)
|
||||||
|
{
|
||||||
|
$this->listViewService = $listViewService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @param Response $response
|
||||||
|
* @param array $args
|
||||||
|
* @param ListViewColumnsParams $params
|
||||||
|
* @return HttpResponse
|
||||||
|
*/
|
||||||
|
public function getListViewColumns(Request $request, Response $response, array $args, ListViewColumnsParams $params)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$jsonResponse = $this->listViewService->getListViewDefs($params);
|
||||||
|
|
||||||
|
return $this->generateResponse($response, $jsonResponse, 200);
|
||||||
|
} catch (Exception $exception) {
|
||||||
|
return $this->generateErrorResponse($response, $exception, 400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
94
Api/V8/Controller/ListViewSearchController.php
Normal file
94
Api/V8/Controller/ListViewSearchController.php
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* SugarCRM Community Edition is a customer relationship management program developed by
|
||||||
|
* SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
|
||||||
|
*
|
||||||
|
* SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd.
|
||||||
|
* Copyright (C) 2011 - 2018 SalesAgility Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU Affero General Public License version 3 as published by the
|
||||||
|
* Free Software Foundation with the addition of the following permission added
|
||||||
|
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
||||||
|
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
||||||
|
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License along with
|
||||||
|
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
||||||
|
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
||||||
|
*
|
||||||
|
* The interactive user interfaces in modified source and object code versions
|
||||||
|
* of this program must display Appropriate Legal Notices, as required under
|
||||||
|
* Section 5 of the GNU Affero General Public License version 3.
|
||||||
|
*
|
||||||
|
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||||
|
* these Appropriate Legal Notices must retain the display of the "Powered by
|
||||||
|
* SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
|
||||||
|
* reasonably feasible for technical reasons, the Appropriate Legal Notices must
|
||||||
|
* display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM".
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Api\V8\Controller;
|
||||||
|
|
||||||
|
if (!defined('sugarEntry') || !sugarEntry) {
|
||||||
|
die('Not A Valid Entry Point');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
use Api\V8\Param\ListViewSearchParams;
|
||||||
|
use Api\V8\Service\ListViewSearchService;
|
||||||
|
use Exception;
|
||||||
|
use Slim\Http\Request;
|
||||||
|
use Slim\Http\Response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ListViewSearchController
|
||||||
|
*
|
||||||
|
* @author gyula
|
||||||
|
*/
|
||||||
|
class ListViewSearchController extends BaseController
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ListViewSearchService
|
||||||
|
*/
|
||||||
|
protected $listViewSearchService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ListViewSearchService $listViewSearchService
|
||||||
|
*/
|
||||||
|
public function __construct(ListViewSearchService $listViewSearchService)
|
||||||
|
{
|
||||||
|
$this->listViewSearchService = $listViewSearchService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @param Response $response
|
||||||
|
* @param array $args
|
||||||
|
* @param ListViewSearchParams $params
|
||||||
|
* @return HttpResponse
|
||||||
|
*/
|
||||||
|
public function getModuleSearchDefs(Request $request, Response $response, array $args, ListViewSearchParams $params)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$jsonResponse = $this->listViewSearchService->getListViewSearchDefs($params);
|
||||||
|
|
||||||
|
return $this->generateResponse($response, $jsonResponse, 200);
|
||||||
|
} catch (Exception $exception) {
|
||||||
|
return $this->generateErrorResponse($response, $exception, 400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
51
Api/V8/Controller/LogoutController.php
Normal file
51
Api/V8/Controller/LogoutController.php
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\Controller;
|
||||||
|
|
||||||
|
use Api\V8\Service\LogoutService;
|
||||||
|
use League\OAuth2\Server\ResourceServer;
|
||||||
|
use Slim\Http\Request;
|
||||||
|
use Slim\Http\Response;
|
||||||
|
|
||||||
|
class LogoutController extends BaseController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var LogoutService
|
||||||
|
*/
|
||||||
|
protected $logoutService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ResourceServer
|
||||||
|
*/
|
||||||
|
protected $resourceServer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param LogoutService $logoutService
|
||||||
|
* @param ResourceServer $resourceServer
|
||||||
|
*/
|
||||||
|
public function __construct(LogoutService $logoutService, ResourceServer $resourceServer)
|
||||||
|
{
|
||||||
|
$this->logoutService = $logoutService;
|
||||||
|
$this->resourceServer = $resourceServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Request $request
|
||||||
|
* @param Response $response
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function __invoke(Request $request, Response $response)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$accessToken = $this->resourceServer
|
||||||
|
->validateAuthenticatedRequest($request)
|
||||||
|
->getAttribute('oauth_access_token_id');
|
||||||
|
|
||||||
|
$logoutResponse = $this->logoutService->logout($accessToken);
|
||||||
|
|
||||||
|
return $this->generateResponse($response, $logoutResponse, 200);
|
||||||
|
} catch (\Exception $exception) {
|
||||||
|
return $this->generateErrorResponse($response, $exception, 400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
125
Api/V8/Controller/MetaController.php
Normal file
125
Api/V8/Controller/MetaController.php
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* SugarCRM Community Edition is a customer relationship management program developed by
|
||||||
|
* SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
|
||||||
|
*
|
||||||
|
* SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd.
|
||||||
|
* Copyright (C) 2011 - 2018 SalesAgility Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU Affero General Public License version 3 as published by the
|
||||||
|
* Free Software Foundation with the addition of the following permission added
|
||||||
|
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
||||||
|
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
||||||
|
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License along with
|
||||||
|
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
||||||
|
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
||||||
|
*
|
||||||
|
* The interactive user interfaces in modified source and object code versions
|
||||||
|
* of this program must display Appropriate Legal Notices, as required under
|
||||||
|
* Section 5 of the GNU Affero General Public License version 3.
|
||||||
|
*
|
||||||
|
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||||
|
* these Appropriate Legal Notices must retain the display of the "Powered by
|
||||||
|
* SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
|
||||||
|
* reasonably feasible for technical reasons, the Appropriate Legal Notices must
|
||||||
|
* display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM".
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Api\V8\Controller;
|
||||||
|
|
||||||
|
if (!defined('sugarEntry') || !sugarEntry) {
|
||||||
|
die('Not A Valid Entry Point');
|
||||||
|
}
|
||||||
|
|
||||||
|
use Api\V8\Param\GetFieldListParams;
|
||||||
|
use Api\V8\Service\MetaService;
|
||||||
|
use Api\V8\Service\UserService;
|
||||||
|
use Exception;
|
||||||
|
use Slim\Http\Request;
|
||||||
|
use Slim\Http\Response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MetaController
|
||||||
|
*/
|
||||||
|
class MetaController extends BaseController
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var UserService
|
||||||
|
*/
|
||||||
|
private $metaService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param MetaService $metaService
|
||||||
|
*/
|
||||||
|
public function __construct(MetaService $metaService)
|
||||||
|
{
|
||||||
|
$this->metaService = $metaService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @param Response $response
|
||||||
|
* @param array $args
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function getModuleList(Request $request, Response $response, array $args)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$jsonResponse = $this->metaService->getModuleList($request);
|
||||||
|
|
||||||
|
return $this->generateResponse($response, $jsonResponse, 200);
|
||||||
|
} catch (Exception $exception) {
|
||||||
|
return $this->generateErrorResponse($response, $exception, 400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @param Response $response
|
||||||
|
* @param array $args
|
||||||
|
* @param GetFieldListParams $fieldListParams
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function getFieldList(Request $request, Response $response, array $args, GetFieldListParams $fieldListParams)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$jsonResponse = $this->metaService->getFieldList($request, $fieldListParams);
|
||||||
|
|
||||||
|
return $this->generateResponse($response, $jsonResponse, 200);
|
||||||
|
} catch (Exception $exception) {
|
||||||
|
return $this->generateErrorResponse($response, $exception, 400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Request $request
|
||||||
|
* @param Response $response
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function getSwaggerSchema(Request $request, Response $response)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$jsonResponse = $this->metaService->getSwaggerSchema();
|
||||||
|
|
||||||
|
return $this->generateResponse($response, $jsonResponse, 200);
|
||||||
|
} catch (Exception $exception) {
|
||||||
|
return $this->generateErrorResponse($response, $exception, 400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
122
Api/V8/Controller/ModuleController.php
Normal file
122
Api/V8/Controller/ModuleController.php
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\Controller;
|
||||||
|
|
||||||
|
use Api\V8\Param\CreateModuleParams;
|
||||||
|
use Api\V8\Param\DeleteModuleParams;
|
||||||
|
use Api\V8\Param\GetModuleParams;
|
||||||
|
use Api\V8\Param\GetModulesParams;
|
||||||
|
use Api\V8\Param\UpdateModuleParams;
|
||||||
|
use Api\V8\Service\ModuleService;
|
||||||
|
use Slim\Http\Request;
|
||||||
|
use Slim\Http\Response;
|
||||||
|
|
||||||
|
class ModuleController extends BaseController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var ModuleService
|
||||||
|
*/
|
||||||
|
protected $moduleService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ModuleService $moduleService
|
||||||
|
*/
|
||||||
|
public function __construct(ModuleService $moduleService)
|
||||||
|
{
|
||||||
|
$this->moduleService = $moduleService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Request $request
|
||||||
|
* @param Response $response
|
||||||
|
* @param array $args
|
||||||
|
* @param GetModuleParams $params
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function getModuleRecord(Request $request, Response $response, array $args, GetModuleParams $params)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$jsonResponse = $this->moduleService->getRecord($params, $request->getUri()->getPath());
|
||||||
|
|
||||||
|
return $this->generateResponse($response, $jsonResponse, 200);
|
||||||
|
} catch (\Exception $exception) {
|
||||||
|
return $this->generateErrorResponse($response, $exception, 400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Request $request
|
||||||
|
* @param Response $response
|
||||||
|
* @param array $args
|
||||||
|
* @param GetModulesParams $params
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function getModuleRecords(Request $request, Response $response, array $args, GetModulesParams $params)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$jsonResponse = $this->moduleService->getRecords($params, $request);
|
||||||
|
|
||||||
|
return $this->generateResponse($response, $jsonResponse, 200);
|
||||||
|
} catch (\Exception $exception) {
|
||||||
|
return $this->generateErrorResponse($response, $exception, 400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Request $request
|
||||||
|
* @param Response $response
|
||||||
|
* @param array $args
|
||||||
|
* @param CreateModuleParams $params
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function createModuleRecord(Request $request, Response $response, array $args, CreateModuleParams $params)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$jsonResponse = $this->moduleService->createRecord($params, $request);
|
||||||
|
|
||||||
|
return $this->generateResponse($response, $jsonResponse, 201);
|
||||||
|
} catch (\Exception $exception) {
|
||||||
|
return $this->generateErrorResponse($response, $exception, 400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Request $request
|
||||||
|
* @param Response $response
|
||||||
|
* @param array $args
|
||||||
|
* @param UpdateModuleParams $params
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function updateModuleRecord(Request $request, Response $response, array $args, UpdateModuleParams $params)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$jsonResponse = $this->moduleService->updateRecord($params, $request);
|
||||||
|
|
||||||
|
return $this->generateResponse($response, $jsonResponse, 201);
|
||||||
|
} catch (\Exception $exception) {
|
||||||
|
return $this->generateErrorResponse($response, $exception, 400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Request $request
|
||||||
|
* @param Response $response
|
||||||
|
* @param array $args
|
||||||
|
* @param DeleteModuleParams $params
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function deleteModuleRecord(Request $request, Response $response, array $args, DeleteModuleParams $params)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$jsonResponse = $this->moduleService->deleteRecord($params);
|
||||||
|
|
||||||
|
return $this->generateResponse($response, $jsonResponse, 200);
|
||||||
|
} catch (\Exception $exception) {
|
||||||
|
return $this->generateErrorResponse($response, $exception, 400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
114
Api/V8/Controller/RelationshipController.php
Normal file
114
Api/V8/Controller/RelationshipController.php
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\Controller;
|
||||||
|
|
||||||
|
use Api\V8\Param\CreateRelationshipParams;
|
||||||
|
use Api\V8\Param\CreateRelationshipByLinkParams;
|
||||||
|
use Api\V8\Param\DeleteRelationshipParams;
|
||||||
|
use Api\V8\Param\GetRelationshipParams;
|
||||||
|
use Api\V8\Service\RelationshipService;
|
||||||
|
use Slim\Http\Request;
|
||||||
|
use Slim\Http\Response;
|
||||||
|
|
||||||
|
class RelationshipController extends BaseController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var RelationshipService
|
||||||
|
*/
|
||||||
|
protected $relationshipService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param RelationshipService $relationshipService
|
||||||
|
*/
|
||||||
|
public function __construct(RelationshipService $relationshipService)
|
||||||
|
{
|
||||||
|
$this->relationshipService = $relationshipService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Request $request
|
||||||
|
* @param Response $response
|
||||||
|
* @param array $args
|
||||||
|
* @param GetRelationshipParams $params
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function getRelationship(Request $request, Response $response, array $args, GetRelationshipParams $params)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$jsonResponse = $this->relationshipService->getRelationship($params);
|
||||||
|
|
||||||
|
return $this->generateResponse($response, $jsonResponse, 200);
|
||||||
|
} catch (\Exception $exception) {
|
||||||
|
return $this->generateErrorResponse($response, $exception, 400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Request $request
|
||||||
|
* @param Response $response
|
||||||
|
* @param array $args
|
||||||
|
* @param CreateRelationshipParams $params
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function createRelationship(
|
||||||
|
Request $request,
|
||||||
|
Response $response,
|
||||||
|
array $args,
|
||||||
|
CreateRelationshipParams $params
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
$jsonResponse = $this->relationshipService->createRelationship($params);
|
||||||
|
|
||||||
|
return $this->generateResponse($response, $jsonResponse, 201);
|
||||||
|
} catch (\Exception $exception) {
|
||||||
|
return $this->generateErrorResponse($response, $exception, 400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Request $request
|
||||||
|
* @param Response $response
|
||||||
|
* @param array $args
|
||||||
|
* @param CreateRelationshipByLinkParams $params
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function createRelationshipByLink(
|
||||||
|
Request $request,
|
||||||
|
Response $response,
|
||||||
|
array $args,
|
||||||
|
CreateRelationshipByLinkParams $params
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
$jsonResponse = $this->relationshipService->createRelationshipByLink($params);
|
||||||
|
|
||||||
|
return $this->generateResponse($response, $jsonResponse, 201);
|
||||||
|
} catch (\Exception $exception) {
|
||||||
|
return $this->generateErrorResponse($response, $exception, 400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Request $request
|
||||||
|
* @param Response $response
|
||||||
|
* @param array $args
|
||||||
|
* @param DeleteRelationshipParams $params
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function deleteRelationship(
|
||||||
|
Request $request,
|
||||||
|
Response $response,
|
||||||
|
array $args,
|
||||||
|
DeleteRelationshipParams $params
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
$jsonResponse = $this->relationshipService->deleteRelationship($params);
|
||||||
|
|
||||||
|
return $this->generateResponse($response, $jsonResponse, 200);
|
||||||
|
} catch (\Exception $exception) {
|
||||||
|
return $this->generateErrorResponse($response, $exception, 400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
89
Api/V8/Controller/UserController.php
Normal file
89
Api/V8/Controller/UserController.php
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* SugarCRM Community Edition is a customer relationship management program developed by
|
||||||
|
* SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
|
||||||
|
*
|
||||||
|
* SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd.
|
||||||
|
* Copyright (C) 2011 - 2018 SalesAgility Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU Affero General Public License version 3 as published by the
|
||||||
|
* Free Software Foundation with the addition of the following permission added
|
||||||
|
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
||||||
|
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
||||||
|
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License along with
|
||||||
|
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
||||||
|
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
||||||
|
*
|
||||||
|
* The interactive user interfaces in modified source and object code versions
|
||||||
|
* of this program must display Appropriate Legal Notices, as required under
|
||||||
|
* Section 5 of the GNU Affero General Public License version 3.
|
||||||
|
*
|
||||||
|
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||||
|
* these Appropriate Legal Notices must retain the display of the "Powered by
|
||||||
|
* SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
|
||||||
|
* reasonably feasible for technical reasons, the Appropriate Legal Notices must
|
||||||
|
* display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM".
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Api\V8\Controller;
|
||||||
|
|
||||||
|
if (!defined('sugarEntry') || !sugarEntry) {
|
||||||
|
die('Not A Valid Entry Point');
|
||||||
|
}
|
||||||
|
|
||||||
|
use Api\V8\Service\UserService;
|
||||||
|
use Exception;
|
||||||
|
use Slim\Http\Request;
|
||||||
|
use Slim\Http\Response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UserController
|
||||||
|
*
|
||||||
|
* @author gyula
|
||||||
|
*/
|
||||||
|
class UserController extends BaseController
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var UserService
|
||||||
|
*/
|
||||||
|
protected $userService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param UserService $userService
|
||||||
|
*/
|
||||||
|
public function __construct(UserService $userService)
|
||||||
|
{
|
||||||
|
$this->userService = $userService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @param Response $response
|
||||||
|
* @param array $args
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function getCurrentUser(Request $request, Response $response, array $args)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$jsonResponse = $this->userService->getCurrentUser($request);
|
||||||
|
return $this->generateResponse($response, $jsonResponse, 200);
|
||||||
|
} catch (Exception $exception) {
|
||||||
|
return $this->generateErrorResponse($response, $exception, 400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
94
Api/V8/Controller/UserPreferencesController.php
Normal file
94
Api/V8/Controller/UserPreferencesController.php
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* SugarCRM Community Edition is a customer relationship management program developed by
|
||||||
|
* SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
|
||||||
|
*
|
||||||
|
* SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd.
|
||||||
|
* Copyright (C) 2011 - 2018 SalesAgility Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU Affero General Public License version 3 as published by the
|
||||||
|
* Free Software Foundation with the addition of the following permission added
|
||||||
|
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
||||||
|
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
||||||
|
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License along with
|
||||||
|
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
||||||
|
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
||||||
|
*
|
||||||
|
* The interactive user interfaces in modified source and object code versions
|
||||||
|
* of this program must display Appropriate Legal Notices, as required under
|
||||||
|
* Section 5 of the GNU Affero General Public License version 3.
|
||||||
|
*
|
||||||
|
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||||
|
* these Appropriate Legal Notices must retain the display of the "Powered by
|
||||||
|
* SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
|
||||||
|
* reasonably feasible for technical reasons, the Appropriate Legal Notices must
|
||||||
|
* display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM".
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Api\V8\Controller;
|
||||||
|
|
||||||
|
if (!defined('sugarEntry') || !sugarEntry) {
|
||||||
|
die('Not A Valid Entry Point');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
use Api\V8\Param\GetUserPreferencesParams;
|
||||||
|
use Api\V8\Service\UserPreferencesService;
|
||||||
|
use Exception;
|
||||||
|
use Slim\Http\Request;
|
||||||
|
use Slim\Http\Response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UserPreferencesController
|
||||||
|
*
|
||||||
|
* @author gyula
|
||||||
|
*/
|
||||||
|
class UserPreferencesController extends BaseController
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var UserPreferencesService
|
||||||
|
*/
|
||||||
|
protected $userPreferencesService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param UserPreferencesService $userPreferencesService
|
||||||
|
*/
|
||||||
|
public function __construct(UserPreferencesService $userPreferencesService)
|
||||||
|
{
|
||||||
|
$this->userPreferencesService = $userPreferencesService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @param Response $response
|
||||||
|
* @param array $args
|
||||||
|
* @param GetUserPreferencesParams $params
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function getUserPreferences(Request $request, Response $response, array $args, GetUserPreferencesParams $params)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$jsonResponse = $this->userPreferencesService->getUserPreferences($params);
|
||||||
|
|
||||||
|
return $this->generateResponse($response, $jsonResponse, 200);
|
||||||
|
} catch (Exception $exception) {
|
||||||
|
return $this->generateErrorResponse($response, $exception, 400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
40
Api/V8/Factory/ParamsMiddlewareFactory.php
Normal file
40
Api/V8/Factory/ParamsMiddlewareFactory.php
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\Factory;
|
||||||
|
|
||||||
|
use Api\V8\Middleware\ParamsMiddleware;
|
||||||
|
use Psr\Container\ContainerInterface as Container;
|
||||||
|
use Slim\Http\Request;
|
||||||
|
use Slim\Http\Response;
|
||||||
|
use Api\V8\BeanDecorator\BeanManager;
|
||||||
|
|
||||||
|
class ParamsMiddlewareFactory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Container
|
||||||
|
*/
|
||||||
|
protected $container;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Container $container
|
||||||
|
*/
|
||||||
|
public function __construct(Container $container)
|
||||||
|
{
|
||||||
|
$this->container = $container;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $containerId
|
||||||
|
*
|
||||||
|
* @return callable
|
||||||
|
*/
|
||||||
|
public function bind($containerId)
|
||||||
|
{
|
||||||
|
$container = $this->container;
|
||||||
|
|
||||||
|
return function (Request $request, Response $response, callable $next) use ($containerId, $container) {
|
||||||
|
$paramMiddleware = new ParamsMiddleware($container->get($containerId), $container->get(BeanManager::class));
|
||||||
|
|
||||||
|
return $paramMiddleware($request, $response, $next);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
66
Api/V8/Factory/ValidatorFactory.php
Normal file
66
Api/V8/Factory/ValidatorFactory.php
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\Factory;
|
||||||
|
|
||||||
|
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||||
|
|
||||||
|
class ValidatorFactory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var ValidatorInterface
|
||||||
|
*/
|
||||||
|
protected $validator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ValidatorInterface $validator
|
||||||
|
*/
|
||||||
|
public function __construct(ValidatorInterface $validator)
|
||||||
|
{
|
||||||
|
$this->validator = $validator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \Symfony\Component\Validator\Constraint[] $constraints
|
||||||
|
* @param boolean $allowNull
|
||||||
|
*
|
||||||
|
* @return \Closure
|
||||||
|
*/
|
||||||
|
public function createClosure(array $constraints, $allowNull = false)
|
||||||
|
{
|
||||||
|
return function ($value) use ($constraints, $allowNull) {
|
||||||
|
if ($allowNull && $value === null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$violations = $this->validator->validate($value, $constraints);
|
||||||
|
|
||||||
|
return !$violations->count();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \Symfony\Component\Validator\Constraint[] $constraints
|
||||||
|
* @param boolean $allowNull
|
||||||
|
*
|
||||||
|
* @return \Closure
|
||||||
|
*/
|
||||||
|
public function createClosureForIterator(array $constraints, $allowNull = false)
|
||||||
|
{
|
||||||
|
return function ($value) use ($constraints, $allowNull) {
|
||||||
|
if ($allowNull && $value === null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_array($value) && !$value instanceof \Iterator) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($value as $v) {
|
||||||
|
if ($this->validator->validate($v, $constraints)->count()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
153
Api/V8/Helper/ModuleListProvider.php
Normal file
153
Api/V8/Helper/ModuleListProvider.php
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* SugarCRM Community Edition is a customer relationship management program developed by
|
||||||
|
* SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
|
||||||
|
*
|
||||||
|
* SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd.
|
||||||
|
* Copyright (C) 2011 - 2018 SalesAgility Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU Affero General Public License version 3 as published by the
|
||||||
|
* Free Software Foundation with the addition of the following permission added
|
||||||
|
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
||||||
|
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
||||||
|
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License along with
|
||||||
|
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
||||||
|
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
||||||
|
*
|
||||||
|
* The interactive user interfaces in modified source and object code versions
|
||||||
|
* of this program must display Appropriate Legal Notices, as required under
|
||||||
|
* Section 5 of the GNU Affero General Public License version 3.
|
||||||
|
*
|
||||||
|
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||||
|
* these Appropriate Legal Notices must retain the display of the "Powered by
|
||||||
|
* SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
|
||||||
|
* reasonably feasible for technical reasons, the Appropriate Legal Notices must
|
||||||
|
* display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM".
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Api\V8\Helper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ModuleListProvider
|
||||||
|
* @package Api\V8\Helper
|
||||||
|
*/
|
||||||
|
class ModuleListProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getModuleList()
|
||||||
|
{
|
||||||
|
global $current_user;
|
||||||
|
|
||||||
|
$modules = query_module_access_list($current_user);
|
||||||
|
\ACLController::filterModuleList($modules, false);
|
||||||
|
$modules = $this->removeInvisibleModules($modules);
|
||||||
|
$modules = $this->markACLAccess($modules);
|
||||||
|
$modules = $this->addModuleLabels($modules);
|
||||||
|
|
||||||
|
return $modules;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $modules
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
private function addModuleLabels($modules)
|
||||||
|
{
|
||||||
|
global $app_list_strings;
|
||||||
|
|
||||||
|
foreach ($modules as $moduleName => &$moduleData) {
|
||||||
|
$moduleData['label'] = $app_list_strings['moduleList'][$moduleName];
|
||||||
|
}
|
||||||
|
return $modules;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $modules
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function removeInvisibleModules($modules)
|
||||||
|
{
|
||||||
|
global $modInvisList;
|
||||||
|
|
||||||
|
foreach ($modInvisList as $invis) {
|
||||||
|
unset($modules[$invis]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $modules;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $modules
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
private function markACLAccess($modules)
|
||||||
|
{
|
||||||
|
global $current_user;
|
||||||
|
|
||||||
|
$modulesWithAccess = [];
|
||||||
|
$moduleActions = \ACLAction::getUserActions($current_user->id, true);
|
||||||
|
|
||||||
|
foreach ($moduleActions as $moduleName => $value) {
|
||||||
|
if (!in_array($moduleName, $modules, true)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$access = $this->buildAccessArray($moduleName, $value['module']);
|
||||||
|
if (!count($access)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$modulesWithAccess[$moduleName] = [
|
||||||
|
'label' => '',
|
||||||
|
'access' => array_unique($access)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $modulesWithAccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $actions
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function buildAccessArray($moduleName, $actions)
|
||||||
|
{
|
||||||
|
$access = [];
|
||||||
|
foreach ($actions as $actionName => $record) {
|
||||||
|
if (!$this->hasACL($record['aclaccess'], $moduleName)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$access[] = $actionName;
|
||||||
|
}
|
||||||
|
return $access;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $level
|
||||||
|
* @param $module
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function hasACL($level, $module)
|
||||||
|
{
|
||||||
|
global $current_user;
|
||||||
|
|
||||||
|
if (is_admin(is_admin($current_user))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $level >= ACL_ALLOW_ENABLED;
|
||||||
|
}
|
||||||
|
}
|
21
Api/V8/Helper/VarDefHelper.php
Normal file
21
Api/V8/Helper/VarDefHelper.php
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\Helper;
|
||||||
|
class VarDefHelper
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param \SugarBean $bean
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAllRelationships(\SugarBean $bean)
|
||||||
|
{
|
||||||
|
$relations = [];
|
||||||
|
$linkedFields = $bean->get_linked_fields();
|
||||||
|
foreach ($linkedFields as $relation => $varDef) {
|
||||||
|
if (isset($varDef['module']) && $bean->load_relationship($relation)) {
|
||||||
|
$relations[$relation] = $varDef['module'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $relations;
|
||||||
|
}
|
||||||
|
}
|
49
Api/V8/JsonApi/Helper/AttributeObjectHelper.php
Normal file
49
Api/V8/JsonApi/Helper/AttributeObjectHelper.php
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\JsonApi\Helper;
|
||||||
|
|
||||||
|
use Api\V8\BeanDecorator\BeanManager;
|
||||||
|
use Api\V8\JsonApi\Response\AttributeResponse;
|
||||||
|
|
||||||
|
class AttributeObjectHelper
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var BeanManager
|
||||||
|
*/
|
||||||
|
protected $beanManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param BeanManager $beanManager
|
||||||
|
*/
|
||||||
|
public function __construct(BeanManager $beanManager)
|
||||||
|
{
|
||||||
|
$this->beanManager = $beanManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \SugarBean $bean
|
||||||
|
* @param array|null $fields
|
||||||
|
*
|
||||||
|
* @return AttributeResponse
|
||||||
|
*/
|
||||||
|
public function getAttributes(\SugarBean $bean, $fields = null)
|
||||||
|
{
|
||||||
|
$bean->fixUpFormatting();
|
||||||
|
|
||||||
|
// using the ISO 8601 format for dates
|
||||||
|
$attributes = array_map(function ($value) {
|
||||||
|
return is_string($value)
|
||||||
|
? (\DateTime::createFromFormat('Y-m-d H:i:s', $value)
|
||||||
|
? date(\DateTime::ATOM, strtotime($value))
|
||||||
|
: $value)
|
||||||
|
: $value;
|
||||||
|
}, $bean->toArray());
|
||||||
|
|
||||||
|
if ($fields !== null) {
|
||||||
|
$attributes = array_intersect_key($attributes, array_flip($fields));
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($attributes['id']);
|
||||||
|
|
||||||
|
return new AttributeResponse($attributes);
|
||||||
|
}
|
||||||
|
}
|
60
Api/V8/JsonApi/Helper/PaginationObjectHelper.php
Normal file
60
Api/V8/JsonApi/Helper/PaginationObjectHelper.php
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\JsonApi\Helper;
|
||||||
|
|
||||||
|
use Api\V8\JsonApi\Response\MetaResponse;
|
||||||
|
use Api\V8\JsonApi\Response\PaginationResponse;
|
||||||
|
use Slim\Http\Request;
|
||||||
|
|
||||||
|
class PaginationObjectHelper
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param integer $totalPages
|
||||||
|
* @param integer $numOfRecords
|
||||||
|
*
|
||||||
|
* @return MetaResponse
|
||||||
|
*/
|
||||||
|
public function getPaginationMeta($totalPages, $numOfRecords)
|
||||||
|
{
|
||||||
|
return new MetaResponse(
|
||||||
|
['total-pages' => $totalPages, 'records-on-this-page' => $numOfRecords]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Request $request
|
||||||
|
* @param integer $totalPages
|
||||||
|
* @param integer $number
|
||||||
|
*
|
||||||
|
* @return PaginationResponse
|
||||||
|
*/
|
||||||
|
public function getPaginationLinks(Request $request, $totalPages, $number)
|
||||||
|
{
|
||||||
|
$pagination = new PaginationResponse();
|
||||||
|
|
||||||
|
if ($number > 1) {
|
||||||
|
$pagination->setFirst($this->createPaginationLink($request, 1));
|
||||||
|
$pagination->setPrev($this->createPaginationLink($request, $number - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($number + 1 <= $totalPages) {
|
||||||
|
$pagination->setNext($this->createPaginationLink($request, $number + 1));
|
||||||
|
$pagination->setLast($this->createPaginationLink($request, $totalPages));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $pagination;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Request $request
|
||||||
|
* @param integer $number
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function createPaginationLink(Request $request, $number)
|
||||||
|
{
|
||||||
|
$queryParams = $request->getQueryParams();
|
||||||
|
$queryParams['page']['number'] = $number;
|
||||||
|
|
||||||
|
return sprintf('%s?%s', $request->getUri()->getPath(), urldecode(http_build_query($queryParams)));
|
||||||
|
}
|
||||||
|
}
|
46
Api/V8/JsonApi/Helper/RelationshipObjectHelper.php
Normal file
46
Api/V8/JsonApi/Helper/RelationshipObjectHelper.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\JsonApi\Helper;
|
||||||
|
|
||||||
|
use Api\V8\Helper\VarDefHelper;
|
||||||
|
use Api\V8\JsonApi\Response\LinksResponse;
|
||||||
|
use Api\V8\JsonApi\Response\RelationshipResponse;
|
||||||
|
|
||||||
|
class RelationshipObjectHelper
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var VarDefHelper
|
||||||
|
*/
|
||||||
|
protected $varDefHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param VarDefHelper $varDefHelper
|
||||||
|
*/
|
||||||
|
public function __construct(VarDefHelper $varDefHelper)
|
||||||
|
{
|
||||||
|
$this->varDefHelper = $varDefHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \SugarBean $bean
|
||||||
|
* @param string $uriPath
|
||||||
|
*
|
||||||
|
* @return RelationshipResponse
|
||||||
|
*/
|
||||||
|
public function getRelationships(\SugarBean $bean, $uriPath)
|
||||||
|
{
|
||||||
|
$relationships = $this->varDefHelper->getAllRelationships($bean);
|
||||||
|
asort($relationships);
|
||||||
|
|
||||||
|
$relationshipsLinks = [];
|
||||||
|
foreach (array_unique($relationships) as $relationshipName => $module) {
|
||||||
|
$linkResponse = new LinksResponse();
|
||||||
|
$linkResponse->setRelated(
|
||||||
|
sprintf('%s/%s/%s', $uriPath, 'relationships', $relationshipName)
|
||||||
|
);
|
||||||
|
|
||||||
|
$relationshipsLinks[$module] = ['links' => $linkResponse];
|
||||||
|
}
|
||||||
|
|
||||||
|
return new RelationshipResponse($relationshipsLinks);
|
||||||
|
}
|
||||||
|
}
|
108
Api/V8/JsonApi/Repository/Filter.php
Normal file
108
Api/V8/JsonApi/Repository/Filter.php
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\JsonApi\Repository;
|
||||||
|
|
||||||
|
class Filter
|
||||||
|
{
|
||||||
|
// operators so far
|
||||||
|
const OP_EQ = '=';
|
||||||
|
const OP_NEQ = '<>';
|
||||||
|
const OP_GT = '>';
|
||||||
|
const OP_GTE = '>=';
|
||||||
|
const OP_LT = '<';
|
||||||
|
const OP_LTE = '<=';
|
||||||
|
|
||||||
|
const OP_AND = 'AND';
|
||||||
|
const OP_OR = 'OR';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \DBManager
|
||||||
|
*/
|
||||||
|
private $db;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \DBManager $db
|
||||||
|
*/
|
||||||
|
public function __construct(\DBManager $db)
|
||||||
|
{
|
||||||
|
$this->db = $db;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \SugarBean $bean
|
||||||
|
* @param array $params
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
* @throws \InvalidArgumentException When field is not found or is not an array.
|
||||||
|
*/
|
||||||
|
public function parseWhere(\SugarBean $bean, array $params)
|
||||||
|
{
|
||||||
|
$operator = self::OP_AND;
|
||||||
|
if (isset($params['operator'])) {
|
||||||
|
$this->checkOperator($params['operator']);
|
||||||
|
$operator = strtoupper($params['operator']);
|
||||||
|
unset($params['operator']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$params = $this->addDeletedParameter($params);
|
||||||
|
|
||||||
|
$where = [];
|
||||||
|
foreach ($params as $field => $expr) {
|
||||||
|
if (empty($bean->field_defs[$field])) {
|
||||||
|
throw new \InvalidArgumentException(sprintf(
|
||||||
|
'Filter field %s in %s module is not found',
|
||||||
|
$field,
|
||||||
|
$bean->getObjectName()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_array($expr)) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('Filter field %s must be an array', $field));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($expr as $op => $value) {
|
||||||
|
$this->checkOperator($op);
|
||||||
|
$where[] = sprintf(
|
||||||
|
'%s.%s %s %s',
|
||||||
|
$bean->getTableName(),
|
||||||
|
$field,
|
||||||
|
constant(sprintf('%s::OP_%s', self::class, strtoupper($op))),
|
||||||
|
$this->db->quoted($value)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode(sprintf(' %s ', $operator), $where);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only return deleted records if they were explicitly requested
|
||||||
|
*
|
||||||
|
* @param array $params
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function addDeletedParameter(array $params)
|
||||||
|
{
|
||||||
|
if (!array_key_exists('deleted', $params)) {
|
||||||
|
$params['deleted'] = [
|
||||||
|
'eq' => 0
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $params;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $op
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException When the given operator is invalid.
|
||||||
|
*/
|
||||||
|
private function checkOperator($op)
|
||||||
|
{
|
||||||
|
$operator = sprintf('%s::OP_%s', self::class, strtoupper($op));
|
||||||
|
if (!defined($operator)) {
|
||||||
|
throw new \InvalidArgumentException(
|
||||||
|
sprintf('Filter operator %s is invalid', $op)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
36
Api/V8/JsonApi/Repository/Sort.php
Normal file
36
Api/V8/JsonApi/Repository/Sort.php
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\JsonApi\Repository;
|
||||||
|
|
||||||
|
class Sort
|
||||||
|
{
|
||||||
|
const ORDER_BY_ASC = 'ASC';
|
||||||
|
const ORDER_BY_DESC = 'DESC';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We don't support multiple sorting. for now.
|
||||||
|
*
|
||||||
|
* @param \SugarBean $bean
|
||||||
|
* @param string $value
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
* @throws \InvalidArgumentException When sort field is not found in the bean.
|
||||||
|
*/
|
||||||
|
public function parseOrderBy(\SugarBean $bean, $value)
|
||||||
|
{
|
||||||
|
$orderBy = self::ORDER_BY_ASC;
|
||||||
|
if (strpos($value, '-') === 0) {
|
||||||
|
$orderBy = self::ORDER_BY_DESC;
|
||||||
|
$value = ltrim($value, '-');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($bean->field_defs[$value])) {
|
||||||
|
throw new \InvalidArgumentException(sprintf(
|
||||||
|
'Sort field %s in %s module is not found',
|
||||||
|
$value,
|
||||||
|
$bean->getObjectName()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sprintf('%s %s', $value, $orderBy);
|
||||||
|
}
|
||||||
|
}
|
29
Api/V8/JsonApi/Response/AttributeResponse.php
Normal file
29
Api/V8/JsonApi/Response/AttributeResponse.php
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\JsonApi\Response;
|
||||||
|
|
||||||
|
class AttributeResponse extends MetaResponse
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*
|
||||||
|
* @see http://jsonapi.org/format/#document-resource-object-attributes
|
||||||
|
*/
|
||||||
|
private static $forbiddenKeys = ['relationships', 'links'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array|\stdClass $properties
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException When attribute object includes forbidden keys.
|
||||||
|
*/
|
||||||
|
public function __construct($properties = [])
|
||||||
|
{
|
||||||
|
parent::__construct($properties);
|
||||||
|
|
||||||
|
$invalidKeys = array_intersect_key($properties, array_flip(self::$forbiddenKeys));
|
||||||
|
if ($invalidKeys) {
|
||||||
|
throw new \InvalidArgumentException(
|
||||||
|
'Attribute object must not contain these keys: ' . implode(', ', array_keys($invalidKeys))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
120
Api/V8/JsonApi/Response/DataResponse.php
Normal file
120
Api/V8/JsonApi/Response/DataResponse.php
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\JsonApi\Response;
|
||||||
|
|
||||||
|
class DataResponse implements \JsonSerializable
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var AttributeResponse
|
||||||
|
*/
|
||||||
|
private $attributes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var RelationshipResponse
|
||||||
|
*/
|
||||||
|
private $relationships;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var LinksResponse
|
||||||
|
*/
|
||||||
|
private $links;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $type
|
||||||
|
* @param string $id
|
||||||
|
*/
|
||||||
|
public function __construct($type, $id)
|
||||||
|
{
|
||||||
|
$this->type = $type;
|
||||||
|
$this->id = $id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getType()
|
||||||
|
{
|
||||||
|
return $this->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getId()
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AttributeResponse
|
||||||
|
*/
|
||||||
|
public function getAttributes()
|
||||||
|
{
|
||||||
|
return $this->attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param AttributeResponse $attributes
|
||||||
|
*/
|
||||||
|
public function setAttributes(AttributeResponse $attributes)
|
||||||
|
{
|
||||||
|
$this->attributes = $attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return RelationshipResponse
|
||||||
|
*/
|
||||||
|
public function getRelationships()
|
||||||
|
{
|
||||||
|
return $this->relationships;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param RelationshipResponse $relationships
|
||||||
|
*/
|
||||||
|
public function setRelationships(RelationshipResponse $relationships)
|
||||||
|
{
|
||||||
|
$this->relationships = $relationships;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return LinksResponse
|
||||||
|
*/
|
||||||
|
public function getLinks()
|
||||||
|
{
|
||||||
|
return $this->links;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param LinksResponse $links
|
||||||
|
*/
|
||||||
|
public function setLinks(LinksResponse $links)
|
||||||
|
{
|
||||||
|
$this->links = $links;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function jsonSerialize()
|
||||||
|
{
|
||||||
|
$response = [
|
||||||
|
'type' => $this->getType(),
|
||||||
|
'id' => $this->getId(),
|
||||||
|
'attributes' => $this->getAttributes(),
|
||||||
|
'relationships' => $this->getRelationships(),
|
||||||
|
'links' => $this->getLinks()
|
||||||
|
];
|
||||||
|
|
||||||
|
return array_filter($response);
|
||||||
|
}
|
||||||
|
}
|
92
Api/V8/JsonApi/Response/DocumentResponse.php
Normal file
92
Api/V8/JsonApi/Response/DocumentResponse.php
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\JsonApi\Response;
|
||||||
|
|
||||||
|
class DocumentResponse implements \JsonSerializable
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array|DataResponse|DataResponse[]
|
||||||
|
*/
|
||||||
|
private $data = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var MetaResponse
|
||||||
|
*/
|
||||||
|
private $meta;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var LinksResponse
|
||||||
|
*/
|
||||||
|
private $links;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array|DataResponse|DataResponse[]
|
||||||
|
*/
|
||||||
|
public function getData()
|
||||||
|
{
|
||||||
|
return $this->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array|DataResponse|DataResponse[] $data
|
||||||
|
*/
|
||||||
|
public function setData($data)
|
||||||
|
{
|
||||||
|
$this->data = $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return MetaResponse
|
||||||
|
*/
|
||||||
|
public function getMeta()
|
||||||
|
{
|
||||||
|
return $this->meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param MetaResponse $meta
|
||||||
|
*/
|
||||||
|
public function setMeta(MetaResponse $meta)
|
||||||
|
{
|
||||||
|
$this->meta = $meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return LinksResponse
|
||||||
|
*/
|
||||||
|
public function getLinks()
|
||||||
|
{
|
||||||
|
return $this->links;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param LinksResponse $links
|
||||||
|
*/
|
||||||
|
public function setLinks(LinksResponse $links)
|
||||||
|
{
|
||||||
|
$this->links = $links;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function jsonSerialize()
|
||||||
|
{
|
||||||
|
$response = [
|
||||||
|
'data' => $this->getData()
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!$this->getData() && !$this->getMeta()) {
|
||||||
|
$this->setMeta(new MetaResponse(['message' => 'Request was successful, but there is no result']));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->getMeta()) {
|
||||||
|
$response = ['meta' => $this->getMeta()] + $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->getLinks()) {
|
||||||
|
$response['links'] = $this->getLinks();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
}
|
158
Api/V8/JsonApi/Response/ErrorResponse.php
Normal file
158
Api/V8/JsonApi/Response/ErrorResponse.php
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\JsonApi\Response;
|
||||||
|
|
||||||
|
use Api\Core\Config\ApiConfig;
|
||||||
|
use Exception;
|
||||||
|
use JsonSerializable;
|
||||||
|
|
||||||
|
class ErrorResponse implements JsonSerializable
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
private $status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $title;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $detail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @var Exception
|
||||||
|
*/
|
||||||
|
private $exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In debug mode, ErrorResponse should shows full description about occurred exceptions.
|
||||||
|
*
|
||||||
|
* @todo documentation needs to be updated at this point (about debug exceptions)
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
protected $debugExceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param bool|null $debugExceptions optional - using ApiConfig setting by default
|
||||||
|
*/
|
||||||
|
public function __construct($debugExceptions = null)
|
||||||
|
{
|
||||||
|
$this->debugExceptions =
|
||||||
|
null === $debugExceptions ?
|
||||||
|
ApiConfig::getDebugExceptions() :
|
||||||
|
$debugExceptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
|
public function getStatus()
|
||||||
|
{
|
||||||
|
return $this->status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param integer $status
|
||||||
|
*/
|
||||||
|
public function setStatus($status)
|
||||||
|
{
|
||||||
|
$this->status = $status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getTitle()
|
||||||
|
{
|
||||||
|
return $this->title;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $title
|
||||||
|
*/
|
||||||
|
public function setTitle($title)
|
||||||
|
{
|
||||||
|
$this->title = $title;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getDetail()
|
||||||
|
{
|
||||||
|
return $this->detail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $detail
|
||||||
|
*/
|
||||||
|
public function setDetail($detail)
|
||||||
|
{
|
||||||
|
$this->detail = $detail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param Exception $exception
|
||||||
|
*/
|
||||||
|
public function setException(Exception $exception)
|
||||||
|
{
|
||||||
|
$this->exception = $exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param Exception $exception
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected static function exceptionToArray(Exception $exception)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'code' => $exception->getCode(),
|
||||||
|
'file' => $exception->getFile(),
|
||||||
|
'line' => $exception->getLine(),
|
||||||
|
'message' => $exception->getMessage(),
|
||||||
|
'previous' => self::exceptionToArray($exception->getPrevious()),
|
||||||
|
'trace' => $exception->getTrace(),
|
||||||
|
'traceAsString' => $exception->getTraceAsString(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getExceptionArray()
|
||||||
|
{
|
||||||
|
if (!$this->exception) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return self::exceptionToArray($this->exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function jsonSerialize()
|
||||||
|
{
|
||||||
|
$ret = [
|
||||||
|
'errors' => [
|
||||||
|
'status' => $this->getStatus(),
|
||||||
|
'title' => $this->getTitle(),
|
||||||
|
'detail' => $this->getDetail(),
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
// do it only in debug mode!!!!
|
||||||
|
if ($this->debugExceptions) {
|
||||||
|
$ret['errors']['exception'] = $this->getExceptionArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
}
|
60
Api/V8/JsonApi/Response/LinksResponse.php
Normal file
60
Api/V8/JsonApi/Response/LinksResponse.php
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\JsonApi\Response;
|
||||||
|
|
||||||
|
class LinksResponse implements \JsonSerializable
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $self;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string|array
|
||||||
|
*/
|
||||||
|
private $related;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getSelf()
|
||||||
|
{
|
||||||
|
return $this->self;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $self
|
||||||
|
*/
|
||||||
|
public function setSelf($self)
|
||||||
|
{
|
||||||
|
$this->self = $self;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array|string
|
||||||
|
*/
|
||||||
|
public function getRelated()
|
||||||
|
{
|
||||||
|
return $this->related;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array|string $related
|
||||||
|
*/
|
||||||
|
public function setRelated($related)
|
||||||
|
{
|
||||||
|
$this->related = $related;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function jsonSerialize()
|
||||||
|
{
|
||||||
|
$response = [
|
||||||
|
'self' => $this->getSelf(),
|
||||||
|
'related' => $this->getRelated()
|
||||||
|
];
|
||||||
|
|
||||||
|
return array_filter($response);
|
||||||
|
}
|
||||||
|
}
|
55
Api/V8/JsonApi/Response/MetaResponse.php
Normal file
55
Api/V8/JsonApi/Response/MetaResponse.php
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\JsonApi\Response;
|
||||||
|
|
||||||
|
class MetaResponse implements \JsonSerializable
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $properties = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Meta object can contain any properties.
|
||||||
|
*
|
||||||
|
* @param array|\stdClass $properties
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException When bean is not found with the given id.
|
||||||
|
*/
|
||||||
|
public function __construct($properties = [])
|
||||||
|
{
|
||||||
|
if (!is_array($properties) && !$properties instanceof \stdClass) {
|
||||||
|
throw new \InvalidArgumentException('The properties must be an array or sdtClass');
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($properties as $property => $value) {
|
||||||
|
$this->$property = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $name
|
||||||
|
*
|
||||||
|
* @return mixed|null
|
||||||
|
*/
|
||||||
|
public function __get($name)
|
||||||
|
{
|
||||||
|
return isset($this->properties[$name]) ? $this->properties[$name] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $name
|
||||||
|
* @param mixed $value
|
||||||
|
*/
|
||||||
|
public function __set($name, $value)
|
||||||
|
{
|
||||||
|
$this->properties[$name] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function jsonSerialize()
|
||||||
|
{
|
||||||
|
return $this->properties;
|
||||||
|
}
|
||||||
|
}
|
102
Api/V8/JsonApi/Response/PaginationResponse.php
Normal file
102
Api/V8/JsonApi/Response/PaginationResponse.php
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\JsonApi\Response;
|
||||||
|
|
||||||
|
class PaginationResponse extends LinksResponse
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $first;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $prev;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $next;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $last;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getFirst()
|
||||||
|
{
|
||||||
|
return $this->first;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $first
|
||||||
|
*/
|
||||||
|
public function setFirst($first)
|
||||||
|
{
|
||||||
|
$this->first = $first;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getPrev()
|
||||||
|
{
|
||||||
|
return $this->prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $prev
|
||||||
|
*/
|
||||||
|
public function setPrev($prev)
|
||||||
|
{
|
||||||
|
$this->prev = $prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getNext()
|
||||||
|
{
|
||||||
|
return $this->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $next
|
||||||
|
*/
|
||||||
|
public function setNext($next)
|
||||||
|
{
|
||||||
|
$this->next = $next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getLast()
|
||||||
|
{
|
||||||
|
return $this->last;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $last
|
||||||
|
*/
|
||||||
|
public function setLast($last)
|
||||||
|
{
|
||||||
|
$this->last = $last;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function jsonSerialize()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'first' => $this->getFirst(),
|
||||||
|
'prev' => $this->getPrev(),
|
||||||
|
'next' => $this->getNext(),
|
||||||
|
'last' => $this->getLast()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
6
Api/V8/JsonApi/Response/RelationshipResponse.php
Normal file
6
Api/V8/JsonApi/Response/RelationshipResponse.php
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\JsonApi\Response;
|
||||||
|
|
||||||
|
class RelationshipResponse extends MetaResponse
|
||||||
|
{
|
||||||
|
}
|
109
Api/V8/Middleware/ParamsMiddleware.php
Normal file
109
Api/V8/Middleware/ParamsMiddleware.php
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\Middleware;
|
||||||
|
|
||||||
|
use Api\V8\JsonApi\Response\ErrorResponse;
|
||||||
|
use Api\V8\Param\BaseParam;
|
||||||
|
use Exception;
|
||||||
|
use LoggerManager;
|
||||||
|
use Slim\Http\Request;
|
||||||
|
use Slim\Http\Response;
|
||||||
|
use Api\V8\BeanDecorator\BeanManager;
|
||||||
|
|
||||||
|
class ParamsMiddleware
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var BaseParam
|
||||||
|
*/
|
||||||
|
private $params;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var BeanManager
|
||||||
|
*/
|
||||||
|
private $beanManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ParamsMiddleware constructor.
|
||||||
|
* @param BaseParam $params
|
||||||
|
* @param BeanManager $beanManager
|
||||||
|
*/
|
||||||
|
public function __construct(BaseParam $params, BeanManager $beanManager)
|
||||||
|
{
|
||||||
|
$this->params = $params;
|
||||||
|
$this->beanManager = $beanManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Request $request
|
||||||
|
* @param Response $httpResponse
|
||||||
|
* @param callable $next
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function __invoke(Request $request, Response $httpResponse, callable $next)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$this->setCurrentUserGlobal($request);
|
||||||
|
$parameters = $this->getParameters($request);
|
||||||
|
$this->params->configure($parameters);
|
||||||
|
$request = $request->withAttribute('params', $this->params);
|
||||||
|
} catch (Exception $exception) {
|
||||||
|
$response = new ErrorResponse();
|
||||||
|
$response->setStatus(400);
|
||||||
|
$msg = $exception->getMessage();
|
||||||
|
$dbg = "\nCode:" . $exception->getCode() .
|
||||||
|
"\n" . $exception->getFile() . ':' . $exception->getLine() .
|
||||||
|
"\nTrace:\n" . $exception->getTraceAsString() .
|
||||||
|
"\n";
|
||||||
|
LoggerManager::getLogger()->fatal("API Exception detected:\nMessage was: $msg\nException details:\n$dbg");
|
||||||
|
$response->setDetail($msg);
|
||||||
|
|
||||||
|
return $httpResponse->withJson(
|
||||||
|
$response,
|
||||||
|
400,
|
||||||
|
JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request, $httpResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Request $request
|
||||||
|
*/
|
||||||
|
protected function setCurrentUserGlobal(Request $request)
|
||||||
|
{
|
||||||
|
$oauth2Token = $this->beanManager->newBeanSafe('OAuth2Tokens');
|
||||||
|
|
||||||
|
$oauth2Token->retrieve_by_string_fields(
|
||||||
|
['access_token' => $request->getAttribute('oauth_access_token_id')]
|
||||||
|
);
|
||||||
|
|
||||||
|
$currentUser = $this->beanManager->getBeanSafe('Users', $oauth2Token->assigned_user_id);
|
||||||
|
|
||||||
|
$GLOBALS['current_user'] = $currentUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Request $request
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function getParameters(Request $request)
|
||||||
|
{
|
||||||
|
$routeParams = array_map(
|
||||||
|
function ($value) {
|
||||||
|
return is_bool($value) ? $value : urldecode($value);
|
||||||
|
},
|
||||||
|
$request->getAttribute('route')->getArguments()
|
||||||
|
);
|
||||||
|
|
||||||
|
$queryParams = $request->getQueryParams();
|
||||||
|
$parsedBody = $request->getParsedBody();
|
||||||
|
|
||||||
|
return array_merge(
|
||||||
|
$routeParams,
|
||||||
|
isset($queryParams) ? $queryParams : [],
|
||||||
|
isset($parsedBody) ? $parsedBody : []
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
2
Api/V8/OAuth2/.gitignore
vendored
Normal file
2
Api/V8/OAuth2/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
private.key
|
||||||
|
public.key
|
12
Api/V8/OAuth2/Entity/AccessTokenEntity.php
Normal file
12
Api/V8/OAuth2/Entity/AccessTokenEntity.php
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\OAuth2\Entity;
|
||||||
|
|
||||||
|
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
||||||
|
use League\OAuth2\Server\Entities\Traits\AccessTokenTrait;
|
||||||
|
use League\OAuth2\Server\Entities\Traits\EntityTrait;
|
||||||
|
use League\OAuth2\Server\Entities\Traits\TokenEntityTrait;
|
||||||
|
|
||||||
|
class AccessTokenEntity implements AccessTokenEntityInterface
|
||||||
|
{
|
||||||
|
use AccessTokenTrait, TokenEntityTrait, EntityTrait;
|
||||||
|
}
|
27
Api/V8/OAuth2/Entity/ClientEntity.php
Normal file
27
Api/V8/OAuth2/Entity/ClientEntity.php
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\OAuth2\Entity;
|
||||||
|
|
||||||
|
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||||
|
use League\OAuth2\Server\Entities\Traits\ClientTrait;
|
||||||
|
use League\OAuth2\Server\Entities\Traits\EntityTrait;
|
||||||
|
|
||||||
|
class ClientEntity implements ClientEntityInterface
|
||||||
|
{
|
||||||
|
use EntityTrait, ClientTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $name
|
||||||
|
*/
|
||||||
|
public function setName($name)
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $uri
|
||||||
|
*/
|
||||||
|
public function setRedirectUri($uri)
|
||||||
|
{
|
||||||
|
$this->redirectUri = $uri;
|
||||||
|
}
|
||||||
|
}
|
11
Api/V8/OAuth2/Entity/RefreshTokenEntity.php
Normal file
11
Api/V8/OAuth2/Entity/RefreshTokenEntity.php
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\OAuth2\Entity;
|
||||||
|
|
||||||
|
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
|
||||||
|
use League\OAuth2\Server\Entities\Traits\EntityTrait;
|
||||||
|
use League\OAuth2\Server\Entities\Traits\RefreshTokenTrait;
|
||||||
|
|
||||||
|
class RefreshTokenEntity implements RefreshTokenEntityInterface
|
||||||
|
{
|
||||||
|
use RefreshTokenTrait, EntityTrait;
|
||||||
|
}
|
28
Api/V8/OAuth2/Entity/UserEntity.php
Normal file
28
Api/V8/OAuth2/Entity/UserEntity.php
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\OAuth2\Entity;
|
||||||
|
|
||||||
|
use League\OAuth2\Server\Entities\UserEntityInterface;
|
||||||
|
|
||||||
|
class UserEntity implements UserEntityInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var $userId
|
||||||
|
*/
|
||||||
|
private $userId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $userId
|
||||||
|
*/
|
||||||
|
public function __construct($userId)
|
||||||
|
{
|
||||||
|
$this->userId = $userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function getIdentifier()
|
||||||
|
{
|
||||||
|
return $this->userId;
|
||||||
|
}
|
||||||
|
}
|
124
Api/V8/OAuth2/Repository/AccessTokenRepository.php
Normal file
124
Api/V8/OAuth2/Repository/AccessTokenRepository.php
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Api\V8\OAuth2\Repository;
|
||||||
|
|
||||||
|
use Api\V8\BeanDecorator\BeanManager;
|
||||||
|
use Api\V8\OAuth2\Entity\AccessTokenEntity;
|
||||||
|
use DateTime;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
||||||
|
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||||
|
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||||
|
use OAuth2Tokens;
|
||||||
|
use User;
|
||||||
|
|
||||||
|
class AccessTokenRepository implements AccessTokenRepositoryInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var AccessTokenEntity
|
||||||
|
*/
|
||||||
|
private $accessTokenEntity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var BeanManager
|
||||||
|
*/
|
||||||
|
private $beanManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param AccessTokenEntity $accessTokenEntity
|
||||||
|
* @param BeanManager $beanManager
|
||||||
|
*/
|
||||||
|
public function __construct(AccessTokenEntity $accessTokenEntity, BeanManager $beanManager)
|
||||||
|
{
|
||||||
|
$this->accessTokenEntity = $accessTokenEntity;
|
||||||
|
$this->beanManager = $beanManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function getNewToken(ClientEntityInterface $clientEntity, array $scopes, $userIdentifier = null)
|
||||||
|
{
|
||||||
|
$this->accessTokenEntity->setClient($clientEntity);
|
||||||
|
|
||||||
|
// we keep this even we don't have scopes atm
|
||||||
|
foreach ($scopes as $scope) {
|
||||||
|
$this->accessTokenEntity->addScope($scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->accessTokenEntity->setUserIdentifier($userIdentifier);
|
||||||
|
|
||||||
|
return $this->accessTokenEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function persistNewAccessToken(AccessTokenEntityInterface $accessTokenEntity)
|
||||||
|
{
|
||||||
|
$clientId = $accessTokenEntity->getClient()->getIdentifier();
|
||||||
|
$userId = null;
|
||||||
|
|
||||||
|
/** @var User $user */
|
||||||
|
$client = $this->beanManager->getBeanSafe('OAuth2Clients', $clientId);
|
||||||
|
|
||||||
|
switch ($client->allowed_grant_type) {
|
||||||
|
case 'password':
|
||||||
|
$userId = $accessTokenEntity->getUserIdentifier();
|
||||||
|
break;
|
||||||
|
case 'client_credentials':
|
||||||
|
$userId = $client->assigned_user_id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($userId === null) {
|
||||||
|
throw new InvalidArgumentException('No user found');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var OAuth2Tokens $token */
|
||||||
|
$token = $this->beanManager->newBeanSafe(OAuth2Tokens::class);
|
||||||
|
|
||||||
|
$token->access_token = $accessTokenEntity->getIdentifier();
|
||||||
|
|
||||||
|
$token->access_token_expires = $accessTokenEntity->getExpiryDateTime()->format('Y-m-d H:i:s');
|
||||||
|
|
||||||
|
$token->client = $clientId;
|
||||||
|
|
||||||
|
$token->assigned_user_id = $userId;
|
||||||
|
|
||||||
|
$token->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*
|
||||||
|
* @throws InvalidArgumentException When access token is not found.
|
||||||
|
*/
|
||||||
|
public function revokeAccessToken($tokenId)
|
||||||
|
{
|
||||||
|
$token = $this->beanManager->newBeanSafe(OAuth2Tokens::class);
|
||||||
|
$token->retrieve_by_string_fields(
|
||||||
|
['access_token' => $tokenId]
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($token->id === null) {
|
||||||
|
throw new InvalidArgumentException('Access token is not found for this client');
|
||||||
|
}
|
||||||
|
|
||||||
|
$token->mark_deleted($token->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function isAccessTokenRevoked($tokenId)
|
||||||
|
{
|
||||||
|
/** @var OAuth2Tokens $token */
|
||||||
|
$token = $this->beanManager->newBeanSafe(OAuth2Tokens::class);
|
||||||
|
$token->retrieve_by_string_fields(
|
||||||
|
['access_token' => $tokenId]
|
||||||
|
);
|
||||||
|
|
||||||
|
return $token->id === null || $token->token_is_revoked === '1' || new DateTime() > new DateTime($token->access_token_expires);
|
||||||
|
}
|
||||||
|
}
|
47
Api/V8/OAuth2/Repository/ClientRepository.php
Normal file
47
Api/V8/OAuth2/Repository/ClientRepository.php
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\OAuth2\Repository;
|
||||||
|
|
||||||
|
use Api\V8\BeanDecorator\BeanManager;
|
||||||
|
use Api\V8\OAuth2\Entity\ClientEntity;
|
||||||
|
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
|
||||||
|
|
||||||
|
class ClientRepository implements ClientRepositoryInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var ClientEntity
|
||||||
|
*/
|
||||||
|
private $clientEntity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var BeanManager
|
||||||
|
*/
|
||||||
|
private $beanManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ClientEntity $clientEntity
|
||||||
|
* @param BeanManager $beanManager
|
||||||
|
*/
|
||||||
|
public function __construct(ClientEntity $clientEntity, BeanManager $beanManager)
|
||||||
|
{
|
||||||
|
$this->clientEntity = $clientEntity;
|
||||||
|
$this->beanManager = $beanManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function getClientEntity($clientIdentifier, $grantType, $clientSecret = null, $mustValidateSecret = true)
|
||||||
|
{
|
||||||
|
/** @var \OAuth2Clients $client */
|
||||||
|
$client = $this->beanManager->getBeanSafe(\OAuth2Clients::class, $clientIdentifier);
|
||||||
|
if ($mustValidateSecret && hash('sha256', $clientSecret) !== $client->secret) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->clientEntity->setIdentifier($clientIdentifier);
|
||||||
|
$this->clientEntity->setName($client->name);
|
||||||
|
$this->clientEntity->setRedirectUri(isset($client->redirect_uri) ? $client->redirect_uri : '');
|
||||||
|
|
||||||
|
return $this->clientEntity;
|
||||||
|
}
|
||||||
|
}
|
92
Api/V8/OAuth2/Repository/RefreshTokenRepository.php
Normal file
92
Api/V8/OAuth2/Repository/RefreshTokenRepository.php
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\OAuth2\Repository;
|
||||||
|
|
||||||
|
use Api\V8\BeanDecorator\BeanManager;
|
||||||
|
use Api\V8\OAuth2\Entity\RefreshTokenEntity;
|
||||||
|
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
|
||||||
|
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
|
||||||
|
|
||||||
|
class RefreshTokenRepository implements RefreshTokenRepositoryInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var BeanManager
|
||||||
|
*/
|
||||||
|
private $beanManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param BeanManager $beanManager
|
||||||
|
*/
|
||||||
|
public function __construct(BeanManager $beanManager)
|
||||||
|
{
|
||||||
|
$this->beanManager = $beanManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function getNewRefreshToken()
|
||||||
|
{
|
||||||
|
return new RefreshTokenEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException When access token is not found.
|
||||||
|
*/
|
||||||
|
public function persistNewRefreshToken(RefreshTokenEntityInterface $refreshTokenEntity)
|
||||||
|
{
|
||||||
|
/** @var \OAuth2Tokens $token */
|
||||||
|
$token = $this->beanManager->newBeanSafe(\OAuth2Tokens::class);
|
||||||
|
$token->retrieve_by_string_fields(
|
||||||
|
['access_token' => $refreshTokenEntity->getAccessToken()->getIdentifier()]
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($token->id === null) {
|
||||||
|
throw new \InvalidArgumentException('Access token is not found for this client');
|
||||||
|
}
|
||||||
|
|
||||||
|
$token->refresh_token = $refreshTokenEntity->getIdentifier();
|
||||||
|
$token->refresh_token_expires = $refreshTokenEntity->getExpiryDateTime()->format('Y-m-d H:i:s');
|
||||||
|
$token->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException When refresh token is not found.
|
||||||
|
*/
|
||||||
|
public function revokeRefreshToken($tokenId)
|
||||||
|
{
|
||||||
|
$token = $this->beanManager->newBeanSafe(\OAuth2Tokens::class);
|
||||||
|
$token->retrieve_by_string_fields(
|
||||||
|
['refresh_token' => $tokenId],
|
||||||
|
true,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($token->id === null) {
|
||||||
|
throw new \InvalidArgumentException('Refresh token is not found for this client');
|
||||||
|
}
|
||||||
|
|
||||||
|
$token->mark_deleted($token->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function isRefreshTokenRevoked($tokenId)
|
||||||
|
{
|
||||||
|
/** @var \OAuth2Tokens $token */
|
||||||
|
$token = $this->beanManager->newBeanSafe(\OAuth2Tokens::class);
|
||||||
|
$token->retrieve_by_string_fields(
|
||||||
|
['refresh_token' => $tokenId]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (new \DateTime() > new \DateTime($token->refresh_token_expires) || $token->id === null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
28
Api/V8/OAuth2/Repository/ScopeRepository.php
Normal file
28
Api/V8/OAuth2/Repository/ScopeRepository.php
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\OAuth2\Repository;
|
||||||
|
|
||||||
|
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||||
|
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
|
||||||
|
|
||||||
|
class ScopeRepository implements ScopeRepositoryInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function getScopeEntityByIdentifier($identifier)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function finalizeScopes(
|
||||||
|
array $scopes,
|
||||||
|
$grantType,
|
||||||
|
ClientEntityInterface $clientEntity,
|
||||||
|
$userIdentifier = null
|
||||||
|
) {
|
||||||
|
// we just return scopes for now
|
||||||
|
return $scopes;
|
||||||
|
}
|
||||||
|
}
|
51
Api/V8/OAuth2/Repository/UserRepository.php
Normal file
51
Api/V8/OAuth2/Repository/UserRepository.php
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\OAuth2\Repository;
|
||||||
|
|
||||||
|
use Api\V8\BeanDecorator\BeanManager;
|
||||||
|
use Api\V8\OAuth2\Entity\UserEntity;
|
||||||
|
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||||
|
use League\OAuth2\Server\Repositories\UserRepositoryInterface;
|
||||||
|
|
||||||
|
class UserRepository implements UserRepositoryInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var BeanManager
|
||||||
|
*/
|
||||||
|
private $beanManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param BeanManager $beanManager
|
||||||
|
*/
|
||||||
|
public function __construct(BeanManager $beanManager)
|
||||||
|
{
|
||||||
|
$this->beanManager = $beanManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException If user does not exist or the password is invalid.
|
||||||
|
*/
|
||||||
|
public function getUserEntityByUserCredentials(
|
||||||
|
$username,
|
||||||
|
$password,
|
||||||
|
$grantType,
|
||||||
|
ClientEntityInterface $clientEntity
|
||||||
|
) {
|
||||||
|
/** @var \User $user */
|
||||||
|
$user = $this->beanManager->newBeanSafe('Users');
|
||||||
|
$user->retrieve_by_string_fields(
|
||||||
|
['user_name' => $username]
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($user->id === null) {
|
||||||
|
throw new \InvalidArgumentException('No user found with this username: ' . $username);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!\User::checkPassword($password, $user->user_hash)) {
|
||||||
|
throw new \InvalidArgumentException('The password is invalid: ' . $password);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new UserEntity($user->id);
|
||||||
|
}
|
||||||
|
}
|
98
Api/V8/Param/BaseParam.php
Normal file
98
Api/V8/Param/BaseParam.php
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\Param;
|
||||||
|
|
||||||
|
use Api\V8\BeanDecorator\BeanManager;
|
||||||
|
use Api\V8\Factory\ValidatorFactory;
|
||||||
|
use Api\V8\Param\Options\BaseOption;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
abstract class BaseParam implements \JsonSerializable
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $parameters = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ValidatorFactory
|
||||||
|
*/
|
||||||
|
protected $validatorFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var BeanManager
|
||||||
|
*/
|
||||||
|
protected $beanManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ValidatorFactory $validatorFactory
|
||||||
|
* @param BeanManager $beanManager
|
||||||
|
*/
|
||||||
|
public function __construct(ValidatorFactory $validatorFactory, BeanManager $beanManager)
|
||||||
|
{
|
||||||
|
$this->validatorFactory = $validatorFactory;
|
||||||
|
$this->beanManager = $beanManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $arguments
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
final public function configure(array $arguments)
|
||||||
|
{
|
||||||
|
$optionsResolver = new OptionsResolver();
|
||||||
|
$this->setDefined($optionsResolver, $arguments);
|
||||||
|
$this->configureParameters($optionsResolver);
|
||||||
|
$this->parameters = $optionsResolver->resolve($arguments);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We can overwrite this method, if necessary
|
||||||
|
*
|
||||||
|
* @param OptionsResolver $resolver
|
||||||
|
* @param array $arguments
|
||||||
|
*/
|
||||||
|
public function setDefined(OptionsResolver $resolver, array $arguments)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure parameters.
|
||||||
|
*
|
||||||
|
* @param OptionsResolver $resolver
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
abstract protected function configureParameters(OptionsResolver $resolver);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure already defined options.
|
||||||
|
*
|
||||||
|
* @param OptionsResolver $optionResolver
|
||||||
|
* @param array $options
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException If option is not exist.
|
||||||
|
*/
|
||||||
|
protected function setOptions(OptionsResolver $optionResolver, array $options)
|
||||||
|
{
|
||||||
|
foreach ($options as $key => $option) {
|
||||||
|
if (!class_exists($option)) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('Option %s does not exist!', $option));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var BaseOption $class */
|
||||||
|
$class = new $option($this->validatorFactory, $this->beanManager);
|
||||||
|
$class->add($optionResolver);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function jsonSerialize()
|
||||||
|
{
|
||||||
|
return $this->parameters;
|
||||||
|
}
|
||||||
|
}
|
56
Api/V8/Param/CreateModuleDataParams.php
Normal file
56
Api/V8/Param/CreateModuleDataParams.php
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\Param;
|
||||||
|
|
||||||
|
use Api\V8\Param\Options as ParamOption;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
|
class CreateModuleDataParams extends BaseParam
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getType()
|
||||||
|
{
|
||||||
|
return $this->parameters['type'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getId()
|
||||||
|
{
|
||||||
|
return isset($this->parameters['id']) ? $this->parameters['id'] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAttributes()
|
||||||
|
{
|
||||||
|
return isset($this->parameters['attributes']) ? $this->parameters['attributes'] : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
protected function configureParameters(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
// need to make this more simple
|
||||||
|
$resolver
|
||||||
|
->setDefined('id')
|
||||||
|
->setAllowedTypes('id', 'string')
|
||||||
|
->setAllowedValues('id', $this->validatorFactory->createClosure([
|
||||||
|
new Assert\NotBlank(),
|
||||||
|
new Assert\Uuid(['strict' => false]),
|
||||||
|
]));
|
||||||
|
|
||||||
|
$this->setOptions(
|
||||||
|
$resolver,
|
||||||
|
[
|
||||||
|
ParamOption\Type::class,
|
||||||
|
ParamOption\Attributes::class,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
36
Api/V8/Param/CreateModuleParams.php
Normal file
36
Api/V8/Param/CreateModuleParams.php
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\Param;
|
||||||
|
|
||||||
|
use Symfony\Component\OptionsResolver\Options;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
|
class CreateModuleParams extends BaseParam
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return CreateModuleDataParams
|
||||||
|
*/
|
||||||
|
public function getData()
|
||||||
|
{
|
||||||
|
return $this->parameters['data'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
protected function configureParameters(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver
|
||||||
|
->setRequired('data')
|
||||||
|
->setAllowedTypes('data', 'array')
|
||||||
|
->setAllowedValues('data', $this->validatorFactory->createClosureForIterator([
|
||||||
|
new Assert\NotBlank(),
|
||||||
|
]))
|
||||||
|
->setNormalizer('data', function (Options $options, $values) {
|
||||||
|
$dataParams = new CreateModuleDataParams($this->validatorFactory, $this->beanManager);
|
||||||
|
$dataParams->configure($values);
|
||||||
|
|
||||||
|
return $dataParams;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
69
Api/V8/Param/CreateRelationshipByLinkParams.php
Normal file
69
Api/V8/Param/CreateRelationshipByLinkParams.php
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\Param;
|
||||||
|
|
||||||
|
use Api\V8\Param\Options as ParamOption;
|
||||||
|
use Symfony\Component\OptionsResolver\Options;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
|
class CreateRelationshipByLinkParams extends CreateRelationshipParams
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getLinkedFieldName()
|
||||||
|
{
|
||||||
|
return $this->parameters['linkFieldName'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
protected function configureParameters(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$this->setOptions(
|
||||||
|
$resolver,
|
||||||
|
[
|
||||||
|
ParamOption\ModuleName::class,
|
||||||
|
ParamOption\Id::class,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$resolver
|
||||||
|
->setRequired('data')
|
||||||
|
->setAllowedTypes('data', 'array')
|
||||||
|
->setAllowedValues('data', $this->validatorFactory->createClosureForIterator([
|
||||||
|
new Assert\NotBlank(),
|
||||||
|
]))
|
||||||
|
->setNormalizer('data', function (Options $options, $value) {
|
||||||
|
$dataParams = new GetRelationshipDataParams($this->validatorFactory, $this->beanManager);
|
||||||
|
$dataParams->configure($value);
|
||||||
|
|
||||||
|
return $dataParams;
|
||||||
|
});
|
||||||
|
|
||||||
|
$resolver
|
||||||
|
->setDefined('sourceBean')
|
||||||
|
->setDefault('sourceBean', function (Options $options) {
|
||||||
|
return $this->beanManager->getBeanSafe(
|
||||||
|
$options->offsetGet('moduleName'),
|
||||||
|
$options->offsetGet('id')
|
||||||
|
);
|
||||||
|
})
|
||||||
|
->setAllowedTypes('sourceBean', \SugarBean::class);
|
||||||
|
|
||||||
|
$resolver
|
||||||
|
->setDefined('relatedBean')
|
||||||
|
->setDefault('relatedBean', function (Options $options) {
|
||||||
|
$dataParams = $options->offsetGet('data');
|
||||||
|
|
||||||
|
return $this->beanManager->getBeanSafe(
|
||||||
|
$dataParams->getType(),
|
||||||
|
$dataParams->getId()
|
||||||
|
);
|
||||||
|
})
|
||||||
|
->setAllowedTypes('relatedBean', \SugarBean::class);
|
||||||
|
|
||||||
|
$this->setOptions($resolver, [ParamOption\LinkFieldName::class]);
|
||||||
|
}
|
||||||
|
}
|
99
Api/V8/Param/CreateRelationshipParams.php
Normal file
99
Api/V8/Param/CreateRelationshipParams.php
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\Param;
|
||||||
|
|
||||||
|
use Api\V8\Param\Options as ParamOption;
|
||||||
|
use Symfony\Component\OptionsResolver\Options;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
|
class CreateRelationshipParams extends BaseParam
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getModuleName()
|
||||||
|
{
|
||||||
|
return $this->parameters['moduleName'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getId()
|
||||||
|
{
|
||||||
|
return $this->parameters['id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return GetRelationshipDataParams
|
||||||
|
*/
|
||||||
|
public function getData()
|
||||||
|
{
|
||||||
|
return $this->parameters['data'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \SugarBean
|
||||||
|
*/
|
||||||
|
public function getSourceBean()
|
||||||
|
{
|
||||||
|
return $this->parameters['sourceBean'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \SugarBean
|
||||||
|
*/
|
||||||
|
public function getRelatedBean()
|
||||||
|
{
|
||||||
|
return $this->parameters['relatedBean'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
protected function configureParameters(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$this->setOptions(
|
||||||
|
$resolver,
|
||||||
|
[
|
||||||
|
ParamOption\ModuleName::class,
|
||||||
|
ParamOption\Id::class,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$resolver
|
||||||
|
->setRequired('data')
|
||||||
|
->setAllowedTypes('data', 'array')
|
||||||
|
->setAllowedValues('data', $this->validatorFactory->createClosureForIterator([
|
||||||
|
new Assert\NotBlank(),
|
||||||
|
]))
|
||||||
|
->setNormalizer('data', function (Options $options, $value) {
|
||||||
|
$dataParams = new GetRelationshipDataParams($this->validatorFactory, $this->beanManager);
|
||||||
|
$dataParams->configure($value);
|
||||||
|
|
||||||
|
return $dataParams;
|
||||||
|
});
|
||||||
|
|
||||||
|
$resolver
|
||||||
|
->setDefined('sourceBean')
|
||||||
|
->setDefault('sourceBean', function (Options $options) {
|
||||||
|
return $this->beanManager->getBeanSafe(
|
||||||
|
$options->offsetGet('moduleName'),
|
||||||
|
$options->offsetGet('id')
|
||||||
|
);
|
||||||
|
})
|
||||||
|
->setAllowedTypes('sourceBean', \SugarBean::class);
|
||||||
|
|
||||||
|
$resolver
|
||||||
|
->setDefined('relatedBean')
|
||||||
|
->setDefault('relatedBean', function (Options $options) {
|
||||||
|
$dataParams = $options->offsetGet('data');
|
||||||
|
|
||||||
|
return $this->beanManager->getBeanSafe(
|
||||||
|
$dataParams->getType(),
|
||||||
|
$dataParams->getId()
|
||||||
|
);
|
||||||
|
})
|
||||||
|
->setAllowedTypes('relatedBean', \SugarBean::class);
|
||||||
|
}
|
||||||
|
}
|
38
Api/V8/Param/DeleteModuleParams.php
Normal file
38
Api/V8/Param/DeleteModuleParams.php
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\Param;
|
||||||
|
|
||||||
|
use Api\V8\Param\Options as ParamOption;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
class DeleteModuleParams extends BaseParam
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getModuleName()
|
||||||
|
{
|
||||||
|
return $this->parameters['moduleName'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getId()
|
||||||
|
{
|
||||||
|
return $this->parameters['id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
protected function configureParameters(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$this->setOptions(
|
||||||
|
$resolver,
|
||||||
|
[
|
||||||
|
ParamOption\ModuleName::class,
|
||||||
|
ParamOption\Id::class,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
85
Api/V8/Param/DeleteRelationshipParams.php
Normal file
85
Api/V8/Param/DeleteRelationshipParams.php
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\Param;
|
||||||
|
|
||||||
|
use Api\V8\Param\Options as ParamOption;
|
||||||
|
use Symfony\Component\OptionsResolver\Options;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
|
class DeleteRelationshipParams extends BaseParam
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getModuleName()
|
||||||
|
{
|
||||||
|
return $this->parameters['moduleName'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getId()
|
||||||
|
{
|
||||||
|
return $this->parameters['id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getLinkedFieldName()
|
||||||
|
{
|
||||||
|
return $this->parameters['linkFieldName'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getRelatedBeanId()
|
||||||
|
{
|
||||||
|
return $this->parameters['relatedBeanId'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \SugarBean
|
||||||
|
*/
|
||||||
|
public function getSourceBean()
|
||||||
|
{
|
||||||
|
return $this->parameters['sourceBean'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
protected function configureParameters(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$this->setOptions(
|
||||||
|
$resolver,
|
||||||
|
[
|
||||||
|
ParamOption\ModuleName::class,
|
||||||
|
ParamOption\Id::class,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$resolver
|
||||||
|
->setRequired('relatedBeanId')
|
||||||
|
->setAllowedTypes('relatedBeanId', 'string')
|
||||||
|
->setAllowedValues('relatedBeanId', $this->validatorFactory->createClosure([
|
||||||
|
new Assert\NotBlank(),
|
||||||
|
new Assert\Uuid(['strict' => false]),
|
||||||
|
]));
|
||||||
|
|
||||||
|
$resolver
|
||||||
|
->setDefined('sourceBean')
|
||||||
|
->setDefault('sourceBean', function (Options $options) {
|
||||||
|
return $this->beanManager->getBeanSafe(
|
||||||
|
$options->offsetGet('moduleName'),
|
||||||
|
$options->offsetGet('id')
|
||||||
|
);
|
||||||
|
})
|
||||||
|
->setAllowedTypes('sourceBean', \SugarBean::class);
|
||||||
|
|
||||||
|
// dependency on sourceBean field
|
||||||
|
$this->setOptions($resolver, [ParamOption\LinkFieldName::class]);
|
||||||
|
}
|
||||||
|
}
|
73
Api/V8/Param/GetFieldListParams.php
Normal file
73
Api/V8/Param/GetFieldListParams.php
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* SugarCRM Community Edition is a customer relationship management program developed by
|
||||||
|
* SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
|
||||||
|
*
|
||||||
|
* SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd.
|
||||||
|
* Copyright (C) 2011 - 2018 SalesAgility Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU Affero General Public License version 3 as published by the
|
||||||
|
* Free Software Foundation with the addition of the following permission added
|
||||||
|
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
||||||
|
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
||||||
|
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License along with
|
||||||
|
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
||||||
|
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
||||||
|
*
|
||||||
|
* The interactive user interfaces in modified source and object code versions
|
||||||
|
* of this program must display Appropriate Legal Notices, as required under
|
||||||
|
* Section 5 of the GNU Affero General Public License version 3.
|
||||||
|
*
|
||||||
|
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||||
|
* these Appropriate Legal Notices must retain the display of the "Powered by
|
||||||
|
* SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
|
||||||
|
* reasonably feasible for technical reasons, the Appropriate Legal Notices must
|
||||||
|
* display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM".
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Api\V8\Param;
|
||||||
|
|
||||||
|
if (!defined('sugarEntry') || !sugarEntry) {
|
||||||
|
die('Not A Valid Entry Point');
|
||||||
|
}
|
||||||
|
|
||||||
|
use Api\V8\Param\Options as ParamOption;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class GetFieldListParams
|
||||||
|
* @package Api\V8\Param
|
||||||
|
*/
|
||||||
|
class GetFieldListParams extends BaseParam
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getModule()
|
||||||
|
{
|
||||||
|
return $this->parameters['moduleName'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param OptionsResolver $resolver
|
||||||
|
*/
|
||||||
|
protected function configureParameters(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$this->setOptions($resolver, [ParamOption\ModuleName::class]);
|
||||||
|
}
|
||||||
|
}
|
47
Api/V8/Param/GetModuleParams.php
Normal file
47
Api/V8/Param/GetModuleParams.php
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\Param;
|
||||||
|
|
||||||
|
use Api\V8\Param\Options as ParamOption;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
class GetModuleParams extends BaseParam
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getModuleName()
|
||||||
|
{
|
||||||
|
return $this->parameters['moduleName'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getId()
|
||||||
|
{
|
||||||
|
return $this->parameters['id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array|null
|
||||||
|
*/
|
||||||
|
public function getFields()
|
||||||
|
{
|
||||||
|
return isset($this->parameters['fields']) ? $this->parameters['fields'] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
protected function configureParameters(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$this->setOptions(
|
||||||
|
$resolver,
|
||||||
|
[
|
||||||
|
ParamOption\ModuleName::class,
|
||||||
|
ParamOption\Id::class,
|
||||||
|
ParamOption\Fields::class,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
75
Api/V8/Param/GetModulesParams.php
Normal file
75
Api/V8/Param/GetModulesParams.php
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\Param;
|
||||||
|
|
||||||
|
use Api\V8\Param\Options as ParamOption;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
class GetModulesParams extends BaseParam
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getModuleName()
|
||||||
|
{
|
||||||
|
return $this->parameters['moduleName'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array|null
|
||||||
|
*/
|
||||||
|
public function getFields()
|
||||||
|
{
|
||||||
|
return isset($this->parameters['fields']) ? $this->parameters['fields'] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return PageParams
|
||||||
|
*/
|
||||||
|
public function getPage()
|
||||||
|
{
|
||||||
|
return isset($this->parameters['page'])
|
||||||
|
? $this->parameters['page']
|
||||||
|
: new PageParams($this->validatorFactory, $this->beanManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getSort()
|
||||||
|
{
|
||||||
|
return isset($this->parameters['sort']) ? $this->parameters['sort'] : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getFilter()
|
||||||
|
{
|
||||||
|
return isset($this->parameters['filter']) ? $this->parameters['filter'] : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function getDeleted()
|
||||||
|
{
|
||||||
|
return strpos($this->getFilter(), ".deleted = '1'") !== false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
protected function configureParameters(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$this->setOptions(
|
||||||
|
$resolver,
|
||||||
|
[
|
||||||
|
ParamOption\ModuleName::class,
|
||||||
|
ParamOption\Fields::class,
|
||||||
|
ParamOption\Page::class,
|
||||||
|
ParamOption\Sort::class,
|
||||||
|
ParamOption\Filter::class
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
38
Api/V8/Param/GetRelationshipDataParams.php
Normal file
38
Api/V8/Param/GetRelationshipDataParams.php
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\Param;
|
||||||
|
|
||||||
|
use Api\V8\Param\Options as ParamOption;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
class GetRelationshipDataParams extends BaseParam
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getType()
|
||||||
|
{
|
||||||
|
return $this->parameters['type'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getId()
|
||||||
|
{
|
||||||
|
return $this->parameters['id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
protected function configureParameters(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$this->setOptions(
|
||||||
|
$resolver,
|
||||||
|
[
|
||||||
|
ParamOption\Type::class,
|
||||||
|
ParamOption\Id::class,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
68
Api/V8/Param/GetRelationshipParams.php
Normal file
68
Api/V8/Param/GetRelationshipParams.php
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\Param;
|
||||||
|
|
||||||
|
use Api\V8\Param\Options as ParamOption;
|
||||||
|
use Symfony\Component\OptionsResolver\Options;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
class GetRelationshipParams extends BaseParam
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getModuleName()
|
||||||
|
{
|
||||||
|
return $this->parameters['moduleName'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getId()
|
||||||
|
{
|
||||||
|
return $this->parameters['id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getLinkedFieldName()
|
||||||
|
{
|
||||||
|
return $this->parameters['linkFieldName'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \SugarBean
|
||||||
|
*/
|
||||||
|
public function getSourceBean()
|
||||||
|
{
|
||||||
|
return $this->parameters['sourceBean'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
protected function configureParameters(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$this->setOptions(
|
||||||
|
$resolver,
|
||||||
|
[
|
||||||
|
ParamOption\ModuleName::class,
|
||||||
|
ParamOption\Id::class,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$resolver
|
||||||
|
->setDefined('sourceBean')
|
||||||
|
->setDefault('sourceBean', function (Options $options) {
|
||||||
|
return $this->beanManager->getBeanSafe(
|
||||||
|
$options->offsetGet('moduleName'),
|
||||||
|
$options->offsetGet('id')
|
||||||
|
);
|
||||||
|
})
|
||||||
|
->setAllowedTypes('sourceBean', [\SugarBean::class]);
|
||||||
|
|
||||||
|
// dependency on sourceBean field
|
||||||
|
$this->setOptions($resolver, [ParamOption\LinkFieldName::class]);
|
||||||
|
}
|
||||||
|
}
|
74
Api/V8/Param/GetUserPreferencesParams.php
Normal file
74
Api/V8/Param/GetUserPreferencesParams.php
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* SugarCRM Community Edition is a customer relationship management program developed by
|
||||||
|
* SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
|
||||||
|
*
|
||||||
|
* SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd.
|
||||||
|
* Copyright (C) 2011 - 2018 SalesAgility Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU Affero General Public License version 3 as published by the
|
||||||
|
* Free Software Foundation with the addition of the following permission added
|
||||||
|
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
||||||
|
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
||||||
|
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License along with
|
||||||
|
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
||||||
|
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
||||||
|
*
|
||||||
|
* The interactive user interfaces in modified source and object code versions
|
||||||
|
* of this program must display Appropriate Legal Notices, as required under
|
||||||
|
* Section 5 of the GNU Affero General Public License version 3.
|
||||||
|
*
|
||||||
|
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||||
|
* these Appropriate Legal Notices must retain the display of the "Powered by
|
||||||
|
* SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
|
||||||
|
* reasonably feasible for technical reasons, the Appropriate Legal Notices must
|
||||||
|
* display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM".
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Api\V8\Param;
|
||||||
|
|
||||||
|
if (!defined('sugarEntry') || !sugarEntry) {
|
||||||
|
die('Not A Valid Entry Point');
|
||||||
|
}
|
||||||
|
|
||||||
|
use Api\V8\Param\Options as ParamOption;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GetUserPreferencesParams
|
||||||
|
*
|
||||||
|
* @author gyula
|
||||||
|
*/
|
||||||
|
class GetUserPreferencesParams extends BaseParam
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getUserId()
|
||||||
|
{
|
||||||
|
return $this->parameters['id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param OptionsResolver $resolver
|
||||||
|
*/
|
||||||
|
protected function configureParameters(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$this->setOptions($resolver, [ParamOption\Id::class]);
|
||||||
|
}
|
||||||
|
}
|
79
Api/V8/Param/ListViewColumnsParams.php
Normal file
79
Api/V8/Param/ListViewColumnsParams.php
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* SugarCRM Community Edition is a customer relationship management program developed by
|
||||||
|
* SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
|
||||||
|
*
|
||||||
|
* SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd.
|
||||||
|
* Copyright (C) 2011 - 2018 SalesAgility Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU Affero General Public License version 3 as published by the
|
||||||
|
* Free Software Foundation with the addition of the following permission added
|
||||||
|
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
||||||
|
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
||||||
|
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License along with
|
||||||
|
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
||||||
|
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
||||||
|
*
|
||||||
|
* The interactive user interfaces in modified source and object code versions
|
||||||
|
* of this program must display Appropriate Legal Notices, as required under
|
||||||
|
* Section 5 of the GNU Affero General Public License version 3.
|
||||||
|
*
|
||||||
|
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||||
|
* these Appropriate Legal Notices must retain the display of the "Powered by
|
||||||
|
* SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
|
||||||
|
* reasonably feasible for technical reasons, the Appropriate Legal Notices must
|
||||||
|
* display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM".
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Api\V8\Param;
|
||||||
|
|
||||||
|
use Api\V8\Param\Options as ParamOption;
|
||||||
|
use Api\V8\Param\OptionsResolver;
|
||||||
|
|
||||||
|
if (!defined('sugarEntry') || !sugarEntry) {
|
||||||
|
die('Not A Valid Entry Point');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ListViewColumnsParams
|
||||||
|
*
|
||||||
|
* @author gyula
|
||||||
|
*/
|
||||||
|
class ListViewColumnsParams extends BaseParam
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getModuleName()
|
||||||
|
{
|
||||||
|
return $this->parameters['moduleName'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param \Api\V8\Param\OptionsResolver $resolver
|
||||||
|
*/
|
||||||
|
protected function configureParameters(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$this->setOptions(
|
||||||
|
$resolver,
|
||||||
|
[
|
||||||
|
ParamOption\ModuleName::class,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
79
Api/V8/Param/ListViewSearchParams.php
Normal file
79
Api/V8/Param/ListViewSearchParams.php
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* SugarCRM Community Edition is a customer relationship management program developed by
|
||||||
|
* SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
|
||||||
|
*
|
||||||
|
* SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd.
|
||||||
|
* Copyright (C) 2011 - 2018 SalesAgility Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU Affero General Public License version 3 as published by the
|
||||||
|
* Free Software Foundation with the addition of the following permission added
|
||||||
|
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
||||||
|
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
||||||
|
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License along with
|
||||||
|
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
||||||
|
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
||||||
|
*
|
||||||
|
* The interactive user interfaces in modified source and object code versions
|
||||||
|
* of this program must display Appropriate Legal Notices, as required under
|
||||||
|
* Section 5 of the GNU Affero General Public License version 3.
|
||||||
|
*
|
||||||
|
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||||
|
* these Appropriate Legal Notices must retain the display of the "Powered by
|
||||||
|
* SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
|
||||||
|
* reasonably feasible for technical reasons, the Appropriate Legal Notices must
|
||||||
|
* display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM".
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Api\V8\Param;
|
||||||
|
|
||||||
|
if (!defined('sugarEntry') || !sugarEntry) {
|
||||||
|
die('Not A Valid Entry Point');
|
||||||
|
}
|
||||||
|
|
||||||
|
use Api\V8\Param\Options as ParamOption;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ListViewSearchParams
|
||||||
|
*
|
||||||
|
* @author gyula
|
||||||
|
*/
|
||||||
|
class ListViewSearchParams extends BaseParam
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getModuleName()
|
||||||
|
{
|
||||||
|
return $this->parameters['moduleName'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param OptionsResolver $resolver
|
||||||
|
*/
|
||||||
|
protected function configureParameters(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$this->setOptions(
|
||||||
|
$resolver,
|
||||||
|
[
|
||||||
|
ParamOption\ModuleName::class,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
52
Api/V8/Param/Options/Attributes.php
Normal file
52
Api/V8/Param/Options/Attributes.php
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Api\V8\Param\Options;
|
||||||
|
|
||||||
|
use InvalidArgumentException;
|
||||||
|
use OutOfBoundsException;
|
||||||
|
use Symfony\Component\OptionsResolver\Options;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
|
class Attributes extends BaseOption
|
||||||
|
{
|
||||||
|
// Paradox regex that accepts everything (Match at beginning/end of each word and don't match at beginning/end of each word).
|
||||||
|
const REGEX_ATTRIBUTE_PATTERN = '/\b\B/';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*
|
||||||
|
* @throws InvalidArgumentException If attributes parameters have invalid property.
|
||||||
|
*/
|
||||||
|
public function add(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver
|
||||||
|
->setDefined('attributes')
|
||||||
|
->setAllowedTypes('attributes', 'array')
|
||||||
|
->setAllowedValues('attributes', $this->validatorFactory->createClosureForIterator([
|
||||||
|
new Assert\Regex([
|
||||||
|
'pattern' => self::REGEX_ATTRIBUTE_PATTERN,
|
||||||
|
'match' => false,
|
||||||
|
]),
|
||||||
|
]))
|
||||||
|
->setNormalizer('attributes', function (Options $options, $values) {
|
||||||
|
$bean = $this->beanManager->newBeanSafe($options->offsetGet('type'));
|
||||||
|
|
||||||
|
foreach ($values as $attribute => $value) {
|
||||||
|
$invalidProperty =
|
||||||
|
!property_exists($bean, $attribute) &&
|
||||||
|
!array_key_exists($attribute, $bean->field_defs) &&
|
||||||
|
!array_key_exists($attribute, $bean->field_name_map);
|
||||||
|
if ($invalidProperty) {
|
||||||
|
throw new OutOfBoundsException(sprintf(
|
||||||
|
'Property %s in %s module is invalid',
|
||||||
|
$attribute,
|
||||||
|
$bean->getObjectName()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $values;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
47
Api/V8/Param/Options/BaseOption.php
Normal file
47
Api/V8/Param/Options/BaseOption.php
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\Param\Options;
|
||||||
|
|
||||||
|
use Api\V8\BeanDecorator\BeanManager;
|
||||||
|
use Api\V8\Factory\ValidatorFactory;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
abstract class BaseOption
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var ValidatorFactory
|
||||||
|
*/
|
||||||
|
protected $validatorFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var BeanManager
|
||||||
|
*/
|
||||||
|
protected $beanManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ValidatorFactory $validatorFactory
|
||||||
|
* @param BeanManager $beanManager
|
||||||
|
*/
|
||||||
|
public function __construct(ValidatorFactory $validatorFactory, BeanManager $beanManager)
|
||||||
|
{
|
||||||
|
$this->validatorFactory = $validatorFactory;
|
||||||
|
$this->beanManager = $beanManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param OptionsResolver $resolver
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
abstract public function add(OptionsResolver $resolver);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $class
|
||||||
|
* @see https://github.com/rappasoft/laravel-helpers#class_basename
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function getOptionName($class)
|
||||||
|
{
|
||||||
|
return lcfirst(basename(str_replace('\\', '/', $class)));
|
||||||
|
}
|
||||||
|
}
|
53
Api/V8/Param/Options/Fields.php
Normal file
53
Api/V8/Param/Options/Fields.php
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\Param\Options;
|
||||||
|
|
||||||
|
use Symfony\Component\OptionsResolver\Options;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
|
class Fields extends BaseOption
|
||||||
|
{
|
||||||
|
const REGEX_FIELD_PATTERN = '/[^\w\-,]/';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException In case fields are invalid.
|
||||||
|
*/
|
||||||
|
public function add(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver
|
||||||
|
->setDefined('fields')
|
||||||
|
->setAllowedTypes('fields', 'array')
|
||||||
|
->setAllowedValues('fields', $this->validatorFactory->createClosureForIterator([
|
||||||
|
new Assert\NotBlank(),
|
||||||
|
new Assert\Regex([
|
||||||
|
'pattern' => self::REGEX_FIELD_PATTERN,
|
||||||
|
'match' => false,
|
||||||
|
]),
|
||||||
|
], true))
|
||||||
|
->setNormalizer('fields', function (Options $options, $values) {
|
||||||
|
$bean = $this->beanManager->newBeanSafe(key($values));
|
||||||
|
$attributes = $bean->toArray();
|
||||||
|
$fields = explode(',', array_shift($values));
|
||||||
|
|
||||||
|
$invalidFields = array_filter($fields, function ($field) use ($attributes) {
|
||||||
|
return !array_key_exists($field, $attributes);
|
||||||
|
});
|
||||||
|
|
||||||
|
if ($invalidFields) {
|
||||||
|
throw new \InvalidArgumentException(
|
||||||
|
sprintf(
|
||||||
|
'The following field%s in %s module %s not found: %s',
|
||||||
|
count($invalidFields) > 1 ? 's' : '',
|
||||||
|
$bean->getObjectName(),
|
||||||
|
count($invalidFields) > 1 ? 'are' : 'is',
|
||||||
|
implode(', ', $invalidFields)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $fields;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
34
Api/V8/Param/Options/Filter.php
Normal file
34
Api/V8/Param/Options/Filter.php
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\Param\Options;
|
||||||
|
|
||||||
|
use Api\V8\JsonApi\Repository\Filter as FilterRepository;
|
||||||
|
use Symfony\Component\OptionsResolver\Options;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
|
class Filter extends BaseOption
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function add(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver
|
||||||
|
->setDefaults(['filter' => [
|
||||||
|
'deleted' => [
|
||||||
|
'eq' => 0
|
||||||
|
]]])
|
||||||
|
->setDefined('filter')
|
||||||
|
->setAllowedTypes('filter', 'array')
|
||||||
|
->setAllowedValues('filter', $this->validatorFactory->createClosure([
|
||||||
|
new Assert\NotBlank(),
|
||||||
|
]))
|
||||||
|
->setNormalizer('filter', function (Options $options, $values) {
|
||||||
|
// we don't support multiple level filtering. for now.
|
||||||
|
$bean = $this->beanManager->newBeanSafe($options->offsetGet('moduleName'));
|
||||||
|
$filter = new FilterRepository($bean->db);
|
||||||
|
|
||||||
|
return $filter->parseWhere($bean, $values);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
21
Api/V8/Param/Options/Id.php
Normal file
21
Api/V8/Param/Options/Id.php
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\Param\Options;
|
||||||
|
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
|
class Id extends BaseOption
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function add(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver
|
||||||
|
->setRequired('id')
|
||||||
|
->setAllowedTypes('id', 'string')
|
||||||
|
->setAllowedValues('id', $this->validatorFactory->createClosure([
|
||||||
|
new Assert\Regex('/^(\d+|[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/i')
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
}
|
40
Api/V8/Param/Options/LinkFieldName.php
Normal file
40
Api/V8/Param/Options/LinkFieldName.php
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\Param\Options;
|
||||||
|
|
||||||
|
use Symfony\Component\OptionsResolver\Options;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
|
class LinkFieldName extends BaseOption
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Has a dependency of bean field.
|
||||||
|
*
|
||||||
|
* @inheritdoc
|
||||||
|
* @throws \RuntimeException If relationship cannot loaded
|
||||||
|
*/
|
||||||
|
public function add(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver
|
||||||
|
->setRequired('linkFieldName')
|
||||||
|
->setAllowedTypes('linkFieldName', ['string'])
|
||||||
|
->setAllowedValues('linkFieldName', $this->validatorFactory->createClosure([
|
||||||
|
new Assert\NotBlank(),
|
||||||
|
new Assert\Regex([
|
||||||
|
'pattern' => ModuleName::REGEX_MODULE_NAME_PATTERN,
|
||||||
|
'match' => false,
|
||||||
|
]),
|
||||||
|
]))
|
||||||
|
->setNormalizer('linkFieldName', function (Options $options, $value) {
|
||||||
|
$bean = $options->offsetGet('sourceBean');
|
||||||
|
|
||||||
|
if (!$bean->load_relationship($value)) {
|
||||||
|
throw new \RuntimeException(
|
||||||
|
sprintf('Cannot load relationship %s for %s module', $value, $bean->getObjectName())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
27
Api/V8/Param/Options/ModuleName.php
Normal file
27
Api/V8/Param/Options/ModuleName.php
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\Param\Options;
|
||||||
|
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
|
class ModuleName extends BaseOption
|
||||||
|
{
|
||||||
|
const REGEX_MODULE_NAME_PATTERN = '/^(\d|\W)|\W/';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function add(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver
|
||||||
|
->setRequired('moduleName')
|
||||||
|
->setAllowedTypes('moduleName', 'string')
|
||||||
|
->setAllowedValues('moduleName', $this->validatorFactory->createClosure([
|
||||||
|
new Assert\NotBlank(),
|
||||||
|
new Assert\Regex([
|
||||||
|
'pattern' => self::REGEX_MODULE_NAME_PATTERN,
|
||||||
|
'match' => false,
|
||||||
|
]),
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
}
|
35
Api/V8/Param/Options/Page.php
Normal file
35
Api/V8/Param/Options/Page.php
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\Param\Options;
|
||||||
|
|
||||||
|
use Api\V8\Param\PageParams;
|
||||||
|
use Symfony\Component\OptionsResolver\Options;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
|
class Page extends BaseOption
|
||||||
|
{
|
||||||
|
const REGEX_PAGE_PATTERN = '/[^\d]/';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function add(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver
|
||||||
|
->setDefined('page')
|
||||||
|
->setAllowedTypes('page', 'array')
|
||||||
|
->setAllowedValues('page', $this->validatorFactory->createClosureForIterator([
|
||||||
|
new Assert\NotBlank(),
|
||||||
|
new Assert\Regex([
|
||||||
|
'pattern' => self::REGEX_PAGE_PATTERN,
|
||||||
|
'match' => false,
|
||||||
|
]),
|
||||||
|
], true))
|
||||||
|
->setNormalizer('page', function (Options $options, $values) {
|
||||||
|
$pageParams = new PageParams($this->validatorFactory, $this->beanManager);
|
||||||
|
$pageParams->configure($values);
|
||||||
|
|
||||||
|
return $pageParams;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
35
Api/V8/Param/Options/Sort.php
Normal file
35
Api/V8/Param/Options/Sort.php
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\Param\Options;
|
||||||
|
|
||||||
|
use Api\V8\JsonApi\Repository\Sort as SortRepository;
|
||||||
|
use Symfony\Component\OptionsResolver\Options;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
|
class Sort extends BaseOption
|
||||||
|
{
|
||||||
|
const REGEX_SORT_PATTERN = '/[^\w\-]/';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function add(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver
|
||||||
|
->setDefined('sort')
|
||||||
|
->setAllowedTypes('sort', 'string')
|
||||||
|
->setAllowedValues('sort', $this->validatorFactory->createClosure([
|
||||||
|
new Assert\NotBlank(),
|
||||||
|
new Assert\Regex([
|
||||||
|
'pattern' => self::REGEX_SORT_PATTERN,
|
||||||
|
'match' => false,
|
||||||
|
]),
|
||||||
|
], true))
|
||||||
|
->setNormalizer('sort', function (Options $options, $value) {
|
||||||
|
$bean = $this->beanManager->newBeanSafe($options->offsetGet('moduleName'));
|
||||||
|
$sort = new SortRepository();
|
||||||
|
|
||||||
|
return $sort->parseOrderBy($bean, $value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
25
Api/V8/Param/Options/Type.php
Normal file
25
Api/V8/Param/Options/Type.php
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\Param\Options;
|
||||||
|
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
|
class Type extends BaseOption
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function add(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver
|
||||||
|
->setRequired('type')
|
||||||
|
->setAllowedTypes('type', 'string')
|
||||||
|
->setAllowedValues('type', $this->validatorFactory->createClosure([
|
||||||
|
new Assert\NotBlank(),
|
||||||
|
new Assert\Regex([
|
||||||
|
'pattern' => ModuleName::REGEX_MODULE_NAME_PATTERN,
|
||||||
|
'match' => false,
|
||||||
|
]),
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
}
|
45
Api/V8/Param/PageParams.php
Normal file
45
Api/V8/Param/PageParams.php
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\Param;
|
||||||
|
|
||||||
|
use Api\V8\BeanDecorator\BeanManager;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
|
class PageParams extends BaseParam
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
|
public function getSize()
|
||||||
|
{
|
||||||
|
return isset($this->parameters['size']) ? (int)$this->parameters['size'] : BeanManager::DEFAULT_ALL_RECORDS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
|
public function getNumber()
|
||||||
|
{
|
||||||
|
return isset($this->parameters['number']) ? (int)$this->parameters['number'] : BeanManager::DEFAULT_OFFSET;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
protected function configureParameters(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver
|
||||||
|
->setDefined('size')
|
||||||
|
->setAllowedTypes('size', 'string')
|
||||||
|
->setAllowedValues('size', $this->validatorFactory->createClosure([
|
||||||
|
new Assert\GreaterThan(0),
|
||||||
|
]));
|
||||||
|
|
||||||
|
$resolver
|
||||||
|
->setDefined('number')
|
||||||
|
->setAllowedTypes('number', 'string')
|
||||||
|
->setAllowedValues('number', $this->validatorFactory->createClosure([
|
||||||
|
new Assert\GreaterThan(0),
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
}
|
47
Api/V8/Param/UpdateModuleDataParams.php
Normal file
47
Api/V8/Param/UpdateModuleDataParams.php
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\Param;
|
||||||
|
|
||||||
|
use Api\V8\Param\Options as ParamOption;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
class UpdateModuleDataParams extends BaseParam
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getType()
|
||||||
|
{
|
||||||
|
return $this->parameters['type'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getId()
|
||||||
|
{
|
||||||
|
return $this->parameters['id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAttributes()
|
||||||
|
{
|
||||||
|
return isset($this->parameters['attributes']) ? $this->parameters['attributes'] : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
protected function configureParameters(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$this->setOptions(
|
||||||
|
$resolver,
|
||||||
|
[
|
||||||
|
ParamOption\Type::class,
|
||||||
|
ParamOption\Id::class,
|
||||||
|
ParamOption\Attributes::class,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
37
Api/V8/Param/UpdateModuleParams.php
Normal file
37
Api/V8/Param/UpdateModuleParams.php
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
<?php
|
||||||
|
namespace Api\V8\Param;
|
||||||
|
|
||||||
|
use Symfony\Component\OptionsResolver\Options;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
|
class UpdateModuleParams extends BaseParam
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return CreateModuleDataParams
|
||||||
|
*/
|
||||||
|
public function getData()
|
||||||
|
{
|
||||||
|
return $this->parameters['data'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
protected function configureParameters(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
// need to make this more simple
|
||||||
|
$resolver
|
||||||
|
->setRequired('data')
|
||||||
|
->setAllowedTypes('data', 'array')
|
||||||
|
->setAllowedValues('data', $this->validatorFactory->createClosureForIterator([
|
||||||
|
new Assert\NotBlank(),
|
||||||
|
]))
|
||||||
|
->setNormalizer('data', function (Options $options, $values) {
|
||||||
|
$dataParams = new UpdateModuleDataParams($this->validatorFactory, $this->beanManager);
|
||||||
|
$dataParams->configure($values);
|
||||||
|
|
||||||
|
return $dataParams;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
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