diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index e1a050c43f..1280f6b775 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -4,7 +4,7 @@ Thank you for contributing to the PrestaShop developer documentation! Please take the time to edit the "Answers" rows below with the necessary information. Check out our contribution guidelines on how to contribute: -https://devdocs.prestashop.com/8/contribute/documentation/how/ +https://devdocs.prestashop-project.org/8/contribute/documentation/how/ ------------------------------------------------------------------------------> | Questions | Answers diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1589d30cc9..c43ec88de9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,7 +20,7 @@ jobs: - name: Setup Hugo uses: peaceiris/actions-hugo@v2 with: - hugo-version: '0.82.0' + hugo-version: '0.85.0' extended: true - name: Find version from branch name (pull request) @@ -55,4 +55,6 @@ jobs: mv _current "src/content/$VERSION" - name: Build + env: + DEVDOCS_GITHUB_READ_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: cd src/ && hugo diff --git a/README.md b/README.md index 8988633359..a31b83a39f 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,11 @@ [![Build](https://github.com/PrestaShop/docs/actions/workflows/build.yml/badge.svg)](https://github.com/PrestaShop/docs/actions/workflows/build.yml) [![DevDocs Site update](https://github.com/PrestaShop/docs/actions/workflows/update-site.yml/badge.svg)](https://github.com/PrestaShop/docs/actions/workflows/update-site.yml) -This documentation is available at https://devdocs.prestashop.com/ +This documentation is available at [https://devdocs.prestashop-project.org/](https://devdocs.prestashop-project.org/) ## Contributing -Contributions are more than welcome! [Find out how](https://devdocs.prestashop.com/8/contribute/documentation/how/). +Contributions are more than welcome! [Find out how](https://devdocs.prestashop-project.org/8/contribute/documentation/how/). ## Rendering the site locally diff --git a/_index.md b/_index.md index 8c0b96dce1..7e56c7d17e 100644 --- a/_index.md +++ b/_index.md @@ -3,8 +3,9 @@ title: PrestaShop 8 Documentation menuTitle: PrestaShop 8 versionId: "8" # this should match the physical directory in devdocs-site versionGithubPath: "8.x" # this should match the branch name in github -versionMeta: Dev # only one version can be current! +versionMeta: Current # only one version can be current! chapter: true +hookListUrl: "/8/modules/concepts/hooks/list-of-hooks" # this allows for dynamic hook results in algolia's docsearch --- # PrestaShop 8 Documentation diff --git a/basics/_index.md b/basics/_index.md index e64fdcef06..d88ed4ec46 100755 --- a/basics/_index.md +++ b/basics/_index.md @@ -3,6 +3,8 @@ title: Basics weight: 1 pre: "1. " chapter: true +showOnHomepage: true +icon: fa-play --- ### Chapter 1 diff --git a/basics/deployment/_index.md b/basics/deployment/_index.md index 0b78074608..71abd64652 100644 --- a/basics/deployment/_index.md +++ b/basics/deployment/_index.md @@ -1,6 +1,7 @@ --- title: Deployment -weight: 18 +weight: 40 +showOnHomepage: true --- # Deployment diff --git a/basics/installation/_index.md b/basics/installation/_index.md index 229d8e08b8..ce60cb1777 100644 --- a/basics/installation/_index.md +++ b/basics/installation/_index.md @@ -1,6 +1,7 @@ --- title: Installation -weight: 15 +weight: 20 +showOnHomepage: true --- # Installation diff --git a/basics/installation/configuration.md b/basics/installation/configuration.md deleted file mode 100644 index b0ae071a25..0000000000 --- a/basics/installation/configuration.md +++ /dev/null @@ -1,119 +0,0 @@ ---- -title: Configuration -weight: 30 ---- - -# Configuring PrestaShop - -By default, PrestaShop is configured to provide a secure and stable environment to both the shop administrator and the customers. - -As a developer, there are several changes that you could and should bring to the default installation in order to help you code better, spot bugs faster, and generally make a great PrestaShop product. - -## Disabling the cache and forcing Smarty compilation - -When your development has an impact on the front office, whether you are building a theme or simply a module which displays information to the customer, you should force the template file compilation and disable the cache, so as to always see the result of your changes directly. - -Go to the “Performance” page under the “Advanced parameters” menu to change the following Smarty settings: - -* Template cache: switch it to “Force compilation”. -* Cache: disable it. - -Forcing the compilation of Smarty will always slow down the loading time of the page. Make sure that your production store is set to only recompile templates if there are updated files, and that its cache is enabled. - -## Displaying error messages - -PrestaShop’s default settings prevent the customer to see any server error message or any debugging code. - -You, on the other hand, need this information in order to correct any potential mistake in your code. To that end, open the `/config/defines.inc.php` file, and edit it to set `_PS_MODE_DEV_` to `true`: - -```php -caching = false;` as it is. - -`$smarty->compile_check` should be left to `false` in development mode. - -`$smarty->debugging` gives access to Smarty debug information when displaying a page. That setting is more easily modified in the “Performance” page of the advanced parameters menu : the “Debug console” option enables you to choose between never displaying Smarty’s debug information, always displaying it, or only displaying it when you add `?SMARTY_DEBUG` to the URL of the page you want to test, which can be very useful. - -When in production mode, `$smarty->force_compile` must be set to `false`, as it will give a 30% boost to your page load time. - -On the other hand, when editing a `.tpl` file, you must delete the `/var/cache/(dev|prod)/smarty/compile` folder (except the `index.php` file) in order to see your changes applied or clear cache directly from Back-Office. - -Note that this setting can be made directly from the back office, in the “Performance” page under the “Advanced parameters” menu. - -### parameters.php - -This file contains some of important settings such as database connection details and caching mechanism. If you change something in this file, make sure to delete cache files manually from `/var/cache/(dev|prod)` folder. - -## Disable the Back-Office token protection - -Back-Office pages require the use of a token. If needed, this protection can be disabled using an environment variable: - -### Apache with mod_headers - -```bash -SetEnv _TOKEN_ disabled -``` - -### Nginx with ngx_http_headers_module - -```bash -add_header _TOKEN_ disabled; -``` diff --git a/basics/installation/httpd.md b/basics/installation/httpd.md index b6e41f6481..e21ab89bca 100644 --- a/basics/installation/httpd.md +++ b/basics/installation/httpd.md @@ -44,12 +44,13 @@ It may be incomplete, and remember you must adapt it for your own server's needs ## With PHP-FPM You first have to ensure you have the `php-fpm` binary and Apache's FastCGI installed. -On a Debian based, packages are `libapache2-mod-fcgid` and `php7.1-fpm`. +On a Debian based, packages are `libapache2-mod-fcgid` and `php7.2-fpm`. After installing these packages, fpm service will automatically be started. PHP-FPM uses so-called pools to handle incoming FastCGI requests. Here's an example: + ```ini ; a pool called www [www] @@ -57,7 +58,7 @@ user = www-data group = www-data ; use a unix domain socket -listen = /var/run/php/php7.1-fpm.sock +listen = /var/run/php/php7.2-fpm.sock ; or listen on a TCP socket ; listen = 127.0.0.1:9000 @@ -92,7 +93,7 @@ Don't forget to edit this configuration to make it works. # with mod_rewrite or mod_autoindex # SetHandler proxy:fcgi://127.0.0.1:9000 - SetHandler proxy:unix:/var/run/php/php7.1-fpm.sock|fcgi://dummy + SetHandler proxy:unix:/var/run/php/php7.2-fpm.sock|fcgi://dummy DocumentRoot /path/to/prestashop diff --git a/basics/installation/install-from-cli.md b/basics/installation/install-from-cli.md new file mode 100644 index 0000000000..268c6669c1 --- /dev/null +++ b/basics/installation/install-from-cli.md @@ -0,0 +1,111 @@ +--- +title: Installing PrestaShop from CLI +menuTitle: Installation from CLI +weight: 15 +--- + +# Installing PrestaShop from CLI + +Since version 1.5.4, PrestaShop has a command-line installer. + +This special installer makes it possible to install PrestaShop without the need to use a web browser: simply put the content of the zip archive on your web server or pull code from an official PrestaShop repository, and you can install PrestaShop through your command-line interface (CLI). + +{{% notice info %}} +If deploying from sources (PrestaShop repository), you must first install Composer dependencies. +Install them with `composer install` from project's root directory. +{{% /notice %}} + +The point of having a CLI installer in addition to the regular in-browser installer is to provide a solution to some advanced users, who often prefer command-line interfaces as they tend to give a more concise and powerful means to control a program or operating system. We can see the advantage of CLI installer in Continuous Integration processes. + +## How to use it + +To use the CLI installer, use your terminal, go to the `/install` (or `/install-dev`) folder, and start the script with this command: + +```shell +php index_cli.php +``` + +This command, by default, will display the various available options: + +| Argument | Description | Default value | Allowed values | +| :-------------- | :----------------------------------------- | :--------------------------- | :---------------------------------------------------------------------------------------------------- | +| `step` | Installation steps to execute | all | all, database, fixtures, theme, modules, postInstall | +| `language` | Language ISO code to install | en | 2 letters ISO 639-1 code ([ISO 639-1][iso-639-1]) with available translation files in `/translations` | +| `all_languages` | Installs all available languages | 0 | 0, 1 | +| `timezone` | Set timezone of instance | Europe/Paris | Valid timezone ([TZ Database][tz-database]) | +| `base_uri` | Base URI (appended after domain name) | / | Any URI | +| `domain` | Domain name for the shop (without http/s) | localhost | Any domain name or IP address | +| `db_server` | Database server hostname | localhost | Any valid MySQL valid server name or IP address | +| `db_user` | Database server user | root | Any valid MySQL user name | +| `db_password` | Database server password | "" | The valid password for `db_user` | +| `db_name` | Database name | prestashop | _string_ | +| `db_clear` | Drop existing tables | 1 | 0, 1 | +| `db_create` | Create the database if not exists | 0 | 0, 1 | +| `prefix` | Prefix of table names | ps\_ | _string_ | +| `engine` | Engine for MySQL | InnoDB | InnoDB, MyISAM | +| `name` | Name of the shop | PrestaShop | _string_ | +| `activity` | Default activity of the shop | 0 | Id of an activity ([Complete list of activities][activities]) | +| `country` | Country of the shop | fr | 2 letters Alpha-2 code of ISO-3166 list([ISO-3166][iso-3166]) | +| `firstname` | Admin user firstname | John | _string_ | +| `lastname` | Admin user lastname | Doe | _string_ | +| `password` | Admin user password | Correct Horse Battery Staple | _string_ | +| `email` | Admin user email | pub@prestashop.com | _string_ | +| `license` | Show PrestaShop license after installation | 0 | 0, 1 | +| `theme` | Theme name to install | "" (classic) | Theme name (located in `/themes`) | +| `ssl` | Enable SSL (from PS 1.7.4) | 0 | 0, 1 | +| `rewrite` | Enable rewrite engine | 1 | 0, 1 | +| `fixtures` | Install fixtures | 1 | 0, 1 | +| `modules` | Modules to install, separated by comma | [] (all) | _array_ of module names (located in `/modules`) | + +- All the options from the regular in-browser installer are available, with their default values listed above. +- Almost all default option values can be left as is because you can edit them all from the PrestaShop Back Office once the installation is complete. + +{{% notice info %}} +Note that the e-mail and password are used to create the administrator's Back Office account. +{{% /notice %}} + +To start the installation, we recommend that you provide at least these arguments : + +- `domain`. The domain name where your shop will be available. +- `db_server`. The database server address. +- `db_name`. The name of the database you want to use. **We strongly recommend that you change the default `prestashop` value** +- `db_user`. The username for the database you want to use. +- `db_password`. The password for the database username above. +- `prefix`. **We strongly recommend that you change the default `ps_` value.** +- `email`. Your email to connect to the Back Office. +- `password`. The password to connect to the Back Office. + +Example: + +```shell +php index_cli.php + --domain=example.com + --db_server=sql.example.com + --db_name=myshop + --db_user=root + --db_password=123456789 + --prefix=myshop_ + --email=me@example.com + --password=mystrongpassword +``` + +If the installation completes without any errors, you should see the following confirmation: + +```shell +-- Installation successful! -- +``` + +{{% notice info %}} +Before running this command, please note that your database must be created with a `CREATE DATABASE xxx;` statement. +If the database is not created, please use argument `--db_create=1` to create the database. +{{% /notice %}} + +{{% notice info %}} +If your MySQL server is configured on a different port than `3306`, please specify it in the `db_server` argument like this : +`--db_server=sql.example.com:3307` +{{% /notice %}} + +[iso-639-1]: https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes +[tz-database]: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones +[activities]: https://github.com/PrestaShop/PrestaShop/blob/8.0.x/src/PrestaShopBundle/Form/Admin/Configure/ShopParameters/General/PreferencesType.php#L211-L230 +[iso-3166]: https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes diff --git a/basics/installation/localhost.md b/basics/installation/localhost.md index 7111319777..dab8bd3ccc 100644 --- a/basics/installation/localhost.md +++ b/basics/installation/localhost.md @@ -2,6 +2,7 @@ title: Installing a local environment menuTitle: Development environment weight: 15 +mostViewedPage: true --- # Installing PrestaShop for development @@ -16,14 +17,14 @@ Read [System Requirements][system-requirements]. Installing any web-application locally requires that you first install the adequate environment, namely the Apache web server, the PHP language interpreter, the MySQL database server, and ideally a MySQL admin tool such as phpMyAdmin tool. -This is called an *AMP package: Apache+MySQL+PHP and the operating system, giving WAMP (Windows+Apache+MySQL+PHP), MAMP (Mac OS X+…) and LAMP (Linux+…). Since all of the items packaged are open-source, these installers are most of the time free. +This is called an *AMP package: Apache+MySQL+PHP and the operating system, giving WAMP (Windows+Apache+MySQL+PHP), MAMP (macOS…) and LAMP (Linux+…). Since all of the items packaged are open-source, these installers are most of the time free. Here is a selection of free AMP installers: -* [XAMPP](https://www.apachefriends.org/download.html) (Windows, Mac OS X, Linux, Solaris) +* [XAMPP](https://www.apachefriends.org/download.html) (Windows, macOS, Linux, Solaris) * [WampServer](http://www.wampserver.com/) (Windows) * [EasyPHP](https://www.easyphp.org/) (Windows) -* [MAMP](https://www.mamp.info/en/mamp/) (Windows, Mac OS X) +* [MAMP](https://www.mamp.info/en/mamp/) (Windows, macOS) * [Laragon](https://laragon.org/) (Windows) To install LAMP on your computer follow these steps (tested on Debian Buster). @@ -123,11 +124,11 @@ If you intend to work on PrestaShop itself, we suggest using Git to clone the so As stated above, if you decide to work on PrestaShop itself, it's best to clone the PrestaShop repository and work using git. Depending on the version of PrestaShop you want to work on, you will need to choose the right branch: -* The [develop branch](https://github.com/PrestaShop/PrestaShop/tree/develop) contains the current work in progress for the next minor or major version. +* The [develop branch](https://github.com/PrestaShop/PrestaShop/tree/8.0.x) contains the current work in progress for the next minor or major version. - **This is the right branch to contribute new features, refactors, small bug fixes, etc.** * The maintenance branches (_8.0.x, ..._) contains all patches made for each minor version. - For example, the _8.0.x_ branch contains all patches from 8.0.0 to 8.0.99. - - Whenever a new minor or major version is ready for release, a new maintenance branch is created. For example, _8.0.x_ for version 8.0.0, _8.1.x_ for 8.1.0, 8.2.x_ for 8.2.0, and so forth. + - Whenever a new minor or major version is ready for release, a new maintenance branch is created. For example, _8.0.x_ for version 8.0.0, _8.1.x_ for 8.1.0, and so forth. - **Only the most recent maintenance branch accepts new contributions** {{% /callout %}} @@ -155,16 +156,26 @@ composer install # or alternatively: make composer ``` + ### JavaScript and CSS dependencies PrestaShop uses NPM to manage dependencies and [Webpack][webpack] to compile them into static assets. -You only need NodeJS 8.x (14.x recommended [get it here][nodejs]), NPM will take care of it all. +You only need NodeJS 14.x (16.x recommended [get it here][nodejs]), NPM will take care of it all. ```bash cd /path/to/prestashop make assets ``` +You can also compile assets for the particular element of the system: + +- `make admin-default` - for the legacy back office theme +- `make admin-new-theme` - for the new back office theme +- `make front-core` - front office theme core assets +- `make front-classic` - front office default theme assets +- `make front` - all assets for the the front office +- `make admin` - all assets for the the back office + Alternatively, you can [compile assets][compile-assets] manually. @@ -174,8 +185,6 @@ PrestaShop needs recursive write permissions on several directories: - ./admin-dev/autoupgrade - ./app/config -- ./app/logs -- ./app/Resources/translations - ./cache - ./config - ./download @@ -190,13 +199,15 @@ PrestaShop needs recursive write permissions on several directories: - ./var You can set up the appropriate permissions using this command: + ```bash -$ chmod -R +w admin-dev/autoupgrade app/config app/logs app/Resources/translations cache config download img log mails modules override themes translations upload var +$ chmod -R +w admin-dev/autoupgrade app/config var/logs cache config download img log mails modules override themes translations upload var ``` If you do not have some of the folders above, please create them before changing permissions. For example: + ```bash -$ mkdir log app/logs +$ mkdir log var/logs ``` To ease up your life on a development environment, we suggest to make Apache run with your own user and group. @@ -224,7 +235,7 @@ You may find this error message the first time you open up the Back Office. This problem may arise in case-insensitive file systems like MacOS due to a misconfiguration. Check your Apache configuration and make sure that the root directory path to your PrestaShop matches the capitalization of the actual system path exactly. A typical error is for example having a folder named `/path/to/PrestaShop` (capital P, capital S) and then configuring it in Apache as `/path/to/Prestashop` (missing the capital S). -[getting-started-guide]: https://doc.prestashop.com/display/PS17/Getting+Started +[getting-started-guide]: https://docs.prestashop-project.org/v.8-documentation/v/english/getting-started [system-requirements]: {{< relref "system-requirements" >}} [clone-the-repository]: {{< relref "/8/themes/getting-started/setting-up-your-local-environment" >}} [compile-assets]: {{< relref "/8/development/compile-assets" >}} diff --git a/basics/installation/nginx.md b/basics/installation/nginx.md index ef958cf3ce..99dcebf1d8 100644 --- a/basics/installation/nginx.md +++ b/basics/installation/nginx.md @@ -141,4 +141,4 @@ server { } ``` -[nginx-scale]: {{< ref "1.7/scale/webservers/nginx" >}} +[nginx-scale]: {{< ref "8/scale/webservers/nginx" >}} diff --git a/basics/installation/system-requirements.md b/basics/installation/system-requirements.md index 7a2178f40e..cbaf9a4a82 100644 --- a/basics/installation/system-requirements.md +++ b/basics/installation/system-requirements.md @@ -2,6 +2,7 @@ title: System requirements for PrestaShop 8 menuTitle: System requirements weight: 10 +mostViewedPage: true --- + +# Notable changes in PrestaShop 8.1 + +## PHP support + +PrestaShop 8.1 has the same PHP requirement as Prestashop 8.0. + +[PrestaShop 8.0][80-changes] added support for PHP 8.0 and PHP 8.1 and required at least PHP 7.2.5. + +## New product page + +The new Product page in Back Office has been introduced. [Discover how to extend it with modules in this chapter][new-product-page]. + +## Notable changes + +* Introduction of `_raw` parameter on translations to avoid html escaping in translator. [PR#30415](https://github.com/PrestaShop/PrestaShop/pull/30415) +* Changed location of Smarty caching type configuration from database to `config/defines.inc.php` [PR#29172](https://github.com/PrestaShop/PrestaShop/pull/29172) +* Improve extendability of the new product page form in BO: added `NavigationTabType` to create custom tabs in BO product page [PR#28752](https://github.com/PrestaShop/PrestaShop/pull/28752) +* Moved grid column type classes, see deprecation list below [PR#30800](https://github.com/PrestaShop/PrestaShop/pull/30800) +* Behavior change: when deleting an image type, its images are now deleted [PR#30510](https://github.com/PrestaShop/PrestaShop/pull/30510) +* Auto update of modules configuration option is no longer available [PR#30467](https://github.com/PrestaShop/PrestaShop/pull/30467) +* Added getters in `CmsController`, `OrderConfirmationController`, `ProductController`, `CategoryController`, `ManufacturerController`, `SupplierController` [PR#30408](https://github.com/PrestaShop/PrestaShop/pull/30408) +* Added `Currency::getDefaultCurrencyId()` method to avoid retrieving `PS_CURRENCY_DEFAULT` from configuration in various classes [PR#30398](https://github.com/PrestaShop/PrestaShop/pull/30398) +* `actionAjaxDieBefore` now receives its `value` parameter via reference [PR#30347](https://github.com/PrestaShop/PrestaShop/pull/30347) +* Deprecated `Validate::isAnything()` since it was always returning `true` [PR#30163](https://github.com/PrestaShop/PrestaShop/pull/30163) +* Refactored frontend sitemap and introduced `actionModifyFrontendSitemap` hook [PR#29797](https://github.com/PrestaShop/PrestaShop/pull/29797) +* Introduced `actionGenerateDocumentReference` hook to allow overriding order reference [PR#29781](https://github.com/PrestaShop/PrestaShop/pull/29781) +* Introduced 3 new hooks about Contact Page: `displayContactRightColumn`, `displayContactContent`, `displayContactLeftColumn` in `classic` and `hummingbird` themes, and removed related widget hooks [PR#29516](https://github.com/PrestaShop/PrestaShop/pull/29516) +* Introduced `Tools::getCurrentUrl()` to retrieve the current URL in a hook [PR#28541](https://github.com/PrestaShop/PrestaShop/pull/28541) +* BC break: `Shop::getBaseURL()` use secure mode by default [PR#28469](https://github.com/PrestaShop/PrestaShop/pull/28469) +* Vue was upgraded from 2.6 to 3.2, see below [PR#28463](https://github.com/PrestaShop/PrestaShop/pull/28463) +* Customer Settings > Customer page is now multistore compatible [PR#27608](https://github.com/PrestaShop/PrestaShop/pull/27608) +* Introduced `PrestaShop\PrestaShop\Core\Security\PasswordGenerator` class to generate random passwords with multiples types/lengths [PR#31004](https://github.com/PrestaShop/PrestaShop/pull/31004) +* Introduced `PrestaShop\PrestaShop\Core\Security\Hashing` class to hash a password from a plain text and a salt with md5 [PR#31004](https://github.com/PrestaShop/PrestaShop/pull/31004) +* Introduced `actionProductPriceCalculation` hook [PR#27927](https://github.com/PrestaShop/PrestaShop/pull/27927) +* Added a new Smarty variable `theme_dir` in front controllers [PR#30383](https://github.com/PrestaShop/PrestaShop/pull/30383) +* Added a feature to disable `core.js` loading on custom themes [PR#29995](https://github.com/PrestaShop/PrestaShop/pull/29995). [More informations][corejs-informations] +* Added supplier url and manufacturer url to Smarty `{url}` helper [PR#30242](https://github.com/PrestaShop/PrestaShop/pull/30342) and [PR#30314](https://github.com/PrestaShop/PrestaShop/pull/30314) +* Fixed modules autoloaders and service configurations registrations priority [PR#30588](https://github.com/PrestaShop/PrestaShop/pull/30588). [More informations]({{< relref "/8/modules/concepts/services/#advanced-services-parameters-_instanceof-or-interface-binding-manual-tags" >}}) + +## BC Breaks (Backward Compatibility Breaks) + +* `Shop::getBaseURL()` use secure mode by default [PR#28469](https://github.com/PrestaShop/PrestaShop/pull/28469) +* For the class `PrestaShop\PrestaShop\Core\Domain\TaxRulesGroup\QueryResult`, constructor parameters are now `TaxRulesGroupId $taxRulesGroupId, string $name, bool $active, array $shopAssociationIds` [PR#28812](https://github.com/PrestaShop/PrestaShop/pull/28812) +* Webservice does now respect the maximum image upload size set in back office (`PS_LIMIT_UPLOAD_IMAGE_VALUE`) [PR#29135](https://github.com/PrestaShop/PrestaShop/pull/29135) + +## Deprecations + +### PHP + +* `PrestaShop\PrestaShop\Core\String\CharacterCleaner` → Its use is not required +* `Customer::validateController()` → The password check has been moved in controllers and this method is not called anywhere since 1.7.0 +* `Prestashop\PrestaShop\Core\Grid\Column\Type\BooleanColumn` → moved to `PrestaShop\PrestaShop\Core\Grid\Column\Type\Common\BooleanColumn` +* `Prestashop\PrestaShop\Core\Grid\Column\Type\ColorColumn` → moved to `PrestaShop\PrestaShop\Core\Grid\Column\Type\Common\ColorColumn` +* `Prestashop\PrestaShop\Core\Grid\Column\Type\Common\IdentifierColumn` → moved to `PrestaShop\PrestaShop\Core\Grid\Column\Type\Common\IdentifierColumn` +* `Prestashop\PrestaShop\Core\Grid\Column\Type\DataColumn` → moved to `PrestaShop\PrestaShop\Core\Grid\Column\Type\Common\DataColumn` +* `Prestashop\PrestaShop\Core\Grid\Column\Type\DisableableLinkColumn` → moved to `PrestaShop\PrestaShop\Core\Grid\Column\Type\Common\DisableableLinkColumn` +* `Prestashop\PrestaShop\Core\Grid\Column\Type\LinkGroupColumn` → moved to `PrestaShop\PrestaShop\Core\Grid\Column\Type\Common\LinkGroupColumn` +* `Prestashop\PrestaShop\Core\Grid\Column\Type\OrderPriceColumn` → moved to `PrestaShop\PrestaShop\Core\Grid\Column\Type\Order\OrderPriceColumn` +* `Prestashop\PrestaShop\Core\Grid\Column\Type\PreviewColumn` → moved to `PrestaShop\PrestaShop\Core\Grid\Column\Type\Common\PreviewColumn` +* `Prestashop\PrestaShop\Core\Grid\Column\Type\PrivateColumn` → moved to `PrestaShop\PrestaShop\Core\Grid\Column\Type\Common\PrivateColumn` +* `CmsController::$cms` → use `$cmsControllerInstance->getCms()` instead +* `CmsController::$cms_category` → use `$cmsControllerInstance->getCmsCategory()` instead +* `Validate::isAnything()` → will be removed in 9.0 since returns always `true` + +## Updated dependencies + +### PHP libraries + +| Library name | Old version | New version | +|------------------------------------|---------------------------------------------------------------|---------------| +| api-platform/core | _~ Not present ~_ | ^2.7 | +| lcobucci/jwt | _~ Not present ~_ | ^3.4.6 | +| league/oauth2-server | _~ Not present ~_ | ^8.3 | +| nyholm/psr7 | _~ Not present ~_ | ^1.5 | +| symfony/psr-http-message-bridge | _~ Not present ~_ | ^2.1 | + +### JS libraries + +| Library name | Old version | New version | +|------------------------------------|---------------------------------------------------------------|---------------| +| vue | 2.6.x | 3.2.x | + +{{% notice note %}} +As `Vue` 2.x [will reach EOL on December 31st, 2023](https://v2.vuejs.org/lts/), `Vue` dependency was bumped to 3.2. +Every linked dependencies were also bumped to higher version to keep 3.2 compatibility. +Please refer to: [PR#28463](https://github.com/PrestaShop/PrestaShop/pull/28463) for an exhaustive list. +{{% /notice %}} + +[80-changes]: {{< relref "8/modules/core-updates/8.0.md" >}} +[corejs-informations]: {{< relref "8/themes/getting-started/theme-yml" >}} +[new-product-page]: {{< relref "8/modules/sample-modules/extend-product-page" >}} \ No newline at end of file diff --git a/modules/core-updates/_index.md b/modules/core-updates/_index.md index 58e76a01fb..6138600419 100644 --- a/modules/core-updates/_index.md +++ b/modules/core-updates/_index.md @@ -2,6 +2,7 @@ title: Core changes weight: 60 chapter: true +showOnHomepage: true --- # Core changes diff --git a/modules/core-updates/img/password-policy-bo.png b/modules/core-updates/img/password-policy-bo.png new file mode 100644 index 0000000000..91d58cc581 Binary files /dev/null and b/modules/core-updates/img/password-policy-bo.png differ diff --git a/modules/core-updates/img/password-policy-fo.png b/modules/core-updates/img/password-policy-fo.png new file mode 100644 index 0000000000..beb37ddfae Binary files /dev/null and b/modules/core-updates/img/password-policy-fo.png differ diff --git a/modules/core-updates/new-password-policy.md b/modules/core-updates/new-password-policy.md new file mode 100644 index 0000000000..602d10bf07 --- /dev/null +++ b/modules/core-updates/new-password-policy.md @@ -0,0 +1,73 @@ +--- +title: New password policy based on zxcvbn +menuTitle: New password policy +--- + +# New password policy introduced in 8.0.x + +A new password policy was introduced in 8.0.x for Customers and Employees passwords. + +This password policy is based on `Zxcvbn`. + +{{% notice note %}} +`Zxcvbn` is a password strength estimation library that is designed to help developers create secure password policies for their applications. It was developed by DropBox and [is available as an open-source library](https://github.com/dropbox/zxcvbn). + +It estimates the strength of a password by analyzing various factors such as its length, the use of special characters, and the presence of common words or patterns. The goal of zxcvbn is to provide a more accurate and user-friendly way of assessing password strength compared to traditional approaches, which often rely on simple checks such as minimum length or the presence of certain types of characters. + +To use `Zxcvbn`, you provide the password as input to the library and it returns an estimated strength score. The score is a number between 0 and 4, with higher numbers indicating stronger passwords. This score is then used to provide feedback to users on the strength of their chosen password. +{{% /notice %}} + +When creating / updating a `Customer` account, or an `Employee` account, the `Zxcvnb` api is used to determine the score, and make an instant feedback using Javascript to the `User`: + +![Password policy in back office for Employees](../img/password-policy-bo.png) + +![Password policy in front office for Customers](../img/password-policy-fo.png) + +## Changes introduced in PrestaShop by this new policy + +This new password policy introduced some backward compatibility breaks: + +* File `jquery-passy.js` is no longer available +* Form field `change-password` is no longer working as it was for [passy](https://timseverien.github.io/passy/) integration +* The password now requires a correct length whatever is it the Front or the Back Office +* `AddEmployeeCommand` now requires `hasEnabledGravatar`, `minLength`, `maxLength` and `minScore` +* `EditEmployeeCommand::setPlainPassword` now requires `minLength`, `maxLength` and `minScore` +* `Employee\ValueObject::Password` now requires `minLength`, `maxLength` and `minScore` +* `Employee/EmployeeType` now requires an instance of `ConfigurationInterface` +* `ChangePasswordType` now requires an instance of `ConfigurationInterface` +* `Core/Domain/Employee/ValueObject/Password::MIN_LENGTH` and `Core/Domain/Employee/ValueObject/Password::MAX_LENGTH` are no longer available +* `Employee\ValueObject\Password::__construct` signature changed to `string $password, int $minLength, int $maxLength, int $minScore` +* `PrestaShopBundle/Form/Admin/Type/ChangePasswordType::__construct` now require a `ConfigurationInterface` + +And some deprecations: + +* `Validate::isPlaintextPassword` is deprecated +* `Validate::isPasswdAdmin` is deprecated + +{{% notice note %}} +Please note that the library is loaded asyncronously in `core.js` because of its size. +{{% /notice %}} + +## Upgrade guide for your module / theme + +### How to update your code for backend development + +If your module is creating / updating `Customers` or `Employees`, make sure to update your code according to the BC breaks and deprecations indicated above. + +### How to update your frontend theme + +If your theme is creating / updating `Customers` or `Employees`, make sure to update your code according to the BC breaks related to themes (`jquery-passy.js` no longer available, and form field `change-password` no longer working). + +If your theme is extending `PrestaShop/classic-theme`, + +- make sure your modifications (if any) to `template/customer/_partials/customer-form.tpl` does not change the `div` added around `password fields`: + +``` +
+ {form_field field=$field} +
+``` + +- make sure your modifications on your theme does not alter the requirement of `_partials/password-policy-template.tpl` in the Javascripts includes. + +- make sure your modifications on your theme does not alter the `templates/_partials/form-fields.tpl` file on the password field, [please refer here for requirements](https://github.com/PrestaShop/classic-theme/pull/21/files#diff-2b3eb6586609ac820d08cd566e45c06c2dd477060b2ffadeda1fb1d2941d69b7). \ No newline at end of file diff --git a/modules/creation/_index.md b/modules/creation/_index.md index 405a5ca7e1..36ce1b90aa 100644 --- a/modules/creation/_index.md +++ b/modules/creation/_index.md @@ -1,6 +1,7 @@ --- title: "Getting Started" weight: 10 +showOnHomepage: true --- # Getting Started diff --git a/modules/creation/displaying-content-in-front-office.md b/modules/creation/displaying-content-in-front-office.md index ea1e84e9c0..02b545c9ec 100644 --- a/modules/creation/displaying-content-in-front-office.md +++ b/modules/creation/displaying-content-in-front-office.md @@ -64,7 +64,7 @@ Add the following to your mymodule.php file: { $this->context->controller->registerStylesheet( 'mymodule-style', - $this->_path.'views/css/mymodule.css', + 'modules/' . $this->name . '/views/css/mymodule.css', [ 'media' => 'all', 'priority' => 1000, @@ -73,7 +73,7 @@ Add the following to your mymodule.php file: $this->context->controller->registerJavascript( 'mymodule-javascript', - $this->_path.'views/js/mymodule.js', + 'modules/' . $this->name . '/views/js/mymodule.js', [ 'position' => 'bottom', 'priority' => 1000, @@ -308,8 +308,11 @@ class mymoduledisplayModuleFrontController extends ModuleFrontController - *display.tpl* -``` -Welcome to my shop! +```smarty +{extends file='page.tpl'} +{block name='page_content'} + Welcome to my shop! +{/block} ``` Let's explore `display.php`, our first PrestaShop front-end controller, @@ -390,8 +393,11 @@ in our TPL file. - *mymodule.tpl* -``` -{$my_module_message} +```smarty +{extends file='page.tpl'} +{block name='page_content'} + {$my_module_message} +{/block} ``` PrestaShop adds its own set of variables. For instance, diff --git a/modules/creation/external-services.md b/modules/creation/external-services.md index 382674f01f..d35de1f21a 100644 --- a/modules/creation/external-services.md +++ b/modules/creation/external-services.md @@ -73,7 +73,7 @@ HTTP requests can be triggered from a shop to an external service. Several methods allows requests to be sent (in order of preference): -* [Guzzle](https://github.com/guzzle/guzzle). The version 5 is included from PrestaShop {{< minver v="1.7.0" >}}, but can be included in your module as well for older PS versions. +* [Guzzle](https://github.com/guzzle/guzzle). The version 7.4 is included from PrestaShop {{< minver v="8.0" >}} (version 5 in {{< minver v="1.7.0" >}}), but can be included in your module as well for older PS versions. * Loading in memory another version of guzzle in the same namespace will trigger errors on the shop. * Example with PS Checkout module: [Inclusion in composer.json](https://github.com/PrestaShopCorp/ps_checkout/blob/578135d8bef2d99b8056ebc0bd709e9a87d661e6/composer.json#L28) & [implementation](https://github.com/PrestaShopCorp/ps_checkout/blob/ef48da09735e6e64b42364a703b5a74d41cd24d9/classes/Api/Payment/Dispute.php) * [\Tools::file_get_contents(...)](https://github.com/PrestaShop/PrestaShop/blob/a07a569b45ab6afc777f25aba505997004e5f70a/classes/Tools.php#L2212-L2223) diff --git a/modules/creation/good-practices.md b/modules/creation/good-practices.md index 2168712a9a..fa79b02cce 100644 --- a/modules/creation/good-practices.md +++ b/modules/creation/good-practices.md @@ -52,9 +52,9 @@ menuTitle: Good practices - When your module has forms, you should: - show a confirmation message if everything went fine or an error message if it did not. - - make sure information entered by customers are correct. If you ask a sum, it has to be only numbers. More information about the Validate class of PrestaShop [here](https://github.com/PrestaShop/PrestaShop/blob/develop/classes/Validate.php). + - make sure information entered by customers are correct. If you ask a sum, it has to be only numbers. More information about the Validate class of PrestaShop [here](https://github.com/PrestaShop/PrestaShop/blob/8.0.x/classes/Validate.php). -- Consider carefully casting your variables and use pSQL/bqSQL in the SQL requests to avoid any injections (read [Best Practices of the Db Class](https://doc.prestashop.com/display/PS16/Best+Practices+of+the+Db+Class)). Make sure your files are properly protected (especially if your module uses a cron for example) to avoid anyone being able to execute them. As a result, you are required to use a token! +- Consider carefully casting your variables and use pSQL/bqSQL in the SQL requests to avoid any injections (read [Best Practices of the Db Class](https://docs.prestashop-project.org/1-6-documentation/developer-guide/developer-tutorials/best-practices-of-the-db-class)). Make sure your files are properly protected (especially if your module uses a cron for example) to avoid anyone being able to execute them. As a result, you are required to use a token! - The use of overrides is permitted, however if we decide that too many (2 / 3 max) have been used and/or the modifications are too dangerous, we will refuse your module. If you're unsure, don't hesitate to get in touch. @@ -85,9 +85,9 @@ add a preliminary check before using them (I.e with `extension_loaded`). This pr **A few recommendations for your email templates** -- Use our [official SDK](https://github.com/PrestaShop/email-templates-sdk) to develop your emails: +- Use our [official SDK](https://github.com/PrestaShopCorp/email-templates-sdk) to develop your emails: - Make sure to submit on Addons a valid zip, built with the SDK. -- Test your emails with the [official module](https://github.com/PrestaShop/email-templates-sdk). +- Test your emails with the [official module](https://github.com/PrestaShopCorp/email-templates-sdk). [coding-standards]: {{< ref "8/development/coding-standards" >}} [display-content-front-office]: {{< ref "8/modules/creation/displaying-content-in-front-office" >}} diff --git a/modules/creation/module-translation/classic-system.md b/modules/creation/module-translation/classic-system.md index c000187382..9cbf2bbbe9 100644 --- a/modules/creation/module-translation/classic-system.md +++ b/modules/creation/module-translation/classic-system.md @@ -243,7 +243,6 @@ sprintf=['[foo]' => 'some replacement, '%bar%' => 'something else'] {{% /notice %}} - #### Interpolating HTML You may need to add HTML content in your translated string. Writing it directly in the string (original or translated) won't work, as the special characters would be escaped to avoid XSS security issues. @@ -401,7 +400,7 @@ $this->l('Some '. $var . ' wording'); public function translate($wording) { $this->l($wording); } -``` +``` ### Language codes @@ -415,5 +414,5 @@ In the meantime, refer to this list for the equivalences between language codes [iso-619-1]: https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes [ietf-language-tags]: https://en.wikipedia.org/wiki/IETF_language_tag -[legacy-to-standard]: https://github.com/PrestaShop/PrestaShop/blob/1.7.6.x/app/Resources/legacy-to-standard-locales.json +[legacy-to-standard]: https://github.com/PrestaShop/PrestaShop/blob/8.0.x/app/Resources/legacy-to-standard-locales.json [new-translation-system]: {{< ref "new-system" >}} diff --git a/modules/creation/module-translation/new-system.md b/modules/creation/module-translation/new-system.md index e6d5128606..ca0940e515 100644 --- a/modules/creation/module-translation/new-system.md +++ b/modules/creation/module-translation/new-system.md @@ -52,7 +52,7 @@ To make your module translatable, you need to adapt your module's source code. F Don't worry if you don't translate everything to all languages right away. Any wording left untranslated will be shown in its original language. Because of this, we suggest writing all your wordings in English, and then translating them to other languages. {{% /notice %}} -### Translation domain +### Translation domain {#translation-domain} An important part of the new translation system is **Translation Domains**, which replaces the classic system's [contextualization][contextualization]. In the new translation system, all wordings must be linked to at least one translation domain. @@ -122,12 +122,14 @@ When translating wordings in the module's main class, since it extends the `Modu version = '1.0.0'; + $this->author = 'Me'; $this->displayName = $this->trans('My module', [], 'Modules.Mymodule.Mymodule'); - $this->description = $this->trans('Description of my module.', [], 'Modules.Mymodule.Mymodule'); + $this->description = $this->trans('Description of my module. Made by: %author%, Current Version: %version%', ['%version%' => $this->version ,'%author% => $this->author], 'Modules.Mymodule.Mymodule'); } } ``` @@ -136,25 +138,25 @@ Since the module is called MyModule, the translation domain should be `Modules.M #### Module controllers -`ModuleAdminController` and `ModuleFrontController` can access the module instance via the `$this->module` property. +`ModuleAdminController` and `ModuleFrontController` can access the module instance and translator via the `$this->module` property and `getTranslator()` public accessor. ```php title = $this->module->trans('My module title', [], 'Modules.Mymodule.Something'); + $this->title = $this->module->getTranslator()->trans('My module title', [], 'Modules.Mymodule.Something'); } } ``` -Symfony controllers work exactly the same as the Core's. Just use `$this->trans` method. +Symfony controllers work exactly the same as the Core's. Just use `$this->trans()` method. {{% notice warning %}} -Be aware that in symfony controllers, the second and third arguments have been swapped to make `$replacements` optional. +Be aware that in Symfony controllers, the second and third arguments have been swapped to make `$replacements` optional. {{% /notice %}} ```php @@ -172,27 +174,32 @@ class SomeAdminController extends FrameworkBundleAdminController #### Other classes -Other classes will need to retrieve the module's instance somehow. We recommend passing it as a parameter in the constructor and storing it for later use. +Other classes will need to retrieve the module's translator instance somehow. We recommend passing it as a parameter in the constructor and storing it for later use. ```php module = $module + $this->translator = $translator } public function foo() { - $this->text = $this->module->trans('My text to translate', [], 'Modules.Mymodule.Custommoduleclass'); + $this->text = $this->translator->trans('My text to translate', [], 'Modules.Mymodule.Custommoduleclass'); } } + +// from within the module: +$customModuleClass = new _NAMESPACE_\CustomModuleClass($this->getTranslator()); ``` -If you really need to, you can also retrieve a new instance of your module using `Module::getInstanceByName('mymodulename')`. This should be avoided though, as it's not a good practice. +{{% notice info %}} +If you really need to, you can also retrieve a new instance of your module using `$module = Module::getInstanceByName('mymodulename')`, and then access the `translator` with `$module->getTranslator()`. This should be avoided though, as it's not a good practice. +{{% /notice %}} ### Templates @@ -298,7 +305,7 @@ In Twig files, you can use `trans_default_domain` to set up your default domain. {% trans_default_domain 'Modules.Mymodule.Foo' %} {{ 'Hello world'|trans }} {{ 'Something else'|trans }} -``` +``` ## Distributing your translations diff --git a/modules/creation/tutorial.md b/modules/creation/tutorial.md index 9953490226..0091c54aee 100644 --- a/modules/creation/tutorial.md +++ b/modules/creation/tutorial.md @@ -10,12 +10,12 @@ weight: 1 Before you start writing code for your PrestaShop module, we recommend reading PrestaShop's [Coding standards]({{< ref "/8/development/coding-standards" >}}). Configuring your IDE hints or using [automated tools](https://github.com/PrestaShop/php-dev-tools) can help you make sure you follow the project's standards properly. {{% /notice %}} -Let's create a simple first module; this will enable us to better describe its structure. We will name it **"My module"**. +Let's create a first simple module, this will allow us to better describe its structure. We will name it **"My module"**. First, create the module's folder, in PrestaShop's `/modules` folder. Let's call it `mymodule`. This will be the module's "technical" name. {{% notice tip %}} -Technical names can only accept lower case alphanumeric characters (`[a-z0-9]`). Although accepted, we strongly discourage using underscores because they don't work with translation domains. +Technical names can only accept lower case alphanumeric characters (`[a-z0-9]`). [Although accepted, we strongly discourage using underscores because they don't work with translation domains]({{< ref "/8/modules/creation/module-translation/new-system#translation-domain" >}}). {{% /notice %}} This folder must contain the main file, a PHP file of the same name as the folder, which will handle most of the processing: `mymodule.php`. @@ -64,7 +64,7 @@ At this stage, if you place the module's folder on the `/modules` folder, the mo ## The constructor method -Now, let's fill the class' code block with the essential constructor lines. Since the constructor is the first method to be called when the module is loaded by PrestaShop, this is the best place to set its details. +Now, let's create the constructor method of the module. Since the constructor is the first method to be called when the module is loaded by PrestaShop, this is the best place to set its details. ```php name = 'mymodule'; @@ -243,51 +243,14 @@ public function uninstall() As you can see, our three blocks of code (`__construct()`, `install()` and `uninstall()`) all make use of a new object, `Configuration`. -This is a PrestaShop-specific object that allows to easily manage all the shop's settings. It stores its data on the `ps_configuration` database table. +This PrestaShop-specific object allows you to easily manage all the shop's settings. It stores its data on the `PREFIX_configuration` database table. -### The main methods - -This component has three main methods, allowing you to perform basic CRUD operations: - -`Configuration::get('myVariable')` -: Retrieves a specific value from the database. - -`Configuration::updateValue('myVariable', $value)` -: Updates an existing setting with a new value. If the setting does not yet exist, it creates it with that value. - -`Configuration::deleteByName('myVariable')` -: Deletes the setting. - - -Note that when using `updateValue()`, the content of `$value` can be anything, be it a string, a number, a serialized PHP array or a JSON object. As long as you properly code the data handling function, anything goes. For instance, here is how to handle a PHP array using the `Configuration` object: - -```php -}}). +You can read more about this component in [Legacy Configuration object]({{< ref "/8/development/components/configuration/backward-compatibility" >}}) and [Configuration storage]({{< ref "/8/development/components/configuration" >}}). {{% /notice %}} -### Retrieving external values from the ps_configuration data table - -You are not limited to your own variables: PrestaShop stores all its own configuration settings in the `ps_configuration` database table. There are literally hundreds of settings, and you can access them just as easily as you would access your own. For instance: - -- `Configuration::get('PS_LANG_DEFAULT')`: retrieves the ID for the default language. -- `Configuration::get('PS_TIMEZONE')`: retrieves the name of the current timezone, in standard TZ format (see: [List of tz database time zones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)). -- `Configuration::get('PS_DISTANCE_UNIT')`: retrieves the default distance unit ("km" for kilometers, etc.). -- `Configuration::get('PS_SHOP_EMAIL')`: retrieves the main contact e-mail address. -- `Configuration::get('PS_NB_DAYS_NEW_PRODUCT')`: retrieves the number of days during which a newly-added product is considered "New" by PrestaShop. - -Dive into the `ps_configuration` table to discover many other settings! - ## The Shop object The `install()` method also references this: @@ -326,8 +289,32 @@ There are many free icon libraries available on the web. Here are a few: ## Installing the module +You have two options to install a module: from the back office interface or using the Symfony Console component (CLI-base installation) + +### Install module from the back office interface + Now that all basics are in place, reload the back office's "Module Catalog" page, in the "Front office features" section, you should find your module. Install it (or reset it if it is already installed). +### Install module from CLI using the Symfony Console component + +Access your project's directory with a CLI, and run: + +```shell +php bin/console prestashop:module install mymodule +``` + +Where `mymodule` is your module's name. + +To uninstall the module, run the following: + +```shell +php bin/console prestashop:module uninstall mymodule +``` + +For more informations, please read [the reference of the ModuleCommand]({{< ref "/8/development/components/console/prestashop-module" >}}) + +### The config.xml file + During the module's installation, PrestaShop automatically creates a small `config.xml` file in the module's folder, which stores the module's information. You should be very careful when editing this file by hand. ## Keeping things secure @@ -347,9 +334,5 @@ header('Location: ../'); exit; ``` -## Further reading - -{{< children />}} - [existing-tab-sections]: {{< ref "/8/modules/concepts/module-class/#tab" >}} -[multistore]: {{< ref "/8/development/multistore/" >}} +[multistore]: {{< ref "/8/development/multistore/" >}} \ No newline at end of file diff --git a/modules/introduction.md b/modules/introduction.md index 0756e235ff..112ff40531 100644 --- a/modules/introduction.md +++ b/modules/introduction.md @@ -39,7 +39,7 @@ Modules can: PrestaShop 1.7 was built so that modules that were written for PS 1.6 can work almost as-is — save for minor changes and a cosmetic update, the template files being in need of adapting to the 1.7 default theme. -The major module development changes in PrestaShop 1.7 are explained in details [in this Build article](https://build.prestashop.com/news/module-development-changes-in-17/), and are integrated into this updated documentation. If you already know how to create a module that works with PS 1.6, we strongly advise you to read that article from top to bottom in order to get up to speed with 1.7 development. +The major module development changes in PrestaShop 1.7 are explained in details [in this Build article](https://build.prestashop-project.org/news/module-development-changes-in-17/), and are integrated into this updated documentation. If you already know how to create a module that works with PS 1.6, we strongly advise you to read that article from top to bottom in order to get up to speed with 1.7 development. Some native modules have had their names changed in PrestaShop 1.7. [See the full list here]({{< ref "/8/development/native-modules/_index.md#module-name-changes-since-16" >}}). diff --git a/modules/payment/_index.md b/modules/payment/_index.md index d5adb798d3..077d27dbcd 100644 --- a/modules/payment/_index.md +++ b/modules/payment/_index.md @@ -32,7 +32,7 @@ To make a payment module for PrestaShop 1.7, you'll have to respect some element - You'll have to register the two following methods: `hookPaymentOptions()` & `hookPaymentReturn()` and register these hooks. - You must not have a submit button into your module's HTML code. It will automatically be generated by PrestaShop. -In the `hookPaymentOptions()` method, you have to return an array of *[PaymentOption](https://github.com/PrestaShop/PrestaShop/blob/develop/src/Core/Payment/PaymentOption.php)*. +In the `hookPaymentOptions()` method, you have to return an array of *[PaymentOption](https://github.com/PrestaShop/PrestaShop/blob/8.0.x/src/Core/Payment/PaymentOption.php)*. How to generate your PaymentOption ---------------------------------- @@ -76,11 +76,25 @@ We have identified four cases of payment module: The minimal variables to set are `$callToActionText` and `$form`. You can check the `getEmbeddedPaymentOption()` method of *[paymentexample](https://github.com/PrestaShop/paymentexample)* to have an example. -#### iFrame +#### iframe -: The payment form is displayed on the merchant's website, but inside an iFrame. +: The payment form is displayed on the merchant's website, but inside an iframe. The minimal variables to set are `$callToActionText` and `$additionalInformation`. You can check the `getIframePaymentOption()` method of *[paymentexample](https://github.com/PrestaShop/paymentexample)* to have an example. + +Payment modules rules +--------------------- + +We do have extra rules for Payment Modules as this type of modules require higher security. +Note that there are some modules which create the Order with a pending order status during the payment processing (1), while others wait for the payment system's approval to create it (2). But none of them create an order before the customer passed the payment service (bank, PayPal...). + +* Make sure you double check the id_cart before creating the order. + * The purpose is to make sure another customer cannot validate a cart which isn't his. + +* if (2), make sure the amount you use to validateOrder() comes from the external payment system. Do not use Cart->getOrderTotal(); + * For security reasons, always proceed as explained. + +* For (2), when receiving a call to process the payment, make sure you double check the source of the call using a signature or a token. Those values must not be known of all. Migrating from 1.6 to 1.7 ------------------------- @@ -89,7 +103,7 @@ Migrating from 1.6 to 1.7 You need to change the *payment* hook where your module is hooked on by *paymentOption*. **It's not a display hook anymore**, so you must not use the `$this->display()` method to retrieve a template, but use the `$this->context->smarty->fetch()` method instead. -Then, implement the `hookPaymentOptions()` function to return an array of *[PaymentOption](https://github.com/PrestaShop/PrestaShop/blob/develop/src/Core/Payment/PaymentOption.php)*. +Then, implement the `hookPaymentOptions()` function to return an array of *[PaymentOption](https://github.com/PrestaShop/PrestaShop/blob/8.0.x/src/Core/Payment/PaymentOption.php)*. Next, you'll need to identify the type of your payment module to know which variables are mandatory. diff --git a/modules/sample-modules/_index.md b/modules/sample-modules/_index.md index 9299da1f67..18bb9c6a36 100644 --- a/modules/sample-modules/_index.md +++ b/modules/sample-modules/_index.md @@ -1,10 +1,47 @@ --- -title: Sample modules +title: Sample modules and how to's weight: 80 +showOnHomepage: true --- -# Sample modules +# Sample modules and how to guides + +The PrestaShop Community has made example modules and how-to guides to help you understand how to implement hooks, admin grids, manage entities... and a lot more. {{% children %}} +## Example modules repository + * [See all our example modules (GitHub)](https://github.com/PrestaShop/example-modules) + +This repository hosts example modules built and maintained by project members and the community. +These modules demonstrate good use cases for developers willing to customize the software. + +### Extending Symfony pages + +- [Extending a Symfony form - how to insert a field inside an existing form](https://github.com/PrestaShop/example-modules/tree/master/demoextendsymfonyform1) +- [Demo Extending a Symfony Form - 2](https://github.com/PrestaShop/example-modules/tree/master/demoextendsymfonyform2) - how to insert an input inside a Symfony form - 2 +- [Demo Extending a Symfony Form - 3](https://github.com/PrestaShop/example-modules/tree/master/demoextendsymfonyform3) - how to use CQRS in a module +- [Demo View Order Hooks](https://github.com/PrestaShop/example-modules/tree/master/demovieworderhooks) +- [Demo Extend a Grid](https://github.com/PrestaShop/example-modules/tree/master/demoextendgrid) +- [Demo Extend Product Form V2](https://github.com/PrestaShop/example-modules/tree/master/demoproductform) + +### Using a tool / concept + +#### Symfony + +- [Demo Creating a Symfony Console command](https://github.com/PrestaShop/example-modules/tree/master/democonsolecommand) +- [Demo Using PrestaShop Symfony Form Types](https://github.com/PrestaShop/example-modules/tree/master/demosymfonyform) +- [Demo Creating modern Controllers and associate Tabs to them](https://github.com/PrestaShop/example-modules/tree/master/democontrollertabs) + +#### Database + +- [Demo Using Doctrine entities](https://github.com/PrestaShop/example-modules/tree/master/demodoctrine) +- [Demo How to override an ObjectModel](https://github.com/PrestaShop/example-modules/tree/master/demooverrideobjectmodel) + +#### Other + +- [Demo Adding a Mail Theme](https://github.com/PrestaShop/example-modules/tree/master/example_module_mailtheme) +- [Demo Javascript Router component usage](https://github.com/PrestaShop/example-modules/tree/master/demojsrouting) +- [Demo Multistore form](https://github.com/PrestaShop/example-modules/tree/master/demomultistoreform) +- [Demo Grid](https://github.com/PrestaShop/example-modules/tree/master/demo_grid) \ No newline at end of file diff --git a/modules/sample-modules/extend-product-page.md b/modules/sample-modules/extend-product-page.md new file mode 100644 index 0000000000..3f2d3ee8d0 --- /dev/null +++ b/modules/sample-modules/extend-product-page.md @@ -0,0 +1,576 @@ +--- +title: Extending the new product page form +weight: 3 +--- + +# Extending the new product page form {{< minver v="8.1.0" >}} + +The new Back Office product page introduced in {{< minver v="8.1.0" >}} removed several hooks which were previously available on the page. Complete list of removed hooks: + +- `displayAdminProductsCombinationBottom` +- `displayAdminProductsSeoStepBottom` +- `displayAdminProductsShippingStepBottom` +- `displayAdminProductsQuantitiesStepBottom` +- `displayAdminProductsMainStepLeftColumnBottom` +- `displayAdminProductsMainStepLeftColumnMiddle` +- `displayAdminProductsMainStepRightColumnBottom` +- `displayAdminProductsOptionsStepTop` +- `displayAdminProductsOptionsStepBottom` +- `displayAdminProductsPriceStepBottom` + +The only `displayAdminProduct*` hook that was not removed is: + +- `displayAdminProductsExtra` + +{{% notice info %}} +Although kept for backward compatibility, this hook (`displayAdminProductsExtra`) is not recommended for new modules. +{{% /notice %}} + +In this guide, we will discover how to extend the product page by adding custom fields, in the old and new ways of doing this. + +Finally, we will discover how to add a new tab to the product page, which is possible for a new product page from PrestaShop 8.1. + +## Add a custom field, before {{< minver v="8.1.0" >}} + +A custom field, before {{< minver v="8.1.0" >}}, was added by hooking to one of the `displayAdminProducts` hooks. + +For example, to add a custom field, in the `SEO` tab, you had to create a module with this content: + +`demooldhooks.php`: + +```php +declare(strict_types=1); + +use Symfony\Component\Form\Extension\Core\Type\TextType; + +class DemoOldHooks extends Module +{ + public function __construct() + { + // [...] + } + + /** + * @return bool + */ + public function install() + { + return parent::install() && $this->registerHook(['displayAdminProductsSeoStepBottom']); + } + + public function hookDisplayAdminProductsSeoStepBottom($params) + { + $productId = $params['id_product']; + $formFactory = $this->get('form.factory'); + $twig = $this->get('twig'); + + $product = new Product($productId); + + $form = $formFactory + ->createNamedBuilder('seo_special_field', TextType::class, "") + ->getForm(); + + $template = '@Modules/demooldhooks/views/templates/seo_special_field.html.twig'; + + return $twig->render($template, [ + 'seo_special_field' => $form->createView() + ]); + } +} +``` + +`views/templates/seo_special_field.html.twig`: + +```php +

SEO Special field

+{{ form_widget(seo_special_field) }} +``` + +Before {{< minver v="8.1.0" >}}, that would produce: + +![Custom field in SEO tab in older versions of PrestaShop](../img/old-product-form/seo-custom-field.png) + +From {{< minver v="8.1.0" >}}, this field won't be displayed as a hook (`displayAdminProductsSeoStepBottom`) is no longer available. + +## Add a custom field, from {{< minver v="8.1.0" >}} + +To do exactly the same, from {{< minver v="8.1.0" >}}, we will implement `actionProductFormBuilderModifier` hook and modify product's FormBuilder. + +First, create a module, with a `composer.json` file, [as instructed here]({{< relref "/8/modules/concepts/composer" >}}). + +`demonewhooks.php`: + +```php +declare(strict_types=1); + +use DemoNewHooks\Form\Modifier\ProductFormModifier; + +class DemoNewHooks extends Module +{ + public function __construct() + { + // [...] + } + + /** + * @return bool + */ + public function install() + { + return parent::install() && $this->registerHook(['actionProductFormBuilderModifier']); + } + + /** + * Modify product form builder + * + * @param array $params + */ + public function hookActionProductFormBuilderModifier(array $params): void + { + /** @var ProductFormModifier $productFormModifier */ + $productFormModifier = $this->get(ProductFormModifier::class); + $productId = (int) $params['id']; + + $productFormModifier->modify($productId, $params['form_builder']); + } +} +``` + +`config/services.yml`: + +```yml +services: + DemoNewHooks\Form\Modifier\ProductFormModifier: + autowire: true + public: true + arguments: + $formBuilderModifier: '@form.form_builder_modifier' +``` + +`src/Form/Modifier/ProductFormModifier.php`: + +```php +declare(strict_types=1); + +namespace DemoNewHooks\Form\Modifier; + +use PrestaShopBundle\Form\FormBuilderModifier; +use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\Form\FormBuilderInterface; + +final class ProductFormModifier +{ + /** + * @var FormBuilderModifier + */ + private $formBuilderModifier; + + /** + * @param FormBuilderModifier $formBuilderModifier + */ + public function __construct( + FormBuilderModifier $formBuilderModifier + ) { + $this->formBuilderModifier = $formBuilderModifier; + } + + /** + * @param int|null $productId + * @param FormBuilderInterface $productFormBuilder + */ + public function modify( + int $productId, + FormBuilderInterface $productFormBuilder + ): void { + + $seoTabFormBuilder = $productFormBuilder->get('seo'); + $this->formBuilderModifier->addAfter( + $seoTabFormBuilder, // the tab + 'tags', // the input/form from which to insert after/before + 'demo_module_custom_field', // your field name + TextType::class, // your field type + [ + 'label' => 'SEO Special Field', // you can remove the label if you dont need it by passing 'label' => false + 'label_attr' => [ // customize label with any HTML attribute + 'title' => 'h2', + 'class' => 'text-info', + ], + 'attr' => [ + 'placeholder' => 'SEO Special field', + ], + // this is just an example, but in real case scenario, you could have some data provider class to handle more complex cases + 'data' => "", + 'empty_data' => '', + 'form_theme' => '@PrestaShop/Admin/TwigTemplateForm/prestashop_ui_kit_base.html.twig', + ] + ); + } +} +``` + +This module uses a Form Builder Modifier (`FormBuilderModifier`), and adds a `TextType` field to the `SEO` tab form, after the existing `tags` form element. + +`FormBuilderModifier` is hooked to the `actionProductFormBuilderModifier`. + +These changes produces the below's: + +![Custom field in SEO tab in newer versions of PrestaShop](../img/new-product-form/seo-custom-field.png) + +{{% notice note %}} +This new way of adding custom fields to the product page allows you for more precise positioning. You can now position your fields/forms exactly where you want. +{{% /notice %}} + +## Cheatsheet for old/new hooks / new hooks + +### Hook: actionProductFormBuilderModifier + +- Hook : [`actionFormBuilderModifier`]({{< relref "/8/modules/concepts/hooks/list-of-hooks/actionFormBuilderModifier" >}}) + +| Old hook | Location on page | Form tab | Inserted | +| --- | --- | --- | --- | +| `displayAdminProductsSeoStepBottom` | Bottom of SEO tab | `seo` | after `tags` | +| `displayAdminProductsCombinationBottom` | Bottom of Combinations tab | `combinations` | after `availability` | +| `displayAdminProductsShippingStepBottom` | Bottom of Shipping tab | `shipping` | after `carriers` | +| `displayAdminProductsQuantitiesStepBottom` | Bottom of Quantities tab | `stock` | after `low_stock_threshold` | +| `displayAdminProductsMainStepLeftColumnBottom` | Basic settings tab, under related product | `description` | after `related_products` | +| `displayAdminProductsMainStepLeftColumnMiddle` | Basic settings tab, under description | `description` | after `description` | +| `displayAdminProductsMainStepRightColumnBottom` | Basic settings tab, under create a category | `description` | after `categories` | +| `displayAdminProductsOptionsStepTop` | Top of Options tab | `options` | before `visibility` | +| `displayAdminProductsOptionsStepBottom` | Bottom of Options tab | `options` | after `product_suppliers` | +| `displayAdminProductsPriceStepBottom` | Bottom of Pricing tab | `pricing` | after `priority_management` | + +Form Type details: [`EditProductFormType`](https://github.com/PrestaShop/PrestaShop/blob/8.1.0-beta.1/src/PrestaShopBundle/Form/Admin/Sell/Product/EditProductFormType.php) + +## Extend a subform + +Subforms can be extended as well, for example, to add a new input on each combination of a product: + +- Hook to actionProductCombinationFormBuilderModifier ([`actionFormBuilderModifier`]({{< relref "/8/modules/concepts/hooks/list-of-hooks/actionFormBuilderModifier" >}})) + +```php +/** + * Hook that modifies the combination form structure. + * + * @param array $params + */ +public function hookActionCombinationFormFormBuilderModifier(array $params): void +{ + /** @var CombinationFormModifier $productFormModifier */ + $productFormModifier = $this->get(CombinationFormModifier::class); + $combinationId = isset($params['id']) ? new CombinationId((int) $params['id']) : null; + + $productFormModifier->modify($combinationId, $params['form_builder']); +} +``` + +`src/Form/Modifier/CombinationFormModifier.php`: + +```php +// [...] +class CombinationFormModifier +{ + // [...] + + /** + * @param CombinationId|null $combinationId + * @param FormBuilderInterface $combinationFormBuilder + */ + public function modify( + ?CombinationId $combinationId, + FormBuilderInterface $combinationFormBuilder + ): void { + $idValue = $combinationId ? $combinationId->getValue() : null; + $customCombination = new CustomCombination($idValue); + $this->addCustomField($customCombination, $combinationFormBuilder); + } + + /** + * @param CustomCombination $customCombination + * @param FormBuilderInterface $combinationFormBuilder + * + * @see demoproductform::hook + */ + private function addCustomField(CustomCombination $customCombination, FormBuilderInterface $combinationFormBuilder): void + { + $this->formBuilderModifier->addAfter( + $combinationFormBuilder, + 'references', + 'demo_module_custom_field', + TextType::class, + [ + 'label' => $this->translator->trans('Demo custom field', [], 'Modules.Demoproductform.Admin'), + 'label_attr' => [ + 'title' => 'h2', + 'class' => 'text-info', + ], + 'attr' => [ + 'placeholder' => $this->translator->trans('Your example text here', [], 'Modules.Demoproductform.Admin'), + ], + 'data' => $customCombination->custom_field, + 'empty_data' => '', + 'form_theme' => '@PrestaShop/Admin/TwigTemplateForm/prestashop_ui_kit_base.html.twig', + ] + ); + } +} +``` + +This example will add a `TextType` input on each `Combination` of a `Product`. +A complete working example and implementation is available in our [example-module repository](https://github.com/PrestaShop/example-modules/tree/master/demoproductform). + +## Add a custom tab to the product page + +{{< minver v="8.1.0" >}} introduced a new feature: custom tabs on the product page. + +A complete working example of implementation is available in our [example-module repository](https://github.com/PrestaShop/example-modules/tree/master/demoproductform). + +- You can extend the product form builder with `actionProductFormBuilderModifier` hook with a created modifier: + +`demonewhooks.php`: + +```php +declare(strict_types=1); + +use DemoNewHooks\Form\Modifier\ProductFormModifier; + +class DemoNewHooks extends Module +{ + public function __construct() + { + // [...] + } + + /** + * @return bool + */ + public function install() + { + return parent::install() && $this->registerHook(['actionProductFormBuilderModifier']); + } + + /** + * Modify product form builder + * + * @param array $params + */ + public function hookActionProductFormBuilderModifier(array $params): void + { + /** @var ProductFormModifier $productFormModifier */ + $productFormModifier = $this->get(ProductFormModifier::class); + $productId = (int) $params['id']; + + $productFormModifier->modify($productId, $params['form_builder']); + } +} +``` + +`config/services.yml`: + +```yml +services: + DemoNewHooks\Form\Modifier\ProductFormModifier: + autowire: true + public: true + arguments: + $formBuilderModifier: '@form.form_builder_modifier' +``` + +`src/Form/Modifier/ProductFormModifier.php`: + +```php +declare(strict_types=1); + +namespace DemoNewHooks\Form\Modifier; + +use PrestaShopBundle\Form\FormBuilderModifier; +use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\Form\FormBuilderInterface; + +final class ProductFormModifier +{ + /** + * @var FormBuilderModifier + */ + private $formBuilderModifier; + + /** + * @param FormBuilderModifier $formBuilderModifier + */ + public function __construct( + FormBuilderModifier $formBuilderModifier + ) { + $this->formBuilderModifier = $formBuilderModifier; + } + + /** + * @param int|null $productId + * @param FormBuilderInterface $productFormBuilder + */ + public function modify( + int $productId, + FormBuilderInterface $productFormBuilder + ): void { + + } +} +``` + +- Create a new Type for your custom tab, for example `CustomTabType`, and add a `MoneyType` input in this tab: + +`src/Form/Type/CustomTabType.php`: + +```php +declare(strict_types=1); + +namespace PrestaShop\Module\DemoProductForm\Form\Type; + +use PrestaShopBundle\Form\Admin\Type\TranslatorAwareType; +use Symfony\Component\Form\Extension\Core\Type\MoneyType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Component\Validator\Constraints\NotBlank; +use Symfony\Component\Validator\Constraints\PositiveOrZero; +use Symfony\Component\Validator\Constraints\Type; + +class CustomTabType extends TranslatorAwareType +{ + /** + * @var \Currency + */ + private $defaultCurrency; + + /** + * @param TranslatorInterface $translator + * @param array $locales + * @param \Currency $defaultCurrency + */ + public function __construct( + TranslatorInterface $translator, + array $locales, + \Currency $defaultCurrency + ) { + parent::__construct($translator, $locales); + $this->defaultCurrency = $defaultCurrency; + } + + /** + * {@inheritDoc} + */ + public function buildForm(FormBuilderInterface $builder, array $options) + { + parent::buildForm($builder, $options); + $builder + ->add('custom_price', MoneyType::class, [ + 'label' => $this->trans('My custom price', 'Modules.Demoproductform.Admin'), + 'label_tag_name' => 'h3', + 'currency' => $this->defaultCurrency->iso_code, + 'required' => false, + 'constraints' => [ + new NotBlank(), + new Type(['type' => 'float']), + new PositiveOrZero(), + ], + ]) + ; + } + + /** + * {@inheritDoc} + */ + public function configureOptions(OptionsResolver $resolver) + { + parent::configureOptions($resolver); + + $resolver + ->setDefaults([ + 'label' => $this->trans('Customization', 'Modules.Demoproductform.Admin'), + ]) + ; + } +} +``` + +Declare your service in your `config.yml`: + +```yml +services: + DemoNewHooks\Form\Type\CustomTabType: + class: DemoNewHooks\Form\Type\CustomTabType + parent: 'form.type.translatable.aware' + public: true + arguments: + - '@=service("prestashop.adapter.data_provider.currency").getDefaultCurrency()' + tags: + - { name: form.type } +``` + +Add a `use` statement in your `ProductFormModifier`: + +```php +use DemoNewHooks\Form\Type\CustomTabType; +``` + +Finally, add this `CustomTabType` to the `$productFormBuilder` variable in your `modify` method in the `ProductFormModifier`: + +```php +/** + * @param int|null $productId + * @param FormBuilderInterface $productFormBuilder + */ +public function modify( + int $productId, + FormBuilderInterface $productFormBuilder +): void { + + $idValue = $productId ? $productId->getValue() : null; + $customProduct = new CustomProduct($idValue); + + $this->formBuilderModifier->addAfter( + $productFormBuilder, + 'pricing', + 'custom_tab', + CustomTabType::class, + [ + 'data' => [ + 'custom_price' => $customProduct->custom_price, + ], + ] + ); +} +``` + +{{% notice note %}} +Any type added directly to the `$productFormBuilder` (and not to a sub-tab) will be considered as a tab. +{{% /notice %}} + +## Backwards compatibility for displayAdminProductsExtra hook + +A custom Form Type `ExtraModulesType` has been added to {{< minver v="8.1.0" >}}, to allow backward compatibility for modules implementing `displayAdminProductsExtra` hook. + +If a module registers to `displayAdminProductsExtra` hook, a custom tab will be added on the new product page, handled by `ExtraModulesType`. + +{{% notice info %}} +Although kept for backward compatibility, this hook (`displayAdminProductsExtra`) is not recommended for new modules. +{{% /notice %}} + +```php +public function hookDisplayAdminProductsExtra(array $params): string +{ + $productId = $params['id_product']; + $customProduct = new CustomProduct($productId); + + /** @var EngineInterface $twig */ + $twig = $this->get('twig'); + + return $twig->render('@Modules/demoproductform/views/templates/admin/extra_module.html.twig', [ + 'customProduct' => $customProduct, + ]); +} +``` + +A complete working example and implementation is available in our [example-module repository](https://github.com/PrestaShop/example-modules/tree/master/demoproductform). + +## Handle data modified by FormBuilderModifier + +You need to implement the corresponding [`actionAfterCreateFormHandler`]({{< relref "/8/modules/concepts/hooks/list-of-hooks/actionAfterCreateFormHandler" >}}) or [`actionAfterUpdateFormHandler`]({{< relref "/8/modules/concepts/hooks/list-of-hooks/actionAfterUpdateFormHandler" >}}) hook, as shown in our [example-module repository](https://github.com/PrestaShop/example-modules/tree/master/demoproductform). diff --git a/modules/sample-modules/extending-sf-form-with-upload-image-field.md b/modules/sample-modules/extending-sf-form-with-upload-image-field.md index 6ebab6de80..59d64a4a8d 100644 --- a/modules/sample-modules/extending-sf-form-with-upload-image-field.md +++ b/modules/sample-modules/extending-sf-form-with-upload-image-field.md @@ -222,7 +222,7 @@ below to `DemoExtendSymfonyForm2` class. ``` Let's create `SupplierExtraImage` entity class. We use [Doctrine] - ({{ relref "/8/modules/concepts/doctrine/" }}) + ({{< relref "/8/modules/concepts/doctrine/" >}}) which is available for PrestaShop modules since version 1.7.6. ```php @@ -364,7 +364,7 @@ class SupplierExtraImageRepository extends EntityRepository Let's create hook `hookActionSupplierFormBuilderModifier` function inside Main module class. This is a hook available for [CRUD forms] -({{ relref "/8/modules/sample-modules/grid-and-identifiable-object-form-hooks-usage/" }}) in +({{< relref "/8/modules/sample-modules/grid-and-identifiable-object-form-hooks-usage" >}}) in PrestaShop Symfony pages. ```php @@ -607,6 +607,3 @@ Let's add `UploadImage` function to main class: You can find the ready solution in PrestaShop example-modules github repository: https://github.com/PrestaShop/example-modules/tree/master/demoextendsymfonyform2 {{% /notice %}} - - - diff --git a/modules/sample-modules/grid-and-identifiable-object-form-hooks-usage.md b/modules/sample-modules/grid-and-identifiable-object-form-hooks-usage.md index dac844b772..b55b51ca37 100644 --- a/modules/sample-modules/grid-and-identifiable-object-form-hooks-usage.md +++ b/modules/sample-modules/grid-and-identifiable-object-form-hooks-usage.md @@ -110,6 +110,7 @@ class Ps_DemoCQRSHooksUsage extends Module // ... } ``` + This hook, through `$params` array, received `GridDefinition` that defines how the grid is rendered. See [Grid definition]({{< relref "/8/development/components/grid/#grid-definition" >}}) for more information. In this sample a new toggable column which determines if the customer is eligible to review products is added just after another column which has id `optin`. The sample code also demonstrates how add new filter. @@ -159,7 +160,6 @@ class CustomerReviewController extends FrameworkBundleAdminController - As this is a Symfony controller, we must configure the related routing (read more about [symfony routing](https://symfony.com/doc/current/routing.html)), which means create a route in `ps_democqrshooksusage/config/routes.yml` file: ```yml - ps_democqrshooksusage_toggle_is_allowed_for_review: path: demo-cqrs-hook-usage/{customerId}/toggle-is-allowed-for-review methods: [POST] @@ -175,7 +175,7 @@ Route name `ps_democqrshooksusage_toggle_is_allowed_for_review` matches the one ### Extending grid query builder By just extending grid definition we won't be able to display any data since we need to fetch it first. Luckily, we can add additional sql -conditions by extending [doctrine's query builder](https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/query-builder.html). +conditions by extending [doctrine's query builder](https://www.doctrine-project.org/projects/doctrine-orm/en/2.7/reference/query-builder.html). ```php }}) at 1.7.7.0 release. + ```php }}). Also we map this entity with the repository with `repositoryClass="PrestaShop\Module\DemoViewOrderHooks\Repository\OrderSignatureRepository"`. This mapping allows to use functions of `SignatureRepository` instead of only the `EntityRepository`. @@ -443,9 +443,10 @@ class OrderSignaturePresenter } } ``` -Then lets use Symfony Dependency Injection + +Then let's use Symfony Dependency Injection (https://www.freecodecamp.org/news/a-quick-intro-to-dependency-injection-what-it-is-and-when-to-use-it-7578c84fa88f/). -and [create services configuration]({{ relref "/8/modules/concepts/services/#symfony-services" }}) for the above +and [create services configuration]({{< relref "/8/modules/concepts/services/#symfony-services" >}}) for the above classes in `demovieworderhooks/config/services.yml`. The intention behind dependency injection is to achieve Separation of Concerns of construction and use of objects. This can increase readability and code reuse, reduce dependencies, lead to more testable code. @@ -521,8 +522,8 @@ card.html.twig {% endblock %} ``` -Lets add several methods to `DemoViewOrderHooks` class. -`getModuleTemplatePath` - get's the path of the templates folder. +Let's add several methods to `DemoViewOrderHooks` class. +`getModuleTemplatePath` - get the path of the templates folder. ```php }})). We add this code at the bottom of the main module class `demovieworderhooks.php` and also add the missing `use` statements for new classes. diff --git a/modules/testing/basic-checks.md b/modules/testing/basic-checks.md index c7b0faa710..e4da949cd5 100644 --- a/modules/testing/basic-checks.md +++ b/modules/testing/basic-checks.md @@ -48,7 +48,7 @@ If some errors are reported by this tool, this gives you the opportunity : ## Coding standards -Modules follows the same rules as the core. The [coding standards chapter]({{< ref "1.7/development/coding-standards" >}}) of this project provides more details about it. +Modules follows the same rules as the core. The [coding standards chapter]({{< ref "8/development/coding-standards" >}}) of this project provides more details about it. Following the same rules as the core requires the configuration file to be available in your project. These rules are distributed and maintained on a repository `prestashop/php-dev-tools` available on [Packagist](https://packagist.org/packages/prestashop/php-dev-tools) which can be required via composer. @@ -61,7 +61,7 @@ composer require --dev prestashop/php-dev-tools php vendor/bin/prestashop-coding-standards cs-fixer:init ``` -These commands install and prepare your projet for php-cs-fixer and the core standards. The commands have run successfully if a file `.php_cs.dist` exists in the root folder. +These commands install and prepare your project for php-cs-fixer and the core standards. The commands have run successfully if a file `.php_cs.dist` exists in the root folder. [PHP-CS-Fixer](https://packagist.org/packages/friendsofphp/php-cs-fixer) is used to check the code style, and is automatically included in your project if you required `prestashop/php-dev-tools` by following the commands above. diff --git a/modules/testing/resources.md b/modules/testing/resources.md index c39da4a9b7..9c1ad47be7 100644 --- a/modules/testing/resources.md +++ b/modules/testing/resources.md @@ -140,8 +140,8 @@ php: ## Core Functional tests -PrestaShop provides its own test suite, running with puppeteer. It covers the features of PrestaShop and grows each time a bug is resolved or a feature is added. +PrestaShop provides its own test suite, running with [Playwright](https://playwright.dev). It covers the features of PrestaShop and grows each time a bug is resolved or a feature is added. These tests are launched every time a change is suggested to the core, but you can also run them with your module installed. This will ensure your module code does not break a critical feature of the core. -This section will be completed when these tests will be available on a dedicated repository. In the meantime you can already reach them on GitHub, in the [tests/UI](https://github.com/PrestaShop/PrestaShop/tree/develop/tests/UI) of PrestaShop files. +This section will be completed when these tests are available on a dedicated repository. In the meantime, you can already reach them on GitHub, in the [tests/UI](https://github.com/PrestaShop/PrestaShop/tree/8.0.x/tests/UI) of PrestaShop files. diff --git a/project/release/minor-release-lifecycle.md b/project/release/minor-release-lifecycle.md index 8c99f48b62..279b1d469c 100644 --- a/project/release/minor-release-lifecycle.md +++ b/project/release/minor-release-lifecycle.md @@ -56,8 +56,8 @@ For example, if you are a payment module developer, just installing your module If however you find a problem, you can - - [Report this as a bug on GitHub](https://github.com/PrestaShop/PrestaShop/issues) (read [how to report issues]({{ relref "/8/contribute/contribute-reporting-issues/" }})) - - Submit a bug fix by creating a [pull request](https://github.com/PrestaShop/PrestaShop/compare) (read the [contribution guidelines]({{ relref "/8/contribute/contribution-guidelines/" }})) + - [Report this as a bug on GitHub](https://github.com/PrestaShop/PrestaShop/issues) (read [how to report issues]({{< relref "/8/contribute/contribute-reporting-issues" >}})) + - Submit a bug fix by creating a [pull request](https://github.com/PrestaShop/PrestaShop/compare) (read the [contribution guidelines]({{< relref "/8/contribute/contribution-guidelines/" >}})) ## Release Candidate @@ -98,4 +98,4 @@ The global duration for all the process is about 6 months. This is why we expect _(This article was originally published on our blog: [PrestaShop 1.7 Minor Release Lifecycle -](https://build.prestashop.com/news/ps17-patch-release-lifecycle/))_ +](https://build.prestashop-project.org/news/ps17-minor-release-lifecycle/))_ diff --git a/project/release/patch-release-lifecycle.md b/project/release/patch-release-lifecycle.md index 9444695e42..feab7185ac 100644 --- a/project/release/patch-release-lifecycle.md +++ b/project/release/patch-release-lifecycle.md @@ -50,4 +50,4 @@ If the campaign reports that no bugs are found, the new patch release is validat _(This article was originally published on our blog: [PrestaShop 1.7 Patch Release Lifecycle -](https://build.prestashop.com/news/ps17-minor-release-lifecycle/))_ +](https://build.prestashop-project.org/news/ps17-patch-release-lifecycle/))_ diff --git a/scale/_index.md b/scale/_index.md index ed2de34d03..1ae9c4da5d 100644 --- a/scale/_index.md +++ b/scale/_index.md @@ -3,6 +3,8 @@ title: Scale weight: 8 pre: "8. " chapter: true +showOnHomepage: true +icon: fa-rocket --- ### Chapter 8 diff --git a/scale/benchmark/_index.md b/scale/benchmark/_index.md index 0394e5664d..607001664a 100755 --- a/scale/benchmark/_index.md +++ b/scale/benchmark/_index.md @@ -2,6 +2,7 @@ title: How to benchmark your PrestaShop menuTitle: How to benchmark weight: 1 +showOnHomepage: true --- How to setup the benchmark of your PrestaShop shop @@ -80,9 +81,9 @@ stock_availables (1): langs ([fr_FR, en_US]): ``` -If you want to customize later the number of entities, just modify the file ```app/config/config.yml``` +If you want to customize later the number of entities, just modify the file `app/config/config.yml` -Then run the following command to generate your initial dataset, which will be stored in the ```generated_data``` +Then run the following command to generate your initial dataset, which will be stored in the `generated_data`` directory ``` @@ -91,18 +92,20 @@ php app/console.php #### How to use this dataset during PrestaShop install? -Actually it's quite simple. Just copy the content of the ```generated_data``` folders (three folders should be -there: data, img and langs) in the PrestaShop ```install/fixtures/fashion``` folders (overwrite the folders already +Actually it's quite simple. Just copy the content of the `generated_data` folders (three folders should be +there: data, img and langs) in the PrestaShop `install/fixtures/fashion` folders (overwrite the folders already there). Then launch a standard PrestaShop install. ### Prepare your shop -Make sure you're not in debug mode! In ```config/defines.inc.php``` you should have: +Make sure you're not in debug mode! In `config/defines.inc.php` you should have: + ```text define('_PS_MODE_DEV_', false); ``` + The smarty cache should be enabled, but the multi-front synchronisation should be disabled for best performances. (those are the default settings). diff --git a/scale/benchmark/back-office.md b/scale/benchmark/back-office.md index a68165df99..7852fc420e 100755 --- a/scale/benchmark/back-office.md +++ b/scale/benchmark/back-office.md @@ -191,7 +191,7 @@ And choose the simulation you want to run ![Gatling](https://i.imgur.com/HQ5eCfZ.png) -In my example I run "[1] basic.BasicExempleSimulation" +In my example I run "[1] basic.BasicExampleSimulation" ![Gatling](https://i.imgur.com/nJdOPsB.png) ##### Well done! Our Gatling installation is ready! @@ -223,10 +223,13 @@ For example if you site is setup in /etc/apache2/sites-enabled/000-default.conf add the value + ```bash SetEnv _TOKEN_ disabled ``` + before + ``` < /VirtualHost > ``` diff --git a/scale/benchmark/front-office.md b/scale/benchmark/front-office.md old mode 100755 new mode 100644 index 5c0005ee3f..9abee03cc1 --- a/scale/benchmark/front-office.md +++ b/scale/benchmark/front-office.md @@ -8,7 +8,7 @@ How to benchmark your PrestaShop Shop (Front-office) ## Automatically benchmark with `Gatling` (recommended) -Follow instruction on **[Back-Office benchmark page]({{ relref "/8/scale/benchmark/back-office/" }})** to get a pre-populated shop and to run Gatling scenarios on it. +Follow instruction on **[Back-Office benchmark page]({{< relref "/8/scale/benchmark/back-office" >}})** to get a pre-populated shop and to run Gatling scenarios on it. **[PrestaShop performance project](https://github.com/PrestaShop/performance-project)** on Github includes Front-Office scenarios you can edit to get your own scenarios running. @@ -20,7 +20,7 @@ Try to always use the latest available version 3. " chapter: true +icon: fa-shield --- ### Chapter 3 # Testing -This section describes how PrestaShop Core is covered by automatic tests. +# How testing works in PrestaShop -{{% children %}} +PrestaShop is a complex software and uses automated testing to ensure that the new additions to the codebase do not break existing behaviors. + +Automated tests are located in `tests` folders + +## What kind of tests does PrestaShop use? + +In the `tests` folder, you will find: + +- [Integration tests](/8/testing/integration-tests/) +- [Unit tests](/8/testing/unit-tests/) +- [User interface tests](/8/testing/ui-tests/) diff --git a/testing/integration-tests/_index.md b/testing/integration-tests/_index.md new file mode 100644 index 0000000000..791b24a3de --- /dev/null +++ b/testing/integration-tests/_index.md @@ -0,0 +1,20 @@ +--- +title: Integration tests +chapter: true +--- + +# Integration tests +## Introduction + +While unit tests can effectively validate the behavior of an isolated PHP class, there are certain classes that cannot be validated in this manner. Additionally, as a significant portion of PrestaShop's logic is written in complex SQL queries, this type of test may not be sufficient to validate them. Therefore, integration tests are also necessary to ensure proper validation and coverage. + +### Stack + +We use the following stack: + +* [Behat](https://behat.org) for tests that are meaningful scenarios from a user point of view +* [PHPUnit](https://phpunit.de) for tests that instead answer the need to test the technical behavior of a class or a component + +## Execute & Create tests + +{{% children %}} diff --git a/testing/how-to-create-your-own-behat-tests.md b/testing/integration-tests/how-to-create-your-own-behat-tests.md similarity index 99% rename from testing/how-to-create-your-own-behat-tests.md rename to testing/integration-tests/how-to-create-your-own-behat-tests.md index b493c421e3..853e243a86 100644 --- a/testing/how-to-create-your-own-behat-tests.md +++ b/testing/integration-tests/how-to-create-your-own-behat-tests.md @@ -1,7 +1,9 @@ --- title: How to create your own Behat tests menuTitle: Creating your own Behat tests -weight: 30 +weight: 20 +aliases: + - /8/testing/how-to-create-your-own-behat-tests/ --- # How to create your own Behat tests or add tests to PrestaShop @@ -92,7 +94,6 @@ For this tutorial, we'll add the new scenario to the `tests/Integration/Behaviou The scenario we want to test is the following: ```yml - On my shop, there is only 1 carrier which can ship my products And his shipping fees of 5.0 euros in zone "US" for product whose price ranges between 0 and 150 euros @@ -106,7 +107,6 @@ The scenario we want to test is the following: Then I convert it to use [Gherkin][2] syntax. This means each step must start with `Given`, `When` or `Then`. We can also use `And` which is an alias for the latest prefix used. ```yml - Scenario: With free shipping voucher, there is no shipping fees Given On my shop, there is only 1 carrier which can ship my products And his shipping fees of 5.0 euros in zone "US" for product whose price ranges between 0 and 150 euros @@ -139,6 +139,7 @@ php ./vendor/bin/behat -c tests/Integration/Behaviour/behat.yml --name="free shi (I use the `--name` filter to allow Behat to target my specific file, and not all the available tests) We can see that Behat detects that some steps are not defined yet and suggests to create them for me: + ``` >> cart suite has undefined steps. Please choose the context to generate snippets: ``` diff --git a/testing/how-to-create-your-own-symfony-controller-tests.md b/testing/integration-tests/how-to-create-your-own-symfony-controller-tests.md similarity index 92% rename from testing/how-to-create-your-own-symfony-controller-tests.md rename to testing/integration-tests/how-to-create-your-own-symfony-controller-tests.md index 2c9c3956c8..88e0e98896 100644 --- a/testing/how-to-create-your-own-symfony-controller-tests.md +++ b/testing/integration-tests/how-to-create-your-own-symfony-controller-tests.md @@ -1,7 +1,9 @@ --- title: How to create your own symfony controller tests menuTitle: Creating your own symfony controller tests -weight: 20 +weight: 30 +aliases: + - /8/testing/how-to-create-your-own-symfony-controller-tests/ --- # How to create your own symfony controller tests or add tests to PrestaShop diff --git a/testing/integration-tests/how-to-execute-tests.md b/testing/integration-tests/how-to-execute-tests.md new file mode 100644 index 0000000000..957d6e47e9 --- /dev/null +++ b/testing/integration-tests/how-to-execute-tests.md @@ -0,0 +1,21 @@ +--- +title: How to execute Integration Tests +menuTitle: Executing integration tests +weight: 10 +--- + +# How to execute Integration Tests + +There are two integration tests suites : + +* one using Behat +* one for PHPUnit tests + +Each suite needs a specific PHPUnit configuration. This is why each test suite has a specific Composer command: + +* `composer integration-tests` +* `composer integration-behaviour-tests` + +{{% notice tip %}} +You can execute the entire PHPUnit test suites using the `composer test-all` command. +{{% /notice %}} \ No newline at end of file diff --git a/testing/introduction.md b/testing/introduction.md deleted file mode 100644 index 26c1ed4103..0000000000 --- a/testing/introduction.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -title: Introduction -weight: 1 ---- - -# How testing works in PrestaShop - -PrestaShop is a complex software and uses automated testing to ensure that the new additions to the codebase do not break existing behaviors. - -Automated tests are located in `tests` folders - -## What kind of tests do PrestaShop use? - -In the `tests` folder, you will find: - -- Unit tests -- Integration tests -- User interface tests - -### Unit tests - -Unit tests are powered by [PHPUnit][1]. They test one and only one php class, mocking/stubbing any dependencies that class has. - -This `Unit` folder meets some rules: - -- One php class = one test file. -- The test filepath must follow the class filepath/ -- Every dependency of the class must be replaced by [test doubles][2]. - -*If there is a hard-coded dependency such as a singleton pattern being used -or a static call, this class cannot be unit tested and should be tested using -integration tests.* - -#### Conventions - -- Use camelCase names for test function names. -- Try to make method names explain the *intent* of the test case as best as possible. Don't hesitate to write long method names if necessary. - - Bad example: `testGetPrice` (no idea what such a test is supposed to do) - - Good example: `testDiscountIsAppliedToFinalPrice` - -### Integration tests - -Unit tests can validate the behavior of a php class when it can be isolated. -However, some classes cannot be validated this way. Moreover, a lot of logic from PrestaShop is written into complex SQL queries that cannot be validated by those kind of tests. This is why we also need integration tests. - -We use 2 technologies for the integration tests in the `Integration` folder: - -- [Behat][3] for tests that are meaningful scenarios from a user point of view -- [PHPUnit][1] for tests which rather answer the need to test the technical behavior of a class or a component - -### User Interface tests - -Finally, we have some user interface tests (also sometimes referred to as web acceptance tests). These tests launch and control a browser that will then go on either the Front Office or the Back Office of a shop and perform several actions to check that the behavior, from the point of view of a browser, is as expected. So these tests send real HTTP requests and check the returned DOM. - -These tests can be found in `UI` folders. - -UI tests rely on [Playwright][4]. - -[1]: https://phpunit.de/ -[2]: https://martinfowler.com/articles/mocksArentStubs.html#TheDifferenceBetweenMocksAndStubs -[3]: https://behat.org/en/latest/ -[4]: https://github.com/microsoft/playwright/ diff --git a/testing/ui-tests/_index.md b/testing/ui-tests/_index.md index e38e77ced1..f5a91e1389 100644 --- a/testing/ui-tests/_index.md +++ b/testing/ui-tests/_index.md @@ -1,10 +1,17 @@ --- title: UI tests -weight: 30 chapter: true --- -# Introduction +# UI Tests + +## Introduction + +We have some user interface tests (sometimes called web acceptance tests). These tests launch and control a browser, and perform several actions to check that the behavior, from the point of view of a real user, is as expected. These tests send actual HTTP requests and check the returned [DOM](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Introduction). + +These tests can be found in `UI` folders. + +### Stack UI tests work by controlling a browser and using the web interface like a real user. @@ -13,9 +20,11 @@ We use the following stack: * [Playwright](https://github.com/microsoft/playwright/) as automation tool * [Mocha](https://mochajs.org/) as test framework * [Chai](https://www.chaijs.com/) as assertion library -* [Faker](https://github.com/marak/Faker.js/) as fake data generator +* [Faker](https://github.com/faker-js/faker) as fake data generator + +## Execute & Create tests -## Running web acceptance tests +{{% children %}} -Everything is explained in [README](https://github.com/PrestaShop/PrestaShop/blob/develop/tests/UI/README.md) in the `tests/UI` folder. +Everything is explained in [README](https://github.com/PrestaShop/PrestaShop/blob/8.0.x/tests/UI/README.md) in the `tests/UI` folder. You'll need a working installation of PrestaShop in order to run the tests. diff --git a/testing/ui-tests/how-to-contribute-and-create-ui-tests.md b/testing/ui-tests/how-to-create-your-own-ui-tests.md similarity index 90% rename from testing/ui-tests/how-to-contribute-and-create-ui-tests.md rename to testing/ui-tests/how-to-create-your-own-ui-tests.md index 7e70bf669e..119275fa6d 100644 --- a/testing/ui-tests/how-to-contribute-and-create-ui-tests.md +++ b/testing/ui-tests/how-to-create-your-own-ui-tests.md @@ -1,10 +1,12 @@ --- -title: How to contribute and create UI tests -menuTitle: Creation of UI tests +title: How to create your own UI tests +menuTitle: Creating your own UI tests weight: 2 +aliases: + - /8/testing/ui-tests/how-to-contribute-and-create-ui-tests/ --- -# How to contribute and create UI tests +# How to create your own UI tests ## Architecture [Page Object Model](https://martinfowler.com/bliki/PageObject.html) (also called Page Object Pattern) is a way to organize your code in a test framework. It encourages you to separate your test logic from your page manipulation logic. @@ -54,13 +56,14 @@ Example: ```js /** * Get order status - * @param page + * @param page {Page} Browser tab * @return {Promise} */ async getOrderStatus(page) { return this.getTextContent(page, `${this.orderStatusesSelect} option[selected='selected']`, false); } ``` + This method returns the text content of the selected option in the Status `select` element in the Orders page. ### Selectors @@ -79,10 +82,10 @@ Each selector must belong to a certain type. Here is a non-exhaustive list: ## Tests ### Campaigns -We currently have 2 [campaigns](https://github.com/PrestaShop/PrestaShop/tree/develop/tests/UI/campaigns) implemented: +We currently have 2 [campaigns](https://github.com/PrestaShop/PrestaShop/tree/8.0.x/tests/UI/campaigns) implemented: -- **Sanity**: its purpose is to validate a Pull Request. Executed on [Travis CI](https://travis-ci.com/), [this campaign](https://github.com/PrestaShop/PrestaShop/tree/develop/tests/UI/campaigns/sanity) must fully pass before merging the PR (one failed test blocks the merge). It consists of a few tests of the core features of PrestaShop: shop installation, orders/products pages in BO, and catalog/cart/checkout process in FO. -- **Functional**: it is the biggest and most important [campaign](https://github.com/PrestaShop/PrestaShop/tree/develop/tests/UI/campaigns/functional). Its purpose is to validate that every feature of PrestaShop works, by testing them one by one. It goes on every page and tests whatever it can: table (filtering, ordering, quick edits, etc), [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) items (orders, customers, products…), setting changes, etc. +- **Sanity**: its purpose is to validate a Pull Request. Executed on [Travis CI](https://travis-ci.com/), [this campaign](https://github.com/PrestaShop/PrestaShop/tree/8.0.x/tests/UI/campaigns/sanity) must fully pass before merging the PR (one failed test blocks the merge). It consists of a few tests of the core features of PrestaShop: shop installation, orders/products pages in BO, and catalog/cart/checkout process in FO. +- **Functional**: it is the biggest and most important [campaign](https://github.com/PrestaShop/PrestaShop/tree/8.0.x/tests/UI/campaigns/functional). Its purpose is to validate that every feature of PrestaShop works, by testing them one by one. It goes on every page and tests whatever it can: table (filtering, ordering, quick edits, etc), [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) items (orders, customers, products…), setting changes, etc. We plan on implementing 2 more campaigns: @@ -101,11 +104,11 @@ The utils directory contain files that are necessary to run tests. #### Globals This file contains all global variables that can be used in test files, pages and common tests. -The description of each variable in this file can be found in [README.md](https://github.com/PrestaShop/PrestaShop/blob/develop/tests/UI/README.md). +The description of each variable in this file can be found in [README.md](https://github.com/PrestaShop/PrestaShop/blob/8.0.x/tests/UI/README.md). #### Setup [Mocha](https://mochajs.org/) gives us the possibility to load and run files before test files (with [\--file option](https://mochajs.org/#-file-filedirectoryglob)). -We use that option to run our `setup.js` file. This file opens only one browser for the whole campaign (and not one browser per test), since we're then running each test file in its [own context](https://github.com/microsoft/playwright/blob/master/docs/api.md#class-browsercontext). +We use that option to run our `setup.js` file. This file opens only one browser for the whole campaign (and not one browser per test), since we're then running each test file in its [own context](https://playwright.dev/docs/api/class-browsercontext). #### Browser helper This helper file is used to centralize the browser and tab functions called in all tests. @@ -136,7 +139,7 @@ Example: const dashboardPage = require('@pages/BO/dashboard'); const customersPage = require('@pages/BO/customers'); ``` - + ### Expect We use the `expect` keyword from the [Chai library](https://www.chaijs.com/api/bdd/). This allows us to write assertions in a much more readable way. You can use whatever way to assert you want/need. Don’t forget that you can use the second argument of `expect` to log out a better error message when your assertion fails. @@ -145,7 +148,7 @@ Example : ```js Const isCustomerConnected = await foLoginPage.isCustomerConnected(page); await expect(isCustomerConnected, 'Customer is disconnected in FO').to.be.true; -``` +``` ### Test identifier Our team thinks it’s very important to be able to follow how tests results evolve, so it’s been decided to add a unique identifier to every step in the test. @@ -190,5 +193,5 @@ The only assumption we have to make is the presence of certain items like Orders If you need to rely on the fixtures too, make sure to use the description of the objects you’re looking for in the `data` folder. If it’s not complete, you can expand it and make a Pull Request, we’ll be happy to improve our datasets ! ### Faker -When we need to create new items, we rely on [Faker](https://github.com/marak/Faker.js/) to create random data. +When we need to create new items, we rely on [Faker](https://github.com/faker-js/faker) to create random data. This helps us make sure we’re testing with randomized sets of data and covering a lot of cases. It’s very important to check the specifications before to make sure you’re properly setting up your faker : input length, authorized characters, range of dates/values, etc. diff --git a/testing/ui-tests/how-to-execute-tests.md b/testing/ui-tests/how-to-execute-tests.md new file mode 100644 index 0000000000..1ee92560ae --- /dev/null +++ b/testing/ui-tests/how-to-execute-tests.md @@ -0,0 +1,23 @@ +--- +title: How to execute UI Tests +menuTitle: Executing UI tests +weight: 10 +--- + +# How to execute UI Tests + +This is thoroughly explained in [README](https://github.com/PrestaShop/PrestaShop/blob/develop/tests/UI/README.md) in the `tests/UI` folder. +You'll need a working installation of PrestaShop in order to run the tests. + +## How to execute specific tests + +If you want to run only one test from a campaign or a couple of tests in the same folder, you can use `test:specific` command. + +To specify which test to run, you can add the `TEST_PATH` parameter in the beginning of the command + +```bash +# To run the **Filter Products** test from sanity campaign +TEST_PATH="sanity/02_productsBO/01_filterProducts" URL_FO="https://domain.tld/" npm run test:specific +# To run all **Products BO** tests +TEST_PATH="sanity/02_productsBO/*" URL_FO="https://domain.tld/" npm run test:specific +``` \ No newline at end of file diff --git a/testing/unit-tests/_index.md b/testing/unit-tests/_index.md new file mode 100644 index 0000000000..dd99d54e3c --- /dev/null +++ b/testing/unit-tests/_index.md @@ -0,0 +1,39 @@ +--- +title: Unit tests +chapter: true +--- + +# Unit tests + +## Introduction + +Unit tests are powered by [PHPUnit](https://phpunit.de). They test one and only one PHP class, mocking/stubbing any dependencies that class might have. + +This `Unit` folder meets some rules: + +- One PHP class = one test file. +- The test file path must follow the class filepath/ +- Every class dependency must be replaced by [test doubles](https://martinfowler.com/articles/mocksArentStubs.html#TheDifferenceBetweenMocksAndStubs). + +*If there is a hard-coded dependency such as a singleton pattern being used +or a static call, this class cannot be unit tested and should be tested using +integration tests.* + +### Stack + +We use the following stack: + +* [PHPUnit](https://phpunit.de) as test framework + + +### Conventions + +- Use `camelCase` names for test function names. +- Try to make method names explain the *intent* of the test case as best as possible. Don't hesitate to write long method names if necessary. + - Bad example: `testGetPrice` (no idea what such a test is supposed to do) + - Good example: `testDiscountIsAppliedToFinalPrice` + + +## Execute & Create tests + +{{% children %}} \ No newline at end of file diff --git a/testing/how-to-create-your-own-unit-tests.md b/testing/unit-tests/how-to-create-your-own-unit-tests.md similarity index 92% rename from testing/how-to-create-your-own-unit-tests.md rename to testing/unit-tests/how-to-create-your-own-unit-tests.md index cb5f08a018..9f1e68e39f 100644 --- a/testing/how-to-create-your-own-unit-tests.md +++ b/testing/unit-tests/how-to-create-your-own-unit-tests.md @@ -1,7 +1,9 @@ --- title: How to create your own unit tests menuTitle: Creating your own unit tests -weight: 10 +weight: 20 +aliases: + - /8/testing/how-to-create-your-own-unit-tests/ --- # How to create your own unit tests or add tests to PrestaShop diff --git a/testing/how-to-launch-tests.md b/testing/unit-tests/how-to-execute-tests.md similarity index 63% rename from testing/how-to-launch-tests.md rename to testing/unit-tests/how-to-execute-tests.md index f65a8b29cd..95adc34d89 100644 --- a/testing/how-to-launch-tests.md +++ b/testing/unit-tests/how-to-execute-tests.md @@ -1,24 +1,14 @@ --- -title: How to execute tests -menuTitle: Executing tests +title: How to execute Unit Tests +menuTitle: Executing unit tests weight: 10 --- -# How to execute the PrestaShop automatic test suite +# How to execute Unit Tests -## Executing Unit/integration test suites - -At least four test suites are available, testing different parts of PrestaShop: - -* Unit tests -* Integrations tests -* Functional tests - -Each suite needs a specific PHPUnit configuration. This is why each test suite has a specific composer command: +You can execute the test suite with specific Composer command: * `composer unit-tests` -* `composer integration-tests` -* `composer integration-behaviour-tests` {{% notice tip %}} You can execute the entire PHPUnit test suites using the `composer test-all` command. @@ -26,7 +16,7 @@ You can execute the entire PHPUnit test suites using the `composer test-all` com ## Executing the Functional test suites -This is thoroughly explained in the [Puppeteer tests Readme file](https://github.com/PrestaShop/PrestaShop/blob/develop/tests/UI/README.md). +This is thoroughly explained in the [Puppeteer tests Readme file](https://github.com/PrestaShop/PrestaShop/blob/8.0.x/tests/UI/README.md). ## Executing only part of phpunit tests diff --git a/themes/_index.md b/themes/_index.md index 7fb36f52db..7027f6fc6d 100644 --- a/themes/_index.md +++ b/themes/_index.md @@ -3,6 +3,8 @@ title: Themes weight: 5 pre: "5. " chapter: true +showOnHomepage: true +icon: fa-paint-brush --- ### Chapter 5 diff --git a/themes/distribution/_index.md b/themes/distribution/_index.md index 3051048509..26f7a2953b 100644 --- a/themes/distribution/_index.md +++ b/themes/distribution/_index.md @@ -1,6 +1,7 @@ --- title: Distribution chapter: true +showOnHomepage: true --- # Distribution diff --git a/themes/getting-started/_index.md b/themes/getting-started/_index.md index 360688f222..6f77e227aa 100644 --- a/themes/getting-started/_index.md +++ b/themes/getting-started/_index.md @@ -3,6 +3,7 @@ title: Getting started with theme development menuTitle: Getting started weight: 1 chapter: true +showOnHomepage: true --- # Getting started diff --git a/themes/getting-started/asset-management/_index.md b/themes/getting-started/asset-management/_index.md index b47e5ccfdc..798f396209 100644 --- a/themes/getting-started/asset-management/_index.md +++ b/themes/getting-started/asset-management/_index.md @@ -227,6 +227,7 @@ assets: priority: 200 attribute: async ``` + In addition, if you want to include a library hosted in a different server you can use the following syntax: ```yaml assets: @@ -244,6 +245,7 @@ assets: priority: 200 server: remote ``` + ### Registering in modules When developing a PrestaShop module, you may want to add specific styles for your templates. The best way is to use the `registerStylesheet` and `registerJavascript` methods provided by the parent `FrontController` class. diff --git a/themes/getting-started/asset-management/webpack.md b/themes/getting-started/asset-management/webpack.md index 701c94bb02..fee90416f0 100644 --- a/themes/getting-started/asset-management/webpack.md +++ b/themes/getting-started/asset-management/webpack.md @@ -33,98 +33,13 @@ If you want to compile your assets using Webpack (and we advise you to), follow - To build your assets once, type `npm run build`. - To rebuild your assets every time you change a file in the _dev folder, type `npm run watch`. - ## Webpack configuration -The [Webpack configuration file for Classic Theme](https://github.com/PrestaShop/PrestaShop/blob/1.7.6.0/themes/classic/_dev/webpack.config.js) is thus: +The [Webpack configuration file for Classic Theme](https://github.com/PrestaShop/classic-theme/blob/develop/_dev/webpack.config.js) is thus: 1. All CSS rules go to the `assets/css/theme.css` file. 2. All JavaScript code go to the `assets/js/theme.js` file. -It provides proper configuration for compile your Sass, Less, Stylus or CSS files into a single CSS file. - -JavaScript code is written in ES6, and compiled to ES5 with Babel. - -If you want to use Stylus or Less, simply edit the command line under the "scripts" section. - -```js -var webpack = require('webpack'); -var ExtractTextPlugin = require("extract-text-webpack-plugin"); - -var plugins = []; - -plugins.push( - new ExtractTextPlugin('../css/theme.css') -); - -module.exports = [{ - // JavaScript - entry: [ - './js/theme.js' - ], - output: { - path: '../assets/js', - filename: 'theme.js' - }, - module: { - loaders: [{ - test: /\.js$/, - exclude: /node_modules/, - loaders: ['babel-loader'] - }] - }, - externals: { - prestashop: 'prestashop' - }, - plugins: plugins, - resolve: { - extensions: ['', '.js'] - } -}, { - // CSS - entry: [ - './css/normalize.css', - './css/example.less', - './css/st/dev.styl', - './css/theme.scss' - ], - output: { - path: '../assets/css', - filename: 'theme.css' - }, - module: { - loaders: [{ - test: /\.scss$/, - loader: ExtractTextPlugin.extract( - "style", - "css-loader?sourceMap!postcss!sass-loader?sourceMap" - ) - }, { - test: /\.styl$/, - loader: ExtractTextPlugin.extract( - "style", - "css-loader?sourceMap!postcss!stylus-loader?sourceMap" - ) - }, { - test: /\.less$/, - loader: ExtractTextPlugin.extract( - "style", - "css-loader?sourceMap!postcss!less-loader?sourceMap" - ) - }, { - test: /\.css$/, - loader: ExtractTextPlugin.extract( - 'style', - 'css-loader?sourceMap!postcss-loader' - ) - }, { - test: /.(png|woff(2)?|eot|ttf|svg)(\?[a-z0-9=\.]+)?$/, - loader: 'file-loader?name=../css/[hash].[ext]' - }] - }, - plugins: plugins, - resolve: { - extensions: ['', '.scss', '.styl', '.less', '.css'] - } -}]; -``` +It provides proper configuration for compile your Sass or CSS files into a single CSS file. + +JavaScript code is written in ES6, and compiled to ES5 with [esbuild](https://github.com/privatenumber/esbuild-loader). diff --git a/themes/getting-started/guidelines.md b/themes/getting-started/guidelines.md index 567b702e16..b556c58de7 100644 --- a/themes/getting-started/guidelines.md +++ b/themes/getting-started/guidelines.md @@ -10,7 +10,7 @@ weight: 1 ##### PHP Code -Your PHP code should be compatible with [PHP compatibility chart]({{ relref "8/basics/installation/system-requirements/#php-compatibility-chart" }}) +Your PHP code should be compatible with [PHP compatibility chart]({{< relref "8/basics/installation/system-requirements#php-compatibility-chart" >}}) ##### HTML / CSS / Javascript @@ -31,7 +31,7 @@ Mobile-wise: Use spaces for indentation in every language (PHP, HTML, CSS, etc.):
4 spaces for PHP files, 2 spaces for all other file types. -Use our [.editorconfig](https://editorconfig.org/) file in order to easily configure your editor: https://github.com/PrestaShop/PrestaShop/blob/develop/.editorconfig +Use our [.editorconfig](https://editorconfig.org/) file in order to easily configure your editor: https://github.com/PrestaShop/PrestaShop/blob/8.0.x/.editorconfig ##### PHP files @@ -58,7 +58,7 @@ We recommend that you follow the [RSCSS structure](https://github.com/rstacruz/r ##### Javascript -Make sure your linter tool follows our .eslint file: https://github.com/PrestaShop/PrestaShop/blob/develop/js/.eslintrc.js +Make sure your linter tool follows our .eslint file: https://github.com/PrestaShop/PrestaShop/blob/8.0.x/js/.eslintrc.js If you wish to write ECMAScript 2015 (ES6) code, we recommend using the [Babel compiler](https://babeljs.io/) to maximize compatibility. diff --git a/themes/getting-started/setting-up-your-local-environment.md b/themes/getting-started/setting-up-your-local-environment.md index b92d2485a7..bf69de10d4 100644 --- a/themes/getting-started/setting-up-your-local-environment.md +++ b/themes/getting-started/setting-up-your-local-environment.md @@ -22,12 +22,12 @@ Open a command line on your (empty) working directory, then: ```bash git clone https://github.com/PrestaShop/PrestaShop.git ``` - + 2. Install dependencies ```bash composer install ``` - + Using git you can choose your PrestaShop version: ```bash git checkout 8.0 @@ -36,7 +36,7 @@ git checkout 8.0 Also we would warn you to test your final result with a zip release, just for safety (since vendor version might be slightly different). {{% notice note %}} -If you haven’t done it yet, we strongly recommend you to read our article [Set Up Your Git For Contributing](https://build.prestashop.com/howtos/misc/set-up-your-git-for-contributing/) +If you haven’t done it yet, we strongly recommend you to read our article [Set Up Your Git For Contributing](https://build.prestashop-project.org/howtos/misc/set-up-your-git-for-contributing/) {{% /notice %}} ## Building your .gitignore file @@ -58,7 +58,7 @@ Generally, you shouldn’t version the following types of files: We suggest that you build your own using https://gitignore.io. {{% notice note %}} -If you are building a full project for a client, you can read our article on [building a gitignore for PrestaShop](https://build.prestashop.com/howtos/misc/prestashop-perfect-gitignore/). +If you are building a full project for a client, you can read our article on [building a gitignore for PrestaShop](https://build.prestashop-project.org/howtos/misc/prestashop-perfect-gitignore/). {{% /notice %}} ## Create your theme from the Classic Theme diff --git a/themes/getting-started/theme-yml.md b/themes/getting-started/theme-yml.md index e3150e9fc7..4af27e329c 100644 --- a/themes/getting-started/theme-yml.md +++ b/themes/getting-started/theme-yml.md @@ -36,7 +36,6 @@ Users will be able to choose the layout for each page from the theme's settings ## Global settings - ### Configuration You can have the theme change the configuration of PrestaShop when the theme is enabled. @@ -48,6 +47,7 @@ You can have the theme change the configuration of PrestaShop when the theme is NEW_PRODUCTS_NBR: 4 PS_PNG_QUALITY: 8 ``` + You can also add custom configuration variables here (to use on modules/themes). ### Modules @@ -178,6 +178,16 @@ When the configuration is changed through the back office interface, only the se order-confirmation: layout-left-side-column ``` +#### Disable loading of `core.js` file in your custom theme {{< minver v="8.1.0" >}} + +You can disable `core.js` loading and provide a custom implementation of the whole logic initially contained in `core.js`. +To do this, use the `core_scripts` option, set to false, in `theme_settings` like in this example: + +```yaml +theme_settings: + core_scripts: false +``` + ## Dependencies When making a theme you may want to add features with custom modules. It's important that these modules diff --git a/themes/reference/_index.md b/themes/reference/_index.md index db2f3a4d87..507c601282 100644 --- a/themes/reference/_index.md +++ b/themes/reference/_index.md @@ -2,6 +2,7 @@ title: Theme development reference menuTitle: Reference weight: 30 +showOnHomepage: true --- # Theme development reference diff --git a/themes/reference/overriding-modules.md b/themes/reference/overriding-modules.md index 19c3f2333a..58dd796373 100644 --- a/themes/reference/overriding-modules.md +++ b/themes/reference/overriding-modules.md @@ -111,21 +111,28 @@ Here an example of generated markup with SmartyDev activated: - + - +
- - - - + + + + +
- + shopping_cart [...] ``` + To use it, simply set the `_PS_MODE_DEV_` constant to `true` in your installation's `/config/defines.inc.php` file: add the `define('_PS_MODE_DEV_', true);` line to that file in order to turn the PrestaShop Developer Mode on, which features SmartyDev. diff --git a/themes/reference/template-inheritance/parent-child-feature.md b/themes/reference/template-inheritance/parent-child-feature.md index e2e2f72021..38d0f0fe66 100644 --- a/themes/reference/template-inheritance/parent-child-feature.md +++ b/themes/reference/template-inheritance/parent-child-feature.md @@ -34,6 +34,7 @@ Then you can create a very minimal theme, containing only the following files: │ └── theme.yml └── preview.png ``` + {{% notice tip %}} It's recommended to copy these files from the Parent theme. {{% /notice %}} diff --git a/themes/reference/templates/notifications.md b/themes/reference/templates/notifications.md index 4abbe3c893..4cc120d72f 100644 --- a/themes/reference/templates/notifications.md +++ b/themes/reference/templates/notifications.md @@ -33,7 +33,7 @@ An array of notification is passed to the templates, containing at least one of ## How to display notifications -In the "Classic" Theme, [notifications are implemented as a partial template file](https://github.com/PrestaShop/PrestaShop/blob/1.7.6.0/themes/classic/templates/_partials/notifications.tpl): +In the "Classic" Theme, [notifications are implemented as a partial template file](https://github.com/PrestaShop/classic-theme/blob/2.0.1/templates/_partials/notifications.tpl): ```smarty ``` -...and are then [included in the template file](https://github.com/PrestaShop/PrestaShop/blob/1.7.6.0/themes/classic/templates/checkout/checkout.tpl#L46-L48): +...and are then [included in the template file](https://github.com/PrestaShop/classic-theme/blob/2.0.1/templates/customer/page.tpl#L32-L34): ```smarty {block name='notifications'} @@ -99,7 +99,7 @@ In the "Classic" Theme, [notifications are implemented as a partial template fil ## Add your own message in your front controller -Your front controller holds [the 4 following variables](https://github.com/PrestaShop/PrestaShop/blob/develop/classes/controller/FrontController.php#L616-L621): +Your front controller holds [the 4 following variables](https://github.com/PrestaShop/PrestaShop/blob/8.0.x/classes/controller/FrontController.php#L637-L640): * ``$this->errors`` * ``$this->success`` @@ -108,7 +108,7 @@ Your front controller holds [the 4 following variables](https://github.com/Prest They are PHP arrays, and they hold messages as a string. -Here is how you can [redirect the customer AND display a message after an action](https://github.com/PrestaShop/PrestaShop/blob/develop/classes/controller/FrontController.php#L614-L633): +Here is how you can [redirect the customer AND display a message after an action](https://github.com/PrestaShop/PrestaShop/blob/8.0.x/classes/controller/FrontController.php#L634-L653): ```php $this->success[] = $this->l('Information successfully updated.'); diff --git a/themes/reference/templates/templates-layouts.md b/themes/reference/templates/templates-layouts.md index 95f45fb29f..d6517d4bb5 100644 --- a/themes/reference/templates/templates-layouts.md +++ b/themes/reference/templates/templates-layouts.md @@ -1,18 +1,21 @@ --- title: Templates & layouts weight: 10 +useMermaid: true --- # Templates & layouts -PrestaShop template file are based on the [Smarty 3 template engine](https://www.smarty.net/v3_overview). +PrestaShop template files are based on the [Smarty 4 template engine](https://smarty-php.github.io/smarty/). + +{{% notice note %}} +On PrestaShop `1.7.x`, template files were based on [Smarty 3 template engine](https://www.smarty.net/v3_overview). +{{% /notice %}} All template files must be stored in the theme's `templates/` subfolder. For instance, the default theme has its template files in the following folder: `/themes/classic/templates`. - -Directory structure ------------------------------------- +## Directory structure Templates are then split between various subfolders. @@ -41,14 +44,13 @@ Template files should be written so that a single .tpl can generate a whole HTML inside a `_partials` folder or subfolder (see our coding standard, linked from the Prologue chapter of this documentation). - ## Templates We make a **clear difference between templates and layout**. * A template extends a layout * The layout holds the global organization of the page -* A template a specify to a feature: the product page for example +* A template is specific to a feature: the product page for example There are many templates in a PrestaShop theme, the main ones includes: @@ -71,17 +73,42 @@ When searching for a template, PrestaShop will check many location to determine which file should be used. It make it very easy to have different template for a given locale or a specific entity id. +More details in [TemplateFinder.php](https://github.com/PrestaShop/PrestaShop/blob/8.0.x/classes/Smarty/TemplateFinder.php#L71-L117). + +#### Product page example + With the product page, the core will check the following locations (in order) and return the first template found: -Example with a product with ID = 3 and locale = en-US +
+graph TD; + A(Lookup for template catalog/product with : locale + entity id) + A-->B(Lookup for template catalog/product with : entity id); + B-->C(Lookup for template catalog/product with : locale); + C-->D(Lookup for template catalog/product); +
+ +Example for the product with ID = 3 and locale = en-US: 1. `en-US/catalog/product-3.tpl` 2. `catalog/product-3.tpl` 3. `en-US/catalog/product.tpl` 4. `catalog/product.tpl` -Another example with category template for the category with ID = 9 and locale = en-US. +#### Category page example + +
+graph TD; + A(Lookup for template catalog/listing/category with : locale + entity id) + A-->B(Lookup for template catalog/listing/category with : entity id); + B-->C(Lookup for template catalog/listing/category with : locale); + C-->D(Lookup for template catalog/listing/category); + D-->E(Lookup for template catalog/listing/product-list with locale); + E-->F(Lookup for template catalog/listing/product-list); + +
+ +Example for the category with ID = 9 and locale = en-US: 1. `en-US/catalog/listing/category-9.tpl` 2. `catalog/listing/category-9.tpl` @@ -94,13 +121,12 @@ This feature is mostly made for developer working on a custom template for a cus ## Layouts -The layout is the organisation of the page, the way in which the parts of your design are arranged. -The typical example is the sidebar: is there a sidebar on your category page or is your product listing -is taking the whole space. +The layout is the organisation of the page: how the parts of your design are arranged. + +The typical example is the sidebar: is there a sidebar on your category page or is your product listing taking the whole space? -In PrestaShop, users are given the ability to change the layout of each page -independently. As a template developer, it's your role to ensure your theme is -compatible. +In PrestaShop, users are given the ability to change the layout of each page independently. +As a template developer, it's your role to ensure your theme is compatible. ![Configure layout](../img/configure-layout.png) @@ -109,7 +135,7 @@ compatible. The layout is the very top level of the [template inheritance]({{< relref "/8/themes/reference/template-inheritance/" >}}) tree. Basically it hold the opening and closing `` tags. -Typical layout files look like the following snippet. This one is a full one +Typical layout files look like the following snippet. This one is a full one: {{% notice note %}} Remember to define as many blocks as possible. @@ -185,4 +211,4 @@ Typical layout files look like the following snippet. This one is a full one ``` From there, each part of the theme will do its job and replace content inside these -bricks, keeping the same organization. +bricks, keeping the same organization. \ No newline at end of file diff --git a/webservice/_index.md b/webservice/_index.md index f1a9a3f08f..a9f121e53f 100644 --- a/webservice/_index.md +++ b/webservice/_index.md @@ -4,6 +4,8 @@ menuTitle: Webservice API weight: 6 pre: "6. " chapter: true +showOnHomepage: true +icon: fa-plug --- ### Chapter 6 diff --git a/webservice/cheat-sheet.md b/webservice/cheat-sheet.md index 657853ab95..541b1098a5 100644 --- a/webservice/cheat-sheet.md +++ b/webservice/cheat-sheet.md @@ -1,6 +1,7 @@ --- title: Cheat sheet weight: 40 +showOnHomepage: true --- # Cheat sheet for Webservice @@ -12,7 +13,7 @@ All these options can be added to your queries as query parameters (either `GET` | Key | Value | Description | |-----|-------|-------------| | **output_format** | `XML, JSON` | Change the output format | -| **ps_method** | `GET, POST, PUT, DELETE` | Override the HTTP method used for the request | +| **ps_method** | `GET, POST, PUT, PATCH, DELETE` | Override the HTTP method used for the request | ## Resource options diff --git a/webservice/getting-started.md b/webservice/getting-started.md index c5f0937522..fc2df9133d 100644 --- a/webservice/getting-started.md +++ b/webservice/getting-started.md @@ -1,6 +1,7 @@ --- title: Getting Started weight: 10 +showOnHomepage: true --- # Getting Started @@ -16,13 +17,14 @@ The PrestaShop web service uses the REST architecture in order to be available o [REST](https://en.wikipedia.org/wiki/REST) defines roughly a style of software architecture, which promotes the use of HTTP methods when building web application, instead of custom methods or protocols such as SOAP or WSDL. It defines several rules, including one that is similar to CRUD, which is described below. {{% /notice %}} -HTTP has several methods that can perform processing on data as defined in the REST architecture, among which are [4 main methods](https://en.wikipedia.org/wiki/HTTP#Request_methods): +HTTP has several methods that can perform processing on data as defined in the REST architecture, among which are [5 main methods](https://en.wikipedia.org/wiki/HTTP#Request_methods): | HTTP/REST | CRUD | SQL | |-----------|--------|--------| | POST | Create | INSERT | | GET | Read | SELECT | | PUT | Update | UPDATE | +| PATCH | Update | UPDATE | | DELETE | Delete | DELETE | ## Enabling & Creating an access to the webservice @@ -31,8 +33,7 @@ Reach the [dedicated page]({{< relref "tutorials/creating-access" >}}). ## Accessing the webservice -Now that your access key is generated you can test your store's webservice, its endpoint is located in the `/api/` folder at the root of your installation of Prestashop. -The quickest way to test your API is to use your browser: +After generating your access key, you can proceed to test your store's webservice. The webservice endpoint is located in the '/api/' folder at the root of your PrestaShop installation. To test your API quickly, you can simply use your browser: * If PrestaShop is installed at the root of your server, you can access the API here: http://example.com/api/ * If PrestaShop is installed in a subfolder of your server, you can access the API here: http://example.com/prestashop/api/ @@ -67,8 +68,8 @@ When you call the root `/api` url you will get a summary of the available APIs y - - + + The Customer, Brand and Customer addresses @@ -192,14 +193,14 @@ This parameter can only be used for listings, not for individual records. If you {{% notice note %}} A response obtained with "display" other than "full" can't be used in a **PUT** (update) request, because the `WebserviceRequest` class validation for fields is the same for **POST** (create) and **PUT** (update). -This should be fixed in a near future with a *yet-to-come-pull-request* introducing the PATCH method! +The **PATCH** method allows using a partial display. {{% /notice %}} ##### Control returned items with "filter" -The **EQUAL** operator is used when you need to get specific items. For exemple, if you want the addresses for customer #1, you can filter your **GET** request with the `filter` parameter: `http://example.com/api/addresses?filter[id_customer]=1` +The **EQUAL** operator is used when you need to get specific items. For example, if you want the addresses for customer #1, you can filter your **GET** request with the `filter` parameter: `http://example.com/api/addresses?filter[id_customer]=1` -The **LIKE** operator is used when you need to search for items. For exemple, if you want the addresses with cities starting with "SAINT": `http://example.com/api/addresses?filter[city]=[saint]%` +The **LIKE** operator is used when you need to search for items. For example, if you want the addresses with cities starting with "SAINT": `http://example.com/api/addresses?filter[city]=[saint]%` The **OR** operator is used when you need to get items matching several criteria: `http://example.com/api/addresses?filter[city]=[paris|lyon]` @@ -212,7 +213,7 @@ Other operators can be used, such as: This can be used in combination with the `display` parameter! Let's say you want to get the mobile phone numbers of customers #1, #7 and #42: `http://example.com/api/addresses?filter[id_customer]=[1|7|42]&display=[phone_mobile]` -You can also filter by dates! A typical example would be a routine in an ERP fetching the orders since the last call: `http://example.com/api/orders?display=full&date=1&filter[date_add]=[2019-11-14%2013:00:00,2019-11-14%2014:00:00]`. In this exemple, we request the orders created on 2019-11-14 between 1pm and 2pm. +You can also filter by dates! A typical example would be a routine in an ERP fetching the orders since the last call: `http://example.com/api/orders?display=full&date=1&filter[date_add]=[2019-11-14%2013:00:00,2019-11-14%2014:00:00]`. In this example, we request the orders created on 2019-11-14 between 1pm and 2pm. {{% notice note %}} Pay attention to: @@ -224,7 +225,7 @@ Pay attention to: ##### Special parameters -The `date=1` parameter must be used to allow date filtering (see exemple above). +The `date=1` parameter must be used to allow date filtering (see example above). The `limit=0,100` parameter can be used to limit the number of returned items (similar to MySQL's LIMIT clause). @@ -234,6 +235,25 @@ The `language=1` or `language=[1|2]` parameter can be used to return only these The `sendemail=1` parameter can be used if you need to change the state of an order AND you want the emails to be sent to the customer: you will have to do a **POST** on `http://example.com/api/order_histories?sendemail=1` +The `sendemail=1` parameter can be used on the `order_carriers` endpoint to send the _in-transit_ email with the tracking number. Example: `http://example.com/api/order_carriers/12345?sendemail=1` +12345 is the order carrier id. + +##### Cache handling + +A cache mechanism has been introduced and bug fixed in {{< minver v="8.0" >}}, it allows you to detect if the content changed between your API calls. + +To use it: + +1) in your first API call, retrieve the header `Content-Sha1` and store it on your side. +2) in your second API call, add a `Local-Content-Sha1` header, with the previously stored `Content-Sha1` value. + +If the content has not changed, the API will return a `304 Not Modified` response code. +If the content has changed, the API will return a `200 Ok` response code. + +{{% notice note %}} +It can be used to avoid unnecessary updates if the resource didn't change since the last API call. +{{% /notice %}} + ### Create a resource To create a resource, you simply need to **GET** the XML blank data for the resource (example `/api/addresses?schema=blank`), fill it with your changes, and send **POST HTTP request** with the whole XML as body content to the `/api/addresses/` URL. @@ -244,6 +264,24 @@ PrestaShop will take care of adding everything in the database, and will return To edit an existing resource: **GET** the full XML file for the resource you want to change (example `/api/addresses/1`), edit its content as needed, then send a **PUT HTTP request** with the whole XML file as a body content to the same URL again. +### Partially update a resource + +To partially edit an existing resource: **GET** a part of the XML file for the resource you want to change (example `/api/addresses/1`), edit its content as needed, then send a **PATCH HTTP request** with the partial XML file as the body content to the same URL again. + +When partially updating a resource, the only required parameter is the `id` of the resource. Then, add the changed `parameters`, and **PATCH** method will handle that partial update. + +Example: update the company name for the address of `id=1` : `PATCH /api/addresses/1` + +```xml + + +
+ + +
+
+``` + ### Using JSON instead of XML The Web services can also output JSON instead of XML. To enable JSON output you have two choices: @@ -259,7 +297,7 @@ Example: ```text https://UCCLLQ9N2ARSHWCXLT74KUKSSK34BFKX@example.com/api/?output_format=JSON -``` +``` ##### HTTP header diff --git a/webservice/reference.md b/webservice/reference.md index 2b7ca4610d..94f59061d2 100644 --- a/webservice/reference.md +++ b/webservice/reference.md @@ -1,6 +1,7 @@ --- title: Reference weight: 30 +showOnHomepage: true --- # Web service reference @@ -11,19 +12,19 @@ All webservice APIs are accessible through the `/api/` gateway. For instance, `h Most resources can be accessed in a REST manner, with the 5 main HTTP request methods: GET, POST, PUT, DELETE, HEAD. The only exceptions are: -| Key | GET | POST | PUT | DELETE | HEAD | -|--------------------------------|:---:|:----:|:---:|:------:|:----:| -| search | ✅ | | | | ✅ | -| stock_availables | ✅ | ✅ | | | ✅ | -| stock_movements | ✅ | | | | ✅ | -| stocks | ✅ | | | | ✅ | -| supply_order_details | ✅ | | | | ✅ | -| supply_order_histories | ✅ | | | | ✅ | -| supply_order_receipt_histories | ✅ | | | | ✅ | -| supply_order_states | ✅ | | | | ✅ | -| supply_orders | ✅ | | | | ✅ | -| warehouse_product_locations | ✅ | | | | ✅ | -| warehouses | ✅ | ✅ | ✅ | | ✅ | +| Key | GET | POST | PUT | PATCH | DELETE | HEAD | +|--------------------------------|:---:|:----:|:---:|:-----:|:------:|:----:| +| search | ✅ | | | | | ✅ | +| stock_availables | ✅ | | ✅ | ✅ | | ✅ | +| stock_movements | ✅ | | | | | ✅ | +| stocks | ✅ | | | | | ✅ | +| supply_order_details | ✅ | | | | | ✅ | +| supply_order_histories | ✅ | | | | | ✅ | +| supply_order_receipt_histories | ✅ | | | | | ✅ | +| supply_order_states | ✅ | | | | | ✅ | +| supply_orders | ✅ | | | | | ✅ | +| warehouse_product_locations | ✅ | | | | | ✅ | +| warehouses | ✅ | ✅ | ✅ | ✅ | | ✅ | All resources have two schemas that are accessible via a parameter: diff --git a/webservice/resources/carriers.md b/webservice/resources/carriers.md index e9842ddea5..5e347bb36d 100644 --- a/webservice/resources/carriers.md +++ b/webservice/resources/carriers.md @@ -6,30 +6,29 @@ title: Carriers ### Carrier -| Name | Format | Required | Max size | Not filterable | Description | -| :----------------------- | :------------ | :------: | -------: | :------------- | :----------------- | -| **deleted** | isBool | ❌ | | | | -| **is_module** | isBool | ❌ | | | | -| **id_tax_rules_group** | | ❌ | | true | Tax rules group ID | -| **id_reference** | | ❌ | | | Reference ID | -| **name** | isCarrierName | ✔️ | 64 | | | -| **active** | isBool | ✔️ | | | | -| **is_free** | isBool | ❌ | | | | -| **url** | isAbsoluteUrl | ❌ | | | | -| **shipping_handling** | isBool | ❌ | | | | -| **shipping_external** | | ❌ | | | | -| **range_behavior** | isBool | ❌ | | | | -| **shipping_method** | isUnsignedInt | ❌ | | | | -| **max_width** | isUnsignedInt | ❌ | | | | -| **max_height** | isUnsignedInt | ❌ | | | | -| **max_depth** | isUnsignedInt | ❌ | | | | -| **max_weight** | isFloat | ❌ | | | | -| **grade** | isUnsignedInt | ❌ | 1 | | | -| **external_module_name** | | ❌ | 64 | | | -| **need_range** | | ❌ | | | | -| **position** | | ❌ | | | | -| **delay** | isGenericName | ✔️ | 512 | | | - +| Name | Format | Required | Max size | Not filterable | Description | +|--------------------------|---------------|----------|----------|----------------|-------------------------------------------------------------------------------------------------------| +| **deleted** | isBool | ❌ | | | | +| **is_module** | isBool | ❌ | | | | +| **id_tax_rules_group** | | ❌ | | true | Tax rules group ID | +| **id_reference** | | ❌ | | | Reference ID | +| **name** | isCarrierName | ✔️ | 64 | | | +| **active** | isBool | ✔️ | | | | +| **is_free** | isBool | ❌ | | | | +| **url** | isAbsoluteUrl | ❌ | | | | +| **shipping_handling** | isBool | ❌ | | | Defines if extra shipping handling cost should be applied to this Carrier | +| **shipping_external** | | ❌ | | | Defines if external module calculates shipping cost | +| **range_behavior** | isBool | ❌ | | | Defines out-of-range behavior for weight, `true`=disable carrier, `false`=apply highest defined range | +| **shipping_method** | isUnsignedInt | ❌ | | | Calculation method : by weight, by price, or free | +| **max_width** | isUnsignedInt | ❌ | | | | +| **max_height** | isUnsignedInt | ❌ | | | | +| **max_depth** | isUnsignedInt | ❌ | | | | +| **max_weight** | isFloat | ❌ | | | | +| **grade** | isUnsignedInt | ❌ | 1 | | | +| **external_module_name** | | ❌ | 64 | | Name of the external module in charge of calculating the shipping cost | +| **need_range** | | ❌ | | | Defines if module needs core range-based shipping cost to calculate final cost | +| **position** | | ❌ | | | | +| **delay** | isGenericName | ✔️ | 512 | | | ### Blank schema diff --git a/webservice/resources/images.md b/webservice/resources/images.md index 4d6940c40d..239ab7aabc 100644 --- a/webservice/resources/images.md +++ b/webservice/resources/images.md @@ -22,14 +22,13 @@ title: Images ```xml - - - - - - - + + + + + + + ``` - diff --git a/webservice/tutorials/_index.md b/webservice/tutorials/_index.md index 614a40ab63..2b94d81b7b 100644 --- a/webservice/tutorials/_index.md +++ b/webservice/tutorials/_index.md @@ -2,6 +2,7 @@ title: Tutorials weight: 20 chapter: true +showOnHomepage: true --- # Tutorials diff --git a/webservice/tutorials/creating-access.md b/webservice/tutorials/creating-access.md index a43ba75061..df8aec91df 100644 --- a/webservice/tutorials/creating-access.md +++ b/webservice/tutorials/creating-access.md @@ -16,7 +16,7 @@ Go in the PrestaShop back office, open the "Web service" page under the "Advance {{< figure src="../../img/enable_webservice.png" title="Enabling Webservice" >}} -### Programatically +### Programmatically The Webservice switch is stored in the configuration table of PrestaShop. @@ -69,15 +69,15 @@ $apiAccess->save(); This first code allows you to pass the authentication layer. You also need access to the resources you expect to use. We need the Api account ID in order to grant it access, and an array having the resource name as key and the array of methods allowed as value. -The available resources can be found in [`WebserviceRequest::getResources()` (link to definition)](https://github.com/PrestaShop/PrestaShop/blob/1.7.6.0/classes/webservice/WebserviceRequest.php#L285]). +The available resources can be found in [`WebserviceRequest::getResources()` (link to definition)](https://github.com/PrestaShop/PrestaShop/blob/8.0.0/classes/webservice/WebserviceRequest.php#L282]). For instance is we want to give all permissions for customers and orders resources for the account we previously created: ```php ['GET' => 1, 'POST' => 1, 'PUT' => 1, 'DELETE' => 1, 'HEAD' => 1], - 'orders' => ['GET' => 1, 'POST' => 1, 'PUT' => 1, 'DELETE' => 1, 'HEAD' => 1], + 'customers' => ['GET' => 1, 'POST' => 1, 'PUT' => 1, 'PATCH' => 1, 'DELETE' => 1, 'HEAD' => 1], + 'orders' => ['GET' => 1, 'POST' => 1, 'PUT' => 1, 'PATCH' => 1, 'DELETE' => 1, 'HEAD' => 1], ]; WebserviceKey::setPermissionForAccount($apiAccess->id, $permissions); diff --git a/webservice/tutorials/prestashop-webservice-lib/create-resource.md b/webservice/tutorials/prestashop-webservice-lib/create-resource.md index 72e76cbce9..4b5530b3d4 100644 --- a/webservice/tutorials/prestashop-webservice-lib/create-resource.md +++ b/webservice/tutorials/prestashop-webservice-lib/create-resource.md @@ -55,16 +55,31 @@ Remember that each resource has its own validation rules (required fields, field ```php customer->children(); -$customerFields->firstname = 'John'; -$customerFields->lastname = 'DOE'; -$customerFields->email = 'john.doe@unknown.com'; -$customerFields->passwd = 'password1234'; - -$createdXml = $webService->add([ - 'resource' => 'customers', - 'postXml' => $blankXml->asXML(), -]); -$newCustomerFields = $createdXml->customer->children(); -echo 'Customer created with ID ' . $newCustomerFields->id . PHP_EOL; +try { + // creating webservice access + $webService = new PrestaShopWebservice('http://example.com/', 'ZR92FNY5UFRERNI3O9Z5QDHWKTP3YIIT', false); + + // call to retrieve the blank schema + $blankXml = $webService->get(['url' => 'http://example.com/api/customers?schema=blank']); + + // get the entity + $customerFields = $blankXml->customer->children(); + + // edit entity fields + $customerFields->firstname = 'John'; + $customerFields->lastname = 'DOE'; + $customerFields->email = 'john.doe@unknown.com'; + $customerFields->passwd = 'password1234'; + + // send entity to webservice + $createdXml = $webService->add([ + 'resource' => 'customers', + 'postXml' => $blankXml->asXML(), + ]); + $newCustomerFields = $createdXml->customer->children(); + echo 'Customer created with ID ' . $newCustomerFields->id . PHP_EOL; +} catch (PrestaShopWebserviceException $ex) { + // Shows a message related to the error + echo 'Other error:
' . $ex->getMessage(); +} ``` diff --git a/webservice/tutorials/prestashop-webservice-lib/setup-library.md b/webservice/tutorials/prestashop-webservice-lib/setup-library.md index 810ec46047..91f7620894 100644 --- a/webservice/tutorials/prestashop-webservice-lib/setup-library.md +++ b/webservice/tutorials/prestashop-webservice-lib/setup-library.md @@ -20,7 +20,7 @@ Now that your webservice is configured and accessible you might want to use it. If you are starting a new project you can init your composer project along with the dependency: ```bash -composer init --require="prestashop/prestashop-webservice-lib:dev-master" -n +composer init --require="prestashop/prestashop-webservice-lib:dev-master" -n composer install ``` @@ -97,6 +97,10 @@ Once the instance is created you can access the following methods: | edit() | PUT | UPDATE | | delete() | DELETE | DELETE | +{{% notice note %}} +**PATCH** method is not available in this library. +{{% /notice %}} + ### Handling errors It is essential that you understand how to handle errors with the webservice library. By implementing error-catch method early, you will more easily detect issues, and be able to correct them on the go. @@ -110,7 +114,7 @@ The error handling is done within a `try...catch` block, with the webservice ins try { // creating webservice access $webService = new PrestaShopWebservice('http://example.com/', 'ZR92FNY5UFRERNI3O9Z5QDHWKTP3YIIT', false); - + // call to retrieve all customers $xml = $webService->get(['resource' => 'customers']); } catch (PrestaShopWebserviceException $ex) { diff --git a/webservice/tutorials/testing-access.md b/webservice/tutorials/testing-access.md index b3f7069b75..6b34ec15ad 100644 --- a/webservice/tutorials/testing-access.md +++ b/webservice/tutorials/testing-access.md @@ -60,18 +60,18 @@ The `/api/` URL gives you the root of all the resources, in the form of an XML f - - + + The Customer, Brand and Customer addresses - - + + The images - - + + The products @@ -91,7 +91,7 @@ Let's see what they look like for the `address` resource. ### Blank schema -`/api/adresses?schema=blank` +`/api/addresses?schema=blank` ```xml @@ -126,7 +126,7 @@ Let's see what they look like for the `address` resource. ### Synopsis schema -`/api/adresses?schema=synopsis` +`/api/addresses?schema=synopsis` ```xml @@ -173,7 +173,7 @@ Example: ```text https://UCCLLQ9N2ARSHWCXLT74KUKSSK34BFKX@example.com/api/?output_format=JSON -``` +``` ### HTTP header