diff --git a/README.md b/README.md index e92e8686..665f3fe1 100644 --- a/README.md +++ b/README.md @@ -65,10 +65,10 @@ The Joomla Manual contains documentation for multiple versions of the Joomla sof The mapping between the versions of the manual in github and the live manual is: -| github manual (development) | Live Docusaurus manual | -| -------------------------------- | ---------------------- | -| /docs | "upcoming" release (shown as /docs/next in the URL) | -| /versioned_docs/version-m.n | version m.n (under "Current releases") | +| github manual (development) | Live Docusaurus manual | +| -------------------------------- |------------------------------------------------------| +| /docs | "upcoming" release (shown as /docs/next in the URL) | +| /versioned_docs/version-m.n | version m.n (under "Current releases") | If your documentation changes relate to multiple versions of Joomla then you should duplicate these changes into multiple versions of Joomla manual. These versions which are updated are currently agreed to be: - the version m.n of the latest full Joomla release ("latest" release) diff --git a/docusaurus.config.js b/docusaurus.config.js index 26283a2e..f1f94cc8 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -84,23 +84,29 @@ const config = { docs: { sidebarPath: require.resolve('./sidebars.js'), editUrl: 'https://github.com/joomla/manual/tree/main/', - lastVersion: '5.1', + lastVersion: '5.2', versions: { 'current': { - label: '5.2 (upcoming)', + label: '5.3 (Upcoming)', banner: 'unreleased' }, + '5.2': { + label: '5.2 (Current)', + }, '5.1': { - label: '5.1', + label: '5.1 (Archived)', + banner: 'unmaintained' }, '5.0': { - label: '5.0', + label: '5.0 (Archived)', + banner: 'unmaintained' }, '4.4': { - label: '4.4', - } + label: '4.4 (Security)', + banner: 'none' + }, }, - /*onlyIncludeVersions: ['current', '4.3'], */ + /* onlyIncludeVersions: ['current', '5.2', '4.4'], */ remarkPlugins: [ // Configure the plugin for parsing the API links [apiLinkPlugin,{ @@ -180,27 +186,6 @@ const config = { }, ], dropdownItemsAfter: [ - { - type: 'html', - value: '', - }, - { - type: 'html', - className: 'dropdown-archived-versions', - value: 'Archived versions', - }, - { - label: '3.x', - href: 'https://docs.joomla.org/Category:Joomla!_3.0', - }, - { - label: '2.5', - href: 'https://docs.joomla.org/Category:Joomla!_2.5', - }, - { - type: 'html', - value: '', - }, { to: '/versions', label: 'All versions', diff --git a/versioned_docs/version-5.2/about/documentation.md b/versioned_docs/version-5.2/about/documentation.md new file mode 100644 index 00000000..64d28c1f --- /dev/null +++ b/versioned_docs/version-5.2/about/documentation.md @@ -0,0 +1,162 @@ +This documentation +================== + +This [Joomla development manual](https://manual.joomla.org/docs/) is built using [Docusaurus 3](https://docusaurus.io/), a modern static website generator. If you want to contribute to it then this page will help you get started. + +Updates to the documentation is managed via the [Joomla manual github repository](https://github.com/joomla/Manual), so you should initially fork this repository into your own github account. Then you can make changes to the documentation files and submit a pull request to the Joomla manual. Ensure that you continue to sync your fork branches with the Joomla manual `main` branch. + +The documentation uses the [Markdown](https://www.markdownguide.org/) syntax, with additional features which Docusaurus provides. + +To make documentation changes you'll probably find it easiest to use one of two options: +1. Install Docusaurus on your own machine, and make changes there +2. Use [github dev](https://github.com/github/dev) to make the changes on the github server. + +## Install Docusaurus + +To install Docusaurus on your own machine you should initialise a local git repository and clone the manual from the forked copy in your githut repository into this git instance. + +Then change directory to your local git repository and issue: + +``` +$ npm install +``` + +Once Docusaurus is installed: + +``` +$ npm run start +``` + +This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. + +``` +$ npm run build +``` + +This command generates static content into the `build` directory and can be served using any static contents hosting service. + +## Use github dev + +To use github dev go to your repository and press the "." (dot) key, as described within the [github.dev guide](https://docs.github.com/en/codespaces/the-githubdev-web-based-editor). You can then: +- create a new git branch for your changes +- create new files and folders, modify and delete existing files, upload files +- preview files (right-click on the file tab) - this will show interpreted markdown, but will not interpret Docusaurus additions +- commit and push changes +- return to github repository (by clicking on GitHub in bottom left, or by replacing github.dev by github.com in the URL) + +## Pull Requests + +Once you raise a pull request on the [Joomla manual](https://github.com/joomla/Manual) a test build is run to identify any problems with your documentation. If you find a check has failed then click on the Details of the check which failed, and you can check the console logs to find the problem. + +When the build succeeds you will be able to see the result of your documentation changes by navigating to a URL like `http://pr-240.manual.joomlacode.org/docs/`, where you replace 240 with the number of your pull request. +This link will be added to the "checks" section in the pull request as "preview". + +## Versions + +The Joomla Manual contains documentation for multiple versions of the Joomla software. + +The mapping between the versions of the manual in github and the live manual is: + +| github manual (development) | Live Docusaurus manual | +| -------------------------------- | ---------------------- | +| /docs | "upcoming" release (shown as /docs/next in the URL) | +| /versioned_docs/version-m.n | version m.n (under "Current releases") | + +If your documentation changes relate to multiple versions of Joomla then you should duplicate these changes into multiple versions of Joomla manual. These versions which are updated are currently agreed to be: +- the version m.n of the latest full Joomla release ("latest" release) +- the version m.n+1 of the next Joomla release ("upcoming" release) +- the last version (m-1.last) of the Joomla previous major version + +Other versions may be present within /versioned_docs but are not updated with the changes, even if the documentation is true for those Joomla versions. + +To minimise changes it's recommended that you initially just make changes within the /docs area, and then raise the pull request. This allows team members to review the documentation, and for you to fix any issues without having to replicate changes to multiple versions. Then when the review process is complete the changes can be replicated to the other versions prior to merging. + +Once the pull request is merged you can delete the branch on your own repository, and sync your `main` branch with the updated Joomla manual `main`. + +## Common Build Problems + +If you use angle brackets or curly brackets in text then always enclose these in backticks, like `

` or `{['a':1, 'b':2]}`. + +Don't use colons (:) in titles. + +Don't use `
` to force a new line (eg in table text); use `
` instead. + +## Docusaurus Additions + +[Front Matter](https://docusaurus.io/docs/next/markdown-features#front-matter) should be used for titles and position in the left-hand sidebar: +``` +--- +title: Best Practices +sidebar-position: 2 +--- +``` + +[Code blocks](https://docusaurus.io/docs/next/markdown-features/code-blocks) are enclosed in 3 backticks, and can have a title: +```php title="hello.php" +public static function hello() +{ + echo "Hello!"; +} +``` +Line numbering and highlighting of individual lines are also supported. + +To aid readability of the markdown please leave a blank line before and after code blocks. + +[Admonitions](https://docusaurus.io/docs/next/markdown-features/admonitions) +We don't use blank lines around content, and we add 2 spaces before the text messages. + +``` +:::note[Developer Note] + Some **content** with _Markdown_ `syntax`. Check [this `api`](#). +::: + +:::note[Joomla Issue] + For issues that affect the documentation - please link to the issue on the Joomla Issue Tracker +::: + +:::tip + Some **content** with _Markdown_ `syntax`. Check [this `api`](#). +::: + +:::info + Some **content** with _Markdown_ `syntax`. Check [this `api`](#). +::: + +:::warning + Some **content** with _Markdown_ `syntax`. Check [this `api`](#). +::: + +:::danger + Some **content** with _Markdown_ `syntax`. Check [this `api`](#). +::: +``` + +Please use the following placeholder for unfinished sections of a document. + +``` +:::note[TODO] + This section is missing, please use the **Edit this Page** link at the bottom of this page to add this section. +::: +``` + +If the page is not completed yet and bigger parts are missing use + +``` +:::caution[TODO] + This page is unfinished, please use the **Edit this Page** link at the bottom of this page to help make it more useful. +::: +``` + +## Diagrams + +Where possible, use [Mermaid](https://mermaid.live) for creating diagrams for inclusion in the documentation. Where Mermaid doesn't provide what you need, then please include the saved diagram from your drawing tool in addition to the image file. + +Images, code zip files, etc should be held in a folder `_assets` at the point in the documentation where they're used. + +## Other Recommendations + +To align with a11y requirements for accessibility, please don't have more than one header level 1: + +``` +# Just One H1 +``` \ No newline at end of file diff --git a/versioned_docs/version-5.2/about/index.md b/versioned_docs/version-5.2/about/index.md new file mode 100644 index 00000000..8a305050 --- /dev/null +++ b/versioned_docs/version-5.2/about/index.md @@ -0,0 +1,10 @@ +--- +sidebar_position: 12 +--- +About +===== +:::caution TODO + +This page is unfinished, please use the **Edit this Page** link at the bottom of this page to help make it more useful. + +::: diff --git a/versioned_docs/version-5.2/about/versioning.md b/versioned_docs/version-5.2/about/versioning.md new file mode 100644 index 00000000..bc09df52 --- /dev/null +++ b/versioned_docs/version-5.2/about/versioning.md @@ -0,0 +1,16 @@ +Versioning the documentation +============================ + +The documentation should reflect the current releases of Joomla!. For each minor version we will have a tagged version in the documentation and update the version dropdown in this documentation. + +## Command to run +When we release a new minor Joomla! version, the documentation will be frozen and the version will be tagged. Use + +```bash npm2yarn +npm run docusaurus docs:version 4.3.0 +``` + +to tag a version. The current state of the documentation will be copied to the ```versioned_docs``` folder and the ```versions.js``` is updated. + +## Update the Versions dropdown +In the ```docusaurus.config.js``` the key ```onlyIncludeVersions``` has to be updated to the latest stable version. Also the ```lastVersion``` has to be updated properly and the ```versions``` labels should be set. diff --git a/versioned_docs/version-5.2/accessibility/atag.md b/versioned_docs/version-5.2/accessibility/atag.md new file mode 100644 index 00000000..d9a87090 --- /dev/null +++ b/versioned_docs/version-5.2/accessibility/atag.md @@ -0,0 +1,12 @@ +--- +sidebar_position: 3 +--- +ATAG Conformance +=========== +In this section we will explain the Authoring Tool Accessibility Guidelines, which level of conformance we are aiming for, and how to learn more about ATAG. + +:::caution TODO + +This page is unfinished, please use the **Edit this Page** link at the bottom of this page to help make it more useful. + +::: diff --git a/versioned_docs/version-5.2/accessibility/best-practices/empty-template.md b/versioned_docs/version-5.2/accessibility/best-practices/empty-template.md new file mode 100644 index 00000000..55136841 --- /dev/null +++ b/versioned_docs/version-5.2/accessibility/best-practices/empty-template.md @@ -0,0 +1,61 @@ +Page Template +=========== +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +:::tip +This is an empty template, intended to be used as a starting point for adding new best practices pages. Try to keep it consistent with other pages and fill out all relevant sections; sections marked "optional" can be removed if not relevant. +::: + +## Overview + +Definition / explanation of what this page is all about. + +### Best Practices +* Add best practices here. +* etc + +### Common Mistakes +* Add common errors here. + +## Who is affected? +People using screen readers need .... + +People with cognitive disabilities need ... etc. + +Who is impacted most by the accessibility of this element? + +## Testing for accessibility + + + +How does someone test that this is accessible with a screenreader? +1. Use the screen reader to navigate to ... +2. Make sure ... +3. Make sure ... +4. If ... then it passes. ✅ +5. If ... then it fails. ❌ + + + + +How does someone test that this is accessible with web inspector? +1. Right Click > Inspect ... on the page. +2. Make sure ... +3. Make sure ... +4. If ... then it passes. ✅ +5. If ... then it fails. ❌ +6. If ... then it passes. ✅ +7. If ... then it fails. ❌ + + + + +## Relevant WCAG Success Criteria +* Link to the WCAG Success Criteria here. For example: +* [WCAG criteria 1.3.1 - Info and Relationships](https://www.w3.org/TR/WCAG22/#info-and-relationships) + +## Relevant ATAG Guidelines (optional) +* Link to the ATAG Guideline(s) here. For example: +* [Guideline A.3.2: (For the authoring tool user interface) Provide authors with enough time.](https://www.w3.org/TR/ATAG20/#gl_a32) + diff --git a/versioned_docs/version-5.2/accessibility/best-practices/index.md b/versioned_docs/version-5.2/accessibility/best-practices/index.md new file mode 100644 index 00000000..22e93b68 --- /dev/null +++ b/versioned_docs/version-5.2/accessibility/best-practices/index.md @@ -0,0 +1,19 @@ +--- +sidebar_position: 4 +--- +Best Practices for Accessible Design +=========== +In this section we will explain different aspects to designing with accessibility in mind. + +Suggested sub-pages: +1. Colours +2. Fonts +3. Images +4. Focus Order +5. (add more) + +:::caution TODO + +This page is unfinished, please use the **Edit this Page** link at the bottom of this page to help make it more useful. + +::: diff --git a/versioned_docs/version-5.2/accessibility/best-practices/tooltip.md b/versioned_docs/version-5.2/accessibility/best-practices/tooltip.md new file mode 100644 index 00000000..45322ea2 --- /dev/null +++ b/versioned_docs/version-5.2/accessibility/best-practices/tooltip.md @@ -0,0 +1,85 @@ +Tooltip +======= +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +## Overview + +Tooltips are useful elements. They allow presenting information with an icon or a short text and adding additional informationn when the users hovers the icon or text. +If several tooltips are on a page, every toolpip must have an own ID. Other wise a screenreader cannot identify which tooltip gives Information to which element. + +## Code Snippet + +```PHPx title="Example Tooltip from com_menus, view menus " + + count_published; ?> + + +``` + +```PHPx title="Example Tooltip frontend - edit icon for an article" + + Edit + + +``` + +### Common Mistakes +- Missing ID. +- ID not uniquee. + +### Example in Joomla + +A tooltip on a element in a table: +administrator/components/com_menus/tmpl/menu/default.php + +A tooltip in the frontend which is visible for editable content (if you have permission for editing) +components/com_content/tmpl/article/form.php + + + + + +## Who is affected? +People using screen readers need .... + +People with cognitive disabilities need ... etc. + +Who is impacted most by the accessibility of this element? + +## Testing for accessibility + + + +How does someone test that this is accessible with a screenreader? +1. Use the screen reader to navigate to ... +2. Make sure ... +3. Make sure ... +4. If ... then it passes. ✅ +5. If ... then it fails. ❌ + + + + +How does someone test that this is accessible with web inspector? +1. Right Click > Inspect ... on the page. +2. Make sure ... +3. Make sure ... +4. If ... then it passes. ✅ +5. If ... then it fails. ❌ +6. If ... then it passes. ✅ +7. If ... then it fails. ❌ + + + + +## Relevant WCAG Success Criteria +* Link to the WCAG Success Criteria here. For example: +* [WCAG criteria 1.3.1 - Info and Relationships](https://www.w3.org/TR/WCAG22/#info-and-relationships) + +## Relevant ATAG Guidelines (optional) +* Link to the ATAG Guideline(s) here. For example: +* [Guideline A.3.2: (For the authoring tool user interface) Provide authors with enough time.](https://www.w3.org/TR/ATAG20/#gl_a32) + diff --git a/versioned_docs/version-5.2/accessibility/code-for-humans.md b/versioned_docs/version-5.2/accessibility/code-for-humans.md new file mode 100644 index 00000000..8644ed5c --- /dev/null +++ b/versioned_docs/version-5.2/accessibility/code-for-humans.md @@ -0,0 +1,12 @@ +--- +sidebar_position: 1 +--- +You code for humans, not machines. +=========== +In this section we will explain what accessibility is and why it matters. This should be evocative and informative; why should people care? + +:::caution TODO + +This page is unfinished, please use the **Edit this Page** link at the bottom of this page to help make it more useful. + +::: diff --git a/versioned_docs/version-5.2/accessibility/element-library/empty-template.md b/versioned_docs/version-5.2/accessibility/element-library/empty-template.md new file mode 100644 index 00000000..a259d176 --- /dev/null +++ b/versioned_docs/version-5.2/accessibility/element-library/empty-template.md @@ -0,0 +1,114 @@ +Element Template +=========== +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +:::tip +This is an empty template, intended to be used as a starting point for adding UI elements to the library. Try to keep it consistent with other elements and fill out all relevant sections; sections marked "optional" can be removed if not relevant. +::: + +## Overview + +Definition / explanation of what this component is/how it works. + + + + + Put front end/Cassiopeia screenshot here, if applicable. Don't forget alt text! + + + + + Put back end/Atum screenshot here, if applicable. Don't forget alt text! + + + + +## Usage +### Requirements (optional) +If this code only works in certain contexts or environments, add that here. For example: +* PHP 8.0+ +* No IE Support + +### Code Snippets + + + + +:::info + +Add notes about using this snippet in the front end, if applicable. + +::: + +```html title="Sample Front End Usage - ie, Cassiopia template" + +``` + + + + +:::info + +Add notes about using this snippet in the back end, if applicable. + +::: + +```html title="Sample Back End Usage - ie, Atum template" + +``` + + + + + + + +### Best Practices +* Add best practices here. For example, "Make sure you only use button elements when it will do an action, instead of navigating to a different page." +* etc + +### Common Mistakes +* Add common errors here. + +## Who is affected? +People using screen readers need .... + +People with cognitive disabilities need ... etc. + +Who is impacted most by the accessibility of this element? + +## Testing for accessibility + + + +How does someone test that this is accessible with a screenreader? +1. Use the screen reader to navigate to ... +2. Make sure ... +3. Make sure ... +4. If ... then it passes. ✅ +5. If ... then it fails. ❌ + + + + +How does someone test that this is accessible with web inspector? +1. Right Click > Inspect ... on the page. +2. Make sure ... +3. Make sure ... +4. If ... then it passes. ✅ +5. If ... then it fails. ❌ +6. If ... then it passes. ✅ +7. If ... then it fails. ❌ + + + + +## Relevant WCAG Success Criteria +* Link to the WCAG Success Criteria here. For example: +* [WCAG criteria 1.3.1 - Info and Relationships](https://www.w3.org/TR/WCAG22/#info-and-relationships) + +## Relevant ATAG Guidelines (optional) +* Link to the ATAG Guideline(s) here. For example: +* [Guideline A.3.2: (For the authoring tool user interface) Provide authors with enough time.](https://www.w3.org/TR/ATAG20/#gl_a32) + diff --git a/versioned_docs/version-5.2/accessibility/element-library/index.md b/versioned_docs/version-5.2/accessibility/element-library/index.md new file mode 100644 index 00000000..3eddf9d8 --- /dev/null +++ b/versioned_docs/version-5.2/accessibility/element-library/index.md @@ -0,0 +1,11 @@ +--- +sidebar_position: 4 +--- +Accessible UI Library +=========== +In this section we will show how to write accessible elements for Joomla. +:::caution TODO + +This page is unfinished, please use the **Edit this Page** link at the bottom of this page to help make it more useful. + +::: diff --git a/versioned_docs/version-5.2/accessibility/further-reading.md b/versioned_docs/version-5.2/accessibility/further-reading.md new file mode 100644 index 00000000..017e35b4 --- /dev/null +++ b/versioned_docs/version-5.2/accessibility/further-reading.md @@ -0,0 +1,12 @@ +--- +sidebar_position: 7 +--- +Further Reading +=========== +Additional accessibility resources can go here. + +:::caution TODO + +This page is unfinished, please use the **Edit this Page** link at the bottom of this page to help make it more useful. + +::: diff --git a/versioned_docs/version-5.2/accessibility/index.md b/versioned_docs/version-5.2/accessibility/index.md new file mode 100644 index 00000000..24a2b965 --- /dev/null +++ b/versioned_docs/version-5.2/accessibility/index.md @@ -0,0 +1,12 @@ +--- +sidebar_position: 6 +--- + +Accessibility +======================= +Accessibility (WCAG 2-1, AA conformance) is a main concern of Joomla. This section describes how to develop accessible extensions for Joomla +:::caution TODO + +This page is unfinished, please use the **Edit this Page** link at the bottom of this page to help make it more useful. + +::: diff --git a/versioned_docs/version-5.2/accessibility/reporting-issues.md b/versioned_docs/version-5.2/accessibility/reporting-issues.md new file mode 100644 index 00000000..a8288f02 --- /dev/null +++ b/versioned_docs/version-5.2/accessibility/reporting-issues.md @@ -0,0 +1,12 @@ +--- +sidebar_position: 6 +--- +Reporting Errors +=========== +How do people report accessibility issues in the CMS or template to us? + +:::caution TODO + +This page is unfinished, please use the **Edit this Page** link at the bottom of this page to help make it more useful. + +::: diff --git a/versioned_docs/version-5.2/accessibility/testing.md b/versioned_docs/version-5.2/accessibility/testing.md new file mode 100644 index 00000000..3e524d79 --- /dev/null +++ b/versioned_docs/version-5.2/accessibility/testing.md @@ -0,0 +1,14 @@ +--- +sidebar_position: 5 +--- +Testing Accessibility +=========== +How should people test the accessibility of their sites? + +Add notes about automated tools, jooA11y, checklists, etc. + +:::caution TODO + +This page is unfinished, please use the **Edit this Page** link at the bottom of this page to help make it more useful. + +::: diff --git a/versioned_docs/version-5.2/accessibility/wcag.md b/versioned_docs/version-5.2/accessibility/wcag.md new file mode 100644 index 00000000..77a20cbf --- /dev/null +++ b/versioned_docs/version-5.2/accessibility/wcag.md @@ -0,0 +1,12 @@ +--- +sidebar_position: 2 +--- +WCAG Conformance +=========== +In this section we will explain the Web Content Authoring Guidelines, which level of conformance we are aiming for, and how to learn more about WCAG. + +:::caution TODO + +This page is unfinished, please use the **Edit this Page** link at the bottom of this page to help make it more useful. + +::: diff --git a/versioned_docs/version-5.2/building-extensions/_assets/screenshot-extension-types.jpg b/versioned_docs/version-5.2/building-extensions/_assets/screenshot-extension-types.jpg new file mode 100644 index 00000000..7f895211 Binary files /dev/null and b/versioned_docs/version-5.2/building-extensions/_assets/screenshot-extension-types.jpg differ diff --git a/versioned_docs/version-5.2/building-extensions/_assets/screenshot-install-extension.jpg b/versioned_docs/version-5.2/building-extensions/_assets/screenshot-install-extension.jpg new file mode 100644 index 00000000..61241f00 Binary files /dev/null and b/versioned_docs/version-5.2/building-extensions/_assets/screenshot-install-extension.jpg differ diff --git a/versioned_docs/version-5.2/building-extensions/components/basic-component b/versioned_docs/version-5.2/building-extensions/components/basic-component new file mode 100644 index 00000000..fc519b2d --- /dev/null +++ b/versioned_docs/version-5.2/building-extensions/components/basic-component @@ -0,0 +1,5 @@ +--- +sidebar_position: 1 +title: Basic Component +--- +Code for a basic component. \ No newline at end of file diff --git a/versioned_docs/version-5.2/building-extensions/components/component-examples/ajaxdemo.md b/versioned_docs/version-5.2/building-extensions/components/component-examples/ajaxdemo.md new file mode 100644 index 00000000..61a20fb2 --- /dev/null +++ b/versioned_docs/version-5.2/building-extensions/components/component-examples/ajaxdemo.md @@ -0,0 +1,101 @@ +--- +title: Ajax demo component +--- + +Ajaxdemo Component +================== + +This is an example component which you can download from [com_ajaxdemo](https://github.com/joomla/manual-examples/tree/main/component-ajaxdemo). + +It demonstrates the use of Ajax within a Joomla component; +for further background see the section [Ajax and JsonResponse](../../../general-concepts/javascript/ajax.md). + +It can be easily adapted to demonstrate the use of [com_ajax](../../../general-concepts/javascript/com-ajax.md) for plugins and templates; +simply change the url in media/js/divide.js to point to com_ajax instead of com_ajaxdemo, and set the other required URL parameters. + +Once you have downloaded the source, zip up the com_ajaxdemo directory and install the component. + +Then go to `/index.php/component/ajaxdemo` to run it on your Joomla instance. + +The component displays a form to capture two numbers A and B, and a button to calculate A/B. +The division is performed by an Ajax call to the server, and if B is zero then an exception is raised. + +Brief summaries of the main source files are provided below. + +## Administrator service provider + +Path: administrator/components/com_ajaxdemo/services/provider.php + +This is boilerplate code for a basic MVC component. For components this file is placed under /administrator in the Joomla filesystem. +If you want to understand it fully then read the [Dependency Injection](../../../general-concepts/dependency-injection/index.md) section. + +From this file Joomla instantiates default [Extension and Dispatcher classes](../../../general-concepts/extension-and-dispatcher/index.md), +and an MVC Factory class which creates Model, View and Controller classes for our component. + +The default Dispatcher class examines the URL `task` parameter, and from it works out the Controller to instantiate. +The default Controller (when no `task` parameter is present) is the DisplayController. +When the Divide button is pressed the JavaScript code sends an Ajax request using `task` set to "ajax.divide". +Based on this the default Dispatcher will instantiate this component's AjaxController and call its `divide` method. + +## Site Display Controller + +Path: components/com_ajaxdemo/src/Controller/DisplayController.php + +This controller's display method is what is run when you go to your site page which displays the form (ie navigate to the URL `.../index.php/component/ajaxdemo`). + +It gets the associated Model and View classes, and calls display() on the View instance. + +## Site Ajaxdemo View + +Path: components/com_ajaxdemo/src/View/Ajaxdemo/HtmlView.php + +This calls the model to set up the form, then calls display() to run the tmpl file. + +## Site Ajaxdemo Model + +Path: components/com_ajaxdemo/src/Model/AjaxdemoModel.php + +This sets up the form as described in [Forms](../../../general-concepts/forms/index.md). + +## Site Ajaxdemo tmpl file + +Path: components/com_ajaxdemo/tmpl/ajaxdemo/default.php + +This uses the [Web Asset Manager](../../../general-concepts/web-asset-manager.md) to attach the JavaScript divide.js which initiates the Ajax call. + +It passes the root URL of your Joomla instance to the JavaScript code using [passing variables to Javascript](../../../general-concepts/javascript/adding-javascript#passing-variables-to-javascript) +as this makes the job of forming the URLs easier. + +Then it outputs the `
` html, including the button with the onclick listener to run the divide.js code. + +## "Divide" XML Form + +Path: components/com_ajaxdemo/forms/divide_form.xml + +This uses [Joomla Standard Form Fields](../../../general-concepts/forms-fields/standard-fields/index.md) for the fields in the form. + +## JavaScript code + +Path: media/com_ajaxdemo/js/divide.js + +The is the code which is run when the Divide button is pressed. + +It initiates the Ajax call and handles the response. + +## Ajax Controller + +Path: components/com_ajaxdemo/src/Controller/AjaxController.php + +This is the controller with the divide() method which gets called when the Ajax request is serviced by Joomla. + +It computes a/b and sends the result back to the JavaScript code using JsonResponse. + +If b is zero then it sends a 'divide by zero' exception into JsonResponse, which gets mapped to a JSON object with success=false passed back. + +It also sets up a couple of dummy enqueued messages to demonstrate this aspect of JsonResponse. + +## media joomla.asset.json file + +Path: media/com_ajaxdemo/joomla.asset.json + +This is the file required by the [Web Asset Manager](../../../general-concepts/web-asset-manager.md) for defining the JavaScript asset and its dependencies. diff --git a/versioned_docs/version-5.2/building-extensions/components/component-examples/example-form-component.md b/versioned_docs/version-5.2/building-extensions/components/component-examples/example-form-component.md new file mode 100644 index 00000000..4daa68c1 --- /dev/null +++ b/versioned_docs/version-5.2/building-extensions/components/component-examples/example-form-component.md @@ -0,0 +1,166 @@ +--- +sidebar_position: 3 +title: Example Form Component +--- + +Example Form Component +====================== + +This is an example component which you can download from [com_exampleform](https://github.com/joomla/manual-examples/tree/main/component-exampleform). + +Once you have downloaded the source, zip up the com_exampleform directory and install the component. + +Then go to `/index.php/component/exampleform` to run it on your Joomla instance. + +It is an MVC component which demonstrates the following: + +- using [Joomla Forms](../../../general-concepts/forms/how-forms-work.md) to capture data in a form +- using several of the [standard form fields](../../../general-concepts/forms-fields/standard-fields/index.md) +- writing a [custom field](../../../general-concepts/forms-fields/custom-fields-overview.md) +- writing a [custom server-side validation rule](../../../general-concepts/forms/server-side-validation.md) +- writing a [custom client-side validation rule](../../../general-concepts/forms/client-side-validation.md) +- writing a [custom form filter](../../../general-concepts/forms-fields/standard-form-field-attributes.md#filter) + +You can easily adapt it to experiment with other standard fields, simply by including the standard field in the form XML file. + +There are comments throughout the code to help you understand it, and brief summaries of the main source files are provided below. + +## Administrator service provider + +Path: administrator/components/com_exampleform/services/provider.php + +This is boilerplate code for a basic MVC component. For components this file is placed under /administrator in the Joomla filesystem. +If you want to understand it fully then read the [Dependency Injection](../../../general-concepts/dependency-injection/index.md) section. + +From this file Joomla instantiates default [Extension and Dispatcher classes](../../../general-concepts/extension-and-dispatcher/index.md), and an MVC Factory class which creates Model, View and Controller classes for our component. + +## Site Display Controller + +Path: components/com_exampleform/src/Controller/DisplayController.php + +This is what is run when you go to your site page which displays the form (ie navigate to the URL `.../index.php/component/exampleform`). + +It gets the associated Model and View classes, and calls display() on the View instance. + +## Site Exampleform View + +Path: components/com_exampleform/src/View/Exampleform/HtmlView.php + +This calls the model to set up the form, then calls display() to run the tmpl file. + +## Site Exampleform Model + +Path: components/com_exampleform/src/Model/ExampleformModel.php + +This sets up the form as described in [Forms](../../../general-concepts/forms/index.md). + +## Site Exampleform tmpl file + +Path: components/com_exampleform/tmpl/exampleform/default.php + +This uses the [Web Asset Manager](../../../general-concepts/web-asset-manager.md) to set up the scripts for client-side validation. + +Then it outputs the `` html, and outputs the fields using [renderFieldset](../../../general-concepts/forms/manipulating-forms.md#fieldsets). + +The Submit button has an onclick listener which calls `Joomla.submitbutton('exampleform.submit')`. +This function will initiate an HTTP POST to the server, with the field values as POST parameters, including the *task* parameter set to 'exampleform.submit'. + +When the HTTP request reaches the server Joomla will examine the *task* parameter, and as a result will call the ExampleformController::submit() method, as described in [Joomla MVC](../mvc/mvc-overview.md). + +## Example XML Form + +Path: components/com_exampleform/forms/example_form.xml + +Most of this involves simply using the [Joomla Standard Form Fields](../../../general-concepts/forms-fields/standard-fields/index.md). + +You can easily add in other standard form fields to experiment with them. + +In addition, the file includes: + +Definition of a [custom field](../../../general-concepts/forms-fields/custom-fields-overview.md): +```xml +addfieldprefix="My\Component\Exampleform\Site\Field" +name="time" +type="mytime" +``` + +Definition of a [custom filter](../../../general-concepts/forms-fields/standard-form-field-attributes.md#filter): +```xml +addfilterprefix="My\Component\Exampleform\Site\Filter" +filter="lettersonly" +``` + +Definition of a [custom client-side validation rule](../../../general-concepts/forms/client-side-validation.md): +```xml +class="inputbox validate-noUppercase" +data-validation-text="Error: No uppercase letters are allowed" +``` + +Definition of a [custom server-side validation rule](../../../general-concepts/forms/server-side-validation.md): +```xml +addruleprefix="My\Component\Exampleform\Site\Rule" +validate="noasterisk" +``` + +Use of the [showon attribute](../../../general-concepts/forms-fields/standard-form-field-attributes.md#showon). + +## Site Exampleform Controller + +Path: components/com_exampleform/src/Controller/ExampleformController.php + +When the form data is sent to the server in an HTTP POST request, Joomla examines the *task* parameter, and as this will be set to 'exampleform.submit' Joomla will call the `submit` function of the ExampleformController class instance. + +This function obtains the array of POST parameters and gets the model to set up the form again from the definition in example_form.xml. + +It then initiates applying the filtering and validation rules of the fields. + +If the data fails validation then the data entries are stored in the session, and a redirect back to the form is issued. +When the HTTP GET request to redisplay the form is received then the `loadFormData` function in the ExampleformModel will retrieve the session data and prefill the fields with the previous entries. + +If the data passes validation then the ExampleformReturn view is instantiated, and the raw data and filtered data passed to it. + +## Site ExampleformReturn View + +Path: components/com_exampleform/src/View/ExampleformReturn/HtmlView.php + +This simply has a function to accept the data from the Controller, which it stores locally. + +## Site ExampleformReturn tmpl file + +Path: components/com_exampleform/tmpl/exampleformReturn/default.php + +This simply outputs the raw and filtered data which was passed to the view. + +Remember that the view and the tmpl file share the same function context, so variables set up in the view are accessible in the tmpl file. + +## Custom Field + +Path: components/com_exampleform/src/Field/MytimeField.php + +This is the source code for the `mytime` custom field. + +## Custom Filter + +Path: components/com_exampleform/src/Filter/LettersonlyFilter.php + +This is the source code for the `lettersonly` custom filter. + +## Custom Validation Rule + +Path: components/com_exampleform/src/Rule/Noasterisk.php + +This is the source code for the `noasterisk` custom server-side validation rule. + +## Media joomla.asset.json file + +Path: media/com_exampleform/joomla.asset.json + +This defines the component's javascript (and CSS) assets, together with their dependancies, as required by the [Web Asset Manager](../../../general-concepts/web-asset-manager.md). + +For components this file is always automatically processed by Joomla. + +## Javascript client-side validation code + +Path: media/com_exampleform/js/no-uppercase.js + +This is javascript code for the custom client-side validation rule. \ No newline at end of file diff --git a/versioned_docs/version-5.2/building-extensions/components/component-examples/index.md b/versioned_docs/version-5.2/building-extensions/components/component-examples/index.md new file mode 100644 index 00000000..15b04c5d --- /dev/null +++ b/versioned_docs/version-5.2/building-extensions/components/component-examples/index.md @@ -0,0 +1,9 @@ +--- +sidebar_position: 3 +title: Example Components +--- + +Component Examples +================== + +In this section you can find worked examples of components of various types. \ No newline at end of file diff --git a/versioned_docs/version-5.2/building-extensions/components/custom-fields.md b/versioned_docs/version-5.2/building-extensions/components/custom-fields.md new file mode 100644 index 00000000..eeeb29b0 --- /dev/null +++ b/versioned_docs/version-5.2/building-extensions/components/custom-fields.md @@ -0,0 +1,3 @@ +Custom Fields +======================= +This is the content for implementing Custom Fields in your component - tbd \ No newline at end of file diff --git a/versioned_docs/version-5.2/building-extensions/components/index.md b/versioned_docs/version-5.2/building-extensions/components/index.md new file mode 100644 index 00000000..41c6e7e6 --- /dev/null +++ b/versioned_docs/version-5.2/building-extensions/components/index.md @@ -0,0 +1,9 @@ +--- +sidebar_position: 2 +title: Components +--- +Components are the main functional units of Joomla and can be viewed as mini-applications. The content is usually displayed in the centre of the web page is usually created by a component. + +Most components have two main parts: an administrator part and a site part. The site part is what is used to render pages of your site when they are requested by your site visitors during normal site operation. The administrator part provides an interface to configure and manage different aspects of the component and is accessible through the Joomla administrator application. + +Joomla comes with a number of core components, for example, com_content for articles, com_contact for contacts and com_menus for setting up the website menus and menu items. \ No newline at end of file diff --git a/versioned_docs/version-5.2/building-extensions/components/mvc/_assets/model-hierarchy.jpg b/versioned_docs/version-5.2/building-extensions/components/mvc/_assets/model-hierarchy.jpg new file mode 100644 index 00000000..8dce86a0 Binary files /dev/null and b/versioned_docs/version-5.2/building-extensions/components/mvc/_assets/model-hierarchy.jpg differ diff --git a/versioned_docs/version-5.2/building-extensions/components/mvc/_assets/mvc-factory-controller.jpg b/versioned_docs/version-5.2/building-extensions/components/mvc/_assets/mvc-factory-controller.jpg new file mode 100644 index 00000000..47c9376c Binary files /dev/null and b/versioned_docs/version-5.2/building-extensions/components/mvc/_assets/mvc-factory-controller.jpg differ diff --git a/versioned_docs/version-5.2/building-extensions/components/mvc/_assets/mvc-factory.jpg b/versioned_docs/version-5.2/building-extensions/components/mvc/_assets/mvc-factory.jpg new file mode 100644 index 00000000..5d221976 Binary files /dev/null and b/versioned_docs/version-5.2/building-extensions/components/mvc/_assets/mvc-factory.jpg differ diff --git a/versioned_docs/version-5.2/building-extensions/components/mvc/_assets/mvc-overview.jpg b/versioned_docs/version-5.2/building-extensions/components/mvc/_assets/mvc-overview.jpg new file mode 100644 index 00000000..bbcb22d6 Binary files /dev/null and b/versioned_docs/version-5.2/building-extensions/components/mvc/_assets/mvc-overview.jpg differ diff --git a/versioned_docs/version-5.2/building-extensions/components/mvc/_assets/post-request-get1.jpg b/versioned_docs/version-5.2/building-extensions/components/mvc/_assets/post-request-get1.jpg new file mode 100644 index 00000000..b6b3b16b Binary files /dev/null and b/versioned_docs/version-5.2/building-extensions/components/mvc/_assets/post-request-get1.jpg differ diff --git a/versioned_docs/version-5.2/building-extensions/components/mvc/_assets/post-request-get2.jpg b/versioned_docs/version-5.2/building-extensions/components/mvc/_assets/post-request-get2.jpg new file mode 100644 index 00000000..81ef3a06 Binary files /dev/null and b/versioned_docs/version-5.2/building-extensions/components/mvc/_assets/post-request-get2.jpg differ diff --git a/versioned_docs/version-5.2/building-extensions/components/mvc/index.md b/versioned_docs/version-5.2/building-extensions/components/mvc/index.md new file mode 100644 index 00000000..47f4ba05 --- /dev/null +++ b/versioned_docs/version-5.2/building-extensions/components/mvc/index.md @@ -0,0 +1,5 @@ +--- +title: Joomla Model View Controller pattern +sidebar_position: 1 +--- +This section describes the MVC pattern as it is implemented in Joomla components. Although you don't need to follow this pattern when developing your own component, it's very much recommended that you do so, as it will make things considerably easier for you in the long run. \ No newline at end of file diff --git a/versioned_docs/version-5.2/building-extensions/components/mvc/library-mvc.md b/versioned_docs/version-5.2/building-extensions/components/mvc/library-mvc.md new file mode 100644 index 00000000..eba2db08 --- /dev/null +++ b/versioned_docs/version-5.2/building-extensions/components/mvc/library-mvc.md @@ -0,0 +1,120 @@ +--- +title: Library MVC Classes +sidebar_position: 4 +--- +Joomla Library MVC Classes +========================== + +Joomla provides several Controller, View and Model library classes, and this section gives an overview of these, and explains when your own component should use each class. However, it doesn't attempt to provide a full description of each class's functionality. The classes can be found in libraries/src/MVC. + +## Base MVC Classes +In practical terms, the lowest level classes you would be likely to use are: +- BaseController in libraries/src/MVC/Controller/BaseController.php +- HtmlView in libraries/src/MVC/View/HtmlView.php (for displaying web pages) +- BaseDatabaseModel in libraries/src/MVC/Model/BaseDatabaseModel.php + +(If your component is responding to an Ajax call with a JSON-encoded object then you would use libraries/src/MVC/View/JsonView.php instead.) + +In general, using these base classes is a good option if your component is displaying a single item on a site page. + +### BaseController +The functionality within BaseController includes: +- the `execute()` method described above, which runs the appropriate Controller function, based on the *task* parameter's `` part (which is passed to it). +- functions for determining the appropriate View and Model classes to use (based on the setting of the view parameter within the HTTP request), and getting the MVCFactory class to create them +- a default `display()` method, which gets instances of the View and Model classes (including providing the View instance with a link to the Model instance), and then calls the `display()` method of the View class. + +### HtmlView +The functionality within HtmlView includes: +- a default `display()` method, which runs the tmpl file +- code for finding the tmpl file, taking into account a layout override which may have been put into the template folder structure +- code for setting the model instance, and subsequently retrieving it + +### BaseDatabaseModel +The functionality within BaseDatabaseModel includes: +- code for getting an instance of the Table class (via the MVCFactory class) +- base code for creating a model "state". This feature is useful if the component and/or several modules shown on the web page all use the same base data. In this case they may share the same Model instance and the model "state" acts like a container for sharing the values of items across the component and modules. + +## Higher-level Controller Classes +There are 2 higher-level controller classes, each of which inherit from BaseController. + +### AdminController +AdminController contains methods which handle the types of operations that can be performed on multiple items, for example: + +- delete +- checking-in +- changing the publishing state +- changing the relative ordering of records + +The code generally calls the related Model method to effect the operation, sets up the message based on the success of the Model operation, and sets up the redirect back to the same page. For this reason it's very useful in Action 2 shown in the diagram above in the [Post/Request/Get pattern](post-redirect-get.md) section. + +The name AdminController suggests that this controller is to be used only on the back end administrator functionality, however, this is not the case. It's appropriate to use it on the site front end as well. + +Note however that it doesn't support the operations enabled by the Batch button on e.g. the Content/Articles page; these POST requests are handled by the FormController. + +### FormController +FormController contains methods which are associated with editing an individual item + +- handling a request to edit an item – which involves checking that the user is allowed to edit the item and that it isn't already checked out, and if these checks pass then the item is checked out (if that component has enabled checkout) and a redirect is issued to display the edit form +- handling a request to add a new item – which involves checking that the user is allowed to create the item and results in a redirect to display a blank edit form +- handling the Save of an item being edited or created from new – the code checks that the user is allowed to perform the operation and calls the appropriate model method to save the new/edited item. +- handling the Cancel of an edit, redirecting the user back to the appropriate page (and checking-in the record if required). +- handling the operations initiated through the Batch button + +The FormController is thus well suited to Actions 3 and 5 shown in the diagrams above in the [Post/Request/Get pattern](post-redirect-get.md) section. + +## Higher-level View Classes +Apart from the CategoryFeedView, which is used for generating a [feed](https://docs.joomla.org/J3.x:Developing_an_MVC_Component/Adding_a_Feed), there are two higher level View classes in common usage: +- CategoryView – for displaying a category and its children +- CategoriesView – for displaying all the categories at a certain level in the category hierarchy, and the number of items associated with each category + +The two classes ListView and FormView seem to be aimed at functionality for displaying a list of records (like the `com_content` administrator View\Articles\HtmlView) and a form for editing a record (like the `com_content` administrator View\Article\HtmlView). However, at time of writing (Joomla 5 alpha has recently appeared), they aren't used by any of the Joomla components, so I wouldn't recommend using them, at least not yet. + +### Higher-level Model Classes +The diagram shows the inheritance tree of the Joomla library MVC models. +![Model Class Hierarchy](_assets/model-hierarchy.jpg "Model Class Hierarchy") + +**ItemModel** is almost the same as BaseDatabaseModel. It just has an extra `getStoreId()` method which is relevant when you have a component and/or several modules sharing the same model and you want to distinguish between data sets relevant to each. + +In addition to `getStoreId()`, **ListModel** has capability relating to obtaining a set of records for display on a web page, including support for pagination. Note that the pagination capability may still be slightly different between the front end and the back end. The ListModel is useful for supporting Action 1 in the diagrams in the [Post/Request/Get pattern](post-redirect-get.md) section. + +**FormModel** includes support for Joomla forms, both for setting up the form so that it can be displayed, and also so that the form data sent in the POST can be validated. In addition, it has methods for implementing checkin and checkout of database records. So it's suitable for handling Actions 3 and 4 in the diagrams. + +**AdminModel** extends FormModel, so it has all the capability for handling forms, but in addition has methods for handling database updates – including capability for adding, updating and deleting records – as well as support for handling operations in batch. So it's suitable for handling Actions 2 and 5 in the diagrams. As with the AdminController, this model is not just appropriate for the administrator functionality, but can be used on the front end as well. + +However, although the FormModel and AdminModel support different cases in the flow associated with editing a record, in practice it's common to use the same model for all the different steps of the flow. All the Joomla core components use the same model across these steps, and so they all extend AdminModel instead of FormModel. + +Something to be aware of if you are using the same model across the "edit item" flow is that your model code is performing 2 purposes: +- preparing data to be shown on a web page +- preparing a form, either for display on a web page or for validating POST data + +When you're using the model because you're handling a POST (i.e. cases 3 and 5 in the diagram) then any effort expended in preparing the data for a web page is going to be wasted. (In fact, in the FormController `getModel()` method call, the parameter `$config` is set to `array('ignore_request' => true)` by default, which results in the model's `populateState` method not being run, to save this wasted effort.) + +## Summary +As we've seen, Joomla has rich functionality in higher level Controller and Model classes which can greatly simplify your code (all of which can be used on both the front end and back end). + +The choice of which controller and model classes to extend is easier on the back end, because you just follow the pattern of the Joomla core components. + +For the front end here's a rough guide to choosing the most appropriate Controller and Model classes to extend; in each case you're using the standard HtmlView as base View class to extend. + +### Simple Display +Simply displaying a record or a set of records, without providing the ability to change anything +- Controller extends BaseController +- Model extends BaseDatabaseModel or (particularly if you're sharing a model between a component and modules) ItemModel if it's a single record, ListModel if it's multiple records. + +### Displaying records, plus operations on selected records +Displaying a form with multiple records (but the form isn't defined in an XML file), including the providing the ability to select several records and apply some sort of operation to them (eg delete, publish): +- Controller extends BaseController +- Model extends ListModel – except if you're using the same model for displaying the form and handling the updates, in which case use AdminModel + +### Handling the HTTP POSTs from the above +- Controller extends AdminController +- Model extends AdminModel + +### Editing a record +Displaying a form with a single record, where the form is defined in an XML file, and allowing the user to edit it, or a blank record and allowing the user to create a record: +- Controller extends BaseController +- Model extends FormModel – except if you're using the same model for displaying the form and handling the updates (as is usually the case), in which case use AdminModel + +### Handling the HTTP POSTs from the above +- Controller extends FormController +- Model extends AdminModel \ No newline at end of file diff --git a/versioned_docs/version-5.2/building-extensions/components/mvc/mvc-factory.md b/versioned_docs/version-5.2/building-extensions/components/mvc/mvc-factory.md new file mode 100644 index 00000000..b47e787d --- /dev/null +++ b/versioned_docs/version-5.2/building-extensions/components/mvc/mvc-factory.md @@ -0,0 +1,117 @@ +--- +title: The MVC Factory Class +sidebar_position: 2 +--- + +MVC Factory Overview +==================== + +The MVC Factory class is used within Joomla to create instances of component Controller, View, Model and Table classes. + +Each component has its own MVCFactory class instance, which is instantiated passing in that component's [namespace prefix](../../../general-concepts/namespaces/defining-your-namespace.md). + +It has functions for creating each of the classes: `createController`, `createView`, `createModel`, `createTable`, and in its simplest form you can pass into each function: +- the `name` - eg "display", "article", etc +- the `prefix` - either "site" or "administrator". + +(You can specify the `name` and `prefix` with or without the capital first letter - Joomla will capitalise the first letter for you). + +The MVCFactory class function will then generate the name of the class to instantiate, and try to [instantiate it](../../../general-concepts/namespaces/finding-classes-with-psr4.md). + +For example, if your component is `com_example` with a namespace prefix \Mycompany\Component\Example then inside your Controller class you could use (where `$this->factory` points to your MVCFactory instance): +```php +$model = $this->factory->createModel('Example', 'Administrator'); +``` +and the MVCFactory function will attempt to instantiate \Mycompany\Component\Example\Administrator\Model\ExampleModel. + +In fact, the library MVC BaseController class makes it even simpler for you, and you just have to call: +```php +$model = $this->getModel('example', 'administrator'); +``` +Note that if your component is running in the front end (site) you can still use the administrator model, and if it's running in the back end (administrator) you can still use the site model. There is no restriction. + +## Creating the MVCFactory class instance +Your component's MVCFactory is created by defining it as a dependendency in your services/provider.php file, as described in [Dependency Injection](../../../general-concepts/dependency-injection/index.md), but you don't have to understand all the intricacies of Joomla Dependency Injection to use it effectively. + +## Creating your Controller class instance + +As described in [Extension and Dispatcher Classes](../../../general-concepts/extension-and-dispatcher/index.md), your Controller class is instantiated within the `dispatch` function of the ComponentDispatcher class. It has an instance variable pointing to the MVCFactory class and will call: +```php +$controller = $this->mvcFactory->createController($name, $client, ..); +``` +passing the `$name` from the first part of the *task* parameter (or "display" if there's no *task* parameter), and `$client` set to "site" or "administrator", depending upon whether this is run on the front end or the back end. + +![Instantiating the Controller](_assets/mvc-factory-controller.jpg "Instantiating the Controller") + +In this diagram (and in the next): +- the "Factory" classes are in blue, and ordinary MVC classes in yellow. +- the dashed blue lines indicate that one class has an instance variable which points to the other class instance +- the solid black lines represent method calls +- the thick solid red lines represent where a Factory class instantiates a class + +## Creating your View, Model and Table class instances + +![Instantiating View, Model, Table](_assets/mvc-factory.jpg "Instantiating View, Model, Table") + +With the Joomla MVC Factory paradigm +- the Controller is responsible for instantiating the View and the Model, and can call `getView` and `getModel` to do this +- the Model is responsible for instantiating the Table, and can call `getTable` to do this + +The View can also get the Model via a `getModel` call, but only if the Controller has set this up by getting the Model instance first and passing this into the View: +```php +$view->setModel($model); +``` + +## Default names for View, Model and Table classes +While the name for the Controller is taken from the *task* parameter, the default names for the View, Model and Table classes are taken from the *view* parameter. These default classes are what will be instantiated if you just call `getView()`, `getModel()` and `getTable()` without any parameters. + +So, for example, the names of the classes created for a request with URL query "?option=com_example&view=viewname" and no *task* parameter will be: +- `\Controller\DisplayController` +- `\View\Viewname\HtmlView` +- `\Model\ViewnameModel` +- `\Table\ViewnameTable` + +## Summary +We've covered a fair bit of background in this section, to give you an understanding of why things work, but it's all to make it easy for you in your MVC classes. + +In your Controller, you can create the View and the Model, and give the View a reference to the Model: +```php +$model = $this->getModel(); // to get the default Model, based on the view= parameter +$foomodel = $this->getModel('foo'); // to get the Model\FooModel +$view = $this->getView(); // to get the default View, based on the view= parameter +$fooview = $this->getView('foo'); // to get the View\Foo\HtmlView +$view->setModel($model, true); // to set the view's default model, accessible inside the view by $this->getModel() +$view->setModel($foomodel); // make the $foomodel accessible to the view by $this->getModel('foo') +``` +To get multiple models you just pass each name to `getModel`: +```php +$foomodel = $this->getModel('foo'); +$barmodel = $this->getModel('bar'); +``` +If your component is running on the front end but you want to get its administrator model, just pass the `$prefix` second parameter: +```php +$model = $this->getModel('foo', 'administrator'); +``` +In your View, you can access the model set up by the Controller: +```php +$model = $this->getModel(); // to get the default model +$foomodel = $this->getModel('foo'); // to get the foo model +``` +In your Model, you can create the Table: +```php +$table = $this->getTable(); // if your Table class matches the view= parameter in the HTTP request +$table = $this->getTable('example'); // to get the ExampleTable class +``` + +## Issues +A key reason for the introduction of the MVCFactory class was to remove the use of the `static::getInstance()` calls to obtain an instance of one of the MVC classes. However, you may find one or two problems with the approach. + +For example, when saving a database record in the Table class (eg in `Joomla\CMS\Table\Content::store()`), Joomla obtains another instance of that Table class in order to verify that the alias which is about to be saved is unique. However, when the Table instance is created it isn't passed a pointer to the MVCFactory instance, so it can't create another instance using the MVCFactory's `createTable` function. In Joomla 4 the solution was to use the deprecated `getInstance()` function: +```php +$table = Table::getInstance('Content', 'JTable', ['dbo' => $this->getDbo()]); +``` +In Joomla 5 it just creates a new version of itself: +```php +$table = new self($this->getDbo(), $this->getDispatcher()); +``` +So you can use a similar approach to avoid using the deprecated `getInstance` method (or just execute a SQL query directly on your database table). \ No newline at end of file diff --git a/versioned_docs/version-5.2/building-extensions/components/mvc/mvc-overview.md b/versioned_docs/version-5.2/building-extensions/components/mvc/mvc-overview.md new file mode 100644 index 00000000..2b4b7313 --- /dev/null +++ b/versioned_docs/version-5.2/building-extensions/components/mvc/mvc-overview.md @@ -0,0 +1,70 @@ +--- +title: MVC Overview +sidebar_position: 1 +--- +MVC Overview +============ + +The diagram below depicts the MVC pattern as it's used in Joomla. This applies to both the admin back end and the site front end. + +![MVC Overview](_assets/mvc-overview.jpg "MVC Overview") + +## Basic Elements + +In this section we will cover the 4 types of classes shown in the diagram. In your component you're likely to have several Controller, View and Model classes, and (if your component uses its own table or tables in the database) one Table class for each database table your component has. + +### Controller +Your Controller code is run whenever there's an incoming HTTP request which is routed to your component. The controller is responsible for analysing the user's request, checking that the user is allowed to perform that action and determining how to satisfy the request. The latter could involve: + +- determining which Model (or Models) will be needed to satisfy the request, and creating an instance of that Model +- making calls to Model methods to make any required database updates +- determining which View should be used to present the web page to the user, and creating an instance of that View or +- if instead the user should receive a redirect to another URL, then determining that redirect URL. + +### View +The MVC View functionality is split into 2 files + +1. A View class file, which is usually just known as the View, and after this we'll just call it the View +2. A tmpl file + +The View specifies what should appear on the web page which is going to be displayed, and collates all the data necessary for outputting the HTTP response. + +After the controller creates the View instance it calls the View's `setModel()` method and passes the Model instance. In this way the View knows which Model to use, and calls the Model's methods to obtain the data required for returning to the user. This data is stored in instance variables of the View. + +The tmpl file (sometimes known as template or layout file - Joomla isn't totally consistent here!) is responsible for outputting the actual HTML of the web page to be displayed. The View doesn't output HTML itself but delegates this to the tmpl file. + +The tmpl contains PHP code which runs within the context of the View. The View class usually extends Joomla\CMS\MVC\View\HtmlView and the `display()` method of this class works out which tmpl to use and then does an `include` of the file. + +This means that if the View holds the response data in, for example, `$this->items` then the tmpl file can access that same `$this->items` when it is outputting the HTML. + +Separating the View and tmpl like this enables another level of flexibility, as you can easily set up a layout override to output the View data using your own preferred HTML. + +### Model +The Model encapsulates the data used by the component. In most cases this data will come from a database, either the Joomla database, or some external database, but it is also possible for the Model to obtain data from other sources, such as via a web services API running on another server. The Model is also responsible for updating the database where appropriate. The purpose of the Model is to isolate the Controller and View from the details of how data is obtained or amended. + +If the component is displaying a form which is defined in XML using the Joomla Form approach, the Model handles the setting-up and configuration of the `Form` instance, ready for the tmpl to output fields using `$form->renderField()` etc. + +### Table +If your extension has one or more database tables, then you should have a Table class for each database table. Your Table class will inherit from the Joomla library Table class, which provides CRUD (Create / Read / Update / Delete) access to the underlying database table. + +The Table class provides access to individual records only, so it would be used by the Model if the requirement was a CRUD operation on an individual record, eg to create or update a record in the database. + +If instead it's required to access several records in the database table, then the Model would access the database directly, rather than using the Table class. + +## The HTTP Request *task* Parameter +Joomla uses the HTTP Request *task* parameter to determine which controller should be used. The *task* parameter can be sent in an HTTP GET or an HTTP POST - Joomla doesn't mind which - and it's just an ordinary HTTP parameter, nothing special. + +The *task* parameter is of the form `.`. The first part identifies the particular Controller class to use, and the second part identifies that class's instance method to call. + +The controller type may be absent in which case the DisplayController class is used. + +If the task parameter is not set at all then the `display()` method in the DisplayController class is run. + +We'll look at some examples later on. + +## Your MVC within Joomla +Of course, your component's MVC code runs within the context of Joomla's library code, really like the meat in a sandwich. When Joomla determines that it should run your component, then it obtains your component's Extension and Dispatcher classes, and it's the `dispatch()` function of the Joomla ComponentDispatcher class which actually analyses the *task* parameter to determine which of your Controller classes to instantiate, as described in [Extension and Dispatcher classes](../../../general-concepts/extension-and-dispatcher/index.md). Then `dispatch()` calls your component's `execute()` method, passing the `` part of the *task* parameter. Assuming your component has Joomla\CMS\MVC\Controller\BaseController in its inheritance chain, then this will result (in the normal case) in your Controller's `method` function being called. + +After the `execute()` method completes the `dispatch()` method will call the Controller's `redirect()` method - we'll see the significance of this later. + +At the other end, the HTML output by the tmpl file doesn't go directly into the HTTP response, but rather is captured by Joomla in a buffer using [PHP Output Buffering](https://www.php.net/manual/en/book.outcontrol.php), and later injected into the final HTML page, together with any modules, messages, etc that need to be included in the web page. \ No newline at end of file diff --git a/versioned_docs/version-5.2/building-extensions/components/mvc/post-redirect-get.md b/versioned_docs/version-5.2/building-extensions/components/mvc/post-redirect-get.md new file mode 100644 index 00000000..8d536197 --- /dev/null +++ b/versioned_docs/version-5.2/building-extensions/components/mvc/post-redirect-get.md @@ -0,0 +1,123 @@ +--- +title: Post-Request-Get Pattern +sidebar_position: 3 +--- + +Post-Request-Get Pattern +======================== + +Joomla follows the [Post/Redirect/Get pattern](https://en.wikipedia.org/wiki/Post/Redirect/Get), which means that when a user submits a form in an HTTP POST, then rather than Joomla responding to the POST with an HTML page, it redirects to another page which the browser will access with an HTTP GET. In this section we'll look at a couple of examples of this, and see how it aligns with the use of the *task* parameter, and later with the Joomla library MVC classes. + +Although Joomla uses the Post-Request-Get Pattern extensively, this doesn't mean that you have to use it everywhere in your own component. For example, if your component has a front-end form which is used to submit an order, then it may make perfect sense to provide the order confirmation text as the HTTP response to the HTTP POST of the order submission. + +## Example 1 Publish Articles +The diagram shows the steps associated within publishing articles on the Joomla back-end. You'll probably find it helpful to perform these operations on your own Joomla instance, and use your browser's devtools to examine the HTTP requests and responses. + +![Publishing Articles](_assets/post-request-get1.jpg "Publishing Articles") + +### Action 1 +The administrator clicks on Content / Articles to display the list of articles. This is simply an HTTP GET request to the `com_content` administrator webpage with the `view` parameter set to `articles`. (If SEF URLs are being used, then it's the Joomla Router which will set up the `view` parameter, based on parsing the incoming URL). The *task* parameter is not set in this HTTP request, and so the `com_content` DisplayController is instantiated and the `display()` method called. Based on the `view` parameter, the default View class is Joomla\Component\Content\Administrator\View\\**Articles**\HtmlView, and the default Model is Joomla\Component\Content\Administrator\Model\\**Articles**Model. + +A key thing to note is that this view displays various buttons at the top of the form. When you select one or more articles, then these buttons become visible in the Actions button drop-down at the top of the page. It is these buttons which trigger an HTTP POST to the server, and embedded within the buttons is what the *task* parameter gets set to within that POST request. + +### Action 2 +The administrator selects a number of articles and then presses the Publish button. At this point it's worth switching on your browser's devtools, and examining the messages. You'll see that pressing Publish triggers: +- an HTTP POST request to the server with +- the *task* parameter set to "articles.publish" +- an array cid[] of the ids of the articles which are affected +- plus a number of other parameters from the pagination / filter fields / batch options - all of which don't concern us here + +This request will then be routed to the `com_content` administrator ArticlesController, and the `publish()` method within it will be called. If you look at the code in administrator/components/com_content/src/Controller/ArticlesController.php you won't find a `publish()` function there, so what will be run will be the `publish()` function in the class it extends, namely Joomla\CMS\MVC\Controller\AdminController in libraries/src/MVC/Controller/AdminController.php. Let's pick out a few lines from that `publish()` method: +```php +$cid = (array) $this->input->get('cid', [], 'int'); +``` +It gets the list of ids which the administrator has selected. +```php +$model = $this->getModel(); +$model->publish($cid, $value); +``` +The `getModel` function is defined in the ArticlesController: +```php +public function getModel($name = 'Article', $prefix = 'Administrator', $config = ['ignore_request' => true]) +{ + return parent::getModel($name, $prefix, $config); +} +``` +and as the default `$name` is 'Article' this will get the `com_content` administrator **Article**Model (instead of the default **Articles**Model). If you look in this file you'll find the `publish()` method, but it basically just has: +```php +return parent::publish($pks, $value); +``` +so the real work of handling the publish operation is in the class which the ArticleModel extends, namely Joomla\CMS\MVC\Model\AdminModel in libraries/src/MVC/Model/AdminModel.php, in its `publish` method. + +Back to the AdminController.php code, a little further on we have: +```php +$ntext = $this->text_prefix . '_N_ITEMS_PUBLISHED'; +$this->setMessage(Text::plural($ntext, \count($cid))); +``` +Here the code is setting up a message which is going to get displayed to the administrator, basically confirming the number of records which have had their status set to Published. + +Finally, at the end of the `publish` function in AdminController.php it has: +```php +$this->setRedirect( + Route::_( + 'index.php?option=' . $this->option . '&view=' . $this->view_list + . $this->getRedirectToListAppend(), + false + ) +); +``` +Here is the Post-Request-Get Pattern in action - Joomla hasn't displayed a web page in response to the POST, rather it has set up a redirect - in this case back to the form which displays the list of articles. + +As mentioned in [MVC Overview](mvc-overview.md) and [Dispatcher Component](../../../general-concepts/extension-and-dispatcher/dispatcher-component.md), after the component's `execute` method finishes the Dispatcher calls the component's `redirect` method. This method (actually in Joomla\CMS\MVC\Controller\BaseController) will do 2 things: +1. Use the Joomla Application's `enqueueMessage` function to store the confirmation message ("n articles published") in the session data +2. Tell the Joomla Application to redirect to the URL which was stored in the `setRedirect` call above. + +If you've been looking at the Joomla source code while you've been reading this page, then you've maybe noticed 2 things. + +Firstly, the `publish()` function in the AdminController is not only handling the `publish` functionality, but also used for setting the state to other values, eg `unpublish`. The Joomla BaseController has a protected instance variable `$taskmap` which maps the `` part of the *task* parameter to the function which will get called, and in the AdminController constructor it has +```php +$this->registerTask('unpublish', 'publish'); +``` +which means that in its `execute` function it will call the `publish` function for the case when *task* is set to "Articles.unpublish" as well. + +This enables sharing of code for 2 operations which are similar, but of course there will be differences in the detail, and in `publish()` it calls +```php +$task = $this->getTask(); +``` +to get the `` part of the *task* parameter, in order to code the differences. Note that in these calls in the Controller code that "task" refers to just the `` part of the *task* parameter; Joomla isn't consistent in its naming here. + +Secondly, did you notice how much of the code to handle the publish operation was actually within the `com_content` code? Very little! Practically all the code was within the Joomla library MVC classes. Making judicious choices in how you name your component's fields and how your component's MVC classes extend the Joomla library classes can make it easy for you to include functionality with very little coding effort. We'll look at the Joomla library MVC classes in more detail in the next section. + +### Action 1 again +The URL redirect at the end of Action 2 results in the display of the list of articles again. However, this time the user will see a message like "2 articles published" at the top of the form. + +There may be 2 administrators logged on simultaneously, and both displaying the list of articles around the same time. How does Joomla know which administrator should be shown the "2 articles published" message? The answer is that it uses cookies. When the administrator's browsers sends the HTTP GET request to display the list of articles it sends in the request all the cookies which the server previously sent to it. One of these will be used by the Joomla Session functionality as an index to the Session data which is stored for that user. The `enqueueMessage` function described above stores a message within this session data, and when Joomla processes the next HTTP request it will see that there's a message stored there and will output it to the page. + +You can see what's stored in your session data by switching on Joomla Debug in the global configuration, and then clicking on the little Joomla symbol at the bottom left of each web page. However you won't see any enqueued messages because when Joomla outputs an enqueued message it removes it from the session, so that it isn't displayed again on the next HTTP request. + +## Example 2 Edit Article +![Editing Articles](_assets/post-request-get2.jpg "Editing Articles") + +### Action 1 +This is the same as above, displaying the list of articles. + +### Action 3 +The administrator clicks on an article to edit it. If you switch off Search Engine Friendly (SEF) URLs in your Global Configuration / Site parameters, then you'll see that the link behind each article title is something like `http://yourdomain.org/administrator/index.php?option=com_content&task=article.edit&id=1`. So the HTTP GET request sent to the server will have *task* set to "article.edit", and this will result in the `com_content` ArticleController being instantiated, and its `edit()` function being called. + +Similar to what we found previously, there's no `edit` function within ArticleController.php, so what is run is the `edit` function in the class it extends, namely Joomla\CMS\MVC\Controller\FormController in libraries/src/MVC/Controller/FormController.php. It basically checks that the user is allowed to perform this operation, and if so, checks the content record out (by setting the `checked_out` and `checked_out_time` columns in the article record in the database), and sets up a redirect to display the article edit form. + +### Action 4 +The redirect results in an HTTP GET to a URL like http://yourdomain.org/administrator/index.php?option=com_content&view=article&layout=edit&id=1. The *task* parameter is not set so this will be handled by the `com_content` DisplayController, in the `display()` function. It will use the `com_content` Article View class in src/View/Article/HtmlView.php, and the tmpl file used will be tmpl/article/edit.php (from the `layout` parameter). This displays the form for editing a single article. + +### Action 5 +When the administrator clicks on `Save & Close` then this will result in an HTTP POST to the server, with the article's field values, and *task* set to "article.save". This will be routed to the `com_content` ArticleController, and its `save()` function. Once again the `save` function is absent, so it drops back to using the `save` function in the class which ArticleController extends, namely Joomla\CMS\MVC\Controller\FormController in libraries/src/MVC/Controller/FormController.php. This function does the following (in its 'happy path'): +- checks the user is allowed to perform the operation +- validates the data (ie the submitted article fields) +- saves the data (via the ArticleModel) +- checks in the record +- enqueues a confirmation message that the save succeeded +- sets up a redirect back to the form showing the list of articles + +### Action 1 again +As before, this displays the list of articles, plus the enqueued message. + diff --git a/versioned_docs/version-5.2/building-extensions/components/quicktasklink.md b/versioned_docs/version-5.2/building-extensions/components/quicktasklink.md new file mode 100644 index 00000000..915c8b8a --- /dev/null +++ b/versioned_docs/version-5.2/building-extensions/components/quicktasklink.md @@ -0,0 +1,81 @@ +Quicktask Link and Icon +======================= + +In general, a component has one or more links to its views. They are defined in the manifest file and added to the menu during installation. + +```xml title="A link to your component " + + + COM_EXAMPLE + + + [..] + +``` +Sometimes it is useful to add a so called quicktask link which enables an action calling from the menu without first visiting the Overview. +You can see this for Joomla core components, for example articles in com_content, here the quicktask is the plus icon and lets you add a new article in a single click. +Your menu link is added in the manfest file during installation. + +## Quicktask Link and Title + +A quicktask link and title are added as params to a menu item. + +```xml title="Quicktask Link and title" + + COM_EXAMPLE + + COM_EXAMPLE_MENU_QUICKTASK_TITLE + index.php?option=com_example&view=example&layout=edit + + +``` +The title translation string needs to appear in the language `.sys.ini` file for the extension + +## Quicktask Icon + +The default icon is the '+' sign indicating create a new item as this is the most common usage in the built-in compponents. + +You can specify a different icon, either as a simple name for the built in common aliased icons (the `icon-` prefix will be automatically added), or as the font-awesome specification. + +```xml title="Quicktask Link and icon" + + COM_EXAMPLE + + COM_EXAMPLE_MENU_QUICKTASK_TITLE + eye + index.php?option=com_example&view=example&layout=view + + +``` + +## Example + +This example shows a complete menu entry with dashboard, submenu and a quicktask. The second item with a quicktask includes a fontawesome icon that has not been aliased. + +```xml + + COM_EXAMPLE + + example + + + + + COM_EXAMPLE_MENU + + COM_EXAMPLE_MENU_QUICKTASK_TITLE + index.php?option=com_example&view=example&layout=edit + + + + COM_EXAMPLE_MENU_CATEGORIES + + COM_EXAMPLE_MENU_CATEGORIES + fas fa-person-hiking + index.php?option=com_categories&view=category&layout=edit&extension=com_example + + + COM_EXAMPLE_MENU_FIELDS + COM_EXAMPLE_MENU_FIELDS_GROUP + +``` diff --git a/versioned_docs/version-5.2/building-extensions/components/routing.md b/versioned_docs/version-5.2/building-extensions/components/routing.md new file mode 100644 index 00000000..08f0a8ad --- /dev/null +++ b/versioned_docs/version-5.2/building-extensions/components/routing.md @@ -0,0 +1,12 @@ +Routing +======= + +## Search engine friendly (SEF) + +Human-readable or clean URLs are URLs that make sense to both humans and search engines because they explain the path to the particular page they point to. + +:::caution TODO + +This page is unfinished, please use the **Edit this Page** link at the bottom of this page to help make it more useful. + +::: diff --git a/versioned_docs/version-5.2/building-extensions/components/table-columns.md b/versioned_docs/version-5.2/building-extensions/components/table-columns.md new file mode 100644 index 00000000..15732659 --- /dev/null +++ b/versioned_docs/version-5.2/building-extensions/components/table-columns.md @@ -0,0 +1,47 @@ +Hide Table Columns +================== + +## User-defined Hide Table Columns +All the core components have a button that lets the user decide which columns of a table to display. + +### Adding Hide Table Columns to your component +Adding this functionality to your own component is very simple and is usually a simple case of adding the code below to the `tmpl` file for the table. + +#### Check if you are you using WebAssetManager +Look for this line of code in the php block at the top of your `tmpl` file. +``` +$wa = $this->document->getWebAssetManager(); +``` + +#### Already using WebAssetManager +Add the following line to your existing code. + +``` +useScript('table.columns') +``` + +Note the line ending. Your final code will look similar to this example + +``` +/** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ +$wa = $this->document->getWebAssetManager(); +$wa->useScript('table.columns') + ->useScript('multiselect'); +``` + +#### Not using WebAssetManager (yet) +Add the following code anywhere in the php block at the top of your `tmpl` file. + +``` +/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ +$wa = $this->document->getWebAssetManager(); +$wa->useScript('table.columns'); +``` + +#### Notes +Your table will need to be a valid html table with a `` and each column a ``. + +Your table can not include `` or `` or `` elements. These will cause the table to display empty columns at the end of the row and will break any classes or styles applied in the ``. ([Tracking Issue](https://github.com/joomla/joomla-cms/issues/43564)) + +If you have multiple tables on the page and you want to prevent the script loading on one of those tables then you can add the class "columns-order-ignore" to the table. + diff --git a/versioned_docs/version-5.2/building-extensions/components/tags.md b/versioned_docs/version-5.2/building-extensions/components/tags.md new file mode 100644 index 00000000..91f69df1 --- /dev/null +++ b/versioned_docs/version-5.2/building-extensions/components/tags.md @@ -0,0 +1,3 @@ +Tags +======================= +This is the content for Tags \ No newline at end of file diff --git a/versioned_docs/version-5.2/building-extensions/custom-script/basic-script.md b/versioned_docs/version-5.2/building-extensions/custom-script/basic-script.md new file mode 100644 index 00000000..898a42e0 --- /dev/null +++ b/versioned_docs/version-5.2/building-extensions/custom-script/basic-script.md @@ -0,0 +1,89 @@ +--- +title: Example PHP Script +sidebar_position: 2 +--- + +Example PHP Script +================== + +:::danger[Developer Notice] + +Creating a script which directly includes loads and boots the CMS framework is not recommended and only needed in +rare cases. Depending on the usecase you should create a [console plugin](../plugins/plugin-examples/basic-console-plugin-helloworld.md) +and extend the Joomla! console application. If you need to create a simple entry point for webrequests write an +[ajax plugin](../plugins/plugin-examples/ajax-plugin.md). + +::: + +## General Approach +To make use of the Joomla framework, and in particular the Joomla APIs, you need to have an `Application` class instance. As `ConsoleApplication` and `CliApplication` both have checks to ensure that their application is run from the command line, and neither `AdministratorApplication` nor `ApiApplication` is appropriate, the clear choice is to build your script upon `SiteApplication`. + +So to build your script you basically have to mirror how Joomla initialises and instantiates `SiteApplication`, which involves: +- running the Joomla start-up PHP files +- instantiating the `SiteApplication` via the Dependency Injection Container (which will instantiate also its key dependencies) +- providing the `Application` class instance with any necessary configuration items (for example, the language to use, user, logging). + +Because the Joomla startup routine changes from time to time you will certainly need to check if your custom scripts work on new versions of Joomla, and you well may need to change them. + +The code below is for a basic custom script which you should store in eg the /cli directory under the root folder of your joomla instance if you want to try running it. +You can comment out all the Optional sections and confirm that it still works ok. +```php +/cli +define('JPATH_BASE', realpath(dirname(__FILE__).'/..')); + +require_once JPATH_BASE . '/includes/defines.php'; +require_once JPATH_BASE . '/includes/framework.php'; + +// Boot the DI container - this will load in the classes in libraries/src/Service/Provider/ +$container = \Joomla\CMS\Factory::getContainer(); + +// We need to set up an alias to get the Session dependency from the DIC +$container->alias(\Joomla\Session\SessionInterface::class, 'session.web.site'); + +// Instantiate the application. +$app = $container->get(\Joomla\CMS\Application\SiteApplication::class); + +// Set what gets returned from Factory::getApplication() +\Joomla\CMS\Factory::$application = $app; + +// Optional - This is so that Joomla can find classes relating to extensions +$app->createExtensionNamespaceMap(); + +// Optional - Set up basic logging framework +if ($app->get('log_everything')) { + Log::addLogger(['text_file' => 'everything.php']); +} +Log::add('logging initialised ok', Log::DEBUG, 'script-debug'); + +// Optional - set up the language and load the joomla library text strings - select your preferred language +$lang = Language::getInstance("en-GB"); +$app->loadLanguage($lang); +$app->getLanguage()->load('lib_joomla', JPATH_ADMINISTRATOR); + +// Write below here what you want your script to do +$db = $container->get(Joomla\Database\DatabaseInterface::class); + +$query = $db->getQuery(true); +$query->select('count(*)') + ->from('#__content'); + +$db->setQuery($query); + +$count = $db->loadResult(); + +echo "

{$count} articles found

"; +``` diff --git a/versioned_docs/version-5.2/building-extensions/custom-script/index.md b/versioned_docs/version-5.2/building-extensions/custom-script/index.md new file mode 100644 index 00000000..f574ee0f --- /dev/null +++ b/versioned_docs/version-5.2/building-extensions/custom-script/index.md @@ -0,0 +1,52 @@ +--- +title: Custom PHP Script +--- + +Custom PHP Script +================= + +:::danger[Developer Notice] + +Creating a script which directly includes loads and boots the CMS framework is not recommended and only needed in +rare cases. Depending on the usecase you should create a [console plugin](../plugins/plugin-examples/basic-console-plugin-helloworld.md) +and extend the Joomla! console application. If you need to create a simple entry point for webrequests write an +[ajax plugin](../plugins/plugin-examples/ajax-plugin.md). + +::: + +## Introduction +By a custom PHP script I mean a PHP script which can be run from a browser. Usually users will navigate using a browser to the Joomla site: + +``` +https://example.com/index.php +``` + +or to the Joomla administrator back-end: + +``` +https://example.com/administrator/index.php +``` + +In this section we look at developing a PHP script (eg myscript.php) which can be put eg in the root folder, so that users will navigate to: + +``` +https://example.com/myscript.php +``` + +:::danger[Developer Notice] + +This will not work with advanced security option [public folder](../../../../migrations/44-50/new-features#added-the-option-to-serve-joomla-from-a-public-folder) introduced in Joomla 5.0. + +::: + +There are several ways which you can use the Joomla framework to perform ad hoc tasks: +- using the Joomla Console application +- using the Joomla Task Scheduler +- using the Joomla Ajax component +- using a custom PHP script + +However, the Joomla Console application requires that the script (cli/joomla.php) be run from the server command line (eg in a cron job), which does make it more complex for users to run the script, in addition to the security risk of providing the extra user access to the command line. + +Similarly to allow users to run a Task Scheduler job you need to grant them access to the administator back-end. + +So for simple ad hoc tasks which you want to allow ordinary website users to run, the custom PHP script is an option. However, you should be aware that the Joomla development team do not formally support this type of script. \ No newline at end of file diff --git a/versioned_docs/version-5.2/building-extensions/custom-script/install.md b/versioned_docs/version-5.2/building-extensions/custom-script/install.md new file mode 100644 index 00000000..5f013884 --- /dev/null +++ b/versioned_docs/version-5.2/building-extensions/custom-script/install.md @@ -0,0 +1,37 @@ +--- +title: Installing a custom script +sidebar_position: 3 +--- + +Install +======= + +:::danger[Developer Notice] + +Creating a script which directly includes loads and boots the CMS framework is not recommended and only needed in +rare cases. Depending on the usecase you should create a [console plugin](../plugins/plugin-examples/basic-console-plugin-helloworld.md) +and extend the Joomla! console application. If you need to create a simple entry point for webrequests write an +[ajax plugin](../plugins/plugin-examples/ajax-plugin.md). + +::: + +## Installing your Custom Script +If you have access to the file system of your web application then you can obviously just copy your script into the folder of your choice. + +If instead you want to install your script in the usual way, then you must use "file" as your extension type in the manifest file, for example. + +```xml + + + Custom Script + 1.0 + Script to count the number of articles in the database + + + myscript.php + + + +``` + +Installing this will result in the script "myscript.php" being put into the Joomla `cli` directory. \ No newline at end of file diff --git a/versioned_docs/version-5.2/building-extensions/custom-script/logging-on.md b/versioned_docs/version-5.2/building-extensions/custom-script/logging-on.md new file mode 100644 index 00000000..f1863c50 --- /dev/null +++ b/versioned_docs/version-5.2/building-extensions/custom-script/logging-on.md @@ -0,0 +1,155 @@ +--- +title: To Logon or not to Logon +sidebar_position: 2 +--- + +To Logon or not to Logon +======================== + +:::danger[Developer Notice] + +Creating a script which directly includes loads and boots the CMS framework is not recommended and only needed in +rare cases. Depending on the usecase you should create a [console plugin](../plugins/plugin-examples/basic-console-plugin-helloworld.md) +and extend the Joomla! console application. If you need to create a simple entry point for webrequests write an +[ajax plugin](../plugins/plugin-examples/ajax-plugin.md). + +::: + +## To logon or not to logon + +As you can see from the script in the previous section, it's not necessary to logon to Joomla to perform a query on the database and output the result. But should you logon to Joomla or not? You've got 3 options: + +- Don't logon +- Logon using credentials that you hard-code into the script +- Check if the user is already logged on. + +Let's consider these options in reverse order. + +## Check if user is logged on +How Joomla knows if a user is logged on is through the use of cookies, as shown in the diagram. + +```mermaid +sequenceDiagram + Client->>+Server: Request + Server-->>Session Store: Create new session + Server->>+Client: Response + Cookie + Note over Client,Server: Cookie includes session information + Client->>+Server: Request + Cookie + Server-->>Session Store: Request session data + Session Store-->>Server: Session data +``` + +When Joomla responds to an HTTP request it sends down cookies to the browser, and these include a session cookie which is like a pointer to session data stored on the server. If a user logs onto the Joomla site, then that session data includes the username with which they logged on. + +When the user next views a page on the site, or submits a form on the site, then the browser sends to the Joomla server all the cookies which the Joomla site previously sent down. Joomla finds the session cookie, and via it the session data, and checks in it to see if there is a logged-on user, and if so, what the associated username is. + +When users are accessing the Joomla site they're actually accessing the script index.php in the top level Joomla directory. However, the browser sends these cookies for all scripts on the same domain. So that if a user navigates to `/cli/myscript.php` then the browser will send in the HTTP request all the cookies stored for that domain. + +So within your script you can get Joomla to find the session cookie, and via it the session data, and can find out the username of the logged-on user. To do this you generally use: + +```php +$user = \Joomla\CMS\Factory::getApplication()->getSession()->get('user'); +``` + +but in this case there is already a variable `$app` pointing to the Application instance, so you can use: + +```php +$user = $app->getSession()->get('user'); +``` + +You'll get back a `Joomla\CMS\User\User` object with +- the id set to 0 if the user isn't logged on, or +- an id > 0 for a logged on user. + +The other properties of this User object you can find at [User API](cms-api://classes/Joomla-CMS-User-User.html). + +If your script uses other Joomla library or extension code then that code may try to access the User object via + +``` +$app->getIdentity(); +``` + +So to enable this to work you need to call + +``` +$app->loadIdentity($user); +``` + +so that a pointer to the User instance is stored in the Application instance. + +## The "remember me" cookie + +The session cookie is valid only for a configurable period of time (set in Global Configuration / System tab, Session lifetime), and if the session cookie has expired then it won't result in the session data yielding any logged-on user. The session lifetime is usually fairly short to reduce the risk of someone else using the same device later and gaining logged-on access to the Joomla site. + +If the user is the sole user of the device, then when they logon they can click the Remember Me checkbox. This results in Joomla issuing a "remember me" cookie, which is a lot longer-lasting than the session cookie. If the user subsequently accesses the Joomla site, then even if the session cookie has expired, the "remember me" cookie will result in the user being treated as logged onto the site. + +In Joomla the "remember me" cookie is implemented using a system plugin (in plugins/system/remember) which listens for the onAfterInitialisation event. If the user is a "guest" and not logged on, then the plugin looks for the presence of the "remember me" cookie, and if it finds it then the associated user is found and treated as logged-on (actually performed by the authentication cookie plugin). + +However, the actual name of the "remember me" cookie incorporates the directory name of the php script where it was issued, which is by default the top level directory containing the site index.php file. So to use the "remember me" cookie you must put your script in the same top-level directory as the site index.php file. + +To use the "remember me" cookie all you have to do is trigger the `onAfterInitialise` event. Then you can check if the session now has the user details. Here's the full code + +```php +// Instantiate the application. +$app = $container->get(\Joomla\CMS\Application\SiteApplication::class); +// Set the application as global app +\Joomla\CMS\Factory::$application = $app; +$user = $app->getSession()->get('user'); +if ($user->id > 0){ + echo "

logged on as {$user->name}

"; +} else { + echo "

not logged on

"; +} + +// Trigger the onAfterInitialise event after ensuring that system plugins are loaded +\Joomla\CMS\Plugin\PluginHelper::importPlugin('system'); +$app->triggerEvent('onAfterInitialise'); + +if ($user->id == 0) { + // check if the remember me plugin has now logged the user in + $user = $app->getSession()->get('user'); + if ($user->id > 0) { + echo "

logged on as {$user->name} via remember me cookie

"; + } else { + echo "

still not logged on

"; + } +} +``` + +Just to repeat, you have to have your custom PHP script in the same top-level folder as the site index.php file, and of course you have to have the "Remember Me" and "Authentication - Cookie" plugins enabled. + +(Incidentally, if you're testing this with a very short session lifetime and wondering why the session cookie isn't expiring, it's maybe because Joomla incorporates "keep alive" functionality, which involves javascript code sending HTTP "keep alive" HTTP requests to the server, which keeps the session cookie being updated and not expiring.) + +## Logging on using hard-coded credentials + +You can do this by + +```php +$username = "myuser"; +$password = "mypassword"; +$credentials = ['username' => $username, 'password' => $password]; +$logged_in = $app->login($credentials, []); +``` + +As you can see from the basic script in the previous section, you don't need to be logged on to perform operations such as database queries. But if you are using Joomla code (eg a `com_content` ArticleModel) then you are likely to find that that code checks permissions before permitting an action, and so you need to be logged-on as an authorised user for the functionality to work. + +Of course, if you're using hard-coded credentials then there's no check that the person running the script is a valid user of the Joomla site, so either the functionality has to be open to anyone, or you have to define some other mechanism to restrict access to the PHP script. + +Also a major danger of this approach is that you can leave someone logged onto your Joomla site with your hard-coded credentials. Someone can run your PHP script, and immediately afterwards access the Joomla site, and find themselves logged on as the username you hard-coded in your script. This is because the Joomla startup routines set up PHP register shutdown functions which receive control when your script finishes. These routines then store the session data which includes your hard-coded username, and the HTTP response to the script includes the session cookie being sent down to the browser. If the user then access the Joomla site the browser sends the session cookie to the server, Joomla reads it and accesses the session data, and treats as logged-on any user found there. + +For this reason it's recommended that you specifically logout the user in your script: + +```php +$app->logout(); +``` + +Even then, if the code you're running causes an exception, and you haven't enclosed it within a try/catch block, then the general Joomla exception handler will gain control, which will cause your script to terminate abruptly before your `logout()` call, and also store the user details in the session data. + +## Summary + +In deciding which logon option to choose here are some factors you may want to consider: + +- is it ok for absolutely anyone to run this script? +- is access to the script adequately restricted by some other means? +- does the Joomla functionality run within the script need to have a logged-on user in order to work correctly? +- if I do hard-code credentials are there fullproof mechanisms in place to ensure that users who run the script don't get logged on accidentally using those credentials? diff --git a/versioned_docs/version-5.2/building-extensions/index.md b/versioned_docs/version-5.2/building-extensions/index.md new file mode 100644 index 00000000..a3d52a6b --- /dev/null +++ b/versioned_docs/version-5.2/building-extensions/index.md @@ -0,0 +1,65 @@ +--- +sidebar_position: 5 +--- +Build Extensions +================ + +Joomla is a rich featured content management system, but if you're building a website with Joomla and you need extra features which aren't available by default, then you can easily extend it with extensions. There are five common types of extensions for Joomla: Components, Modules, Plugins, Templates, and Languages. There are three others: Packages, Files and Libraries. Each of these extensions handle specific functionality (many built-in features of Joomla are implemented using extensions). + +The difference between Joomla components, modules, plugins and templates can be initially confusing. If you're new to Joomla then you may find it useful to watch the video [How Joomla Works - a guide for extension developers](https://youtu.be/JKnq47Yhtvs), which describes how these 4 types of extension fit into the generation of a Joomla web page. Their output is also highlighted in different colours in the diagram below. + +![Screenshot showing extension types](./_assets/screenshot-extension-types.jpg) + +## Components +[Components](./components/index.md) provide the central part of a web page on a Joomla site; each site web page displays the output from one component. They can be thought of as mini applications. Most components have two parts: a site part and an administrator part. For example, `com_content` is the component which handles articles; on the site front-end `com_content` displays articles to website visitors and on the back-end `com_content` provides the functionality for administrators to edit articles. + +In general, components manage the data of the Joomla instance and provide functionality for creating, editing, removing and displaying the data. Often the data management aspects are handled in the administrator back-end and the site front-end simply displays the data, but this split of responsibility is not mandated, and some components provide front-end functionality for creating/editing/removing data. + +When you navigate to a certain page on a site or perform a certain operation such as login/logout then you're selecting the component which is going to be run. That component is the code which is primarily responsible for handling the HTTP Request, executing the requested operation, and displaying the key data on the web page. + +- Examples: Managing articles (com_content), Categories (com_categories), Contacts (com_contact), Images and media files (com_media) +- Management feature: Admin menu → Components → Contacts (for com_contact) + +Examples of component functionality available from third party extensions include backup utilities and support for eCommerce. + +## Modules +[Modules](./modules/index.md) are more lightweight and flexible extensions displayed on a web page. Modules are mostly known as the “boxes” that are arranged around a component, for example: the login module or the breadcrumbs module. Modules are assigned per menu item. So you can decide to show or hide the login module depending on which menu item the user is viewing. + +A module can often be a companion to the component. For example, if your web page displays an article (`com_content` component) then you might have a module (`mod_tags_similar`) in the sidebar which displays links to related articles, or a module which displays an image slider of related photos. + +However, modules do not need to be linked to components, as a matter of fact they don't even need to be linked to anything and can be just static HTML or text. + +- Examples: Latest Articles (mod_articles_latest), Menus (mod_menu), Who's Online (mod_whosonline), Custom HTML (mod_custom) +- Management feature: Admin menu → Content → Site Modules + +If you're just beginning with Joomla extension development then developing a module is the easiest place to start. + +## Plugins +[Plugins](./plugins/index.md) work behind the scenes to modify or enhance the basic Joomla functionality. In the execution of any part of Joomla - be it the core, a module or a component - an event can be triggered. When an event is triggered, plugins which are registered to handle that event execute, and are passed data related to that event. The plugin can then, for example, modify the data and return it to the core Joomla code. For example, a plugin could be used to intercept user-submitted articles and filter out bad words. + +- Examples: Content pagenavigation plugin (which generates the Prev and Next links as shown in the screenshot above) +- Management feature: Admin menu → System → Plugins + +## Templates +A [template](./templates/index.md) is basically the design of your Joomla-powered website. With a template you define the look and feel of your website, primarily based on CSS. Templates have certain fields in which the component (just one) and modules (as many as you like) will be shown. Building a complete Joomla template from scratch is difficult because you have to understand the variety of HTML output by the Joomla components, and the CSS classes which are used within them. However, it is relatively easy to customize the Atum (administrator) and Cassiopeia (site) templates which are shipped with Joomla, particularly as you can use the Joomla child template functionality to simply specify deviations from the parent template. + +- Management feature: Admin menu → System → Templates + +## Languages +Probably the most basic extensions are languages. Languages can be packaged in two ways: either as a core package or as an extension package. In essence, both the core and the extension language package files consist of key/value pairs, which provide the translation of static text strings, assigned within the Joomla source code. These language packs will affect both the front and administrator side of your Joomla instance. Note: these language packs also include an XML meta file which describes the language. + +- Management feature: Admin menu → System → Manage / Languages + +## Libraries +Libraries are standalone PHP snippets that Joomla uses. Note nearly all of Joomla's core code is available as a library within the libraries/src folder. All composer libraries (such as PHPMailer) are installed as a library "vendor" within libraries/vendor. Many of the most popular 3rd party extensions in Joomla use libraries to reuse common functionality across their components. + +## File +The File extension type is used to install individual files into a directory of the Joomla instance. There are no examples in Joomla Core of this type and it is the least used type, however it can be used for example to place [custom scripts](./custom-script/index.md) into the Joomla cli directory or to place template overrides into a specific directory. + +## Packages +Packages are simply a group of any of the above types of extensions. A common use of a package would be to ship a template that also bundles a system plugin. Or a component that also installs a library it uses. In Joomla many language packs install as a package so that the frontend and backend languages can be installed independently. + +## Extension Installation +There are 4 methods of installing an extension. You can install from the Joomla Extension Directory (Install from Web), upload the zip file of an extension, install from a folder or install from a URL. + +![Screenshot showing installing an extension](./_assets/screenshot-install-extension.jpg) \ No newline at end of file diff --git a/versioned_docs/version-5.2/building-extensions/install-update/index.md b/versioned_docs/version-5.2/building-extensions/install-update/index.md new file mode 100644 index 00000000..8c345e9d --- /dev/null +++ b/versioned_docs/version-5.2/building-extensions/install-update/index.md @@ -0,0 +1,5 @@ +--- +sidebar_position: 1 +title: Installation and Update +--- +This section gives an overview of how to install and update extensions on Joomla. \ No newline at end of file diff --git a/versioned_docs/version-5.2/building-extensions/install-update/installation/_assets/changelog-manage.jpg b/versioned_docs/version-5.2/building-extensions/install-update/installation/_assets/changelog-manage.jpg new file mode 100644 index 00000000..c7e0fbbb Binary files /dev/null and b/versioned_docs/version-5.2/building-extensions/install-update/installation/_assets/changelog-manage.jpg differ diff --git a/versioned_docs/version-5.2/building-extensions/install-update/installation/_assets/changelog-update.jpg b/versioned_docs/version-5.2/building-extensions/install-update/installation/_assets/changelog-update.jpg new file mode 100644 index 00000000..66337b24 Binary files /dev/null and b/versioned_docs/version-5.2/building-extensions/install-update/installation/_assets/changelog-update.jpg differ diff --git a/versioned_docs/version-5.2/building-extensions/install-update/installation/_assets/changelog.jpg b/versioned_docs/version-5.2/building-extensions/install-update/installation/_assets/changelog.jpg new file mode 100644 index 00000000..c6d7cf66 Binary files /dev/null and b/versioned_docs/version-5.2/building-extensions/install-update/installation/_assets/changelog.jpg differ diff --git a/versioned_docs/version-5.2/building-extensions/install-update/installation/change-log.md b/versioned_docs/version-5.2/building-extensions/install-update/installation/change-log.md new file mode 100644 index 00000000..52383985 --- /dev/null +++ b/versioned_docs/version-5.2/building-extensions/install-update/installation/change-log.md @@ -0,0 +1,130 @@ +--- +sidebar_position: 3 +title: Changelogs +--- + +Changelogs +========== + +Extension developers can leverage the ability of Joomla to read a changelog file and give a visual representation of the changelog. If a given version is not found in the changelog, the changelog button will not be shown. + +The changes in a release are presented in this manner: + +![Changelog display](./_assets/changelog.jpg) + +## Displaying the Changelog + +Changelogs can be displayed in 2 places within the Joomla administrator back-end. + +1. Manage Extensions + +![Manage Extensions display](./_assets/changelog-manage.jpg) + +You can click on the version number to display the changelog. + +To enable this you must specify in the extension installation manifest file where Joomla should look to find the changelog details, for example: + +```xml +https://example.com/updates/changelog.xml +``` + +Please note: The URL in the changelogurl tag must not have any spaces or line breaks before or after it. + +2. Update Extensions + +![Update Extensions display](./_assets/changelog-update.jpg) + +To enable this you must specify in the extension[ update server](../update-server.md) file where Joomla should look to find the changelog details, for example: + +```xml +https://example.com/updates/changelog.xml +``` + +:::note[Joomla Issue] + This feature does not currently work; see [Joomla issue 43505](https://issues.joomla.org/tracker/joomla-cms/43505). +::: + +## The Changelog File + +An example of a changelog file is below: + +```xml + + + com_lists + component + 4.0.0 + + Item A + Item b + + + Item A + Item b + + + Item A + Item b + + + Item A + Item b + + + Item A + Item b + + + Item A + Item b + + + Item A + Item b + + + + com_lists + component + 0.0.2 + + Big issue + + + +``` + +You may specify multiple `` elements within the `` element, one for each version of the extension. + +Each `` element must have the following 3 nodes: +- element +- type +- version + +This information is used to identify the correct changelog for a given extension, for example: + +```xml +com_lists +component +4.0.0 +``` + +The changelog contains one or more change types. The following change types are supported: +- security: Any security issues that have been fixed +- fix: Any bugs that have been fixed +- language: This is for language changes +- addition: Any new features added +- change: Any changes +- remove: Any features removed +- note: Any extra information to inform the user + +Each node can be repeated as many times as needed. + +The format of the text can be plain text or HTML but in case of HTML, it must be enclosed in CDATA tags as in: + +```xml + + You MUST replace this file

]]> + +``` + diff --git a/versioned_docs/version-5.2/building-extensions/install-update/installation/index.md b/versioned_docs/version-5.2/building-extensions/install-update/installation/index.md new file mode 100644 index 00000000..03c784a0 --- /dev/null +++ b/versioned_docs/version-5.2/building-extensions/install-update/installation/index.md @@ -0,0 +1,10 @@ +--- +sidebar_position: 1 +title: Installing Extensions +--- + +This section covers: +- how to install extensions - by means of a Manifest File +- the overall installation process, and how you can write a Script File to interact with it +- the ChangeLog File +- packages diff --git a/versioned_docs/version-5.2/building-extensions/install-update/installation/install-process.md b/versioned_docs/version-5.2/building-extensions/install-update/installation/install-process.md new file mode 100644 index 00000000..92f23fcd --- /dev/null +++ b/versioned_docs/version-5.2/building-extensions/install-update/installation/install-process.md @@ -0,0 +1,149 @@ +--- +sidebar_position: 2 +title: Install Process and Script Files +--- + +Install Process and Script Files +================================ + +This section provides an overview of the extension install process, and how you can write a Script File to interact with it. + +An installation script file is a class with 5 functions: +- preflight - called at the start of the install process +- install, update, uninstall - called part way through the process: + - install is called when the operation is an initial install of an extension + - update is called when the operation is an install of an existing extensions + - uninstall is called when the operation is a removal of an extension +- postflight - called at the end of the install process + +You can also interact with the process by writing installation plugins which listen for the events described below. + +## Installation Process + +There are various methods for installing an extension in Joomla, and various types of extension, but ultimately, the installation process follows a similar pattern for all. + +When you go to install extensions and select a zip file of an extension to install then this is an overview of what happens: +(If you want to step through this process in a debugger then set a break at administrator/components/com_installer/src/Model/InstallModel.php::install) +- imports the "installer" type plugins, and triggers the 'onInstallerBeforeInstallation' event +- the zip file is stored in the Joomla /tmp folder, and then unzipped into a subfolder of /tmp +- triggers the 'onInstallerBeforeInstaller' event +- triggers the 'onExtensionBeforeInstall' event +- loads the .sys.ini language file from the new install files (or failing that, from the existing extension directory) +- reads basic information about the extension from the manifest file, for example, the type of the extension +- performs a `require_once` of the installer script file +- calls the script file `preflight` function +- copies the extension files from the /tmp folder to their place within the Joomla instance - for example, when installing a site module mod_example, the code would be copied to /modules/mod_example +- writes / updates the extension record in the database (ie this extension's record in the `#__extensions` table) +- performs any functionality specific to that extension type. For example, for new installs of modules it creates a record in the `#__modules` table +- applies any database changes required by this install. +- calls the script file `install` / `update` / `uninstall` function +- tidy-up: + - If there's a record in the `#__updates` table saying that there's a new version available for this extension then it deletes it. + - It copies the manifest file into the target extension directory (for components this will be the component directory under /administrator) +- calls the script file `postflight` function +- triggers the 'onExtensionAfterInstall' event +- triggers the 'onInstallerAfterInstaller' event +- performs some further tidy-up, eg deleting the temporary installation files + +## Example Script File + +The easiest way to write a script file is to use the \Joomla\CMS\Installer\InstallerScriptInterface definition in libraries/src/Installer/InstallerScriptInterface.php. +You simply have to return an instance of a class which implements the 5 installer functions. + +You can either +1. Return an anonymous Script File class which implements InstallerScriptInterface, or +2. Return an anonymous service provider class which puts the Script File class into the Dependency Injection Container using a key InstallerScriptInterface::class. Joomla will then `get` that Script File class from the DIC. + +The example below uses the second approach. + +For an example of the first approach see the [Module Tutorial Step 6](../../modules/module-development-tutorial/step6-script-file.md). + +```php +set( + InstallerScriptInterface::class, + new class ( + $container->get(AdministratorApplication::class), + $container->get(DatabaseInterface::class) + ) implements InstallerScriptInterface { + private AdministratorApplication $app; + private DatabaseInterface $db; + + public function __construct(AdministratorApplication $app, DatabaseInterface $db) + { + $this->app = $app; + $this->db = $db; + } + + public function install(InstallerAdapter $parent): bool + { + $this->app->enqueueMessage('Successful installed.'); + + return true; + } + + public function update(InstallerAdapter $parent): bool + { + $this->app->enqueueMessage('Successful updated.'); + + return true; + } + + public function uninstall(InstallerAdapter $parent): bool + { + $this->app->enqueueMessage('Successful uninstalled.'); + + return true; + } + + public function preflight(string $type, InstallerAdapter $parent): bool + { + return true; + } + + public function postflight(string $type, InstallerAdapter $parent): bool + { + $this->deleteUnexistingFiles(); + + return true; + } + + private function deleteUnexistingFiles() + { + $files = []; // overwrite this line with your files to delete + + if (empty($files)) { + return; + } + + foreach ($files as $file) { + try { + File::delete(JPATH_ROOT . $file); + } catch (\FilesystemException $e) { + echo Text::sprintf('FILES_JOOMLA_ERROR_FILE_FOLDER', $file) . '
'; + } + } + } + } + ); + } +}; +``` diff --git a/versioned_docs/version-5.2/building-extensions/install-update/installation/manifest.md b/versioned_docs/version-5.2/building-extensions/install-update/installation/manifest.md new file mode 100644 index 00000000..5f52ce51 --- /dev/null +++ b/versioned_docs/version-5.2/building-extensions/install-update/installation/manifest.md @@ -0,0 +1,512 @@ +--- +sidebar_position: 1 +title: Manifest Files +--- + +Manifest Files +============== + +You install Joomla extensions by means of a manifest XML file, and there are many Joomla examples which you can use as a basis for your own extension: +- components - in administrator/components, eg administrator/components/com_contact/contact.xml +- modules - in modules or administrator/modules, eg modules/mod_breadcrumbs/mod_breadcrumbs.xml +- plugins - in plugins, eg plugins/system/remember/remember.xml +- templates - in templates or administrator/templates, eg administrator/templates/atum/templateDetails.xml +- languages - in language or administrator/language, eg language/en-GB/install.xml + +This section covers the detailed definition of the XML in a Manifest File. + +## File Naming Convention + +It is important that you name your manifest file correctly. Otherwise you may find that your extension installs, but that your extension's namespace isn't built correctly, and your extension doesn't run. + +Here are the naming rules for the different extension types (as listed in [Building Extensions](../../../building-extensions/index.md)): + +**Components**: for a component called com_example you can use either com_example.xml or example.xml. + +**Modules**: for a module mod_example use mod_example.xml. This must match the module name given in your manifest `` section + +```xml + + services + ... + +``` + +or if you don't yet use a services/provider.php file: + +```xml + + mod_example.php + ... + +``` + +**Plugins**: for a plugin plg_example use example.xml. This must match the plugin name given in your manifest `` section + +```xml + + services + ... + +``` + +or if you don't yet use a services/provider.php file: + +```xml + + example.php + ... + +``` + +**Templates**: your manifest file must be named templateDetails.xml + +**Language**: use install.xml + +**File**, **Library**, **Package**: you can use any name, but libraries are usually named lib_example.xml and packages pkg_example.xml. + +For components, modules and plugins the manifest file must match the 'element' field of your extension's record in the `#__extensions` table (except that for components the "com_" prefix may be omitted). +The 'element' is the internal name within Joomla of the extension. + +In priority order the 'element' database field is set +- from the `` in the manifest file, or +- from the "module=" or "plugin=" attribute in the ``, or +- from the `` (after the text is cleaned). + +## Root Element + +The primary tag of the installation file is + +```xml + +... + +``` + +This starting and closing tag is the same for all extensions. The following attributes are allowed within the tag: + +| Attribute | Values | Applicable To | Description | +| --------------------------------- | ---------------- | ---------------- | -------------------------------------------------------- | +| type | component
file
language
library
module
package
plugin
template | All extensions | | +| method | install
upgrade | All extensions | The install value (default) means the installer will gracefully stop if it finds any existing file/folder of the new extension
The upgrade value allows you to install an upgraded version on top of the existing version | +| client | site
administrator | Modules | Defines whether the module is a front-end site module or back-end administrator module | +| group | *string* | Plugins | The group name specifies for which group of plugins the new plugin is available.
The existing groups are the folder names within the directory /plugins.
The installer will create new folder names for group names that do not exist yet. | + +## Metadata + +The following elements can be used to insert metadata. Although not strictly required, you should define at least the ``, ``, `` and `` tags, all of which are used on the default administrator Manage Extensions form. + +```xml + – extension name (e.g. com_banners). + – author's name (e.g. Joomla! Project) + – date of creation or release (e.g. April 2006) + – a copyright statement (e.g. (C) 2020 - 2030 Open Source Matters. All rights reserved.) + – a license statement (e.g. GNU General Public License version 3 or later; see LICENSE.txt) + – author's email address (e.g. admin@joomla.org) + – URL to the author's website (e.g. www.joomla.org) + – the version number of the extension (e.g. 1.6.0) + – the description of the component (may be shown as a tooltip on the admin Manage Extensions page) + – the internal name of the component. If omitted, name will be cleaned and used +``` + +The `` and `` fields are translatable. If you use language strings for these elements then they should be defined in your language .sys.ini file AND your .ini file. + +## Front-end Files + +```xml + + example.php + examples + +``` + +This is used to copy files from your development "from-folder" into the front-end directory of your installed extension. +You can either identify files individually using `` or copy a complete directory using ``. + +For plugins and modules you should identify the entry point of your code. +If you are using dependency injection within your module or plugin and have a services/provider.php file then use + +```xml + services +or + services +``` + +Here "mod_example" / "example" is the internal name (aka 'element') of your module / plugin. + +If you are not using a services/provider.php file then point to the specific filename: + +```xml + mod_example.php +or + example.php +``` + +## Media Files + +This categories covers: +- your javascript files +- your css files +- any images which are inheritently part of your extension (ie not something an administrator should be able to change). + +(For an example of these sorts of images, consider the flag symbols in media/mod_languages/images/ which are used by the language switcher.) + +In your development area you should store these in separate folders: js/, css/, images/ then use + +```xml + + js + css + images + +``` + +The installer will move these folders into media/com_example/js, media/com_example/css and media/com_example/images, creating the com_example folder if required. + +This media folder is used for both the site front-end and the administrator back-end. + +## Administration section + +```xml + + + +``` + +The administration section is defined in the `` element. Since only components apply to both the site and the administrator, only component manifests can include this element. + +### Administrator Back-end Files + +Files to copy below the administrator directory should be placed in the `` element under the `` and can be used to copy individual files or complete folders, as described above for front-end files. + +### Administrator Menu Links and Submenus + +This maps to menu and submenu links for your component in the administrator sidebar menu (under Components). + +```xml + + COM_EXAMPLE + + + COM_EXAMPLE_SUBMENU_ANOPTION + COM_EXAMPLE_SUBMENU_VIEWNAME + + +``` + +Each `` item can define the following attributes: + +| Attribute | Description | +| ------------------ | ------------------------------------------------------------------------ | +| link | A link to send the user to when the menu item is clicked. You can use "view" instead. | +| view | An URL parameter to add to the link.
For example, `COM_EXAMPLE` in com_example's XML manifest would cause the URL of the menu item to be index.php?option=com_example&view=cpanel.
You can use "link" instead. | +| img | The (relative) path to an image (16x16 pixels) to appear beside the menu item.
Must be an url compatible as a file too (e.g. no spaces) ! | +| alt | alt text for the link | + +You can also create links to dashboards - see the following section for details. + +The value inside the tag is the menu's label. If you use language strings inside these elements then they should be defined in your component's .sys.ini file. + +The installer creates entries in the `#__menu` table for these menu items, and Joomla loads from the database these entries when it builds the administrator menu. + +(Administrator menu items for components such as com_content are defined in the component's preset folder, eg in administrator/components/com_content/presets/content.xml). + +## Dashboards + +You create a dashboard for your component using + +```xml + + example + +``` + +When your component is installed then you can navigate to your dashboard using + +``` +administrator/index.php?option=com_cpanel&view=cpanel&dashboard=example +``` + +This will display at the top the `title` and `icon`, but will initially be empty. +You can define items for your dashboard using a preset and / or by adding administrator modules to it using the position `cpanel-example`, as described in [Dashboard](../../../general-concepts/dashboard.md). + +To create a link to your dashboard use (in your administrator menu section): + +```xml + + COM_EXAMPLE + + example + + + +``` + +The text "example" within the `` tags must match the text within the corresponding tags in the `` element. + +## Configuration + +For modules, plugins and templates you can define configuration using a `` section. +Within the `` tags you specify the configuration fields as described in [Form Fields](../../../general-concepts/forms-fields/index.md). + +There are many examples among the Joomla extensions, see mod_breadcrumbs for example. + +The configuration is defined by navigating to the administrator Manage Modules / Manage Plugins / Template Styles functionality. + +You cannot use `` for defining configuration for components. +For details of how to provide component configuration see [Developing an MVC Component/Adding configuration](https://docs.joomla.org/J3.x:Developing_an_MVC_Component/Adding_configuration), which (though written for Joomla 3) is still applicable. + +:::note[TODO] + Update the above link when the MVC Component Tutorial is included in the manual. +::: + +## Namespace + +Define the namespace prefix for your extension using: + +```xml +Mycompany\Component\Example +``` + +See the manual [Namespace](../../../general-concepts/namespaces/index.md) section for details. + +## SQL + +The SQL section (primarily used by components) enables you to make changes to the database data owned by your extension. + +There are 3 types of changes: +1. **Install** Initial database setup for your extension, for the first version of your extension (or, at least, the first version which configures the database). +2. **Update** Database changes to be applied upgrading to this version from the previous version +3. **Uninstall** Database changes to be applied when the extension is uninstalled. + +For each type of database (eg mysql) you will have: +- 1 SQL file for the install +- 1 SQL file for the uninstall +- a folder containing several update SQL files, each enabling upgrading from the previous version to the current + +Each SQL file contains a series of SQL statements, with table names using the '#__' prefix, eg '#__categories'. + +By convention all these sql files are stored in a folder called "sql" within the administrator folder, which you must define within your administrator files section, eg + +```xml + + + sql + + +``` + +For your install file: + +```xml + + + sql/example.install.sql + + +``` + +You can have several `` elements, for different database drivers. + +For your uninstall file(s): + +```xml + + + sql/example.uninstall.sql + + +``` + +For your update files: + +```xml + + + sql/updates/mysql + + +``` + +where, for example, sql/updates/mysql contains a series of files, eg: +- 0.0.2.sql (for upgrading to v0.0.2) +- 0.0.3.sql (for upgrading from v0.0.2 to v0.0.3), etc. +- 0.0.4.sql (for upgrading from v0.0.3 to v0.0.4), etc. + +If the first version you install is eg 0.0.4 then Joomla will use the initial example.install.sql file, and then apply in order the update files to arrive at v0.0.4. + +If you install one version of the extension then skip some versions before installing the next, then Joomla applies each of the update sql files to go from your previous version to the one you're installing. + +The currently installed version is maintained in the `#__schemas` table. +You can find a worked example in [Developing an MVC Component/Using the database](https://docs.joomla.org/J3.x:Developing_an_MVC_Component/Using_the_database). + +:::note[TODO] + Update the above link when the MVC Component Tutorial is included in the manual. +::: + +## Languages + +You specify your language ini files in a structure like this: + +``` +language + ├─── en-GB + │ ├─── mod_hello.ini + │ └─── mod_hello.sys.ini + └─── fr-FR + ├─── mod_hello.ini + └─── mod_hello.sys.ini +``` + +The subfolder name (eg en-GB) must match the language code of the language your extension is supporting. +You can find the list of all languages supported by Joomla (together with their language codes) via the [Joomla Language Downloads](https://downloads.joomla.org/language-packs). + +(For historical reasons Joomla also supports the language file names being prefixed with the language code, eg en-GB.mod_hello.ini). + +There are 2 ways which you can use to install your extension's language files. + +1. Using the `` tag + +```xml + + com_example.ini + com_example.sys.ini + +``` + +Joomla will copy your language files (from the folder specified in the 'folder' attribute) into the appropriate Joomla language folder: +- under /language for the site front-end (site modules, site templates and components when the `` tag is immediately inside ``). +- under /administrator/language for the administrator back-end (plugins, administrator modules, administrator templates and components when the `` tag is inside ``). + +In your code you can then load your .ini language file using (eg for mod_example): + +```php +Factory::getApplication()->getLanguage()->load('mod_example'); +``` + +2. Copying from a language folder + +```xml + + language + +or + + + language + + +``` + +This will simply copy your 'language' folder into the target folder of your extension. +In this case, you must name your folder "language", as this is the name of the folder where Joomla will look to find your language files. + +To load your .ini language file you must pass the base path for your extension (eg for site module mod_example): + +```php +Factory::getApplication()->getLanguage()->load('mod_example', JPATH_BASE . '/modules/mod_example'); +``` + +The advantage of this second approach is that the language files continue to be closely associated with your extension. + +If an administrator uninstalls a language then +- for option 1 your extension's language files will be deleted +- for option 2 your extension's language files will remain. + +If the administrator then reinstalls the removed language then +- for option 1 your extension will need to be reinstalled to restore its language files for the reinstalled language +- for option 2 no further action is needed. + +## Script File + +```xml +script.php +``` + +This specifies the filename of a script file containing PHP code which is run during the installation process. It is described in [Install Process and Script Files](./install-process.md). + +## Library Files + +This is specific to a manifest of type "library". + +```xml +mylib +``` + +Joomla will treat libraries/mylib as the target directory, and any files and folders will be copied under it. + +If your company has several libraries and you want to group them together under the folder JPATH_SITE/libraries/mycompany then include your company name in the `` tag of each library: + +```xml +mycompany/mylib1 +``` + +```xml +mycompany/mylib2 +``` + +These libraries will then be installed in the JPATH_SITE/libraries/mycompany/mylib1 and JPATH_SITE/libraries/mycompany/mylib2 folders. +Uninstalling mylib1 will still leave mylib2 installed on your site. + +## Update Server + +```xml + + http://example.com/extension.xml + http://example.com/collection.xml + +``` + +Please see [Update Servers](../update-server.md). + +## Changelog + +Specify the URL of the changelog description for this version of your extension: + +```xml +https://example.com/updates/changelog.xml +``` + +The URL in the `` tag must not have any spaces or line breaks before or after it. + +See the section on [ChangeLogs](./change-log.md). + +## Download Keys + +Users can enter their download keys via the Update Sites list, which provides a single place to manage them. +When a user is going to update an extension, Joomla will check if there is a download key. If there is a download key, Joomla will add the download key to the update URL. + +To support download keys you must include the dlid tag in the manifest file. The dlid tag takes 2 arguments: +- prefix +- suffix + +The dlid tag will look like this in your manifest file: + +```xml + +``` + +The prefix will be added before the download key and the suffix after the download key. Using the example above the full query added to the download link will be: + +``` +dlid=KEY&dummy=my.zip +``` + +The key is added before the `onInstallerBeforePackageDownload` event is triggered, so the full URL will be passed to the event. + +## Summary + +This documents which manifest elements are supported during which installation of an extension. + +| Component | File | Language | Library | Module | Package | Plugin | Template | +| :-------: | :--: | :------: | :-----: | :----: | :-----: | :----: | :------: | +| `` | yes | yes | no | no | yes | no | yes | no | +| `` | yes | yes | no | yes | yes | yes | yes | yes | +| `` | no | no | yes | no | no | no | no | no | +| `` | yes | no | yes | yes | yes | no | yes | yes | +| `` | no | no | no | no | yes | no | yes | yes | +| ` + + +... +... + + + +... +``` + +If an inline asset have a multiple dependencies, then the last one will be used for positioning. Example: + +```php +$wa->addInlineScript('content of inline1', ['position' => 'before'], [], ['foo', 'bar']); +$wa->addInlineScript('content of inline2', ['position' => 'after'], [], ['foo', 'bar']); +``` + +Will produce: + +```html +... + + + + +... +``` + +:::note Note + +A named inline asset may be a dependency to another inline asset, however it is not recommended to use an inline asset as dependency to non-inline asset. This will work, but this behavior may change in the future. It's recommended to use "position" instead. +::: + +## Working with ESM importmap +WebAssetManager allows to define [importmap](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap) for your ES modules. +The `script` asset with option `"importmap": true` will be added to `importmap`. Other option available: +- `importmap` boolean, whether the element should be added to `importmap`; +- `importmapName` string, optional, custom module name, example when asset name `foo`, and module name is `@foo`; +- `importmapScope` string, optional, a scope path for the asset in `importmap`; +### Methods to work with ESM importmap +All methods to work with a ESM importmap are the same as methods to work with script asset item. + +## Working with a web component + +Joomla! allows you to use [Web Components](https://developer.mozilla.org/en-US/docs/Web/Web_Components) for your needs. In Joomla! web components are not loaded as regular scripts, but loaded via Web Component loader so that they are loaded asynchronously. + +In all other aspects, working with web components in the Asset Manager is the same as working with a `script` asset item. + +Example json definition of some web components in joomla.asset.json (as ES6 module): + +```json +... +{ + "name": "webcomponent.foobar", + "type": "style", + "uri": "com_example/foobar-custom-element.css", +}, +{ + "name": "webcomponent.foobar", + "type": "script", + "uri": "com_example/foobar-custom-element.js", + "attributes": { + "type": "module" + }, +} +... +``` + +Example with fallback, for browsers that does not support ES6 `module` feature. Note that the legacy script should have `wcpolyfill` dependency, and module script should have dependency from legacy script: + +```json +... +{ + "name": "webcomponent.foobar", + "type": "style", + "uri": "com_example/foobar-custom-element.css", +}, +{ + "name": "webcomponent.foobar-legacy", + "type": "script", + "uri": "com_example/foobar-custom-element-es5.js", + "attributes": { + "nomodule": true, + "defer": true + }, + "dependencies": [ + "wcpolyfill" + ] +}, +{ + "name": "webcomponent.foobar", + "type": "script", + "uri": "com_example/foobar-custom-element.js", + "attributes": { + "type": "module" + }, + "dependencies": [ + "webcomponent.foobar-legacy" + ] +} +... +``` + +Alternatively you can register them in PHP (as ES6 module): + +```php +$wa->registerStyle('webcomponent.foobar', 'com_example/foobar-custom-element.css') + ->registerScript('webcomponent.foobar', 'com_example/foobar-custom-element.js', ['type' => 'module']); +``` + +Attach to document: + +```php +$wa->useStyle('webcomponent.foobar') + ->useScript('webcomponent.foobar'); +``` + +:::note Note + +It is preferred to prefix the asset name with "webcomponent." to make it easily to spot, and distinct it from regular scripts in a layout. +::: + +### Methods to work with web component + +All methods to work with a web component are the same as methods to work with script asset item. + +## Working with a presets + +`Preset` is a special kind of asset item that hold a list of items that has to be enabled, in same way as direct call of `useAsset()` to each of item in the list. +Preset can hold mixed types of assets (script, style, another preset, etc.), the type should be provided after `#` symbol and follows after an asset name, example: `foo#style`, `bar#script`. + +Example json definition of item in joomla.asset.json: + +```json +... +{ + "name": "foobar", + "type": "preset", + "uri": "", + "dependencies": [ + "core#script", + "foobar#style", + "foobar#script", + ] +} +... +``` + +### Methods to work with preset + +Asset Manager offers the following methods for working with preset items: + +```php +/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */ +$wa = Factory::getApplication()->getDocument()->getWebAssetManager(); + +// Attach all items from foobar preset to the document +$wa->usePreset('foobar'); + +// Disable all items from foobar preset from being attached +$wa->disablePreset('foobar'); + +// Register custom item without json definition +$wa->registerPreset('bar', '', [], [], ['core#script', 'bar#script']); + +// And use it later +$wa->usePreset('bar'); + +// Register and attach a custom item in one run +$wa->registerAndUsePreset('bar','', [], [], ['core#script', 'bar#script']); +``` + +## Advanced: Custom WebAssetItem class + +The default class for all WebAsset items is `Joomla\CMS\WebAsset\WebAssetItem`. + +You are also allowed to use a custom class, which must implement `Joomla\CMS\WebAsset\WebAssetItemInterface` or extend `Joomla\CMS\WebAsset\WebAssetItem`. + +A custom class can allow you to do advanced actions, for example, including a script file depending on an active language: + +```php +class MyComExampleAssetItem extends WebAssetItem +{ + public function getUri($resolvePath = true): string + { + $langTag = Factory::getApplication()->getLanguage()->getTag(); + // For script asset use ".js", for style we would use ".css" + $path = 'com_example/bar-' . $langTag . '.js'; + + if ($resolvePath) + { + // For script asset use "script", for style we would use "stylesheet" + $path = $this->resolvePath($path, 'script'); + } + + return $path; + } +} +``` + +Additionally, implementing `Joomla\CMS\WebAsset\WebAssetAttachBehaviorInterface` allows you to add a script option (which may depend on the environment) when your asset is enabled and attached to the Document. + +```php +class MyFancyFoobarAssetItem extends WebAssetItem implements WebAssetAttachBehaviorInterface +{ + public function onAttachCallback(Document $doc): void + { + $user = Factory::getApplication()->getIdentity(); + $doc->addScriptOptions('com_example.fancyfoobar', ['userName' => $user->username]); + } +} +``` + +:::note Important note: + +An asset item that implements `WebAssetAttachBehaviorInterface` should be enabled before [onBeforeCompileHead](https://docs.joomla.org/Plugin/Events/System#onBeforeCompileHead) event, otherwise `onAttachCallback` will be ignored. +::: + +### Defining a custom WebAssetItem class in joomla.asset.json + +In joomla.asset.json you can define which Class should be used with specific AssetItem. +For this you can use 2 properties `namespace` and `class`. `namespace` can be defined at Root level (then it will be used as default namespace for all Asset items in joomla.asset.json) or in the Item level. For example: + +```json +{ + "$schema": "https://developer.joomla.org/schemas/json-schema/web_assets.json", + "name": "com_example", + "version": "4.0.0", + "namespace": "Joomla\Component\Example\WebAsset", + "assets": [ + { + "name": "foo", + "type": "script", + "class": "FooAssetItem", + "uri": "com_example/foo.js" + }, + { + "name": "bar", + "type": "script", + "namespace": "MyFooBar\Library\Example\WebAsset", + "class": "BarAssetItem", + "uri": "com_example/bar.js" + } + ] +} +``` + +Here the asset `foo` will be associated with class `Joomla\Component\Example\WebAsset\FooAssetItem`, and `bar` with class `MyFooBar\Library\Example\WebAsset\BarAssetItem`. + +:::note Note + +If `namespace` are not defined then by default will be used `Joomla\CMS\WebAsset`. When `namespace` is defined but empty, then no namespace will be used, only `class`. Example: +::: + +```json +{ + "$schema": "https://developer.joomla.org/schemas/json-schema/web_assets.json", + "name": "com_example", + "assets": [ + { + "name": "foo", + "type": "script", + "class": "FooAssetItem", + "uri": "com_example/foo.js" + }, + { + "name": "bar", + "type": "script", + "namespace": "", + "class": "BarAssetItem", + "uri": "com_example/bar.js" + } + ] +} +``` + +Here the asset `foo` will be associated with class `Joomla\CMS\WebAsset\FooAssetItem`, and `bar` with class `BarAssetItem` (without namespace). diff --git a/versioned_docs/version-5.2/general-concepts/webservices.md b/versioned_docs/version-5.2/general-concepts/webservices.md new file mode 100644 index 00000000..47c30759 --- /dev/null +++ b/versioned_docs/version-5.2/general-concepts/webservices.md @@ -0,0 +1,407 @@ +Web Services +============ + +Description of the webservices concept + +- Web Services are used to make systems COMMUNICATE each other by using the HTTP protocol and nowadays over TLS (Transport Layer Security). +- Another definition could be Web Services acts like a CONTRACT between a PRODUCER and a CONSUMER via ENDPOINTS. +- Simply put, Web Services are like doors and windows in a house, they are INPUTS and OUTPUTS to the OUTSIDE world. +- In the context on Joomla! as a system, Joomla Webservices API allows Joomla! to INTERACT WITH, EXTERNAL DATASOURCES. Like webapps, mobile,etc... + +## Communicate with the Joomla 4.x Web Services API +The communication with Joomla's Web Services API takes place via specified endpoints. + +- Joomla's core endpoints: https://docs.joomla.org/J4.x:Joomla_Core_APIs +- A collection of Joomla endpoints to use in Postman: https://github.com/alexandreelise/j4x-api-collection + +### Using the Joomla framework + +More often than not, when using the Joomla framework, under the hood it still uses cURL or php streams. Most of the cURL is available with your web hosting provider. Otherwise check phpinfo(); +You should be able to follow along because the examples using the Joomla framework will mimic those with cURL. + +#### Define some variables +First we define some variables that we use in all our cURL requests: +- the URL of your Joomla 4.x website and +- the Joomla's API Token of a Super User account or an account which has at least core.login.api permission and core.login.site to be able to see change current logged-in user's token. + + +```php +// Before passing the HTTP METHOD to CURL +use Joomla\Http\HttpFactory; +use Joomla\Uri\Uri; + +$http = (new HttpFactory())->getAvailableDriver(); +$url = 'https://example.org/api/index.php/v1'; +$uri = new Uri($url); + +// Put your Joomla! Api token in a safe place, for example a password manager or a vault storing secrets +// We should not use environment variables to store secrets. +// Here is why: https://www.trendmicro.com/en_us/research/22/h/analyzing-hidden-danger-of-environment-variables-for-keeping-secrets.html + +$token = ''; +``` + + +#### POST - Create an Article in the Category "Uncategorized" (Category ID = 2) + +```php +$categoryId = 2; // Joomla's default "Uncategorized" Category + +$data = [ +'title' => 'How to add an article to Joomla via the API?', +'alias' => 'how-to-add-article-via-joomla-api', +'articletext' => 'I have no idea...', +'catid' => $categoryId, +'language' => '*', +'metadesc' => '', +'metakey' => '', +]; + +$dataString = json_encode($data); + +// HTTP request headers +$headers = [ +'Accept: application/vnd.api+json', +'Content-Type: application/json', +'Content-Length: ' . mb_strlen($dataString), +sprintf('X-Joomla-Token: %s', trim($token)), +]; + +// Timeout in seconds +$timeout = 30; + +// Set path for creating an article it will set the current uri path part +$uri->setPath('content/articles'); + +// Will be a PSR-7 compatible Response +$response = $http->request('POST', $uri, $dataString, $headers, $timeout); + +// The response body is now a stream, so you need to do +echo $response->body; + +``` + +#### GET - Retrieve all articles from the "Uncategorized" Category + +```php +$categoryId = 2; // Joomla's default "Uncategorized" Category + +// Don't send payload to server +$dataString = null; + +// HTTP request headers +$headers = [ +'Accept: application/vnd.api+json', +'Content-Type: application/json', +sprintf('X-Joomla-Token: %s', trim($token)), +]; + +// Timeout in seconds +$timeout = 30; + +// Set path for getting all articles it will set the current uri path part +$uri->setPath('content/articles'); + +// Will be a PSR-7 compatible Response +$response = $http->request('GET', $uri, $dataString, $headers, $timeout); + +// The response body is now a stream, so you need to do +echo $response->body; + +``` + +#### GET - Retrieve one specific Article + +```php +$articleId = 1; // The Article ID of a specific Article + +// Don't send payload to server +$dataString = null; + +// HTTP request headers +$headers = [ +'Accept: application/vnd.api+json', +'Content-Type: application/json', +sprintf('X-Joomla-Token: %s', trim($token)), +]; + +// Timeout in seconds +$timeout = 30; + +// Set path for getting a specific article it will set the current uri path part +$uri->setPath(sprintf('content/articles/%d', $articleId)); + +// Will be a PSR-7 compatible Response +$response = $http->request('GET', $uri, $dataString, $headers, $timeout); + +// The response body is now a stream, so you need to do +echo $response->body; + +``` + +#### PATCH - Modify a specific Article + +```php +$articleId = 1; // The Article ID of a specific Article + +$data = [ +'id' => $articleId, +'title' => 'How to add an article via the Joomla 4 API?', +'introtext' => 'When using PATCH, articletext MUST be split into two parts or use at least just introtext in order to work properly', +'fulltext' => 'MORE CONTENT if you wish', +]; + +$dataString = json_encode($data); + +// HTTP request headers +$headers = [ +'Accept: application/vnd.api+json', +'Content-Type: application/json', +'Content-Length: ' . mb_strlen($dataString), +sprintf('X-Joomla-Token: %s', trim($token)), +]; + +// Timeout in seconds +$timeout = 30; + +// Set path for partial update of a specific article it will set the current uri path part +$uri->setPath(sprintf('content/articles/%d', $articleId)); + +// Will be a PSR-7 compatible Response +$response = $http->request('PATCH', $uri, $dataString, $headers, $timeout); + +// show response status code +echo $response->code; + +``` + +#### DELETE - Remove a specific Article + +```php +$articleId = 1; // The Article ID of a specific Article + +// Don't send payload to server +$dataString = null; + +// HTTP request headers +$headers = [ +'Accept: application/vnd.api+json', +'Content-Type: application/json', +sprintf('X-Joomla-Token: %s', trim($token)), +]; + +// Timeout in seconds +$timeout = 30; + +// Set path for deleting of a specific article it will set the current uri path part +$uri->setPath(sprintf('content/articles/%d', $articleId)); + +// Will be a PSR-7 compatible Response +$response = $http->request('DELETE', $uri, $dataString, $headers, $timeout); + +// show response status code +echo $response->code; +``` + + +### Using the PHP cURL Functions + +The cURL functions needs to be available and enabled in your PHP configuration, check phpinfo(); + +#### Define some variables + +First we define some variables that we use in all our cURL requests: + +- the URL of your Joomla 4.x website and +- the Joomla's API Token of a Super User account or an account which has at least core.login.api permission and core.login.site to be able to see change current logged-in user's token. + +```php +// Before passing the HTTP METHOD to CURL +$curl = curl_init(); + +$url = 'https://example.org/api/index.php/v1'; + +// Put your Joomla! Api token in a safe place, for example a password manager or a vault storing secrets +// We should not use environment variables to store secrets. +// Here is why: https://www.trendmicro.com/en_us/research/22/h/analyzing-hidden-danger-of-environment-variables-for-keeping-secrets.html +$token = ''; +``` + +#### POST - Create an Article in the Category "Uncategorized" (Category ID = 2) + +```php +$categoryId = 2; // Joomla's default "Uncategorized" Category + + +$data = [ +'title' => 'How to add an article to Joomla via the API?', +'alias' => 'how-to-add-article-via-joomla-api', +'articletext' => 'I have no idea...', +'catid' => $categoryId, +'language' => '*', +'metadesc' => '', +'metakey' => '', +]; + +$dataString = json_encode($data); + +// HTTP request headers +$headers = [ +'Accept: application/vnd.api+json', +'Content-Type: application/json', +'Content-Length: ' . mb_strlen($dataString), +sprintf('X-Joomla-Token: %s', trim($token)), +]; + +curl_setopt_array($curl, [ + CURLOPT_URL => sprintf('%s/%s',$url,'content/articles'), + CURLOPT_RETURNTRANSFER => true, + CURLOPT_ENCODING => 'utf-8', + CURLOPT_MAXREDIRS => 10, + CURLOPT_TIMEOUT => 30, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2TLS, + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_POSTFIELDS => $dataString, + CURLOPT_HTTPHEADER => $headers, + ] +); + +$response = curl_exec($curl); +curl_close($curl); +echo $response; +``` + +#### GET - Retrieve all articles from the "Uncategorized" Category + +```php +$categoryId = 2; // Joomla's default "Uncategorized" Category + + +// HTTP request headers +$headers = [ +'Accept: application/vnd.api+json', +'Content-Type: application/json', +sprintf('X-Joomla-Token: %s', trim($token)), +]; + +curl_setopt_array($curl, [ + CURLOPT_URL => sprintf('%s/content/articles?filter[category]=%d',$url,$categoryId), + CURLOPT_RETURNTRANSFER => true, + CURLOPT_ENCODING => 'utf-8', + CURLOPT_MAXREDIRS => 10, + CURLOPT_TIMEOUT => 30, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2TLS, + CURLOPT_CUSTOMREQUEST => 'GET', + CURLOPT_HTTPHEADER => $headers, + ] +); + +$response = curl_exec($curl); +curl_close($curl); +echo $response; +``` + +#### GET - Retrieve one specific Article + +```php +$articleId = 1; // The Article ID of a specific Article + + +// HTTP request headers +$headers = [ +'Accept: application/vnd.api+json', +'Content-Type: application/json', +sprintf('X-Joomla-Token: %s', trim($token)), +]; +curl_setopt_array($curl, [ + CURLOPT_URL => sprintf('%s/content/articles/%d',$url,$articleId), + CURLOPT_RETURNTRANSFER => true, + CURLOPT_ENCODING => 'utf-8', + CURLOPT_MAXREDIRS => 10, + CURLOPT_TIMEOUT => 30, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2TLS, + CURLOPT_CUSTOMREQUEST => 'GET', + CURLOPT_HTTPHEADER => $headers, + ] +); + +$response = curl_exec($curl); +curl_close($curl); +echo $response; +``` + +#### PATCH - Modify a specific Article + +```php +$articleId = 1; // The Article ID of a specific Article + + +$data = [ +'id' => $articleId, +'title' => 'How to add an article via the Joomla 4 API?', +'introtext' => 'When using PATCH, articletext MUST be split into two parts or use at least just introtext in order to work properly', +'fulltext' => 'MORE CONTENT if you wish', +]; + +$dataString = json_encode($data); + +// HTTP request headers +$headers = [ +'Accept: application/vnd.api+json', +'Content-Type: application/json', +'Content-Length: ' . mb_strlen($dataString), +sprintf('X-Joomla-Token: %s', trim($token)), +]; + +curl_setopt_array($curl, [ + CURLOPT_URL => sprintf('%s/content/articles/%d',$url,$articleId), + CURLOPT_RETURNTRANSFER => true, + CURLOPT_ENCODING => 'utf-8', + CURLOPT_MAXREDIRS => 10, + CURLOPT_TIMEOUT => 30, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2TLS, + CURLOPT_CUSTOMREQUEST => 'PATCH', + CURLOPT_POSTFIELDS => $dataString, + CURLOPT_HTTPHEADER => $headers, + ] +); + +$response = curl_exec($curl); +curl_close($curl); +echo $response; +``` + +#### DELETE - Remove a specific Article + +```php +$articleId = 1; // The Article ID of a specific Article + + +// HTTP request headers +$headers = [ +'Accept: application/vnd.api+json', +'Content-Type: application/json', +sprintf('X-Joomla-Token: %s', trim($token)), +]; + +curl_setopt_array($curl, [ + CURLOPT_URL => sprintf('%s/content/articles/%d',$url,$articleId), + CURLOPT_RETURNTRANSFER => true, + CURLOPT_ENCODING => 'utf-8', + CURLOPT_MAXREDIRS => 10, + CURLOPT_TIMEOUT => 30, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2TLS, + CURLOPT_CUSTOMREQUEST => 'DELETE', + CURLOPT_HTTPHEADER => $headers, + ] +); + +$response = curl_exec($curl); +curl_close($curl); +echo $response; +``` diff --git a/versioned_docs/version-5.2/general-concepts/workflows.md b/versioned_docs/version-5.2/general-concepts/workflows.md new file mode 100644 index 00000000..a8a298bd --- /dev/null +++ b/versioned_docs/version-5.2/general-concepts/workflows.md @@ -0,0 +1,3 @@ +Workflows +======================= +This is the content for Workflows \ No newline at end of file diff --git a/versioned_docs/version-5.2/get-started/codestyle.md b/versioned_docs/version-5.2/get-started/codestyle.md new file mode 100644 index 00000000..bc7780c3 --- /dev/null +++ b/versioned_docs/version-5.2/get-started/codestyle.md @@ -0,0 +1,37 @@ +--- +sidebar_position: 6 +--- +Coding Style Guide +======================= + +Since Joomla version 4.2, Joomla uses the [PSR-12](https://www.php-fig.org/psr/psr-12/) coding standard. You can enable this coding standard in your IDE and get hints if you're not following the coding standard or use an auto fix, too. +We recommend that you follow this standard when developing your own extensions to stay compatible with core and to ensure your code will hopefully work with future versions. + +## Install code style checker +:::caution TODO +Copy from https://docs.joomla.org/Joomla_CodeSniffer and update to the new version +::: + +## Use integrated checker +If you download the full developer version from GitHub of Joomla (not the downloadable installation zip package), you will find a so called "code sniffer", to check for coding standard violations, and a "code fixer" to fix most (but, sometimes, not all) of them. + +To run the code sniffer/fixer you need to start a terminal, navigate to your Joomla root folder (the folder where your Joomla is installed) and run one of the following commands (don't forget the "."): + +### Checking for code style violations + +```./libraries/vendor/bin/phpcs --extensions=php -p --standard=ruleset.xml .``` + +This will run the code style check for the whole Joomla! installation, including your extensions, when installed in Joomla! + +### Fixing code style violations + +```./libraries/vendor/bin/phpcbf --extensions=php -p --standard=ruleset.xml .``` + +This will run the code style fixer for the whole Joomla installation, including your extension. The fixer tries to fix all violation, but sometimes it can't fix all. So it's recommended to run the checker (see above) afterwards and fix the last issues manually. + + +:::caution TODO + +This page is unfinished, please use the **Edit this Page** link at the bottom of this page to help make it more useful. + +::: diff --git a/versioned_docs/version-5.2/get-started/composer.md b/versioned_docs/version-5.2/get-started/composer.md new file mode 100644 index 00000000..8dbcff38 --- /dev/null +++ b/versioned_docs/version-5.2/get-started/composer.md @@ -0,0 +1,13 @@ +--- +sidebar_position: 4 +--- +Composer +======================= +Note that Composer is needed only if you're developing for code for the core Joomla project. + +This is the content for Composer +:::caution TODO + +This page is unfinished, please use the **Edit this Page** link at the bottom of this page to help make it more useful. + +::: diff --git a/versioned_docs/version-5.2/get-started/git/git-basics.md b/versioned_docs/version-5.2/get-started/git/git-basics.md new file mode 100644 index 00000000..2e5e22a5 --- /dev/null +++ b/versioned_docs/version-5.2/get-started/git/git-basics.md @@ -0,0 +1,95 @@ +--- +sidebar_position: 1 +title: "Git Basics" +--- + +## Selected Git Features + +This brief introduction to Git uses the command line to illustrate some of its features. If you want to try it out, download and install Git on your laptop or workstation: [git-scm.com](https://git-scm.com/). + +### Repositories + +A repository is a place where all of the changes in a project are stored. In the simplest case this is a folder named .git in the same folder as the project source files. To get started, create an empty folder, make it the current directory with `cd` and then try this command: + +``` +git init . +``` + +which should result in confirmation that an empty Git repository has been created in a hidden folder named .git (folders starting with a period(.) are usually left out of listings so you don't see them, hence hidden). + +You may also use a remote repository on another computer, which is where GitHub comes in. That will be covered in separate articles. + +Create some content with a text editor and save it in the source folder, the one containing the .git repo (the word repo is often used as a short form of repository). In this article this markdown document, aptly named git.md, is used as an example document. Confirm what you have with a list command: + +``` +ls -al +total 8 +drwxr-xr-x 4 ceford staff 128 26 Aug 07:02 . +drwxr-xr-x+ 99 ceford staff 3168 26 Aug 06:31 .. +drwxr-xr-x 9 ceford staff 288 26 Aug 07:02 .git +-rw-r--r-- 1 ceford staff 1689 26 Aug 07:10 git.md +``` + +You can look at the contents of the .git folder if you wish but as a rule you should not make any changes there yourself. Let the git commands do the work. You can delete the .git folder if you wish without affecting the source text but you will lose any history of changes. + +### Staging + +The next step is to issue a command to add a source file to the index of files that git keeps track of: + +``` +git add git.md +``` + +There is no response to that command - git just does it. + +### Commit + +The commit command tells git to record all changes made to the source files so far: + +``` +git commit -m "Text entered as far as Commit" +``` + +To which the response is: + +``` +[master (root-commit) 913815c] Text entered as far as Commit + 1 file changed, 45 insertions(+) + create mode 100644 git.md +``` + +That strange number, 913815c, is the commit **id** that allows git to keep track of that particular point in history. The text in quotes is the commit message - it should be a short informative description of the changes made in that commit. + +### Branch + +Suppose you want to try a new feature but you are not sure whether you will use it. Or, you are working on a collaborative project and you want to change something contributed by others. This is where branching comes in. You make a branch of your repo, checkout the branch, make your changes and then decide what to do. Try this: + +``` +git branch --list +* master +``` + +The list command indicates that this repo has only one branch, named master. Try these commands: + +``` +git branch myfix +git checkout myfix +git branch --list + master +* myfix +``` +The list shows that there are now two branches and the * indicates that the myfix branch is checked out as the current branch. I can now go ahead and make changes to the myfix branch without affecting the existing content of the master branch. If I decide to use the changes I need to commit them and then either merge the myfix branch into my master branch or ask my collaborator to merge my myfix branch into his master branch. + +When the branch is finished with, by being merged or abandoned, it can be deleted. + +## Full Documentation + +Git has many more commands and options. Mostly you don't need to know them because your IDE handles them for you with Menu items. If you want to look up what a menu item does try this source: + +[Git Documentation](https://git-scm.com/doc) + +If you have been experimenting, remember you can delete the repo (.git) and you will be left with your source files as you see them in your editor. + +## Using an IDE + +One final point: your chosen IDE will not put any IDE specific content in your git repo. It follows that you can change your IDE and expect it to work equally well with your existing repo. diff --git a/versioned_docs/version-5.2/get-started/git/git-manual-pull-checks-passed.png b/versioned_docs/version-5.2/get-started/git/git-manual-pull-checks-passed.png new file mode 100644 index 00000000..364c52a0 Binary files /dev/null and b/versioned_docs/version-5.2/get-started/git/git-manual-pull-checks-passed.png differ diff --git a/versioned_docs/version-5.2/get-started/git/git-manual-vsc-sc.png b/versioned_docs/version-5.2/get-started/git/git-manual-vsc-sc.png new file mode 100644 index 00000000..27cb5326 Binary files /dev/null and b/versioned_docs/version-5.2/get-started/git/git-manual-vsc-sc.png differ diff --git a/versioned_docs/version-5.2/get-started/git/github-joomla-cms.md b/versioned_docs/version-5.2/get-started/git/github-joomla-cms.md new file mode 100644 index 00000000..878bdbbe --- /dev/null +++ b/versioned_docs/version-5.2/get-started/git/github-joomla-cms.md @@ -0,0 +1,166 @@ +--- +sidebar_position: 4 +title: "GitHub Example 2: Joomla! CMS" +--- + +:::caution TODO + +This page is unfinished, but Cliff is working on it! + +::: + +## Getting Started + +If you would like to contribute to Joomla! core code you will need a [GitHub](https://github.com/) account. It is free and takes moments to set up. You will also need a working [LMWX]AMP stack on your local laptop or workstation. You will almost certainly need an IDE too! + +## Fork joomla/joomla-cms on GitHub + +Log in to your GitHub account and type joomla/joomla-cms in the `Search or Jump to...` box at the top left. You need to be in the original joomla-cms repo. + +Click the `Fork` button at the top right of the screen. This will bring up a form asking you to confirm details of the fork you want to make. It is usually sufficient to select the green `Create fork` button. + +That will make a complete copy of the joomla-cms repo as it exists at this time in your own account. If someone updates the original later you can use the `Sync fork` button to bring your repo up to date. + +## Clone your Github fork locally + +The local Apache web server uses a specific folder for individual web sites. For example, on a Mac it may be /Users/username/Sites. You may have many sites for testing and developing different projects, each in a separate subfolder. The clone process will create a folder within your current folder so first open a terminal window and switch to your sites folder: + +``` +cd ~/Sites +``` + +Then type in the clone command: + +``` +git clone https://github.com/yourusername/joomla-cms.git +``` + +This may take a long time! Switch to the joomla-cms folder and list what is in it: + +``` +cd joomla-cms +ls -al +total 2192 +drwxr-xr-x 44 ceford staff 1408 26 Aug 17:28 . +drwxr-xr-x 107 ceford staff 3424 26 Aug 17:26 .. +-rw-r--r-- 1 ceford staff 2174 26 Aug 17:28 .appveyor.yml +-rw-r--r-- 1 ceford staff 13689 26 Aug 17:28 .drone.yml +-rw-r--r-- 1 ceford staff 388 26 Aug 17:28 .editorconfig +drwxr-xr-x 12 ceford staff 384 26 Aug 17:28 .git +drwxr-xr-x 11 ceford staff 352 26 Aug 17:28 .github +-rw-r--r-- 1 ceford staff 1765 26 Aug 17:28 .gitignore +-rw-r--r-- 1 ceford staff 4076 26 Aug 17:28 .php-cs-fixer.dist.php +-rw-r--r-- 1 ceford staff 6748 26 Aug 17:28 CODE_OF_CONDUCT.md +-rw-r--r-- 1 ceford staff 18092 26 Aug 17:28 LICENSE.txt +-rw-r--r-- 1 ceford staff 4469 26 Aug 17:28 README.md +-rw-r--r-- 1 ceford staff 4942 26 Aug 17:28 README.txt +drwxr-xr-x 12 ceford staff 384 26 Aug 17:28 administrator +drwxr-xr-x 6 ceford staff 192 26 Aug 17:28 api +drwxr-xr-x 20 ceford staff 640 26 Aug 17:28 build +-rw-r--r-- 1 ceford staff 6422 26 Aug 17:28 build.xml +drwxr-xr-x 3 ceford staff 96 26 Aug 17:28 cache +drwxr-xr-x 4 ceford staff 128 26 Aug 17:28 cli +-rw-r--r-- 1 ceford staff 461 26 Aug 17:28 codeception.yml +drwxr-xr-x 19 ceford staff 608 26 Aug 17:28 components +-rw-r--r-- 1 ceford staff 3867 26 Aug 17:28 composer.json +-rw-r--r-- 1 ceford staff 419222 26 Aug 17:28 composer.lock +-rw-r--r-- 1 ceford staff 6858 26 Aug 17:28 htaccess.txt +drwxr-xr-x 8 ceford staff 256 26 Aug 17:28 images +drwxr-xr-x 6 ceford staff 192 26 Aug 17:28 includes +-rw-r--r-- 1 ceford staff 1068 26 Aug 17:28 index.php +drwxr-xr-x 16 ceford staff 512 26 Aug 17:28 installation +drwxr-xr-x 5 ceford staff 160 26 Aug 17:28 language +drwxr-xr-x 7 ceford staff 224 26 Aug 17:28 layouts +drwxr-xr-x 16 ceford staff 512 26 Aug 17:28 libraries +drwxr-xr-x 27 ceford staff 864 26 Aug 17:28 modules +-rw-r--r-- 1 ceford staff 538644 26 Aug 17:28 package-lock.json +-rw-r--r-- 1 ceford staff 3983 26 Aug 17:28 package.json +-rw-r--r-- 1 ceford staff 639 26 Aug 17:28 phpunit-pgsql.xml.dist +-rw-r--r-- 1 ceford staff 642 26 Aug 17:28 phpunit.xml.dist +drwxr-xr-x 26 ceford staff 832 26 Aug 17:28 plugins +-rw-r--r-- 1 ceford staff 422 26 Aug 17:28 renovate.json +-rw-r--r-- 1 ceford staff 764 26 Aug 17:28 robots.txt.dist +-rw-r--r-- 1 ceford staff 26187 26 Aug 17:28 ruleset.xml +drwxr-xr-x 5 ceford staff 160 26 Aug 17:28 templates +drwxr-xr-x 8 ceford staff 256 26 Aug 17:28 tests +drwxr-xr-x 3 ceford staff 96 26 Aug 17:28 tmp +-rw-r--r-- 1 ceford staff 2974 26 Aug 17:28 web.config.txt +``` + +## Build a working Joomla site + +The downloaded development branch needs some extra steps to create a working Joomla site. This from the README.md file: + +``` +composer install +npm ci +``` + +Again, it will take a while and you will see flash past the commands to compile the javascript and css files. When done you can point your browser at localhost/joomla-cms and go through the normal install process. + +The site should now work as any normal Joomla site. + +## Making changes + +If you would like to contribute to the Joomla CMS you need to progress through the following stages: + +- **Create and Checkout a branch** in your local repo. This is very important! It will contain a record of the changes you propose to make to the original. +- **Make and Test Changes** and don't forget to check that your code conforms to the Joomla coding standards. +- **Commit and Push** your changes to your remote GitHub repo. +- **Make a Pull request** in your remote repo to ask for your branch to be merged into the main branch. + +### Create and Checkout a branch + +In the terminal window, make sure you are in the root of your site, then: + +* git branch mypatch1 +* git checkout mypatch1 + +where mypatch1 should be some short distinctive piece of text that allows you and others to distinguish between various branches. For example, it could start with your initials and finish with a succinct description of its main purpose, for example `cffixabc`. + +### Make Coding Changes + +This can be as trivial as correcting a language string or as complex as a major new feature. Or you might like to tackle a problem reported in the Issue Tracker. You can always ask for advice or comment there before plunging in to coding. + +## Local Testing + +It is essential that you test your proposed changes locally before making a pull request. You will have been checking your local joomla site to see that your code appears to work properly. However, if your code involves changes to javascript or css files you will need to recompile your sources. So go back to your terminal window and enter: + +``` +npm ci +``` +If you site works without error you are ready to make a pull request. + +### Commit and Push + +Easy with an IDE. In VSCode: +- select the `+` button in the Changes list to commit the changes to the local repository. +- Select the Source Control `...` button followed by Pull, Push / Push To... / and then select your own remote repo to push the changes from your local repo to your remote repo. + +### Make a pull request + +Login to your account on GitHub and select your own joomla-cms repo. In the `Code` section select the branch you wish to commit from the `Switch branches` drop-down list (marked with the branch icon). Click the `Contribute` button and then the `Open Pull Request` button. + +After making a pull request some automatic checks are carried out. All being well after a few minutes you will see this result: + +ToDo + +### Remote Testing + +Your pull request will go into a testing phase where the Joomla developers can examine your code and test it to see if it works and whether it stops anything else from working. Even if it works, others may regard the proposed change or method of implementation as inappropriate and decline to merge your pull request into the main code. Do not take umbrage! It happens all the time, even to the experts. Just move on to something else. + +## Github workflow + +In git you may have multiple remote repositories. You defined one remote repository when you cloned your own remote repo. You may also add the original repo to your list of remote repos. Example: + +``` +git remote -v show +Manual https://github.com/ceford/Manual (fetch) +Manual https://github.com/ceford/Manual (push) +origin https://github.com/joomla/Manual.git (fetch) +origin https://github.com/joomla/Manual.git (push) +``` + +This allows you keep your own fork and clone up to date from your local computer. You just need to pull and merge the original source into your local clone and then push your local clone to your remote fork. The following diagram illustrates the process: + +Github work flow joomla.png diff --git a/versioned_docs/version-5.2/get-started/git/github-manual.md b/versioned_docs/version-5.2/get-started/git/github-manual.md new file mode 100644 index 00000000..4e7cbe7b --- /dev/null +++ b/versioned_docs/version-5.2/get-started/git/github-manual.md @@ -0,0 +1,188 @@ +--- +sidebar_position: 3 +title: "GitHub Example 1: This Manual" +--- + +## Getting Started + +GitHub is a web site that offers repository hosting. Private repos are charged a commercial fee but public repos, such as Joomla, are hosted free of charge. As the name implies, GitHub is based on using Git for repo management. If you want to contribute to Joomla development you need a GitHub account. It only takes a few moments to create one so Give it a try: [GitHub](https://github.com/). You just need your email address to start. You could try it out by contributing content for this documentation. + +## Fork joomla/Manual on GitHub + +Log in to your GitHub account and type joomla/Manual in the `Search or Jump to...` box at the top left. You need to be in the original Manual repo. + +Click the `Fork` button at the top right of the screen. This will bring up a form asking you to confirm details of the fork you want to make. It is usually sufficient to select the green `Create fork` button. + +That will make a complete copy of the Manual repo as it exists at this time in your own account. If someone updates the original later you can use the `Sync fork` button to bring your repo up to date. + +## Clone your Github fork locally + +For local testing of any web site content you will need to install Apache, MySQL, PHP and phpMyAdmin on your laptop or desktop computer. This collection of separate software items is often referred to as a stack. You may see the words LAMP, MAMP, WAMP or XAMP - the first character indicating Linux, Mac, Windows, or All three. Stack installation is covered elsewhere. + +Your local Apache web server uses a specific folder for individual web sites. For example, on a Mac it may be /Users/username/Sites. You may have many sites for testing and developing different projects, each in a separate subfolder. The clone process will create a folder within your current folder so first open a terminal window and switch to your sites folder: + +``` +cd ~/Sites +``` + +Then type in the clone command: + +``` +git clone https://github.com/yourusername/Manual.git + +Cloning into 'Manual'... +remote: Enumerating objects: 833, done. +remote: Counting objects: 100% (65/65), done. +remote: Compressing objects: 100% (39/39), done. +remote: Total 833 (delta 27), reused 55 (delta 24), pack-reused 768 +Receiving objects: 100% (833/833), 1.18 MiB | 3.04 MiB/s, done. +Resolving deltas: 100% (436/436), done. +``` + +Switch to the Manual folder and list what is in it: + +``` +cd Manual +ls -al +total 1824 +drwxr-xr-x 18 ceford staff 576 26 Aug 12:36 . +drwxr-xr-x 107 ceford staff 3424 26 Aug 12:33 .. +-rw-r--r-- 1 ceford staff 1463 26 Aug 12:36 .drone.yml +drwxr-xr-x 12 ceford staff 384 26 Aug 12:36 .git +-rw-r--r-- 1 ceford staff 390 26 Aug 12:36 .gitignore +-rw-r--r-- 1 ceford staff 1445 26 Aug 12:36 README.md +-rw-r--r-- 1 ceford staff 89 26 Aug 12:36 babel.config.js +drwxr-xr-x 12 ceford staff 384 26 Aug 12:36 docs +-rw-r--r-- 1 ceford staff 5062 26 Aug 12:36 docusaurus.config.js +-rw-r--r-- 1 ceford staff 883852 26 Aug 12:36 package-lock.json +-rw-r--r-- 1 ceford staff 1104 26 Aug 12:36 package.json +-rw-r--r-- 1 ceford staff 357 26 Aug 12:36 renovate.json +-rw-r--r-- 1 ceford staff 725 26 Aug 12:36 sidebars.js +drwxr-xr-x 4 ceford staff 128 26 Aug 12:36 src +drwxr-xr-x 3 ceford staff 96 26 Aug 12:36 static +-rw-r--r-- 1 ceford staff 458 26 Aug 12:36 test.sh +-rw-r--r-- 1 ceford staff 4 26 Aug 12:36 versions.json +-rw-r--r-- 1 ceford staff 59 26 Aug 12:36 versionsArchived.json +``` + +That is your copy of the Joomla Programmers Manual. It is a Docusaurus application that needs Node.js installed to run. That is covered elsewhere. To get going you should read the README.md file, where you will find the following commands: + +``` +npm install + +npm run start +``` + +And bingo, your browser will spring to life with your local copy of the Joomla! Programmers Documentation. + +If you go back to your terminal, open a new window and type `git branch --list` you will see there is only one branch named 'main'. This is something to keep in mind. A local repo created with git will have `master` as the name of the primary branch whereas a repo created on GitHub may have a different primary branch name. + +## Bringing up to date + +There are several different ways to keep your repo up to date with the original repo. This is just one: + +* In your own GitHub repo, select the `Sync fork` button and then the `Update branch` button. The latter will only be active if the branch is not up to date. +* In your local terminal window type **git pull** and wait for a message (Already up to date). + +## Making changes + +If you would like to contribute to the Joomla Programmers Manual you need to progress through the following stages: + +- **Create and Checkout a branch** in your local repo. This is very important! It will contain a record of the changes you propose to make to the original. +- **Make Changes** by adding or changing folders or files, and adding images. +- **Commit** your changes to your local repo. +- **Push** your changes from your local repo to your remote GitHub repo. +- **Make a Pull request** in your remote repo to ask for your branch to be **merged** into the main branch. + +### Create and Checkout a branch + +In the terminal window, make sure you are in the root of your site, then: + +* git branch ceffixgit +* git checkout ceffixgit + +where ceffixgit is some short distinctive piece of text that allows you and others to distinguish between various branches. For example, it could start with your initials and finish with a succinct description of its main purpose: `ceffixgit`. + +You may wish to list the branches in your repo: + +``` +git branch --list +* ceffixgit + main +``` +That is a reminder that the main branch is named `main` rather than `master`. + +## Time for an IDE? + +During preparation of this article I created a folder, moved an article into that folder and created two new articles. Remembering all of this and updating the repo from the command line is an error prone chore. So I started Visual Studio Code and used File / Open Folder to open my local ~/Sites/Manual folder. The Source Control icon at the left shows me where I have made changes and the state of those changes. + +![VSCode Source Control](git-manual-vsc-sc.png) + +The moved document shows up marked with a red `D` for Deleted. The added documents show up with a green `U` for Unstaged. In each case I can click the adjacent `+` sign to stage the file to make it ready to commit. As each `+` is clicked it moves from a `Changes ` list into a `Staged Changes` list. + +## Local Testing + +It is essential that you test your proposed changes locally before making a pull request. You will have been checking your local docusaurus site to see that it appears to work properly. However, you also need to check the build stage. This is when static html pages are generated and it can reveal all sorts of additional problems such as broken links or invalid source content. So go back to your terminal window and enter: + +``` +$ npm run build +``` +If it works without error you are ready to make a pull request. + +### Commit and Push + +Easy with an IDE. In VSCode: +- Select the Source Control icon at the left. +- Add a Commit message: a very brief statement of what changed in this commit. +- Either select the `+` button in the Changes list to stage the changes. +- Or select the `Commit` button to commit the changes to the local repository. +- Select the Source Control `...` button followed by Pull, Push / Push To... / and then select your own remote repo to push the changes from your local repo to your remote repo. + +### Make a Pull Request + +Login to your account on GitHub and select your own Manual repo. In the `Code` section select the branch you wish to commit from the `Switch branches` drop-down list (marked with the branch icon). Click the `Contribute` button and then the `Open Pull Request` button. + +After making a pull request some automatic checks are carried out. All being well after a few minutes you will see this result: + +![Pull test result](git-manual-pull-checks-passed.png) + +You can then test the pull request on the live site with the following url: + +``` +http://pr-[prnumber].manual.joomlacode.org +``` + +Where the `[prnumber]` can be obtained from the Pull Requests list (just a number - no brackets). + +### After commit + +If all seems in order, the team who maintain the documentation repo will **commit** your changes to become incorporated into the `main` branch of the original repo. At that point you can delete your branch. From the command line first switch to your local main branch: + +``` +git checkout main +``` + +If you have the folder you are working on open in an IDE you will notice that all of the changes you made will seem to have disappeared. That is because git has replaced the source code stored in the previous branch with the source code stored in the main branch. + +You can delete the branch that has been committed now or you can leave it until later. Don't make any more changes to it! + +``` +git branch --delete ceffixgit +``` + +## Keeping up to date + +Tomorrow, next week, next month, you may want to contribute some more documentation. But in the meantime the original `main` branch of the documentation may have changed with contributions from others. Those contributions may even have changed your last contribution. So before starting anything new you need to bring your local copy of the original repo up to date. + +First go to your GitHub account and open your fork of this Manual: username/Manual. Then click the `Sync fork` button. That should bring your fork up to date. + +Then in your terminal window, change to the folder containing your local clone of your remote fork and issue the git pull command: + + ``` + cd ~/Sites/Manual + git pull + ``` + + That is exactly the same as **Bringing up to date** above. + + You are now ready for your next contribution, for which you need a new branch. diff --git a/versioned_docs/version-5.2/get-started/git/index.md b/versioned_docs/version-5.2/get-started/git/index.md new file mode 100644 index 00000000..c43623f3 --- /dev/null +++ b/versioned_docs/version-5.2/get-started/git/index.md @@ -0,0 +1,175 @@ +--- +sidebar_position: 3 +--- + +Git +=== + +From Wikipedia: [Git](https://en.wikipedia.org/wiki/Git) is free and open source software for distributed version control: tracking changes in any set of files, usually used for coordinating work among programmers collaboratively developing source code during software development. Its goals include speed, data integrity, and support for distributed, non-linear workflows (thousands of parallel branches running on different systems). + +Git is available for all modern platforms. It is mostly associated with managing code such as PHP, Java or Python but it can be used to manage any line-based text such as this documentation written in Markdown format. Git can be used from the command line although most users rely on an Integrated Development Environment (IDE) to compose and run git commands. + +To learn more, start with the Git Basics page and then move on to the cited Github based examples. + +## References + +The following articles are from docs.joomla.org: + +- [Git Branching Quickstart](https://docs.joomla.org/Git_branching_quickstart) +- [Working with git and github](https://docs.joomla.org/Working_with_git_and_github) +- [Git for Testers and Trackers](https://docs.joomla.org/Git_for_Testers_and_Trackers) +- [Setting up Eclipse PDT 2020 and Git for Pulls](https://docs.joomla.org/Setting_up_Eclipse_PDT_2020_and_Git_for_Pulls) +- [My first pull request to Joomla! on Github](https://docs.joomla.org/My_first_pull_request_to_Joomla!_on_Github) + +These references may be deleted when the new documentation is considered _mature_. + +This document provides a quick step by step procedure using command line on how to get a git branch and quickly run a setup. + +## Step 1: Create a fork repo + +1. Create a GitHub account (https://www.github.com - "Sign Up for free") +2. Create a fork of the Joomla repository you want to modify. This can be done by clicking on a fork button. +3. After Clicking on fork. Give name to your forked repo and click on create. +4. Make sure you are logged into your GitHub account: + 1. Go to https://github.com/joomla/joomla-cms/ (Joomla! CMS) or https://github.com/joomla-framework/ (Joomla! Framework) + 2. Click on the "Fork" button on the top right and wait while the process ends. + 3. You now have a fork of the Joomla repo on GitHub under ...github.com/yourusername/joomla-.... + +## Step 2: Create a working copy + +You can create a single working copy for your projects or multiple working copies. In general Git branching allows you to work on multiple project copies in a single working place. If you want to work on concurrent projects you may wish to have multiple working copies. You can work out the flow that works best for you. Complete these instructions per working copy: + +1. Go to your fork on GitHub (e.g. http://github.com/YourName/joomla-cms) +2. By default a "Read, Write Access" link should be selected. If you have set up SSH keys, then use this option. If you haven't, then HTTPS should be selected. Copy the link by highlighting or selecting the "copy to clipboard" option. +3. Now open your terminal on your local machine (Windows: GIT BASH link; Mac: Terminal; Linux: Your favourite terminal emulator) +4. And follow the below commands: + +```bash + +git + +``` + +Here path to target directory is optional. The recommended way is to go to your target folder and open your terminal in that folder and then simply run the above command without providing the path to the target directory. It should look something like this if you are providing a path: + +```bash + +git clone https://github.com/pasamio/joomla-cms.git /Users/pasamio/joomla-cms + +``` + +And if you are in your target directory then you your command should look like this: + +```bash + +git clone https://github.com/pasamio/joomla-cms.git + +``` + +**Note:** Git will automatically create the path to the directory if it doesn't exist. 5. Now go to your cloned repo folder: + +```bash +cd +``` + +For instance: + +```bash +cd /Users/pasamio/joomla-cms +``` + +6. Add a remote origin for the Joomla repository for this fork. Go to https://github.com/joomla/joomla-cms/ and copy the "Git Read-Only" link. +7. You can add remote to your repo by pasting the following commands: + +```bash + +git remote add joomla + +``` + +It should look something like this: + +```bash + +git remote add joomla git://github.com/joomla/joomla-cms.git + +``` + +Congratulations! At this point you've cloned your repository (it will be the remote known as 'origin') and add a remote for the Joomla Project repository you're working on (as 'joomla'). + +### Step 3: Creating a new branch + +Each time you start working on a new feature, bug fix, or concept, We recommend you to start with a new branch. Branching and merging in Git is easier than in Subversion with many conflicts around the same changes being made in two places handled automatically. Each branch can contain a particular project that you are working on and you can easily switch between branches in the same working copy. Because Git is designed to be distributed, you can commit changes to work in a branch prior to switch branches without having to push this to the wider world. + +1. Before creating a new branch, make sure you have latest changes. This can be done by making a pull request: + +```bash + +git pull origin + +``` + +2. From here any updates will have been downloaded from all repositories, most importantly Joomla. +3. Create and checkout a new branch with the following: + +```bash + +git checkout -b joomla/master + +``` + +4. Now you are in your new branch. Most probably the name of your new branch will be appear in square brackets in your ternminal. +5. Now you are ready to make changes to the code. +6. Once you have made required changes its time to stage your code. Staging is an essential process before pushing your code to the repo. Staging simply means that your code is ready to merge with the main source code. +7. You can make commit or stage your code by using the following commands: + +```bash + +git add . +``` + +```bash +git commit -m "your message/ a short description of changes you have made" + +``` + +Here add . means add all files in which you have made changes. 8. Now you are ready to push your code: + +```bash + +git push -u origin + +``` + +This may ask for your GitHub username and password if you are using the HTTP protocol. If you are using the SSH protocol it may ask you for the passphrase for your SSH key. The "-u" option is used to mark this as the "upstream" version and will track against this branch. This means in future you can "git push" and "git pull" to receive updates from this remote and branch automatically (if you're working on your own, you'll likely only be doing a 'git push'). + +Now you've created a new branch, made some chanegs and pushed it your new branch in your forked repo. Now its time to merge it with your master branch. + +## Step 4: Merging with master + +After a while it will become necessary to merge down changes from the upstream repository. This may be because those changes conflict with other changes in the repository (making a pull request "unmergeable"), because you need/want updates from the repository to continue working or just to keep the delta of changes small between your commits. + +You have two major options. The first is to use a simple merge. This will attempt to pick up the changes from the remote repository and merge them locally automatically. This may result in a conflict with your work which you will be required to merge manually (just like what would happen with Subversion if there is a conflict). + +You can merge either by doing an explicit "git merge" or by doing a "git pull". Doing a "git pull" is like doing a "git fetch" followed by a "git merge" and will ensure you're merging the latest changes from the remote repository: + +```bash + +git merge joomla master + +``` + +This will pull down the latest changes from the repository and merge them. You may get a notice that there is a conflict you need to resolve. Once you've resolved the conflict, you will need to do a commit to mark those changes. + +OR you can go to your master branch and make a pull request there. + +```bash +git pull origin + +``` + +:::note TODO + +This section is missing, please use the **Edit this Page** link at the bottom of this page to add this section. + +::: diff --git a/versioned_docs/version-5.2/get-started/ide/eclipse.md b/versioned_docs/version-5.2/get-started/ide/eclipse.md new file mode 100644 index 00000000..027de823 --- /dev/null +++ b/versioned_docs/version-5.2/get-started/ide/eclipse.md @@ -0,0 +1,83 @@ +--- +title: Eclipse +sidebar_position: 3 +--- +Eclipse +======= + +This section explains how to install Eclipse together with Xdebug for developing with Joomla. As these products are both open source projects this option is free of charge. There are videos available online which show you how to install these products, but some of the key steps are explained below. It's assumed you have got an environment such as [WAMP](https://www.wampserver.com/) or [XAMPP](https://www.apachefriends.org/) running on your local machine, and that you're familiar with how to use it. + +## Install Xdebug +Go to [xdebug.org](https://xdebug.org/), click on the Install menu item and follow the instructions for downloading and installing xdebug. + +For example, for Windows using WAMP this will involve copying a .dll file down, moving it into the `/ext` directory below your php version folder, and renaming the file `php_xdebug.dll`. + +If you have several versions of PHP on your machine then you'll need to copy this .dll file into each of the `/ext` subdirectories. + +## Configure PHP +PHP is configured via the `php.ini` file, but WAMP for example uses a file `phpForApache.ini` to configure PHP when its handling web requests. Since you may be wanting to debug both: +- Joomla site and administrator applications (which may use `phpForApache.ini`) and +- Joomla command line applications (which use `php.ini`) + +you should ensure that at least the following key lines of configuration are present in these `.ini` files. (And if you have multiple versions of PHP then the `.ini` files for each version must be configured): + +```php +[DEBUG] +zend_extension="xdebug" +xdebug.mode=debug,develop +xdebug.log_level=0 +``` + +See the Xdebug documentation which describes all of the Xdebug settings to confirm what you specifically need. + +You need the `xdebug.mode` to include `debug` to enable step debugging of your program, and setting it to include `develop` provides an enhanced `var_dump` function, amongst other things. + +The `xdebug.log_level=0` means that only critical problems are logged in the log file. On WAMP if your xdebug log file gets too big then it will cause problems when you want to switch the version of the WAMP database software (mysql). + +## Check Xdebug is working +Write a small PHP script which includes the line: + +```php +var_dump(xdebug_get_code_coverage()); +``` + +Then run this script from the command line and/or from the webserver. If xdebug is correctly running then you'll output an empty array. If not then it will raise an error because it doesn't recognise the `xdebug_get_code_coverage` function. + +## Install Eclipse +If you don't have an existing version of Eclipse installed then you can download a clean version of Eclipse for PHP from [Eclipse PHP Development Tools](https://eclipse.dev/pdt/). If you have an existing version of Eclipse then you can click on Help / Install New Software and then Work with `http://download.eclipse.org/tools/pdt/updates/latest` to obtain the latest PDT software. + +## Configure Eclipse to use Xdebug +Within Eclipse click on Window / Preferences, and then under PHP click on Installed PHPs. Here you should see a list of your PHP versions and the associated debugger. + +Select one of these and click on Edit. In the window which appears click on the Debugger tab. You need to have: +- Debugger - Xdebug should be selected (if you can't select it then it means it's not installed or not properly configured in your php.ini file) +- Port - set to 9003 + +When Xdebug moved from version 2.5 to 3.0 a number of the settings were changed, and the default debugger port was changed from 9000 to 9003. However, you may still find online documentation which relates to the old settings and the old port 9000. + +Click on PHP / Debug and you should see Xdebug set as the Debugger. You can also check the "Break at First Line" checkbox if you want Eclipse to break at the first line of your PHP script by default. + +It's also worth checking in Window / Preferences under General / Web Browser that you've selected to use an external web browser, and your preferred browser. + +## Import a Joomla installation for debugging +Within Eclipse click on File / New - PHP Project. Select "Create project at existing location" and Browse to select your top-level Joomla directory. Give your project a memorable name and click Finish. This will import your Joomla installation code into Eclipse. + +Next you have to define a Debug Configuration. Click on Run / Debug Configurations, and in the window which appears click on the New symbol (top left). You have to specify: +- a name for the debug configuration +- on the Server tab click on Browse and select your site index.php file +- on the Debugger tab ensure that Break at First Line is checked. +- then click Apply to save the debug configuration +- you can then also click Debug to start debugging - and the code should break at the first executable line of index.php. + +After saving the configuration you can run it repeatedly by going again into Run / Debug Configurations, or by clicking the little arrow to the right of the bug symbol in the menubar, and then selecting your debug configuration. + +## Import a Joomla extension folder for development +You can use Eclipse as your IDE to assist with the code development process. To do this you need to import as a project the folder where you are developing your extension. Within Eclipse click on File / New - PHP Project. Select "Create project at existing location" and Browse to select the folder where you're developing your extension. Give your project a memorable name and click Finish. This will import your Joomla code into Eclipse. + +When you import your development code you'll see a lot of errors against your `use` statements, because Eclipse can't find those classes. To resolve this, +- right-click on the project in the Explorer pane, and select Properties. +- Under PHP / Source Paths / Include Path click on the Projects tab. +- Click Add, and select the your Joomla installation project, and click OK. +- Then click on Apply and Close to save everything. + +Then once again right-click on the development project and select Build Project. Eclipse should be able to find the source classes for your `use` statements and the errors should disappear. \ No newline at end of file diff --git a/versioned_docs/version-5.2/get-started/ide/index.md b/versioned_docs/version-5.2/get-started/ide/index.md new file mode 100644 index 00000000..1e33d405 --- /dev/null +++ b/versioned_docs/version-5.2/get-started/ide/index.md @@ -0,0 +1,25 @@ +--- +sidebar_position: 2 +--- +IDE +=== +To develop a Joomla extension we recommend that you use an Integrated Development Environment (IDE). An IDE has many benefits: +- Code completion + - Getting suggestions for code completion which saves researching existing code and helps avoid errors + - Auto-implementing namespace usage + - Type hinting when using well documented classes, methods and functions + - Building auto comments for classes/methods/functions +- Symbolic debugger +- Code analyser + - Automate code style feedback + - Hints for "smelling code" to improve the code quality +- Project/Folder management for extension projects +- Many addons/support for daily coding + +The two current leading IDEs are [Visual Studio Code](get-started/ide/visual-studio-code.md) and [phpStorm](get-started/ide/phpstorm.md) + +:::caution TODO + +This page is unfinished, please use the **Edit this Page** link at the bottom of this page to help make it more useful. + +::: diff --git a/versioned_docs/version-5.2/get-started/ide/phpstorm.md b/versioned_docs/version-5.2/get-started/ide/phpstorm.md new file mode 100644 index 00000000..af541b32 --- /dev/null +++ b/versioned_docs/version-5.2/get-started/ide/phpstorm.md @@ -0,0 +1,11 @@ +--- +title: PhpStorm +sidebar_position: 1 +--- +phpStorm +======== + +## Indentation with Spaces +Joomla uses spaces for indentation. Many people struggle to see the code nesting when the indentation is with spaces instead of tabs. The tab width can be adjusted in the ide but for spaces it is not as simple and you will need to use an extension to provide this functionality. It's not about how it looks, it's about how the brain works and how much time it spends to see nesting. + +For phpStorm you can use [Elastic Indents](https://plugins.jetbrains.com/plugin/14849-elastic-indents) to adjust the visual width of spaced indents and to come close to the benefits of tabbed indentations. diff --git a/versioned_docs/version-5.2/get-started/ide/visual-studio-code.md b/versioned_docs/version-5.2/get-started/ide/visual-studio-code.md new file mode 100644 index 00000000..0303dcb9 --- /dev/null +++ b/versioned_docs/version-5.2/get-started/ide/visual-studio-code.md @@ -0,0 +1,11 @@ +--- +title: Visual Studio +sidebar_position: 2 +--- +Visual Studio Code +================== + +## Indentation with Spaces +Joomla uses spaces for indentation. Many people struggle to see the code nesting when the indentation is with spaces instead of tabs. The tab width can be adjusted in the ide but for spaces it is not as simple and you will need to use an extension to provide this functionality. It's not about how it looks, it's about how the brain works and how much time it spends to see nesting. + +For Visual Studio Code you can use [Stretchy Spaces]([https://plugins.jetbrains.com/plugin/14849-elastic-indents](https://marketplace.visualstudio.com/items?itemName=kylepaulsen.stretchy-spaces&ssr=false#overview) to adjust the visual width of spaced indents and to come close to the benefits of tabbed indentations. diff --git a/versioned_docs/version-5.2/get-started/index.md b/versioned_docs/version-5.2/get-started/index.md new file mode 100644 index 00000000..6266a260 --- /dev/null +++ b/versioned_docs/version-5.2/get-started/index.md @@ -0,0 +1,47 @@ +--- +sidebar_position: 1 +--- + +Get Started +=============== +## Welcome to the Joomla Developers Manual +The purpose of this guide is to give developers an up to date guide showing best practice in +writing and maintaining Joomla extensions. It's aimed at both developers of core Joomla extensions and those developing extensions either for their own use or for making generally available to others. It also offers a migration path for extensions from older Joomla! versions to the latest standard. + +In this section we run through the tools and processes required to set up a local development environment with +the ability to get the most out of the guide as a developer. + +## Quick start +To get started with developing your own extensions for Joomla you'll need to have a local web environment set up - eg using [WAMP](https://www.wampserver.com/), [Bearsampp](https://bearsampp.com) or [XAMPP](https://www.apachefriends.org/). + +It's very useful, though not essential, to have git and a [PHP IDE](./ide/index.md) installed as well. + +Download Joomla from the [Joomla download site](https://downloads.joomla.org/) and install it on your machine. Before you start trying to develop Joomla extensions you should really become familiar with administering a Joomla site - for example publishing articles, using categories and tags, defining menus and menuitems, setting up users, installing extensions and setting configuration parameters. You'll find plenty of information available online. + +That's about it! We recommend that you start with [developing a basic module](../building-extensions/modules/module-development-tutorial/index.md). After that you can explore the [General Concepts](../general-concepts/index.md) and try some of the sample extensions available in [Building Extensions](../building-extensions/index.md). + +You can find an overview of how Joomla works by watching the video [How Joomla Works - a guide for extension developers](https://youtu.be/JKnq47Yhtvs). + +If you get stuck then raise a question on the Joomla [forum](https://forum.joomla.org) or [stack exchange](https://joomla.stackexchange.com/) sites. + +Enjoy! + +## Community +- Check the latest state of the Joomla CMS code at [GitHub](https://github.com/joomla/joomla-cms) +- Find the latest version at [Joomla.org](https://joomla.org) +- Join our [Mattermost-Community](https://joomlacommunity.cloud.mattermost.com/) +- Read the [End-User documentation](https://docs.joomla.org) +- Join our [forum](https://forum.joomla.org) +- Join [Joomla Stack Exchange](https://joomla.stackexchange.com/) + +## Contribute to this documentation + +The Joomla Developers Manual is implemented using [Docusaurus](https://docusaurus.io/), a system that can allow all users of Joomla to +contribute to the documentation using Markdown language. + +A good place to start, if new to Markdown, is the Markdown Guide +https://www.markdownguide.org/ + +The documentation is maintained via [the GitHub Joomla manual](https://github.com/joomla/Manual) where you can at anytime create/edit/delete content to improve the documentation. Click the **Edit this Page** link at the bottom of this page to contribute via a Pull Request. + +If you're intending to contribute regularly to the documentation then you'll probably find it helpful to get involved using the [Joomla Mattermost community](https://joomlacommunity.cloud.mattermost.com/) where you can liaise with others producing documentation, learn about the Docusaurus pitfalls to avoid, etc. diff --git a/versioned_docs/version-5.2/get-started/npm.md b/versioned_docs/version-5.2/get-started/npm.md new file mode 100644 index 00000000..d22b122f --- /dev/null +++ b/versioned_docs/version-5.2/get-started/npm.md @@ -0,0 +1,14 @@ +--- +sidebar_position: 5 +--- +NPM +======================= +Note that NPM is needed only if you're developing for code for the core Joomla project. + +This is the content for NPM + +:::caution TODO + +This page is unfinished, please use the **Edit this Page** link at the bottom of this page to help make it more useful. + +::: diff --git a/versioned_docs/version-5.2/get-started/technical-requirements.md b/versioned_docs/version-5.2/get-started/technical-requirements.md new file mode 100644 index 00000000..f5ed9ef4 --- /dev/null +++ b/versioned_docs/version-5.2/get-started/technical-requirements.md @@ -0,0 +1,56 @@ +--- +sidebar_position: 1 +--- +Technical Requirements +====================== + +All recommended versions are based on the latest released version of each series. + +## Requirements for Supported Software +### Requirements for Joomla! 5.x + +| Software | Recommended[^4] | Minimum[^3] | More Information | +|-------------------------------------------|-----------------|-------------|----------------------------------------------------------------------------| +| [PHP](https://php.net) | 8.3 | 8.1.0 | Modules: json, simplexml, dom, zlib, gd, mysqlnd or pdo_mysql or pdo_pgsql | +| **Databases** | | | | +| [MySQL](https://mysql.com) | 8.1 | 8.0.13 | | +| [MariaDB](https://mariadb.com) | 11.1.0 | 10.4.0 | | +| [PostgreSQL](https://postgresql.org) | 16.0 | 12.0 | | +| **Web Servers** | | | | +| [Apache](https://httpd.apache.org) [^2] | 2.4 | 2.4 | | +| [Nginx](https://nginx.com) | 1.25 | 1.21 | | +| [Microsoft IIS](https://www.iis.net) [^1] | 10 | 10 | | + +### Requirements for Joomla! 4.x + +| Software | Recommended[^4] | Minimum[^3] | More Information | +|--------------------|-----------------|-------------|------------------------------------------------------------------------------------------------------------------| +| PHP | 8.2 | 7.2.5 | https://www.php.net
Modules: json, simplexml, dom, gd, mysqlnd or pdo_mysql or pdo_pgsql | +| **Databases** | | | | +| MySQL | 8.0 | 5.6 | https://www.mysql.com | +| PostgreSQL | 11.0 | 11.0 | https://www.postgresql.org/
(ext/pgsql support in PHP has been removed. Now uses the PostgreSQL PDO Driver) | +| **Web Servers** | | | | +| Apache [^2] | 2.4 | 2.4 | https://www.apache.org | +| Nginx | 1.18 | 1.10 | https://www.nginx.com/resources/wiki/ | +| Microsoft IIS [^1] | 10 | 8 | https://www.iis.net | + +### Requirements for older Versions + +On this page you see only currently supported versions if you need the requirements for older Joomla Versions +please select the old version in the version switcher in the top right corner. Requirements for versions 3 and +lower are listed in the documentention for [4.4](/versioned_docs/version-4.4/get-started/technical-requirements.md). + +## Footnotes + +[^1]: For Microsoft IIS (depending on your setup) you may need the following: PHP, MySQL, Micorosoft URL Rewrite Module, FastCGI + * PHP - [Installation instructions](https://www.php.net/manual/en/install.windows.php) + * MySQL - [Installation instructions](https://dev.mysql.com/doc/mysql/en/windows-installation.html) + * Microsoft URL Rewrite Module - Required for SEO URLs only. For more information, [click here](https://learn.iis.net/page.aspx/460/using-url-rewrite-module/. For information about using ISAPI, [click here](https://docs.joomla.org/S:MyLanguage/Enabling_Search_Engine_Friendly_(SEF)_URLs_on_IIS). + * FastCGI - [Download for IIS6](https://www.iis.net/downloads/default.aspx?tabid=34&g=6&i=1521). [Download for IIS7](https://www.iis.net/downloads/default.aspx?tabid=34&i=1299&g=6). + * For further assistance using Microsoft IIS, visit the [Joomla! IIS forum](https://forum.joomla.org/viewforum.php?f=543). + +[^2]: We always recommend the latest version, the recommended version listed is the version which is known to work. + +[^3]: This is the minimum version which is guaranteed to work, older versions may work but are not supported. + +[^4]: In order to use SEO URLs, you will need to have the Apache mod_rewrite extension installed. diff --git a/versioned_docs/version-5.2/index.md b/versioned_docs/version-5.2/index.md new file mode 100644 index 00000000..ff136feb --- /dev/null +++ b/versioned_docs/version-5.2/index.md @@ -0,0 +1,20 @@ +--- +sidebar_position: 0 +title: Introduction +--- + +Welcome to the Joomla! Programmers Documentation for Joomla 5.2 +=============================================================== + +This documentation hold information for developers of templates, modules, plugins, components, libraries. +In Joomla! context all kind of this software are called extension. People often split extensions in to 2 categories. + +1. Core extension - Extensions which are shipped with Joomla installation package +2. 3rd party extensions - Extensions developed not by Joomla and installed separately + +But basically it shouldn't matter if the extension is provided by Joomla or by an external developer. + +This manual should help any kind of developer, if you are a template creator or just want to write the next +Joomla shop system. Everything you need to understand Joomla development should be found here. +If something is missing (this chance is really since we getting started this new documentation) please don't +hasitate to contribute with a [github pull request](https://github.com/joomla/Manual/) to improve the manual for all of us. diff --git a/versioned_docs/version-5.2/security/common-vulnerabilities.md b/versioned_docs/version-5.2/security/common-vulnerabilities.md new file mode 100644 index 00000000..7125718e --- /dev/null +++ b/versioned_docs/version-5.2/security/common-vulnerabilities.md @@ -0,0 +1,53 @@ +--- +sidebar_position: 3 +--- + +Common Vulnerabilities +====================== + +## Cross-Site-Scripting / XSS +Cross-Site-Scripting issues are by far the most common issues in the Joomla extension ecosystem. + +A brief example: imagine a Joomla comment extension that allows users to comment an article with a subject and a text. +Now imagine the following output template for a comment: + +```php +
+

subject; ?>

+ + text; ?> +
+``` + +Looks straightforward, huh? But now imagine that a user does not use "I love your site" as a comment subject, but ``````. +With the output template given above, the JS provided by the user will be outputted as an executable HTML tag and the evil code will be executed in the browser of each and every user visiting the site where that comment is shown - that's a Cross-Site-Scripting vulnerability. + +### Prevention +#### Filter/validate the user input +In the example above, the provided subject should be filtered and/or validated to only allow required characters - and it should disallow characters that are needed to create HTML tags, i.e. the `<` and `>` characters. +If the user input can contain HTML markup, the markup itself has to be filtered to make sure it only contains safe markup. See [the chapter about input handling](input-handling) for more information. + +#### Escape the output +Unless user generated markup is specifically needed (i.e. because the user can use a WYSIWYG editor) it's highly recommended to escape each and every snippet of user provided content. +Escaping converts HTML markup into plaintext by replacing control-characters like `<` with their HTML entities, i.e. `<`. + +To escape user content in Joomla, use the ```echo $this->escape($evilString)``` method when outputting content in component view or ```echo htmlspecialchars($evilString, ENT_QUOTES, 'UTF-8')``` outside of component views. + +## SQL injections / SQLi +A SQL injection attack is a type of vulnerability where an attacker is able to manipulate a SQL query by injecting user controlled content. + +Learn more about this attack scenario and the prevention in [the chapter about secure DB queries](secure-db-queries). + +## Unrestricted file uploads +Uploading user provided files to a webservers is a potentially dangerous task as it exposes multiple attack vectors at once: +* by uploading a dangerous file type (i.e. a PHP file) an attacker might be able to execute code +* an attacker might be able to control the storage path and thereby store files in directories where that shouldn't be possible +* by uploading large files, the webspace might be filled by an attacker quickly, leading to a denial of service + +Therefore file uploads must be very carefully implemented. Check the ```canUpload``` method of the ```Joomla\CMS\Helper\MediaHelper``` class as it will help you with that. + +## Cross-Site-Request-Forgery / CSRF +CSRF is an attack type where an HTML form on an external, attacker-controlled site is used to perform an attack against a target site. + +### Prevention +Learn more about this in the [CSRF chapter](csrf-protection) of this manual. \ No newline at end of file diff --git a/versioned_docs/version-5.2/security/csrf-protection.md b/versioned_docs/version-5.2/security/csrf-protection.md new file mode 100644 index 00000000..b5cae383 --- /dev/null +++ b/versioned_docs/version-5.2/security/csrf-protection.md @@ -0,0 +1,46 @@ +--- +sidebar_position: 5 +--- + +CSRF Protection +====================== +Cross-Site request forgery is an attack type where an HTML form on an external, attacker-controlled site is used to perform an attack against a target site. + +Imagine the following scenario: +* you are running a Joomla site as an administrator and are currently logged in +* in the same browser you want to buy a super cheap new TV from an online shop that a stranger has just sent you via email +* you click on the "add to cart"-button of that online shop - however, instead of adding the item to a cart, you end up in the Joomla administration of your site, seeing a "the user has been added"-confirmation message + +So, what has just happened? Well, you have been hacked! +The "add to cart"-form in the shop has been manipulated by the attacker: + +```html + + + + + + + +``` + +The form's ```action``` attribute points to the victim's site - and therefore the request data of that form is forged across the two sites: a CSRF is happening. In this scenario, the CSRF is used to create a new user for the attacker - and as that request is executed with the permissions of the currently logged in user, the request succeeds. + +Luckily, this scenario is theoretical as Joomla prevents CSRF attacks with a simple security measure. + +## Prevention +In order to prevent CSRF attacks, a randomly generated string is appended to each and every request that is supposed to perform changes to the site: + +```php +
+ [...] + +
+``` + +The ```form.token``` method generates a hidden input element with a random name and "1" as value. The random name is stored in the user session and thereby Joomla can check if it's included in the request after the form has been submitted. +In order to trigger the check, use the ```$this->checkToken();``` method in controller classes or the ```Session::checkToken()``` method outside of controllers. + +As the random name is stored in the user session and therefore session-specific, it's impossible for an external attacker to include it in the manipulated form. The CSRF attack will fail. + +__Important:__ CSRF tokens are unrelated from permission checks! A passed CSRF check does __not__ prove that a user is logged in, or has specific permissions to execute a given task. \ No newline at end of file diff --git a/versioned_docs/version-5.2/security/forms.md b/versioned_docs/version-5.2/security/forms.md new file mode 100644 index 00000000..f39a6bfa --- /dev/null +++ b/versioned_docs/version-5.2/security/forms.md @@ -0,0 +1,7 @@ +--- +sidebar_position: 6 +--- + +Forms & Validations +====================== +See the [form validation chapter for further information](../general-concepts/forms/server-side-validation). diff --git a/versioned_docs/version-5.2/security/fundamentals.md b/versioned_docs/version-5.2/security/fundamentals.md new file mode 100644 index 00000000..6f78048f --- /dev/null +++ b/versioned_docs/version-5.2/security/fundamentals.md @@ -0,0 +1,41 @@ +--- +sidebar_position: 2 +--- + +Fundamentals +============ +There are a bunch of very basic guidelines that you should follow in order to develop secure code. + +## No 1: All user input is evil + +Consider each and every input from a user as evil input. It can't be trusted and always has to be filtered and/or validated on input and needs escaping on output. + +Please have in mind that this does not only apply to "obvious" sources of user input, like the POST or GET input, but also other sources that are controlled by the user like: +* cookies +* the REQUEST superglobal +* major parts of the SERVER superglobal as it contains user-controlled input like the URL, the domain or the HTTP method +* HTTP request headers + +## No 2: client-side security is no security + +Everything that's happening in a client-side context (=in the browser) is user-controlled. That also means that any security measure that's implemented on the client-side is no security measure at all, as the user can always deactivate or manipulate these checks. + +This fundamental most importantly applies to: +* (form) validation: browser-based input validation is a UX feature (as it provides instant feedback to the user without a page reload) but not a replacement for server-side validation +* access checks: if you, i.e. output a secret string to the browser but hide it via `display:none`, it's still accessible by the user as removing the display-directive is trivial +* rate-limiting: if you limit the number of requests that a client is allowed to perform with client-side measures (i.e. by disabling a button via JS) that's again no protection at all + +## No 3: Don't do your own crypto + +Properly implemented cryptography does a fantastic job to keep secret stuff secret. The hard part however is implementing it properly, as often details decide about whether an implementation is indeed secure or not. +Therefore you should not do your own implementations of cryptographic methods or algorithms. Instead, use "off-the-shelf" implementations like the [libsodium](https://www.php.net/manual/de/book.sodium.php) methods available in PHP. These methods have been developed by people that are way smarter than you and are extensively tested and reviewed. + +## No 4: Don't do security by obscurity + +This rule does not only apply to the actual implementations in your codebase, but also to how you should handle a security issue in your code: once it's patched and the patch has been released, be open about it, notify users about the issue and the patch and outline its criticalness. + +## No 5: Reduce your attack surface + +Every single line of code that you write can contain a security issue and increases your attack surface. Carefully weight the advantages of a new feature against the maintenance effort and the increased attack surface. + +For extension developers that also means that Joomla core classes and features should be used whenever possible instead of writing own implementations, as Joomla's core code is well maintained, tested and has active security coverage by the security team. \ No newline at end of file diff --git a/versioned_docs/version-5.2/security/index.md b/versioned_docs/version-5.2/security/index.md new file mode 100644 index 00000000..6a980528 --- /dev/null +++ b/versioned_docs/version-5.2/security/index.md @@ -0,0 +1,7 @@ +--- +sidebar_position: 7 +--- + +Security +=============== +This section will teach you how to develop secure code for Joomla core and Joomla extensions. \ No newline at end of file diff --git a/versioned_docs/version-5.2/security/input-handling.md b/versioned_docs/version-5.2/security/input-handling.md new file mode 100644 index 00000000..ca27ffba --- /dev/null +++ b/versioned_docs/version-5.2/security/input-handling.md @@ -0,0 +1,8 @@ +--- +sidebar_position: 3 +--- + +Input Handling +====================== + +See the [Input chapter for further information](../general-concepts/input). \ No newline at end of file diff --git a/versioned_docs/version-5.2/security/secure-db-queries.md b/versioned_docs/version-5.2/security/secure-db-queries.md new file mode 100644 index 00000000..460bebdb --- /dev/null +++ b/versioned_docs/version-5.2/security/secure-db-queries.md @@ -0,0 +1,92 @@ +--- +sidebar_position: 4 +--- + +Secure DB Queries +====================== +A SQL injection attack is a type of vulnerability where an attacker is able to manipulate a SQL query by injecting user controlled content. + +Consider the following code snippet: + +```php +$query = $this->db->getQuery(true); +$username = $user->username; +$newPassword = password_hash($newPassword, PASSWORD_DEFAULT); + +$query->update('#__users')->set('password = "' . $newPassword . '"')->where('username = "' . $username . '"'); + +$this->db->setQuery($query)->execute(); +``` + +The code is supposed to update the password of the currently logged-in user who's identified by his username and the resulting query for the user "foobar" will look like this: + +```sql +UPDATE jos_users SET password = "{HASH}" WHERE username = "foobar"; +``` + +Now let's assume that the user chose `foobar" OR username="admin` as his username of choice. That would result in a very different query: + +```sql +UPDATE jos_users SET password = "{HASH}" WHERE username = "foobar" OR username="admin"; +``` + +So, the attacker has injected his user controlled commands in the query, resetting not only his password but also the password of the admin user. + +### Prevention +#### Use prepared statements +This is the gold standard to prevent SQLi attacks. + +The basic principle is simple: instead of integrating the user provided values in the query within the PHP code, query and input values are sent to the DB server in separate calls: + +``` +Prepared Statements +Query: SELECT foobar FROM bar WHERE foo = ? +Data: [? = 'bar'] +``` + +The basic principle is simple: instead of integrating the user provided values in the query within the PHP code, query and input values are sent to the DB server in separate calls. The DB server will then combine queries and values with each other and take care of escaping and/or quotes where necessary. + +So, by separating queries and injected values from each other, an injection becomes impossible. + +##### Implementing Prepared Statements through JDatabaseDriver +Implementing prepared statements in Joomla is very simple and is cross-platform: + +```php +$query = $this->db->getQuery(true) + ->select($this->db->quoteName(array('id', 'password'))) + ->from($this->db->quoteName('#__users')) + ->where($this->db->quoteName('username') . ' = :username') + ->bind(':username', $credentials['username']); +``` + +Within your query you define a so called named placeholder, prefixed with a double-colon. The actual replacement value for that placeholder is then passed to the DB server using the ```bind()``` method. + +The following functions accept arrays to reduce function call overhead: +* bind() +* bindArray() +* whereIn() +* whereNotIn() + +__!If possible you should use prepared statements!__ + +Learn more: +* [The PHP Manual on Prepared statements](https://php.net/manual/en/pdo.prepared-statements.php) +* [Simple Pull Request Implementing a Prepared Statement in Joomla](https://github.com/joomla/joomla-cms/pull/25049/files ) +* [Joomla Framework API](https://api.joomla.org/framework-1/classes/Joomla.Database.DatabaseQuery.html) + + +#### Escape user controlled input +By escaping characters that are considered as control-characters in SQL queries, it's also possible to prevent an attacker from "escaping" from the double-quote-prison that you have built in a query: + +```php +$query = $this->db->getQuery(true); +$username = $user->username; +$newPassword = password_hash($newPassword, PASSWORD_DEFAULT); + +$query->update('#__users')->set('password = "' . $this->db->escape($newPassword) . '"')->where('username = "' . $this->db->escape($username) . '"'); + +$this->db->setQuery($query)->execute(); +``` + +You can also remove the manually added double quotes in the query and use the ```quote()``` and ```quoteName()``` methods as these will by default also escape the provided input. + diff --git a/versioned_docs/version-5.2/testing/automated/concepts.md b/versioned_docs/version-5.2/testing/automated/concepts.md new file mode 100644 index 00000000..f1474b54 --- /dev/null +++ b/versioned_docs/version-5.2/testing/automated/concepts.md @@ -0,0 +1,16 @@ +--- +sidebar_position: 1 +--- + +Concepts +======== + +For Joomla! we are using different strategies to test the application. + +## System Testing versus Unit Testing + +System Testing and Unit Testing are complementary test strategies. In Joomla!, Unit Testing is mainly used to test the framework classes (for example, the classes in libraries/joomla). Unit tests test that an individual method (also known as function) in a class does what it is supposed to do. For example, a unit test is used to test that the methods in the JString class work as expected. Unit testing provides confidence that the framework classes work as expected and allows you to refactor these classes (improve the code without changing the functionality) and still have confidence that they still work correctly. + +System tests test that the application works correctly from the user point of view. For example, a system test can test something simple, for example, that you can create a new menu item for a single article and show the menu item on the site. Or a system test can test something more detailed, for example that the parameters for a module all work as expected. + +Designing and creating system tests requires that you know how to use the application. It does not require that you understand how the program is written. Application knowledge is more important than programming knowledge, so system tests can be designed and written by people with less technical knowledge of PHP or the Joomla! framework. diff --git a/versioned_docs/version-5.2/testing/automated/index.md b/versioned_docs/version-5.2/testing/automated/index.md new file mode 100644 index 00000000..b03defa0 --- /dev/null +++ b/versioned_docs/version-5.2/testing/automated/index.md @@ -0,0 +1,8 @@ +--- +sidebar_position: 1 +--- + +Automated Testing +============= + +Here you will find information about our automated testing, how to write tests and how to set it up. \ No newline at end of file diff --git a/versioned_docs/version-5.2/testing/automated/system/assets/cypress-window1.jpg b/versioned_docs/version-5.2/testing/automated/system/assets/cypress-window1.jpg new file mode 100644 index 00000000..9f6d1a57 Binary files /dev/null and b/versioned_docs/version-5.2/testing/automated/system/assets/cypress-window1.jpg differ diff --git a/versioned_docs/version-5.2/testing/automated/system/assets/cypress-window2.jpg b/versioned_docs/version-5.2/testing/automated/system/assets/cypress-window2.jpg new file mode 100644 index 00000000..dc7406f4 Binary files /dev/null and b/versioned_docs/version-5.2/testing/automated/system/assets/cypress-window2.jpg differ diff --git a/versioned_docs/version-5.2/testing/automated/system/index.md b/versioned_docs/version-5.2/testing/automated/system/index.md new file mode 100644 index 00000000..7dda1533 --- /dev/null +++ b/versioned_docs/version-5.2/testing/automated/system/index.md @@ -0,0 +1,9 @@ +--- +sidebar_position: 2 +--- + + +System Testing +=============== + +We are using [Cypress](https://docs.cypress.io/guides/overview/why-cypress) for our system (end2end) testing. \ No newline at end of file diff --git a/versioned_docs/version-5.2/testing/automated/system/setup.md b/versioned_docs/version-5.2/testing/automated/system/setup.md new file mode 100644 index 00000000..82ef380c --- /dev/null +++ b/versioned_docs/version-5.2/testing/automated/system/setup.md @@ -0,0 +1,82 @@ +--- +sidebar_position: 1 +--- + + +Setup your testing environment +=============== + +## Prepare your Workstation + +You need a set of tools to have a good testing setup. Tools you should have: + +* git +* node (16.16.0 is the current LTS) +* database (mysql 5.6+, mariaDB 10.1+, postgres 11.0+) +* PHP (good to have different versions and the ability to switch) +* Composer, [Installation instructions here](https://getcomposer.org/doc/00-intro.md#installation-linux-unix-macos) +* Webserver (apache 2.4+, nginx 1.18+) +* Editor (PhpStorm, Visual Studio Code) + +:::note + +This is pretty much the same toolset you need for unit testing + +::: + +## MAC OS + +As always there are different ways of installing the listed software. One way is the use of [Valet](https://laravel.com/docs/9.x/valet) in combination with [Homebrew](https://brew.sh/) + +Now as you have all tools installed you can clone the [joomla-cms repository](https://github.com/joomla/joomla-cms). + +1. Open a terminal +2. Go into a directory on you workstation. +3. clone the joomla-cms repository: ```git clone https://github.com/joomla/joomla-cms.git``` another option here is to fork the joomla-cms repo and then clone your fork. We recommend the 2nd way because then you can make changes and Pull Request directly. +4. Go into the joomla-cms directory +5. If you have installed valet, run ```valet link``` +5. Run ```composer install``` +6. Run ```npm ci``` +7. Create a ```cypress.env.json``` file. This file allows to overwrite config setting from ```cypress.config.js``` + + Here is a example ```cypress.env.json``` + + ```json + { + "sitename": "Joomla CMS Test Local", + "name": "jane doe", + "email": "admin@example.com", + "username": "local-admin", + "password": "joomla-17082005", + "db_type": "MySQLi", + "db_host": "localhost", + "db_name": "test_joomla", + "db_user": "root", + "db_password": "password", + "db_prefix": "jos_" + } + ``` + You don't need all settings, just look what you have to change for your local environment compared to ```cypress.config.js``` + +8. Run ```npx cypress open --e2e --browser=chrome --config baseUrl=http://joomla-cms.test``` + + This will open two windows, one you can ignore and one to run the tests + + + ![Cypress Window 1](./assets/cypress-window1.jpg) + + In the following window you can select test and let them run. You need to install first. + + ![Cypress Window 2](./assets/cypress-window2.jpg) + + +## Windows + + + + +:::caution TODO + +This page is unfinished, please use the **Edit this Page** link at the bottom of this page to help make it more useful. + +::: diff --git a/versioned_docs/version-5.2/testing/automated/system/writing-test.md b/versioned_docs/version-5.2/testing/automated/system/writing-test.md new file mode 100644 index 00000000..dd92d8d8 --- /dev/null +++ b/versioned_docs/version-5.2/testing/automated/system/writing-test.md @@ -0,0 +1,15 @@ +--- +sidebar_position: 2 +--- + + +Writing Tests +=============== + + + +:::caution TODO + +This page is unfinished, please use the **Edit this Page** link at the bottom of this page to help make it more useful. + +::: \ No newline at end of file diff --git a/versioned_docs/version-5.2/testing/automated/unit/index.md b/versioned_docs/version-5.2/testing/automated/unit/index.md new file mode 100644 index 00000000..26471fff --- /dev/null +++ b/versioned_docs/version-5.2/testing/automated/unit/index.md @@ -0,0 +1,13 @@ +--- +sidebar_position: 3 +--- + + +Unit Testing +=============== + +:::caution TODO + +This page is unfinished, please use the **Edit this Page** link at the bottom of this page to help make it more useful. + +::: \ No newline at end of file diff --git a/versioned_docs/version-5.2/testing/automated/unit/setup.md b/versioned_docs/version-5.2/testing/automated/unit/setup.md new file mode 100644 index 00000000..dfeb3949 --- /dev/null +++ b/versioned_docs/version-5.2/testing/automated/unit/setup.md @@ -0,0 +1,78 @@ +--- +sidebar_position: 1 +--- + + +Setup your testing environment +=============== + +## Prepare your Workstation + +You need a set of tools to have a good testing setup. Tools you should have: + +* git +* node (16.16.0 is the current LTS) +* database (mysql 5.6+, mariaDB 10.1+, postgres 11.0+) +* PHP (good to have different versions and the ability to switch) +* Composer, [Installation instructions here](https://getcomposer.org/doc/00-intro.md#installation-linux-unix-macos) +* Webserver (apache 2.4+, nginx 1.18+) - **optional** +* Editor (PhpStorm, Visual Studio Code) + +:::note + +This is pretty much the same toolset you need for system testing. Listed version numbers reflect the current state of the time writing. + +::: + +## MAC OS + +As always there are different ways of installing the listed software. One way is the use of [Valet](https://laravel.com/docs/9.x/valet) in combination with [Homebrew](https://brew.sh/) + +Now as you have all tools installed you can clone the [joomla-cms repository](https://github.com/joomla/joomla-cms). + +1. Open a terminal +2. Go into a directory on you workstation. +3. clone the joomla-cms repository: ```git clone https://github.com/joomla/joomla-cms.git``` another option here is to fork the joomla-cms repo and then clone your fork. We recommend the 2nd way because then you can make changes and Pull Request directly. +4. Go into the joomla-cms directory +5. **Optional** - If you have installed valet, run ```valet link``` +5. Run ```composer install``` +6. Run ```npm ci``` +7. Copy ```phpunit.xml.dist``` file to ```phpunit.xml```. This file allows config setting for phpunit. + + Here is a example ```phpunit.xml``` + + ```xml + + + + + ./tests/Unit/Libraries + + + ./tests/Integration/Libraries + + + + + + + + + + + ``` + +8. Run ```phpunit --testdox``` + + + +## Windows + + + + +:::caution TODO + +This page is unfinished, please use the **Edit this Page** link at the bottom of this page to help make it more useful. + +::: diff --git a/versioned_docs/version-5.2/testing/automated/unit/writing-test.md b/versioned_docs/version-5.2/testing/automated/unit/writing-test.md new file mode 100644 index 00000000..dd92d8d8 --- /dev/null +++ b/versioned_docs/version-5.2/testing/automated/unit/writing-test.md @@ -0,0 +1,15 @@ +--- +sidebar_position: 2 +--- + + +Writing Tests +=============== + + + +:::caution TODO + +This page is unfinished, please use the **Edit this Page** link at the bottom of this page to help make it more useful. + +::: \ No newline at end of file diff --git a/versioned_docs/version-5.2/testing/index.md b/versioned_docs/version-5.2/testing/index.md new file mode 100644 index 00000000..ed5df84e --- /dev/null +++ b/versioned_docs/version-5.2/testing/index.md @@ -0,0 +1,17 @@ +--- +sidebar_position: 10 +--- + +Testing +======= + +## Overview + +Testing Software is an important part of software development. For Joomla! we have different levels of testing: + +### Automated Testing + +For the automated testing we are using a continuous integration (CI) server drone. Any change that is made runs a series of tests on the CI system. We test if the code style for PHP, CSS and javascript is correct, run unit test for the supported PHP versions and run end to end tests. All this not only runs on different PHP version we are also testing different database version. At the end of the test we create an installable package with the changes included to support our manually testing. If something fails we save information about the reason. + +### Manually Testing +While automated testing is more focused on making sure that a change doesn't break existing functionality, is manually testing focused on the change itself. Always tow people have to confirm that a change does for what is made. This can be a bugfix or new functionality. diff --git a/versioned_docs/version-5.2/testing/manually/index.md b/versioned_docs/version-5.2/testing/manually/index.md new file mode 100644 index 00000000..77bbe5c9 --- /dev/null +++ b/versioned_docs/version-5.2/testing/manually/index.md @@ -0,0 +1,12 @@ +--- +sidebar_position: 2 +--- + +Manually Testing +============= + +:::caution TODO + +This page is unfinished, please use the **Edit this Page** link at the bottom of this page to help make it more useful. + +::: diff --git a/versioned_docs/version-5.2/user-interface-text/A-Z.md b/versioned_docs/version-5.2/user-interface-text/A-Z.md new file mode 100644 index 00000000..5471c152 --- /dev/null +++ b/versioned_docs/version-5.2/user-interface-text/A-Z.md @@ -0,0 +1,136 @@ +--- +sidebar_position: 2 +--- + +## 'a' or 'an' before H? +* Use 'an' before a silent H: an heir, an hour +* Use 'a' before an aspirated H: a hero, a hotel, a historian +* With abbreviations, be guided by pronunciation: eg an HTML document + +## Abbreviations and acronyms +* The first time you use an abbreviation or acronym explain it in full on each page then refer to it by initials unless it's well known, eg HTML, CSS etc. +* If you think your acronym is well known, please provide evidence that 80% of the UK population will understand, and commonly use, the term. Evidence can be from search analytics or testing of a representative sample. +* Don't use full stops in abbreviations – BBC, not B.B.C. +* Use all capitals if an abbreviation is pronounced as the individual letters (an initialism): HTML, CSS +* If it is an acronym (pronounced as a word) spell out with initial capital, eg Nasa, Nato, Unicef, unless it can be considered to have entered the language as an everyday word, such as laser and sim card. +* Note that pdf is lowercase. + +## Accents +* Use on French, German, Portuguese, Spanish and Irish Gaelic words (but not anglicised French words such as cafe, apart from exposé, lamé, résumé, roué). + +## Americanisms +* Don't use Americanisms. You 'fill in' a form, not 'fill out' a form. +* Exceptions include where it's part of a specific name, eg '4th Mechanized Brigade'. +* Use the 'ise' rather than 'ize' suffix, eg organise not organize (this isn't actually an Americanism but is often seen as such). + +## Amounts +See numbers + +## Check +See select. + +## Colour codes +Hex colours are case insensitive so it doesnt matter if we use upper or lowercase. However we should be consistent in our usage. As the color selector fields uses lowercase then the text should also user lowercase for consistency. + +## Contractions +Use contractions sparingly eg can't. Avoid using you'll, you've, should've, could've, would've etc – these are hard to read. + +## Dates +* use upper case for months eg January, February +* don't use a comma between the month and year, eg 14 June 2012 +* when space is an issue, eg tables, publication titles etc, you can use truncated months, eg Jan, Feb, Mar +* use 'to' in date ranges – not hyphens, en rules or em dashes. For example: copyright year 2011 to 2012 +* Monday to Friday, 9am to 5pm (put different days on a new line, don't separate with a comma etc) +* 10 November to 21 December +* don't use 'quarter' for dates; use the months, for example: 'expenses, Jan to Mar 2013' +* when referring to 'today' (eg in a news article) make sure you include the date as well eg 'The minister announced today (14 June 2012) that…' + +## Email and Email Address +Email should refer to the item that you send +Email address should be used if referring to their actual address + +Example +* Enter an email address for the user. +* Select which mailer for the delivery of site email. + +## File Size display: +* If less than 1 KB, display {'<'}1 KB +* 1 KB to 1,023 KB, display 357 KB +* 1 MB to 1,047 MB, display 2.5MB (only one decimal place) +* 1 GB+, display 3.8 GB (only one decimal place) + +## Geography and regions +* Use lower case for north, south, east and west, except when they're part of a name or recognised region. So, 'the south-west' (compass direction), but 'the South West' (administrative region). +* Use lower case for: the north, the south of England, the south-west, north-east Scotland, south Wales, the west, western Europe, the far east, south-east Asia. +* Use upper case for: East End, West End (London), Middle East, Central America, South America, Latin America. + +## Maths +* Use a minus sign for negative numbers with no space: –6 +* Ratios have no space either side of the colon: 5:12 +* One space each side of symbols: +, –, ×, ÷ and = (eg 2 + 2 = 4) +* Use the minus sign for subtraction not the dash. +* Use the correct symbol for the multiplication sign (×), not the letter x. (× or ×) + +## Measurements +* Use lower case for all measurements eg px, em, w and h +* Use the metric system for mass and non-web measurements eg kg, cm and m +* Use celsius for temperature eg 34c +* For all other measurements use SI + +## Money +* Use the £ symbol with no space: – £75. +* Don't use decimals unless pence are included, for example use: £75.50 but not £75.00. +* Don't use '£0.xx million' for amounts less than £1 million. +* Write out 'pence' in full eg 'calls will cost 4 pence per minute from a landline'. +* Currencies are lowercase. + +## Multi-factor Authentication +Always use the hyphenated word. Multi-factor must always be a single hyphenated word and only the complete words should be capitalised. + +## Numbers +(I have changed this based on the NNG findings (http://www.nngroup.com/articles/web-writing-show-numbers-as-numerals/)) +* Write numbers with digits, not letters (23, not twenty-three). +* Use numerals even when the number is the first word in a sentence or bullet point. +* Use numerals for big numbers up to one billion. As a compromise, you can often use numerals for the significant digits and write out the magnitude as a word. For example, write 24 billion. +* "Enter the **number** of hits to increase the counter by." +* "Limit the **amount** of text to display" + +## Seasons +Try to avoid using them as they are not global. spring, summer, autumn, winter are lowercase. + +## Select +Select a check box item not check a check box item. + +## Sentence length +Don't use long sentences – check any sentences with more than 25 words to see if you can split them to make them clearer. + +## Singular and Plural +In general a string with a constant of ARTICLE_PUBLISHED_1 should have a value of "Article published." and not "1 Article ... + +## Times +* use 'to' in time ranges – not hyphens, en rules or em dashes, eg 10am to 11am (not 10–11am) +* 5:30pm (not 1730hrs) +* midnight, not 00:00 +* midday, not 12 noon, noon or 12pm + +## Titles +Titles should: +* be no longer than 65 characters +* be unique, clear and descriptive +* be front-loaded and optimised for search +* use a colon to break up longer titles +* not have a full stop at the end +* not use acronyms unless they are well-known eg HTML + +## Tooltips +Tooltips should: +* be as short as possible +* end with a full stop +* not repeat the title or body text +* be clear and specific + +## Trademarked Name +This should always be written with a capital letter unless the trademark is for lowercase eg iPhone. + +## Two Factor Authentication +This should not be used. See Multi-factor Authentication. diff --git a/versioned_docs/version-5.2/user-interface-text/action_or_description.md b/versioned_docs/version-5.2/user-interface-text/action_or_description.md new file mode 100644 index 00000000..bf70e0cd --- /dev/null +++ b/versioned_docs/version-5.2/user-interface-text/action_or_description.md @@ -0,0 +1,43 @@ +--- +sidebar_position: 2 +--- + +Action or Description +===================== + +## Archive / Unarchive Vs Archived / Unarchived +* Archive is an action so it is used on buttons +* Unarchive is an action so it is used on buttons +* Archived is a description so it is used in filters and selects +* Unarchived is a description so it is used in filters and selects + +## Check in, Check out +* Check-in is hyphenated when it’s a noun eg I was early for check-in +* Check in is two words when it's a verb eg I walked up to the counter to check in +* Checkout is one word when it's a noun eg you wait in the checkout line +* Check out is two words when it's a verb eg you are ready to check out of the hotel + +## Feature / Unfeature Vs Featured / Unfeatured +* Feature is an action so it is used on buttons +* Unfeature is an action so it is used on buttons +* Featured is a description so it is used in filters and selects +* Unfeatured is a description so it is used in filters and selects + +## Log in, Log out +* Login is one word (not hyphenated) when it's a noun eg go to the login page +* Log in is two words when it's a verb eg you log in with your username +* Logout is one word (not hyphenated) when it's a noun eg select the logout menu +* Log out is two words when it's a verb eg you log out by clicking on the button + +## Logged-in +When counting the number of users we are counting those who are logged-in not logged in. + +## Publish / Unpublish Vs Published / Unpublished +* Publish is an action so it is used on buttons +* Unpublish is an action so it is used on buttons +* Published is a description so it is used in filters and selects +* Unpublished is a description so it is used in filters and selects + +## Trash Vs Trashed +* Trash is an action so it is used on buttons +* Trashed is a description so it is used in filters and selects diff --git a/versioned_docs/version-5.2/user-interface-text/capitalisation.md b/versioned_docs/version-5.2/user-interface-text/capitalisation.md new file mode 100644 index 00000000..5a35f272 --- /dev/null +++ b/versioned_docs/version-5.2/user-interface-text/capitalisation.md @@ -0,0 +1,20 @@ +--- +sidebar_position: 3 +--- + +Capitalisation +============== + +DON'T USE BLOCK CAPITALS FOR LARGE AMOUNTS OF TEXT AS IT'S QUITE HARD TO READ. + +Sentence case is preferable but use capitalisation for: + +* Menu Items +* Labels +* Buttons + +Do not capitalise joining words and words of three characters or less such as and, to, for. + +## Examples +* Show Intro Text +* Position of Article Info diff --git a/versioned_docs/version-5.2/user-interface-text/index.md b/versioned_docs/version-5.2/user-interface-text/index.md new file mode 100644 index 00000000..cf0115d7 --- /dev/null +++ b/versioned_docs/version-5.2/user-interface-text/index.md @@ -0,0 +1,27 @@ +--- +sidebar_position: 999 +--- + +User Interface Text Guidelines +============================== + +The official language of Joomla is en-GB and this guide is intended to assist anyone writing language strings in en-GB (British English). This guide should not be translated but may help serve as a starting point for Translation Teams to localise and produce their own guide. + +## Purpose +* Establish official style guidelines for writing en-GB strings. +* Ensure consistency throughout Joomla. +* Traditional rules of grammar do not always apply to the web. See [Break Grammar Rules on Websites for Clarity](http://www.nngroup.com/articles/break-grammar-rules/). +* See [NNG on American vs British english for the web](http://www.nngroup.com/articles/american-vs-british-english-for-web/). + +## Target audience +* Primary: Developers writing en-GB strings. +* Secondary: Translation teams. + +## Uses +* Primary: Basis for all en-GB strings. +* Secondary: Assist non native en-GB developers writing language strings in en-GB. +* Tertiary: Provide guidelines for translation teams to localise. + +## Notes +### Avoid over-communication +Be explicit wherever necessary but don't explain the obvious. On the web scanning is the norm and too much text weakens the effectiveness of the message - it does not enhance it. diff --git a/versioned_docs/version-5.2/user-interface-text/joomla_name_usage.md b/versioned_docs/version-5.2/user-interface-text/joomla_name_usage.md new file mode 100644 index 00000000..6e72554b --- /dev/null +++ b/versioned_docs/version-5.2/user-interface-text/joomla_name_usage.md @@ -0,0 +1,54 @@ +--- +sidebar_position: 4 +--- + +Use of the Joomla Name +====================== + +"Joomla!" is our name, and as such it deserves everyone's best efforts to protect it. It defines our brand for both our software and our community. It signifies our reputation for excellence. We have specific guidelines for when and how to properly use our trademarks in public-facing content such as marketing materials and Joomla.org web pages. Those guidelines are excessive within a controlled user-facing environment like the Joomla backend. + +## "Joomla!" should always be capitalised ... ALWAYS +Our project's name is a proper name. Please always capitalise the "J" of Joomla. + +## When to bang your Joomla "!" +Our registered trademark is "Joomla!" including the exclamation point. (The exclamation point is sometimes also called a "bang" from both copy editing and comic book usage.) The proper and complete use of our name is with the exclamation point. But, there are many circumstances where including punctuation that also signifies the end of a sentence makes a passage of text difficult to read or confusing. Also, punctuation is not allowed in certain contexts such as aliases and URL's. To clarify when to use the exclamation point, here are simple rules applicable only to Joomla CMS language strings. + +### Rule: No Bang! +References to Joomla in language strings should not include the exclamation point unless it is at the end of a sentence that is intended to be exclamatory. + +#### Rule of thumb +Whenever you can substitute "your Joomla CMS" in place of "Joomla" and still make sense, then it's descriptive and no bang needed. + +### Exception to the Rule: Trademarks that contain Joomla +Whenever the Joomla name is part of or nested inside another multi-word Joomla-related trademark or service mark then the exclamation point should be used even though it is mid-sentence. If the use is a proper name it should have capitalised initials, Joomla should include the exclamation point and it should be followed by a TM indicia. +Examples: References to the Joomla! Extensions Directory™, the Joomla! Framework™ or Joomla! 3.4 as a product. + +--------- + +## When to Include Trademark Indicia ( ® or ™ ) + +### Rule: Do not use ® in language strings +Part of protecting a trademark, whether registered or not, is giving notice to viewers that we consider the mark to be our property. Considering the Joomla! trademark itself, since all backend users must login and will see the Joomla signature and registered trademark indicia on the login module, there is no need to include a registered mark indicia (®) anywhere else in the backend. + +### Rule: Always use ™ following other Joomla-related trademarks +With other Joomla-related trademarks or service marks, such as a reference to the Joomla! Extensions Directory™, the proper indicia to use is the TM indicia (™) at the end of the entire mark. Notice the exclamation point is included and the registered indicia (®) normally used with Joomla standing alone, is removed. The ™ indicia should be used with any reference to a Joomla product or service other than a release of Joomla itself (such as Joomla! 3.4) + +These other trademarks are not registered. Nevertheless, they are protectable trademarks and service marks. A superscript circle-R should NOT be used with them; instead a superscript TM should be used. Because these are unregistered trademarks, extra care is needed to use them consistently on order to emphasize and retain their trademark status. The registration and broader recognition of the main Joomla! wordmark is the reason why we have more flexibility with the Joomla name being used without the exclamation point and as a noun in descriptive context than we do with these other Joomla-related product and service marks. + +---------- + +## Summary +* Refer to Joomla in general without the exclamation point. +* Refer to a specific product release or series as "Joomla! 3" or "Joomla! 3.4" (with an exclamation point.) +* Refer to the JED as Joomla! Extensions Directory™ (with exclamation point and TM indicia.) + +-------------- + +## HTML Codes +For consistent display across fonts, use the html codes for copyright and trademark symbols or indicia. For proper display, wrapping with a superscript `` tag is necessary for positioning the ® indicia. It is not needed for the © or ™ indicia. + +* ® - for a registered trademark indicia use `®` +* ™ - for a trademark indicia use `™` +* © - for a copyright indicia use `©` + +Provenance: This page was written by Marc Antoine Thevenet and Duke Speer on behalf of the Trademark Team. diff --git a/versioned_docs/version-5.2/user-interface-text/punctuation.md b/versioned_docs/version-5.2/user-interface-text/punctuation.md new file mode 100644 index 00000000..66b0ce7d --- /dev/null +++ b/versioned_docs/version-5.2/user-interface-text/punctuation.md @@ -0,0 +1,94 @@ +--- +sidebar_position: 5 +--- + +Punctuation +=========== + +## Ampersand +Unless in a title or referring to a title use 'and' rather than an '&', unless it's part of a trademark. Where it is used then it should be `&` and not `&` + +## Apostrophes +Used to indicate a missing letter or letters (can't, we'd) or a possessive (David's book). + +## Brackets +Use (round brackets), not [square brackets]. The only acceptable use for square brackets is to indicate that it is a placeholder eg [name] is replaced with the real name. + +## Bullet points (ul) and numbered steps (ol) +You can use bullet points to make text easier to read. Make sure that: + +* you always use an introductory line +* the bullets make sense running on from the lead-in line +* you use lower case at the start of the bullet +* you don't use more than one sentence per bullet point – use commas, dashes or semicolons to expand on an item +* you don't put 'or', 'and' after the bullets +* if you add links they appear within the text and not as the whole bullet +* there is no full stop after the last bullet point + +Use numbered steps instead of bullet points to guide a user through a process. You don't need an introductory line and you can use links and downloads (with appropriate markup) in steps. Each step ends in a full stop because each step should be a complete sentence. + +## eg, etc and ie +* Don't use full stops after or between these notations. +* User testing has shown that some people are not familiar with abbreviations such as eg, so consider your audience before abbreviating. + +## Ellipsis +An ellipsis a special character that resembles a set of three periods ( ... ) indicating an omission. In html this is represented by &hellip. There should be a single space on either side. Unless it is at the end of a string where there is no space or period after. +Example +* Read more ... +* Create some text ... add some pictures. + +## etc +* See eg, etc and ie + +## full stop +* See period + +## Hyphenation +Hyphenate: +* 're-' words only if they start with 'e', eg re-evaluate +* co-ordinate +* co-operate + +Don't hyphenate: +* email +* reuse +* reinvent +* reorder +* reopen + +If in doubt, don't use a hyphen. + +## ie +* See eg, etc and ie + +## Italics +Don't use italics. Use 'single quotation marks' if referring to a document, scheme or initiative. + +## Lists +See bullets and steps + +## Period +All sentences end with a period. All tooltips end with a period. Bullet points (ul) do not end with a period. Each Numbered step (ol) ends with a period. + +## Punctuation +For quotes, single quotes and speech marks use the character code not the keyboard. Order of precedence is HTML Name, HTML Decimal Code, Unicode Hexadecimal. + +### Oxford (or serial) comma. +We don't use the Oxford comma so the final item in a list before the 'and' does not have a comma. + +### Quotes and speech marks. +Use `" " "` at the beginning and end. + +### Single quotes +Use either `' '` at the beginning and end. + +Use single quotes: +* in headlines +* for unusual terms +* when referring to words or publications, for example: Download the manual 'Understanding ACL' (PDF, 360KB)' + +## Slashes +A slash (/) should not have spaces around it eg show/hide not show / hide. + +## Spaces +Use only one space after a full stop, not 2. diff --git a/versioned_docs/version-5.2/user-interface-text/references.md b/versioned_docs/version-5.2/user-interface-text/references.md new file mode 100644 index 00000000..ce01c6f1 --- /dev/null +++ b/versioned_docs/version-5.2/user-interface-text/references.md @@ -0,0 +1,27 @@ +--- +sidebar_position: 99 +--- + +External References +=================== + +## Main en-GB Sources +* [gov.uk](https://www.gov.uk/guidance/style-guide/a-to-z-of-gov-uk-style) [(licence)](https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/) +* [The BBC](https://www.bbc.co.uk/newsstyleguide/all/) +* [European Commission Directorate-General for Translation](https://wikis.ec.europa.eu/display/WEBGUIDE/02.+Web+writing+guidelines) + +### Other en-GB Sources +* [The Guardian](http://www.theguardian.com/info/series/guardian-and-observer-style-guide) - [(usage rights)](http://www.theguardian.com/media/mind-your-language/2011/jan/24/mind-your-language-telegraph-style-guide) +* [The Economist - pdf](https://cdn.static-economist.com/sites/default/files/store/Style_Guide_2015.pdf) +* [The Telegraph](http://www.telegraph.co.uk/topics/about-us/style-book/) + +### Useful Reading +* [Nielsen Norman Group](http://www.nngroup.com/articles/) + +### UI Sources +* [Mozilla](https://mozilla-l10n.github.io/styleguides/index.html) +* [Apple](https://developer.apple.com/library/mac/documentation/UserExperience/Conceptual/OSXHIGuidelines/TerminologyWording.html#//apple_ref/doc/uid/20000957-CH15-SW4I) +* [Microsoft](http://msdn.microsoft.com/en-gb/library/windows/desktop/dn742478.aspx) + +### Punctuation Codes +* https://websitebuilders.com/tools/html-codes/punctuation/ diff --git a/versioned_docs/version-5.2/user-interface-text/words2watch.md b/versioned_docs/version-5.2/user-interface-text/words2watch.md new file mode 100644 index 00000000..0edee417 --- /dev/null +++ b/versioned_docs/version-5.2/user-interface-text/words2watch.md @@ -0,0 +1,129 @@ +--- +sidebar_position: 6 +--- + +Words to Watch +============== + +**This is a 'living document' that can be updated as needed over time.** + +Words to Watch (W2W) are words commonly misspelled or which may have variations that depend on the Joomla! style guide choices. + + +| Accepted Word | Unacceptable Word | Detail | +| ------------------------------------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Administrator | administrator | Always capitalise when referring to the Joomla! User level or the Backend Administrator. When referring to the site administrator then it is lowercase | +| address | | Spell with a double d. | +| adapter | adaptor | someone who adapts; adaptor plug | +| a lot | alot | Use as two words, not one. | +| amend and amendment | | Spell with a single m at the beginning. | +| Article | | Capitalise the word Article when referring to the element of Joomla! content. | +| AutoCorrect | | One word with capitalisation as shown | +| Backend | back end back-end | One word not hyphenated or two words. | | +| backup and back up | | Use backup when used as an adjective, as in "he had a backup disk in his bag" and use back up when using it as a verb, as in "don’t forget to back up your hard drive". | +| Banner | | Always capitalise when referring to the Component element or Manager function. | +| bitmap | bit map or bit-map | One word not hyphenated or two words. | +| blacklist | black list | one word not two | +| cacheable | cachable | The 'e' should not be dropped. | +| CAPTCHA | captcha Captcha | Captcha is an acronym that stands for Completely Automated Public Turing test to tell Computers and Humans Apart. It is pronounced as a real word and not spelled out then it should be written as captcha according to our style guide (see acronyms).| +| Category (Manager) | | Always capitalise when referring to the Component element or Manager function. | +| collapsible | collapsable | The correct spelling is -ible | +| command | comand | | +| Contact (Manager) | | Always capitalise when referring to the Component element or Manager function. | +| checkbox | check box | | +| check-in (noun/adjective) (Global) Check-in | checkin (noun/adjective) | We will be using check-in, which must be capitalised when referring to a specific function, Menu Item, or button such as Global Check-in. It is correct to use check in (verb) as in 'check in your materials'. | +| Component (Manager) | | Capitalise the word Component when referring to an Extension in Joomla!. | +| Contact | | Capitalise the word Contact when referring to the element of the Joomla! Contact Component. | +| Control Panel | control panel | Capitalise when referring to the Joomla! Backend functional area. | +| CSS | css | Always capitalise except in code or when a file extension. | +| database | data base | One word not two | +| directory || Do not use. Use folder instead | +| dropdown | drop-down drop down | One word not hyphenated| +| email | E-mail e-mail | No hyphen and lower case. Except Email is obviously correct at the start of a sentence! We will be going with email (lower-case and non hyphenated) for consistency. | +| Extension(s) | extension(s) | Refer to Components, Modules, and Plugins collectively as Extensions. Always capitalise when referring to CMPT’s. | +| file name | filename | Two words rather than one. | +| fine-tune | fine tune finetune | One hyphenated word. | +| folder | |Do not use directory always use folder | +| Frontend | front-end | One word not hyphenated or two words. | | +| Front Page front page | Frontpage frontpage | Always two words. Capitalise the words Front Page when referring to the Menu Item element of Joomla! content. | +| Gmail | GMail | Always capitalise the first letter only| +| Gzip | GZip | Only capitalise the first letter when referring to the name of the program| +| hard disk | hard-disk | Two words. No hyphenation | +| hardware | hard-ware | One word. No hyphenation | +| home page | homepage | Always two words. | +| HTML | HTM html | Always capitalise, except in code or when a file extension. | +| ID | Id id | Always capitalise when referring to a database ID. Lowercase when referring to a CSS id.| +| iframe | Iframe iFrame | Lower case unless at the start of a sentence.| +| information | infos | Always use information. Infos is not a real word| +| internet | Internet | Lower case unless at the start of a sentence or referring to Internet Explorer | +| IP | Ip ip | IP is an acronym that stands for internet protocol. As it is pronounced by spelling out the letters and not as a real word then it should be written as IP, all capitals with no periods, according to our style guide (see acronyms).| +| JavaScript | javascript Java Script | One word but with the J and S capitalised. | +| Joomla! joomla Joomla | | See separate tradmark document | +| joomla_root/ | | Use as the starting point to all references to directories within the core installation to avoid confusion with the web server or database root. | +| keyboard | key board | One word not two | +| licence and license | | Use licence as a noun for the permit you obtain to do something like hunt or drive, but use license when you mean it as a verb, to give permission to or allow someone to do something or for something to occur. | +| login, logon, logoff, and logout | | Noun always one word one “g” the act of logging into or out of a computer or website. NOT the name of the field - that is Username | +| log in, log on, and log off log out | | Verb to go through the procedure of logging in to or out of a website for example. | +| maintenance | maintainence | Spell with -ten- in the middle and end with -ance. | +| Manager | manager | When referring to either the User level or a Manager screen (Poll Manager) it is capitalised. | +| Media Manager | media manager | Capitalise when referring to the Joomla! function. | +| Menu | menu | When referring to a specific menu in Joomla! always capitalise. | +| Menu Item | menu item | Two words and capitalise both when referring to the specific element within Joomla! but not when generally discussing any old menu items | +| metadata | meta data | One word lower case | +| meta [attribute] |meta-description |Always two words and [attribute] is always lowercase| +| misspell | mispell | Spell with a double s. | +| Module | module | Always capitalise when used for a Joomla! Extension. | +| Multi-factor Authentication | multifactor authentication multi factor authentication | Multi-factor must always be a single hyphenated word and only the complete word should be capitalised. | +| multilingual | multi-lingual multi lingual | one word | +| multitasking | multi-tasking multi tasking | one word | +| MySQL | mysql MYSQL | | +| News Feed | newsfeed Newsfeed | Always capitalise when referring to the Component within Joomla!, and always two words. If referring to a news feed and not the component then still two words but not capitalised | +| necessary and necessity | neccessary | Spelled with one c and a double s. | +| OK | Ok, ok | Capitalise both letters | +| online | on-line on line | One word lower case | +| Open Source (OS) | Open source | Capitalise the O and S. | | +| overwrite | over write over-write | One word | +| page break | pagebreak | two words not one| +| password | pass word | One word | +| passkey | Passkey, PassKey | Passkey is a common noun (capitalise as you would do for password) | +| pdf | PDF | lower case | +| PHP | php | Always capitalise except when used as a file extension or in code | +| phpass | PHPass | Always lowercase even when at the start of the sentence or in a title| +| Plugin(s) | plug-in | One word | +| PostScript | Post Script post-script | One word. Capitalise P and S. | +| practice and practise | | Use practice as a noun when describing actually doing something rather than just discussing it or theories about it. | +| program and programme | | program when referring to code; otherwise programme | +| proofread | proof-read | proofed | +|reCAPTCHA | recaptcha Recaptcha ReCaptcha ReCAPTCHA| This is the name of a specific product/service from google so should be spelt exactly this way. It is never capitalised even at the beginning of a sentence.| +| receive | recieve | Use i before e except after c. | +| RSS | rss | Always capitalise except when used as a file extension or in code | +| SEF | Sef sef | Always capitalise | +| semicolon | semi colon semi-colon | One Word | +| separate | seperate | Spell with -par- in the middle. | +|shall| |Do not use. A better word is will. This will be displayed not this shall be displayed| +| software | soft ware soft-ware | One word | +| source code | sourcecode | Two words | +| style sheet | stylesheet style-sheet | Two words no hyphen | +| subdirectory | sub-directory sub directory | One word | +| success and successful | sucess | Spell with a double c and a double s. | +| Super User | Super Administrator super administrator | Always capitalise when referring to the Joomla! User. There is no such thing as a Super Administrator | +| surprise | | Spell with an r before and after the p. | +| text area | text-area textarea | When referring to the area that you enter content then it is two words. When referring to the HTML tag then it is one word| +| toolbar | tool bar tool-bar | One word | +| twelfth | twelth | Spell with an f in the middle. | +| Twitter | twitter | Twitter is a trademark so should always be with a capital | +| unfortunately | | Spell with -ately at the end. | +| URL | Url url | Capitalise except when used in code. | +| User | user | When referring to a specific Joomla! User always capitalise first letter | +| user group | usergroup User Group | Two words lower case| +| Username | user name | One word. You login with the Username NOT the login name | +| UTF-8 | utf-8 utf8 | Always uppercase and hyphenated| +| vCard | VCard vcard Vcard | Always spelt vCard even at the beginning of a sentence or in a label.| +| web | Web | Lower case | +| Web link Web Link | weblink web-link | Two words unhyphenated. Capitalise the words when discussing the Component variant - Web Link Manager. | +| Web services | webservices | Two words with the first word capitalised. When used in a title, label or button then the normal rules apply and both are capitalised. | +| website | web site Web Site Web site | One word not capitalised | +| whitelist | white list | one word not two | +| wi-fi | WIFI wifi WI-FI | Lower case and hyphenated. | +| Word | word | When referring to a Word document this should always be capitalised as it is a trademark | +| World Wide Web (WWW) | Worldwide Web | Capitalise, as it is a proper noun. Three separate words. Capitalise the abbreviation (except in URL’s) | diff --git a/versioned_docs/version-5.2/web-services-api/index.md b/versioned_docs/version-5.2/web-services-api/index.md new file mode 100644 index 00000000..ced695e2 --- /dev/null +++ b/versioned_docs/version-5.2/web-services-api/index.md @@ -0,0 +1,9 @@ +Web Services API +================ + +This is the content for tutorials how to work with the webservices API of Joomla. +:::caution TODO + +This page is unfinished, please use the **Edit this Page** link at the bottom of this page to help make it more useful. + +::: diff --git a/versioned_docs/version-5.2/web-services-api/json-response-format/assets/basic_dashboard_view.png b/versioned_docs/version-5.2/web-services-api/json-response-format/assets/basic_dashboard_view.png new file mode 100644 index 00000000..6a3b4762 Binary files /dev/null and b/versioned_docs/version-5.2/web-services-api/json-response-format/assets/basic_dashboard_view.png differ diff --git a/versioned_docs/version-5.2/web-services-api/json-response-format/index.md b/versioned_docs/version-5.2/web-services-api/json-response-format/index.md new file mode 100644 index 00000000..43d30efc --- /dev/null +++ b/versioned_docs/version-5.2/web-services-api/json-response-format/index.md @@ -0,0 +1,774 @@ +JSON Response Format +==================== + +Joomla by default will return a [JSON API](https://jsonapi.org/) Responses when requested with an Accept: application/json header as well as with the specific JSON API header. Although the Core of Joomla will not support additional content types, **support the ability that developers add additional content types that can be responded**. + +## The Goals + +- Get a JSON response from the Joomla API +- Create the necessary webservices plugin and the API part of the component +- Use a module params for model the data we will send in the API response + +## Not a Goal + +- How create a extension. + This tutorial assumes that you know how to create an extension in Joomla 4. _Keep in mind that at least a plugin and a component are necessary. But do not worry, this component can be very basic, in fact, it will not even need have any Model, it only required that the dashboard view in the administration works correctly_. This will be enough for your API to work. + +![Basic Component Dashboard View](./assets/basic_dashboard_view.png 'Component Dashboard View') + +The necessity for a basic backend part comes from the fact that the XML manifest, the configuration (config.xml) and the permissions (access.xml) files are present only in the backend directory of the component. The XML manifest is necessary for a component to be able to be installed, updated and uninstalled. Moreover, Joomla always creates a backend menu item for the component, meaning that the component must have a backend part with a default view even if it's just to display a message that there is nothing to do with this component in the backend. + +- Develop the tutorial with a generic approach. We building a custom API logic, with a specific approach. Although, after you follow the tutorial, you will be able to do changes for fit your needs. + +## To know before start + +One of the current authentication the Joomla API use is a token based one. (It also has one for credentials, username and password, but you should always avoid using this one). + +As a result, **the core was though and was develop for administration functionality and the idea for the application to interact with itself**. So the Authentication has been designed around that. + +Although, if your content is designed to just outright be public (e.g. blog posts in your app) you can just use the public flag in your webservice plugin (more on this below). + +## Webservices plugin + +Our first lines of code will start in the plugin. The plugin is responsible for registering the routes (endpoints) of our API in addition to indicating the controller of our component who will handle the request. Let's create it. + +In your workspace, create a folder with the name: **plg_webservices_vapi**. Inside the folder, let create a php file of name, **vapi.php**, with the follow content: + +```php +defined('_JEXEC') || die; + +use Joomla\CMS\Plugin\CMSPlugin; +use Joomla\CMS\Router\ApiRouter; +use Joomla\Router\Route; + +class PlgWebservicesVapi extends CMSPlugin +{ + /** + * Registers com_vapi API's routes in the application + * + * @param ApiRouter &$router The API Routing object + * + * @return void + * + */ + public function onBeforeApiRoute(&$router) + { + // Render a list of com_content articles using a specific module + $this->createModuleSiteRoutes($router, 'v1/vapi/modules/:id', 'module.displayModule'); + } + + /** + * Creates routes map for CRUD + * + * @param ApiRouter &$router The API Routing object + * @param string $baseName The route pattern to use for matching + * @param string $controller The name of the controller that will handle the api request. + * @param array $defaults An array of default values that are used when the URL is matched. + * @param bool $publicGets Allow the public to make GET requests. + * + * @return void + * + */ + private function createModuleSiteRoutes(&$router, $baseName, $controller, $defaults = [], $publicGets = true): void + { + $defaults = [ + 'component' => 'com_vapi', + 'public' => $publicGets, + 'format' => [ + 'application/json' + ] + ]; + + $routes = [ + new Route(['GET'], $baseName, $controller, ['id' => '(\d+)'], $defaults), + ]; + + $router->addRoutes($routes); + } +} +``` + +Let highlight some things you should know about this plugin: + +- **onBeforeApiRoute method:** This method is required in each webservices plugin. Here is where you will define your routes (endpoints). You can define these routes inside this method, or in a custom separate method as was done here (this custom method will depend on you the way it will be built, it is not part of the Joomla core). + +- **createModuleSiteRoutes method:** Here you can check the constructor of the `Joomla\Router\Route` class and know well all the params we using for instance the class. But, let extend the descriptions of them here. + + - **\["GET"\]:** The HTTP methods this route supports, all verbs must be in uppercase. All valid methods are ["GET", "POST", "PUT", "DELETE", "HEAD", "TRACE", "PATCH"] + + - **$baseName:** The route pattern to use, or endpoint. In this example, we get here `v1/vapi/modules/:id`. + + - The `v1` part is used for versioning your API. Start with v1 for the first version of your component API. + - The next part should be your component name without the `com_` prefix. This is just a convention for define the routes. + - Only left `modules/:id`. This the **feature** our component handle, plus a `:id` parameter who may exist or not in your endpoint. In our case, this pattern tells Joomla that this route will only match if the `v1/vapi/modules` route is followed by something which will be made available as the request parameter named `id`. If that something does not exist the route does not match and Joomla won't use it. + + - **$controller:** This is the component API controller and the task to execute (a method inside this controller). Have in mind need be separated by a dot. + + - **['id' => '(\d+)']:** If your route pattern has parameters you will provide a regular expression pattern that the value must match for the route to match. In this case, the id parameter (which was defined as `:id` in the pattern) must be an integer consisting of one or more digits (including the value 0). + + - **$defaults:** Last but not least. In this variable we defined: + + - `'component' => 'com_vapi'` The associated component + - `'public' => $publicGets` Need be true if you have a route that you want it to be accessible by unauthenticated users, like how we did. False otherwise. + - `'format' => ['application/json']` Here is where is defined that our application will handle a json format response. Without this, Joomla will use the default JSON-API. + +Before jump to our component code, remember the plugin need have the **vapi.xml** manifest file. Will be a standard manifest, nothing new to add. You can follow any manifest inside the webservices plugins group. + +## Component API part + +**A reminder that before start with this part you need have your component with a basic functionality.** + +In Joomla 4, your component has another optional part: the `api` part. Just like the component's frontend (site) and backend (administrator) it has its own Controllers, Views, and Models to render not HTML pages but JSON result sets. + +Your component XML manifest needs to have an `` section under the `` root node, defining the files and folders included in your component's api part. Typically, it looks like this: + +### XML manifest - API section + +```xml + + + src + + +``` + +In your component root installation folder, create now a new folder called `api`. This folder will have a sub-folder `src`, here is where we will add all our API folders and files. Let start now with our controller. Create now the folder `Controller` with the file **ModuleController.php** and the follow code inside: + +### Controller - Class declaration + +```php +moduleParams = new \Joomla\Registry\Registry($config['moduleParams']); + } + + parent::__construct($config, $factory, $app, $input); + } + + # your methods code from here... +} +``` + +Notice the namespace of the controller. You can change it for your own custom namespace your component already have. You should change **Vapi** who is the name I using in this component, and the prefix **Carlitorweb**, the rest _by conventions_ is better let it as that (but you can change all to fit your needs). + +Also, the JSON-API from the Joomla core extends the controllers from `Joomla\CMS\MVC\Controller\ApiController`. The need in our case is get a JSON response, and for that extends from `\Joomla\CMS\MVC\Controller\BaseController`. + +We also declared 2 properties, one will be used for tell Joomla the view file we expect to use and the other is for set the module params for model the data we will send in the API response. + +Now let see the methods who will be involve in the class: + +### Controller - Methods declaration + +```php +/** + * Set the models and execute the view + * + * @throws \Exception + */ + public function displayModule(): void + { + # your code here... + } + + /** + * Boot the model and set the states + * + * @param \Joomla\Registry\Registry $params The module params + * + */ + protected function getMainModelForView($params): \Joomla\Component\Content\Site\Model\ArticlesModel + { + # your code here... + } + + /** + * Set the module params + * + * @param \Carlitorweb\Component\Vapi\Api\Model\ModuleModel $moduleModel + * + */ + protected function setModuleParams($moduleModel): \Joomla\Registry\Registry + { + # your code here... + } +``` + +`displayModule()` Is the method we defined in our webservices plugin as the task to be execute. This is the first method the controller will use. If you want to test all go as expected, put the follow in the start of this method: + +```php +var_dump(__METHOD__);die; +``` + +Then using your favorite API client like Postman, or Thunder Client from vscode or curl...make a request to the route `[yourLocalRootSiteURL]/api/index.php/v1/vapi/modules/[idOfYourModule]`. You will see this response: + +```log +string(73)"Carlitorweb\Component\Vapi\Api\Controller\ModuleController::displayModule" +``` + +`getMainModelForView()` The purpose of this method is for boot and prepare the _main_ model the view will use. And I wrote _main_ because Joomla allow the view interact with more than one model. + +`setModuleParams()` Here is where we will get the module params to use in `getMainModelForView()`. If you notice, the method use a parameter `\Carlitorweb\Component\Vapi\Api\Model\ModuleModel`. This is a custom Model the API will have, and we need to create. Here is where we will get the module, based in the ID passed as parameter in the requested URL. **At this point, you need to know this ID need match with a already created frontend module in your Joomla administration.** + +Since parameters are so necessary, let's immediately create our model. + +### Model - Class definition + +In the same root where we created our `Controller` folder, let now create the `Model` folder with the file **ModuleModel.php** and the follow code: + +```php +state->get('moduleID', 0); + + if ($mid === 0) { + throw new \InvalidArgumentException( + sprintf( + 'A module ID is necessary in %s', + __METHOD__ + ) + ); + } + + /** @var \Joomla\Database\DatabaseInterface $db */ + $db = $this->getDatabase(); + $query = $this->getModuleQuery($db, $mid); + + // Set the query + $db->setQuery($query); + + // Build a cache ID for the resulting data object + $cacheId = 'com_vapi.moduleId' . $mid; + + try { + /** @var \Joomla\CMS\Cache\Controller\CallbackController $cache */ + $cache = Factory::getContainer()->get(CacheControllerFactoryInterface::class) + ->createCacheController('callback', ['defaultgroup' => 'com_modules']); + + $module = $cache->get(array($db, 'loadObject'), array(), md5($cacheId), false); + } catch (\RuntimeException $e) { + $app->getLogger()->warning( + Text::sprintf('JLIB_APPLICATION_ERROR_MODULE_LOAD', $e->getMessage()), + array('category' => 'jerror') + ); + + return new \stdClass(); + } + + return $module; + } + + /** + * Get the module query + * + * @param int $mid The ID of the module + * @param \Joomla\Database\DatabaseInterface $db + * + */ + protected function getModuleQuery($db, $mid): \Joomla\Database\QueryInterface + { + $query = $db->getQuery(true); + + $query->select('*') + ->from($db->quoteName('#__modules')) + ->where( + $db->quoteName('id') . ' = :moduleId' + ) + ->bind(':moduleId', $mid, ParameterType::INTEGER); + + return $query; + } +} +``` + +Pretty simple model. We get the module ID to search in the line `$this->state->get('moduleID', 0)`. We need provide this ID in our controller (we will do soon). Using then the method ` $this->getModuleQuery()` is builded the database query we will execute after. Finally, we use a try/catch block to get the module object and cache it. + +With the model ready, let get back to our controller, from there we can test if our model is running as should be. + +### Controller - Methods definition + +Now that we can get a specific module, let complete the method `setModuleParams()` + +```php + /** + * Set the module params + * + * @param \Carlitorweb\Component\Vapi\Api\Model\ModuleModel $moduleModel + * + */ + protected function setModuleParams($moduleModel): \Joomla\Registry\Registry + { + // Get the module params + $module = $moduleModel->getModule(); + + if (is_null($module)) { + throw new \UnexpectedValueException( + sprintf( + '$module need be of type object, %s was returned in %s()', + gettype($module), __FUNCTION__ + ) + ); + } + + return $this->moduleParams = new \Joomla\Registry\Registry($module->params); + } +``` + +Let see if the controller property $moduleParams is getting the expected result. For this let edit the main method `displayModule()`: + +```php + /** + * Set the models and execute the view + * + * @throws \Exception + */ + public function displayModule(): void + { + $moduleID = $this->input->get('id', 0, 'int'); + $moduleState = new \Joomla\Registry\Registry(['moduleID' => $moduleID]); + + /** @var \Carlitorweb\Component\Vapi\Api\Model\ModuleModel $moduleModel */ + $moduleModel = $this->factory->createModel('Module', 'Api', ['ignore_request' => true, 'state' => $moduleState]); + + // Set the params who will be used by the model + if(empty($this->moduleParams)) { + $this->setModuleParams($moduleModel); + } + + var_dump($this->moduleParams);die; + } +``` + +- `$this->input->get('id', 0, 'int')`: The value of the `:id` parameter in the URL (the one we defined in the webservices plugin). + +- `'state' => $moduleState`: Notice we passed the ID when load the model. We already saw where we used this ID inside the model. + +Again, using your favorite API client, make a request to the route `[yourLocalRootSiteURL]/api/index.php/v1/vapi/modules/[idOfYourModule]`. You will see something like this: + +```json +object(Joomla\Registry\Registry)#938 (3) { + ["data":protected]=> + object(stdClass)#1090 (44) { + ["mode"]=> + string(6) "normal" + ["show_on_article_page"]=> + int(1) + ["count"]=> + int(0) + ["show_front"]=> + string(4) "only" + ["category_filtering_type"]=> + int(1) + ["catid"]=> + array(5) { + [0]=> + int(2) + [1]=> + int(8) + [2]=> + int(9) + [3]=> + int(10) +..... +``` + +With the params in our hands, let use it. Edit the method `getMainModelForView()`: + +```php + /** + * Boot the model and set the states + * + * @param \Joomla\Registry\Registry $params The module Articles - Category params + * + */ + protected function getMainModelForView($params): \Joomla\Component\Content\Site\Model\ArticlesModel + { + $mvcContentFactory = $this->app->bootComponent('com_content')->getMVCFactory(); + + // Get an instance of the generic articles model + /** @var \Joomla\Component\Content\Site\Model\ArticlesModel $articlesModel */ + $articlesModel = $mvcContentFactory->createModel('Articles', 'Site', ['ignore_request' => true]); + + if (!$articlesModel) { + throw new \RuntimeException(Text::_('JLIB_APPLICATION_ERROR_MODEL_CREATE')); + } + + $appParams = ComponentHelper::getComponent('com_content')->getParams(); + $articlesModel->setState('params', $appParams); + + $articlesModel->setState('filter.published', ContentComponent::CONDITION_PUBLISHED); + + /* + * Set the filters based on the module params + */ + $articlesModel->setState('list.start', 0); + $articlesModel->setState('list.limit', (int) $params->get('count', 0)); + + $catids = $params->get('catid'); + $articlesModel->setState('filter.category_id', $catids); + + // Ordering + $ordering = $params->get('article_ordering', 'a.ordering'); + $articlesModel->setState('list.ordering', $ordering); + $articlesModel->setState('list.direction', $params->get('article_ordering_direction', 'ASC')); + + $articlesModel->setState('filter.featured', $params->get('show_front', 'show')); + + $excluded_articles = $params->get('excluded_articles', ''); + + if ($excluded_articles) { + $excluded_articles = explode("\r\n", $excluded_articles); + $articlesModel->setState('filter.article_id', $excluded_articles); + + // Exclude + $articlesModel->setState('filter.article_id.include', false); + } + + return $articlesModel; + } +``` + +**The params we using to model our data come from the Articles - Category module. That is the ID we request with the `:id` parameter.** (Notice also was not used all the params) + +Not much to explain in this method, you should be familiar with this code. The ArticlesModel is loaded and a set of model states is defined for get the data, based in the module params. + +Let edit again the main method `displayModule()` for test we are getting the ArticlesModel object: + +```php + /** + * Set the models and execute the view + * + * @throws \Exception + */ + public function displayModule(): void + { + $moduleID = $this->input->get('id', 0, 'int'); + $moduleState = new \Joomla\Registry\Registry(['moduleID' => $moduleID]); + + /** @var \Carlitorweb\Component\Vapi\Api\Model\ModuleModel $moduleModel */ + $moduleModel = $this->factory->createModel('Module', 'Api', ['ignore_request' => true, 'state' => $moduleState]); + + // Set the params who will be used by the model + if(empty($this->moduleParams)) { + $this->setModuleParams($moduleModel); + } + + $mainModel = $this->getMainModelForView($this->moduleParams); + + var_dump($mainModel::class);die; + } +``` + +Again, using your favorite API client, make a request to the route `[yourLocalRootSiteURL]/api/index.php/v1/vapi/modules/[idOfYourModule]`. You will get: + +```log +string(49) "Joomla\Component\Content\Site\Model\ArticlesModel" +``` + +With all working, we ready to set our view and get the expected json response. Let edit one last time the main method `displayModule()`: + +```php + /** + * Set the models and execute the view + * + * @throws \Exception + */ + public function displayModule(): void + { + $moduleID = $this->input->get('id', 0, 'int'); + $moduleState = new \Joomla\Registry\Registry(['moduleID' => $moduleID]); + + /** @var \Carlitorweb\Component\Vapi\Api\Model\ModuleModel $moduleModel */ + $moduleModel = $this->factory->createModel('Module', 'Api', ['ignore_request' => true, 'state' => $moduleState]); + + // Set the params who will be used by the model + if(empty($this->moduleParams)) { + $this->setModuleParams($moduleModel); + } + + $mainModel = $this->getMainModelForView($this->moduleParams); + + /** @var \Joomla\CMS\Document\JsonDocument $document */ + $document = $this->app->getDocument(); + + $viewType = $document->getType(); + $viewName = $this->input->get('view', $this->default_view); + $viewLayout = $this->input->get('layout', 'default', 'string'); + + try { + /** @var \Carlitorweb\Component\Vapi\Api\View\Modules\JsonView $view */ + $view = $this->getView( + $viewName, + $viewType, + '', + ['moduleParams' => $this->moduleParams, 'base_path' => $this->basePath, 'layout' => $viewLayout] + ); + } catch (\Exception $e) { + throw new \RuntimeException($e->getMessage()); + } + + // Push the model into the view (as default) + $view->setModel($mainModel, true); + + // Push as secondary model the Module model + $view->setModel($moduleModel); + + $view->document = $this->app->getDocument(); + + $view->display(); + } +``` + +- `$this->getView()`: Joomla will look for a folder **Modules** (the name defined in the `$viewName` variable) inside the folder **View** who need be in the root of our component API part (where we already have the folders Controller and Model). + +- `'moduleParams' => $this->moduleParams`: Notice was send to the view the module params + +- `$view->setModel()`: Here we set in the view object the two models we using in the API. The default model have the data we want to output, and the `$moduleModel` is our custom model (this last one is optional) + +- `$view->display()`: Execute and display the output. + +Let create our last file, the view. + +### View - Class and methods definition + +```php +display['show_date'] = $params->get('show_date', 0); + $this->display['show_date_field'] = $params->get('show_date_field', 'created'); + $this->display['show_date_format'] = $params->get('show_date_format', 'Y-m-d H:i:s'); + $this->display['show_category'] = $params->get('show_category', 0); + $this->display['show_author'] = $params->get('show_author', 0); + $this->display['show_hits'] = $params->get('show_hits', 0); + } + + parent::__construct($config); + } + + /** + * Set the data who will be load + */ + protected function setOutput(array $items = null): void + { + /** @var \Joomla\CMS\MVC\Model\ListModel $mainModel */ + $mainModel = $this->getModel(); + + /** @var \Carlitorweb\Component\Vapi\Api\Model\ModuleModel $moduleModel */ + $moduleModel = $this->getModel('module'); + + if ($items === null) { + $items = []; + + foreach ($mainModel->getItems() as $item) { + $_item = $this->prepareItem($item, $moduleModel); + $items[] = $this->getAllowedPropertiesToRender($_item); + } + } + + // Check for errors. + if (\count($errors = $this->get('Errors'))) { + throw new GenericDataException(implode("\n", $errors), 500); + } + + $this->_output = $items; + } + + /** + * @param \stdClass $item The article to prepare + */ + protected function getAllowedPropertiesToRender($item): \stdClass + { + $allowedFields = new \stdClass; + + foreach($item as $key => $value) { + if (in_array($key, $this->fieldsToRenderList, true)) { + $allowedFields->$key = $value; + } + } + + return $allowedFields; + } + + /** + * Prepare item before render. + * + * @param object $item The model item + * @param ModuleModel $moduleModel + * + * @return object + * + */ + protected function prepareItem($item, $moduleModel) + { + $item->slug = $item->alias . ':' . $item->id; + if ($this->display['show_date']) { + $show_date_field = $this->display['show_date_field']; + $item->displayDate = HTMLHelper::_('date', $item->$show_date_field, $this->display['show_date_format']); + } + + $item->displayCategoryTitle = $this->display['show_category'] ? $item->category_title : ''; + + $item->displayHits = $this->display['show_hits'] ? $item->hits : ''; + $item->displayAuthorName = $this->display['show_author'] ? $item->author : ''; + + return $item; + } + + /** + * Execute and display a template script. + * + * @param string $tpl The name of the template file to parse; automatically searches through the template paths. + * + * @return void + * + */ + public function display($tpl = null) + { + // remove any string that could create an invalid JSON + // such as PHP Notice, Warning, logs... + ob_clean(); + + // this will clean up any previously added headers, to start clean + header_remove(); + + $this->setOutput(); + + parent::display($tpl); + + echo $this->document->render(); + } +} +``` + +- `JsonView`: This is important. The name need be as this, since Joomla will look for this class name. Also, the Joomla core JSON-API extends the view from `Joomla\CMS\MVC\View\JsonApiView`, as the goal of this tutorial is get a JSON response, need be from `\Joomla\CMS\MVC\View\JsonView`. + +- `setOutput()`: Using the `$this->getModel()` method we get access to the models we set in the controller, one by default and another where is needed the name as key reference in the \Joomla\CMS\MVC\View\AbstractView::\_models array. + +- `getAllowedPropertiesToRender()`: If you have a public route you MUST think about which fields you'll be including in your JsonView object. Not all fields are suitable for public display; that could lead to a security vulnerability known as information disclosure. + + For example, your forum component may be saving the IP address alongside the user ID and creation date and time of a forum post. DO NOT make the IP address and user ID available to the public. This combination is considered Personally Identifiable Information and can result in fines! Just the user ID may be privileged information depending on the context of the site (remember that usernames are not privileged information, but the internal user IDs are). + +- `$this->document->render()`: Outputs the document + +One more time, using your favorite API client, make a request to the route `[yourLocalRootSiteURL]/api/index.php/v1/vapi/modules/[idOfYourModule]`. You will get: + +```json +[ + { + "id": 11, + "title": "Typography", + "alias": "typography", + "metakey": "", + "metadesc": "", + "params": {...}, + "displayDate": "2022-11-20 20:49:17", + "displayCategoryTitle": "Typography", + "displayHits": 0, + "displayAuthorName": "Carlos Rodriguez" + } +] +``` + +Nice! Our common JSON response is here for stay ;) diff --git a/versioned_sidebars/version-5.2-sidebars.json b/versioned_sidebars/version-5.2-sidebars.json new file mode 100644 index 00000000..619967e0 --- /dev/null +++ b/versioned_sidebars/version-5.2-sidebars.json @@ -0,0 +1,8 @@ +{ + "manualSidebar": [ + { + "type": "autogenerated", + "dirName": "." + } + ] +} diff --git a/versions.json b/versions.json index 134a1012..f83ef24e 100644 --- a/versions.json +++ b/versions.json @@ -1,4 +1,5 @@ [ + "5.2", "5.1", "5.0", "4.4" diff --git a/versionsArchived.json b/versionsArchived.json index 5b6aa12b..6a5f553e 100644 --- a/versionsArchived.json +++ b/versionsArchived.json @@ -1,3 +1,5 @@ { - "< 4.4": "https://docs.joomla.org/Portal:Developers" + "3.x": "https://docs.joomla.org/Category:Joomla!_3.0", + "2.5": "https://docs.joomla.org/Category:Joomla!_2.5", + "< 2.5": "https://docs.joomla.org/Portal:Developers" }