├── .env
├── .gitattributes
├── .gitignore
├── README.md
├── docker-compose.override.blackfire.yml
├── docker-compose.override.xhprof.yml
├── docker-compose.yml
├── docker
├── logs
│ ├── nginx
│ │ └── .gitkeep
│ └── php
│ │ └── .gitkeep
├── mariadb
│ └── conf
│ │ └── custom.cnf
├── modx
│ ├── storage
│ │ ├── backup
│ │ │ └── .gitkeep
│ │ └── cache
│ │ │ └── .gitkeep
│ └── tools
│ │ └── configurator
│ │ ├── composer.json
│ │ ├── config.inc.php
│ │ ├── example.config.inc.php
│ │ ├── run.php
│ │ ├── src
│ │ ├── Runner
│ │ │ ├── Runner.php
│ │ │ └── RunnerInterface.php
│ │ ├── Tasks
│ │ │ ├── GrantAccessUserTask.php
│ │ │ ├── InstallPackagesTask.php
│ │ │ ├── MiniShop2Task.php
│ │ │ ├── SetOptionsTask.php
│ │ │ ├── Task.php
│ │ │ ├── TaskInterface.php
│ │ │ └── TransportProvidersTask.php
│ │ ├── Traits
│ │ │ ├── DocumentTrait.php
│ │ │ ├── ElementsTrait.php
│ │ │ ├── InitializeTrait.php
│ │ │ ├── OptionTrait.php
│ │ │ ├── PropertiesTrait.php
│ │ │ ├── SecurityTrait.php
│ │ │ └── TransportProviderTrait.php
│ │ └── Utils
│ │ │ └── Logger.php
│ │ └── storage
│ │ └── ms2
│ │ ├── demo
│ │ ├── categories.csv
│ │ ├── products.csv
│ │ ├── products
│ │ │ ├── 1-2-thickbox.jpg
│ │ │ ├── 10-21-thickbox.jpg
│ │ │ ├── 10-22-thickbox.jpg
│ │ │ ├── 100-181-thickbox.jpg
│ │ │ ├── 101-182-thickbox.jpg
│ │ │ ├── 101-183-thickbox.jpg
│ │ │ ├── 101-184-thickbox.jpg
│ │ │ ├── 101-185-thickbox.jpg
│ │ │ ├── 102-186-thickbox.jpg
│ │ │ ├── 103-187-thickbox.jpg
│ │ │ ├── 104-188-thickbox.jpg
│ │ │ ├── 105-189-thickbox.jpg
│ │ │ ├── 106-190-thickbox.jpg
│ │ │ ├── 106-191-thickbox.jpg
│ │ │ ├── 106-192-thickbox.jpg
│ │ │ ├── 106-193-thickbox.jpg
│ │ │ ├── 106-195-thickbox.jpg
│ │ │ ├── 107-196-thickbox.jpg
│ │ │ ├── 107-197-thickbox.jpg
│ │ │ ├── 108-198-thickbox.jpg
│ │ │ ├── 108-199-thickbox.jpg
│ │ │ ├── 108-200-thickbox.jpg
│ │ │ ├── 109-201-thickbox.jpg
│ │ │ ├── 11-23-thickbox.jpg
│ │ │ ├── 11-24-thickbox.jpg
│ │ │ ├── 110-202-thickbox.jpg
│ │ │ ├── 110-203-thickbox.jpg
│ │ │ ├── 111-204-thickbox.jpg
│ │ │ ├── 112-205-thickbox.jpg
│ │ │ ├── 113-206-thickbox.jpg
│ │ │ ├── 114-207-thickbox.jpg
│ │ │ ├── 115-208-thickbox.jpg
│ │ │ ├── 115-209-thickbox.jpg
│ │ │ ├── 116-210-thickbox.jpg
│ │ │ ├── 117-211-thickbox.jpg
│ │ │ ├── 118-212-thickbox.jpg
│ │ │ ├── 119-213-thickbox.jpg
│ │ │ ├── 12-25-thickbox.jpg
│ │ │ ├── 120-214-thickbox.jpg
│ │ │ ├── 121-215-thickbox.jpg
│ │ │ ├── 122-216-thickbox.jpg
│ │ │ ├── 123-217-thickbox.jpg
│ │ │ ├── 124-218-thickbox.jpg
│ │ │ ├── 124-219-thickbox.jpg
│ │ │ ├── 125-220-thickbox.jpg
│ │ │ ├── 126-221-thickbox.jpg
│ │ │ ├── 127-222-thickbox.jpg
│ │ │ ├── 127-223-thickbox.jpg
│ │ │ ├── 127-224-thickbox.jpg
│ │ │ ├── 128-225-thickbox.jpg
│ │ │ ├── 128-226-thickbox.jpg
│ │ │ ├── 129-227-thickbox.jpg
│ │ │ ├── 13-26-thickbox.jpg
│ │ │ ├── 130-228-thickbox.jpg
│ │ │ ├── 131-229-thickbox.jpg
│ │ │ ├── 132-230-thickbox.jpg
│ │ │ ├── 133-231-thickbox.jpg
│ │ │ ├── 134-232-thickbox.jpg
│ │ │ ├── 134-233-thickbox.jpg
│ │ │ ├── 134-234-thickbox.jpg
│ │ │ ├── 135-235-thickbox.jpg
│ │ │ ├── 136-236-thickbox.jpg
│ │ │ ├── 136-237-thickbox.jpg
│ │ │ ├── 136-238-thickbox.jpg
│ │ │ ├── 136-239-thickbox.jpg
│ │ │ ├── 136-240-thickbox.jpg
│ │ │ ├── 137-242-thickbox.jpg
│ │ │ ├── 137-243-thickbox.jpg
│ │ │ ├── 137-244-thickbox.jpg
│ │ │ ├── 137-245-thickbox.jpg
│ │ │ ├── 137-246-thickbox.jpg
│ │ │ ├── 138-247-thickbox.jpg
│ │ │ ├── 138-248-thickbox.jpg
│ │ │ ├── 138-249-thickbox.jpg
│ │ │ ├── 138-250-thickbox.jpg
│ │ │ ├── 138-251-thickbox.jpg
│ │ │ ├── 139-252-thickbox.jpg
│ │ │ ├── 139-253-thickbox.jpg
│ │ │ ├── 139-254-thickbox.jpg
│ │ │ ├── 14-27-thickbox.jpg
│ │ │ ├── 143-260-thickbox.jpg
│ │ │ ├── 143-261-thickbox.jpg
│ │ │ ├── 143-262-thickbox.jpg
│ │ │ ├── 143-263-thickbox.jpg
│ │ │ ├── 144-264-thickbox.jpg
│ │ │ ├── 144-265-thickbox.jpg
│ │ │ ├── 144-266-thickbox.jpg
│ │ │ ├── 144-267-thickbox.jpg
│ │ │ ├── 145-268-thickbox.jpg
│ │ │ ├── 145-269-thickbox.jpg
│ │ │ ├── 145-270-thickbox.jpg
│ │ │ ├── 145-271-thickbox.jpg
│ │ │ ├── 146-272-thickbox.jpg
│ │ │ ├── 146-273-thickbox.jpg
│ │ │ ├── 146-274-thickbox.jpg
│ │ │ ├── 146-275-thickbox.jpg
│ │ │ ├── 147-276-thickbox.jpg
│ │ │ ├── 147-277-thickbox.jpg
│ │ │ ├── 147-278-thickbox.jpg
│ │ │ ├── 148-279-thickbox.jpg
│ │ │ ├── 148-280-thickbox.jpg
│ │ │ ├── 148-281-thickbox.jpg
│ │ │ ├── 148-282-thickbox.jpg
│ │ │ ├── 148-283-thickbox.jpg
│ │ │ ├── 149-284-thickbox.jpg
│ │ │ ├── 149-285-thickbox.jpg
│ │ │ ├── 149-286-thickbox.jpg
│ │ │ ├── 15-28-thickbox.jpg
│ │ │ ├── 15-29-thickbox.jpg
│ │ │ ├── 150-287-thickbox.jpg
│ │ │ ├── 151-288-thickbox.jpg
│ │ │ ├── 152-289-thickbox.jpg
│ │ │ ├── 153-290-thickbox.jpg
│ │ │ ├── 16-30-thickbox.jpg
│ │ │ ├── 17-31-thickbox.jpg
│ │ │ ├── 17-32-thickbox.jpg
│ │ │ ├── 17-33-thickbox.jpg
│ │ │ ├── 17-34-thickbox.jpg
│ │ │ ├── 17-35-thickbox.jpg
│ │ │ ├── 18-37-thickbox.jpg
│ │ │ ├── 19-40-thickbox.jpg
│ │ │ ├── 19-41-thickbox.jpg
│ │ │ ├── 2-3-thickbox.jpg
│ │ │ ├── 2-4-thickbox.jpg
│ │ │ ├── 20-38-thickbox.jpg
│ │ │ ├── 20-39-thickbox.jpg
│ │ │ ├── 21-42-thickbox.jpg
│ │ │ ├── 21-43-thickbox.jpg
│ │ │ ├── 21-44-thickbox.jpg
│ │ │ ├── 21-45-thickbox.jpg
│ │ │ ├── 22-46-thickbox.jpg
│ │ │ ├── 23-47-thickbox.jpg
│ │ │ ├── 23-48-thickbox.jpg
│ │ │ ├── 23-49-thickbox.jpg
│ │ │ ├── 24-50-thickbox.jpg
│ │ │ ├── 24-51-thickbox.jpg
│ │ │ ├── 24-52-thickbox.jpg
│ │ │ ├── 24-53-thickbox.jpg
│ │ │ ├── 24-54-thickbox.jpg
│ │ │ ├── 25-56-thickbox.jpg
│ │ │ ├── 25-57-thickbox.jpg
│ │ │ ├── 26-58-thickbox.jpg
│ │ │ ├── 27-59-thickbox.jpg
│ │ │ ├── 27-60-thickbox.jpg
│ │ │ ├── 27-61-thickbox.jpg
│ │ │ ├── 27-62-thickbox.jpg
│ │ │ ├── 27-63-thickbox.jpg
│ │ │ ├── 28-65-thickbox.jpg
│ │ │ ├── 28-66-thickbox.jpg
│ │ │ ├── 29-67-thickbox.jpg
│ │ │ ├── 29-68-thickbox.jpg
│ │ │ ├── 29-69-thickbox.jpg
│ │ │ ├── 3-5-thickbox.jpg
│ │ │ ├── 30-70-thickbox.jpg
│ │ │ ├── 30-71-thickbox.jpg
│ │ │ ├── 30-72-thickbox.jpg
│ │ │ ├── 31-73-thickbox.jpg
│ │ │ ├── 32-74-thickbox.jpg
│ │ │ ├── 32-75-thickbox.jpg
│ │ │ ├── 32-76-thickbox.jpg
│ │ │ ├── 32-77-thickbox.jpg
│ │ │ ├── 33-78-thickbox.jpg
│ │ │ ├── 34-79-thickbox.jpg
│ │ │ ├── 35-80-thickbox.jpg
│ │ │ ├── 36-81-thickbox.jpg
│ │ │ ├── 37-82-thickbox.jpg
│ │ │ ├── 37-83-thickbox.jpg
│ │ │ ├── 37-84-thickbox.jpg
│ │ │ ├── 37-85-thickbox.jpg
│ │ │ ├── 38-86-thickbox.jpg
│ │ │ ├── 39-87-thickbox.jpg
│ │ │ ├── 4-10-thickbox.jpg
│ │ │ ├── 4-6-thickbox.jpg
│ │ │ ├── 4-7-thickbox.jpg
│ │ │ ├── 4-8-thickbox.jpg
│ │ │ ├── 4-9-thickbox.jpg
│ │ │ ├── 40-88-thickbox.jpg
│ │ │ ├── 40-89-thickbox.jpg
│ │ │ ├── 40-90-thickbox.jpg
│ │ │ ├── 40-91-thickbox.jpg
│ │ │ ├── 41-92-thickbox.jpg
│ │ │ ├── 42-93-thickbox.jpg
│ │ │ ├── 43-94-thickbox.jpg
│ │ │ ├── 44-95-thickbox.jpg
│ │ │ ├── 45-96-thickbox.jpg
│ │ │ ├── 46-97-thickbox.jpg
│ │ │ ├── 47-98-thickbox.jpg
│ │ │ ├── 48-100-thickbox.jpg
│ │ │ ├── 48-99-thickbox.jpg
│ │ │ ├── 49-101-thickbox.jpg
│ │ │ ├── 5-12-thickbox.jpg
│ │ │ ├── 50-102-thickbox.jpg
│ │ │ ├── 51-103-thickbox.jpg
│ │ │ ├── 52-104-thickbox.jpg
│ │ │ ├── 53-105-thickbox.jpg
│ │ │ ├── 54-106-thickbox.jpg
│ │ │ ├── 55-107-thickbox.jpg
│ │ │ ├── 56-108-thickbox.jpg
│ │ │ ├── 57-109-thickbox.jpg
│ │ │ ├── 58-110-thickbox.jpg
│ │ │ ├── 6-13-thickbox.jpg
│ │ │ ├── 60-111-thickbox.jpg
│ │ │ ├── 61-112-thickbox.jpg
│ │ │ ├── 62-113-thickbox.jpg
│ │ │ ├── 63-114-thickbox.jpg
│ │ │ ├── 64-115-thickbox.jpg
│ │ │ ├── 65-116-thickbox.jpg
│ │ │ ├── 66-117-thickbox.jpg
│ │ │ ├── 67-118-thickbox.jpg
│ │ │ ├── 67-119-thickbox.jpg
│ │ │ ├── 67-120-thickbox.jpg
│ │ │ ├── 67-121-thickbox.jpg
│ │ │ ├── 68-122-thickbox.jpg
│ │ │ ├── 69-123-thickbox.jpg
│ │ │ ├── 7-14-thickbox.jpg
│ │ │ ├── 7-15-thickbox.jpg
│ │ │ ├── 7-16-thickbox.jpg
│ │ │ ├── 7-17-thickbox.jpg
│ │ │ ├── 70-124-thickbox.jpg
│ │ │ ├── 71-125-thickbox.jpg
│ │ │ ├── 72-126-thickbox.jpg
│ │ │ ├── 72-127-thickbox.jpg
│ │ │ ├── 72-128-thickbox.jpg
│ │ │ ├── 72-129-thickbox.jpg
│ │ │ ├── 73-130-thickbox.jpg
│ │ │ ├── 73-131-thickbox.jpg
│ │ │ ├── 73-132-thickbox.jpg
│ │ │ ├── 73-133-thickbox.jpg
│ │ │ ├── 74-134-thickbox.jpg
│ │ │ ├── 75-135-thickbox.jpg
│ │ │ ├── 76-136-thickbox.jpg
│ │ │ ├── 77-137-thickbox.jpg
│ │ │ ├── 78-138-thickbox.jpg
│ │ │ ├── 78-139-thickbox.jpg
│ │ │ ├── 78-140-thickbox.jpg
│ │ │ ├── 79-141-thickbox.jpg
│ │ │ ├── 8-18-thickbox.jpg
│ │ │ ├── 8-19-thickbox.jpg
│ │ │ ├── 80-142-thickbox.jpg
│ │ │ ├── 80-143-thickbox.jpg
│ │ │ ├── 81-144-thickbox.jpg
│ │ │ ├── 82-145-thickbox.jpg
│ │ │ ├── 82-146-thickbox.jpg
│ │ │ ├── 83-147-thickbox.jpg
│ │ │ ├── 84-148-thickbox.jpg
│ │ │ ├── 84-149-thickbox.jpg
│ │ │ ├── 85-150-thickbox.jpg
│ │ │ ├── 86-151-thickbox.jpg
│ │ │ ├── 87-152-thickbox.jpg
│ │ │ ├── 88-153-thickbox.jpg
│ │ │ ├── 89-154-thickbox.jpg
│ │ │ ├── 9-20-thickbox.jpg
│ │ │ ├── 90-155-thickbox.jpg
│ │ │ ├── 91-156-thickbox.jpg
│ │ │ ├── 91-157-thickbox.jpg
│ │ │ ├── 91-158-thickbox.jpg
│ │ │ ├── 91-159-thickbox.jpg
│ │ │ ├── 91-160-thickbox.jpg
│ │ │ ├── 92-162-thickbox.jpg
│ │ │ ├── 92-163-thickbox.jpg
│ │ │ ├── 93-164-thickbox.jpg
│ │ │ ├── 94-165-thickbox.jpg
│ │ │ ├── 94-166-thickbox.jpg
│ │ │ ├── 94-167-thickbox.jpg
│ │ │ ├── 94-169-thickbox.jpg
│ │ │ ├── 94-170-thickbox.jpg
│ │ │ ├── 95-172-thickbox.jpg
│ │ │ ├── 96-173-thickbox.jpg
│ │ │ ├── 97-174-thickbox.jpg
│ │ │ ├── 97-175-thickbox.jpg
│ │ │ ├── 97-177-thickbox.jpg
│ │ │ ├── 97-178-thickbox.jpg
│ │ │ ├── 98-179-thickbox.jpg
│ │ │ └── 99-180-thickbox.jpg
│ │ ├── vendors.csv
│ │ └── vendors
│ │ │ ├── asus.jpg
│ │ │ ├── bosch.jpg
│ │ │ ├── canon.jpg
│ │ │ ├── dlink.jpg
│ │ │ ├── motorola.jpg
│ │ │ ├── nikon.jpg
│ │ │ ├── panasonic.jpg
│ │ │ ├── philips.jpg
│ │ │ └── samsung.jpg
│ │ ├── pages
│ │ ├── cart.tpl
│ │ └── category.tpl
│ │ └── templates
│ │ ├── cart.tpl
│ │ ├── category.tpl
│ │ └── product.tpl
├── nginx
│ ├── default.conf.template
│ └── ssl
│ │ └── .gitkeep
├── php
│ ├── Dockerfile
│ ├── conf
│ │ ├── opcache.ini
│ │ ├── php.ini
│ │ ├── xdebug.ini
│ │ └── xhprof.ini
│ ├── sh
│ │ ├── modx-clear-db.sh
│ │ ├── modx-clear-site.sh
│ │ ├── modx-configure.sh
│ │ ├── modx-docker-start.sh
│ │ ├── modx-download.sh
│ │ ├── modx-export.sh
│ │ ├── modx-generate-ssl.sh
│ │ ├── modx-import.sh
│ │ ├── modx-install.sh
│ │ ├── modx-uninstall.sh
│ │ └── modx-upgrade.sh
│ └── xhprof
│ │ ├── composer.json
│ │ └── handler.php
├── volume
│ └── mariadb
│ │ └── .gitkeep
└── xhgui
│ ├── Dockerfile
│ ├── apache.conf
│ ├── config.php
│ ├── mongo.init.d
│ └── xhgui.js
│ └── templates
│ └── runs
│ └── view.twig
├── docs
├── images
│ ├── architecture-dark.svg
│ ├── architecture-light.svg
│ └── video-cover.jpg
└── readme-ru.md
└── www
└── .gitkeep
/.env:
--------------------------------------------------------------------------------
1 | PHP_VERSION=7.4
2 | MODX_VERSION=2.8.8-pl
3 |
4 | MODX_INSTALL_ENABLE=1
5 | MODX_USE_CACHE_SOURCE=1
6 |
7 | MODX_CONFIGURE_ENABLE=0
8 | MODX_CONFIGURE_DEV_MODE=0
9 |
10 | MODX_DB_SERVER=mariadb
11 | MODX_DB_NAME=modx
12 | MODX_DB_USER=modx
13 | MODX_DB_PASSWORD=modx
14 | MODX_DB_CONNECTION_CHARSET=utf8mb4
15 | MODX_DB_CHARSET=utf8mb4
16 | MODX_DB_CHARSET_COLLATION=utf8mb4_general_ci
17 | MODX_TABLE_PREFIX=random:8
18 | MODX_HTTPS_PORT=443
19 | MODX_HTTP_HOST=localhost
20 | MODX_LANGUAGE=en
21 | MODX_CMS_ADMIN=admin
22 | MODX_CMS_PASS=admin
23 | MODX_CMS_EMAIL=email@example.local
24 | MODX_CORE_PATH=/var/www/html/core/
25 | MODX_BASE_PATH=/var/www/html/
26 | MODX_BASE_URL=/
27 | MODX_CONNECTORS_PATH=/var/www/html/connectors/
28 | MODX_CONNECTORS_URL=/connectors/
29 | MODX_MANAGER_PATH=/var/www/html/manager/
30 | MODX_MANAGER_URL=/manager/
31 | MODX_REMOVE_SETUP_DIRECTORY=1
32 |
33 | MODX_IMPORT_DB=1
34 | MODX_IMPORT_SITE=1
35 |
36 | MODX_EXPORT_DB=1
37 | MODX_EXPORT_SITE=1
38 | MODX_EXPORT_OVERWRITE_CONFIG=0
39 |
40 | MODX_EXPORT_DB_SERVER=
41 | MODX_EXPORT_DB_NAME=
42 | MODX_EXPORT_DB_USER=
43 | MODX_EXPORT_DB_PASSWORD=
44 | MODX_EXPORT_HTTP_HOST=
45 | MODX_EXPORT_CORE_PATH=
46 | MODX_EXPORT_BASE_PATH=
47 | MODX_EXPORT_BASE_URL=
48 | MODX_EXPORT_ASSETS_PATH=
49 | MODX_EXPORT_ASSETS_URL=
50 | MODX_EXPORT_CONNECTORS_PATH=
51 | MODX_EXPORT_CONNECTORS_URL=
52 | MODX_EXPORT_MANAGER_PATH=
53 | MODX_EXPORT_MANAGER_URL=
54 |
55 | XDEBUG_ENABLE=0
56 | XHPROF_ENABLE=0
57 |
58 | XHGUI_PORT=8181
59 | XHGUI_MONGO_URI=mongodb://mongo:27017/xhprof
60 | XHGUI_MONGO_HOSTNAME=mongo
61 | XHGUI_MONGO_DATABASE=xhprof
62 |
63 | BLACKFIRE_ENABLE=0
64 | BLACKFIRE_CLIENT_ID=
65 | BLACKFIRE_CLIENT_TOKEN=
66 | BLACKFIRE_SERVER_ID=
67 | BLACKFIRE_SERVER_TOKEN=
68 |
69 | SSH_ENABLE=1
70 | SSH_LOGIN=dev
71 | SSH_PASSWORD=dev
72 |
73 | SSL_PATH=/etc/nginx/ssl
74 | SSL_GENERATE=1
75 |
76 | NGINX_PORT=80
77 |
78 | SMTP_PORT=1025
79 | SMTP_HOST=mailhog
80 |
81 | MAILHOG_PORT=8025
82 |
83 | MARIADB_PORT=3306
84 | PHPMYADMIN_PORT=8080
85 |
86 | MYSQL_ROOT_PASSWORD=root
87 |
88 | ROOT_PATH=/var/www/html
89 | SERVER_NAME=localhost
90 | LOCALE=en_US.UTF-8
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 | *.sh text eol=lf
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | *.key
3 | *.pem
4 | *.crt
5 | *.csr
6 | *.logxw
--------------------------------------------------------------------------------
/docker-compose.override.blackfire.yml:
--------------------------------------------------------------------------------
1 | services:
2 | php:
3 | build:
4 | args:
5 | BLACKFIRE_ENABLE: ${BLACKFIRE_ENABLE}
6 |
7 | blackfire:
8 | image: blackfire/blackfire:2
9 | ports: ["8307"]
10 | env_file:
11 | - .env
--------------------------------------------------------------------------------
/docker-compose.override.xhprof.yml:
--------------------------------------------------------------------------------
1 | services:
2 | php:
3 | build:
4 | args:
5 | XHPROF_ENABLE: ${XHPROF_ENABLE}
6 | mongo:
7 | image: mongo:latest
8 | container_name: xhgui-mongo
9 | volumes:
10 | - mongo_data:/data/db
11 | - ./docker/xhgui/mongo.init.d:/docker-entrypoint-initdb.d
12 | ports:
13 | - "27017:27017"
14 | environment:
15 | - MONGO_INITDB_DATABASE=xhprof
16 | command: --storageEngine=wiredTiger
17 | xhgui:
18 | build:
19 | context: ./docker/xhgui
20 | dockerfile: Dockerfile
21 | container_name: xhgui
22 | ports:
23 | - "${XHGUI_PORT}:80"
24 | env_file:
25 | - .env
26 | depends_on:
27 | - mongo
28 |
29 | volumes:
30 | mongo_data:
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | nginx:
3 | image: nginx:latest
4 | container_name: nginx
5 | ports:
6 | - "443:443"
7 | - "${NGINX_PORT}:80"
8 | volumes:
9 | - ./www:${ROOT_PATH}
10 | - ./docker/nginx/ssl:${SSL_PATH}
11 | - ./docker/logs/nginx:/var/log/nginx
12 | - ./docker/nginx/default.conf.template:/etc/nginx/templates/default.conf.template
13 | env_file:
14 | - .env
15 | depends_on:
16 | - php
17 |
18 | mariadb:
19 | image: mariadb:latest
20 | container_name: mariadb
21 | volumes:
22 | - ./docker/volume/mariadb:/var/lib/mysql
23 | - ./docker/mariadb/conf/custom.cnf:/etc/mysql/conf.d/custom.cnf:ro
24 | ports:
25 | - "${MARIADB_PORT}:3306"
26 | environment:
27 | MYSQL_DATABASE: ${MODX_DB_NAME}
28 | MYSQL_USER: ${MODX_DB_USER}
29 | MYSQL_PASSWORD: ${MODX_DB_PASSWORD}
30 | env_file:
31 | - .env
32 |
33 | php:
34 | container_name: "php-${PHP_VERSION}"
35 | build:
36 | context: ./docker/php
37 | dockerfile: Dockerfile
38 | args:
39 | LOCALE: ${LOCALE}
40 | SMTP_PORT: ${SMTP_PORT}
41 | SMTP_HOST: ${SMTP_HOST}
42 | ROOT_PATH: ${ROOT_PATH}
43 | PHP_VERSION: ${PHP_VERSION}
44 | XDEBUG_ENABLE: ${XDEBUG_ENABLE}
45 | SSH_ENABLE: ${SSH_ENABLE}
46 | SSH_LOGIN: ${SSH_LOGIN}
47 | SSH_PASSWORD: ${SSH_PASSWORD}
48 | volumes:
49 | - ./www:${ROOT_PATH}
50 | - ./docker/logs/php:/var/log/php-fpm
51 | - ./docker/nginx/ssl:${SSL_PATH}
52 | - ./docker/modx/tools:/usr/local/modx/tools
53 | - ./docker/modx/storage:/usr/local/modx/storage
54 | - ./docker/php/conf/php.ini:/usr/local/etc/php/conf.d/php.ini
55 | - ./docker/php/conf/xdebug.ini:/usr/local/etc/php/conf.d/xdebug.ini
56 | - ./docker/php/conf/xhprof.ini:/usr/local/etc/php/conf.d/xhprof.ini
57 | - ./docker/php/conf/opcache.ini:/usr/local/etc/php/conf.d/opcache.ini
58 | environment:
59 | MODX_RESET: ${MODX_RESET:-0}
60 | MODX_IMPORT: ${MODX_IMPORT:-0}
61 | env_file:
62 | - .env
63 | ports:
64 | - "2222:22"
65 | depends_on:
66 | - mariadb
67 | # restart: unless-stopped
68 |
69 | phpmyadmin:
70 | image: phpmyadmin:latest
71 | container_name: phpmyadmin
72 | environment:
73 | PMA_HOST: mariadb
74 | PMA_PORT: 3306
75 | UPLOAD_LIMIT: ${PHPMYADMIN_UPLOAD_LIMIT:-100M}
76 | ports:
77 | - "${PHPMYADMIN_PORT}:80"
78 | depends_on:
79 | - mariadb
80 |
81 | mailhog:
82 | image: mailhog/mailhog
83 | container_name: mailhog
84 | ports:
85 | - "${MAILHOG_PORT}:8025"
86 | - "${SMTP_PORT}:1025"
--------------------------------------------------------------------------------
/docker/logs/nginx/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Prihod/docker-modx/4fa05bd11e002f3e867d46cfa59956c613a33d52/docker/logs/nginx/.gitkeep
--------------------------------------------------------------------------------
/docker/logs/php/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Prihod/docker-modx/4fa05bd11e002f3e867d46cfa59956c613a33d52/docker/logs/php/.gitkeep
--------------------------------------------------------------------------------
/docker/mariadb/conf/custom.cnf:
--------------------------------------------------------------------------------
1 | [mysqld]
2 | sql_mode="NO_ENGINE_SUBSTITUTION"
--------------------------------------------------------------------------------
/docker/modx/storage/backup/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Prihod/docker-modx/4fa05bd11e002f3e867d46cfa59956c613a33d52/docker/modx/storage/backup/.gitkeep
--------------------------------------------------------------------------------
/docker/modx/storage/cache/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Prihod/docker-modx/4fa05bd11e002f3e867d46cfa59956c613a33d52/docker/modx/storage/cache/.gitkeep
--------------------------------------------------------------------------------
/docker/modx/tools/configurator/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "autoload": {
3 | "psr-4": {
4 | "App\\": "src/"
5 | }
6 | },
7 | "require": {
8 | "php": "^7.4"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/docker/modx/tools/configurator/config.inc.php:
--------------------------------------------------------------------------------
1 | [
14 | 'name' => 'modstore.pro',
15 | 'service_url' => 'https://modstore.pro/extras/',
16 | 'username' => '',
17 | 'api_key' => '',
18 | ],
19 | ];
20 | $config['install_packages'] = [
21 | 'ace' => [
22 | 'name' => 'Ace',
23 | 'version' => '',
24 | 'provider' => 'modx.com',
25 | ],
26 | 'controlerrorlog' => [
27 | 'name' => 'controlErrorLog',
28 | ],
29 | 'console' => [
30 | 'name' => 'Console',
31 | ],
32 | ];
33 |
34 | $config['set_options'] = [
35 | 'friendly_urls' => 1,
36 | 'use_alias_path' => 1,
37 | ];
38 |
39 | $config['grant_access_user'] = [
40 | 'manager' => [
41 | 'users' => [[
42 | 'username' => 'manager',
43 | 'password' => '',
44 | 'email' => '',
45 | ]],
46 | 'context_key' => 'mgr',
47 | 'group_name' => 'Manager',
48 | 'access_role_name' => '',
49 | 'access_role_authority' => 9,
50 | 'access_policy_name' => '',
51 | 'access_policy_template_name' => '',
52 | 'access_policy_template_override' => 'AdministratorTemplate',
53 | // see more (en) https://gist.github.com/Prihod/09ff88088c67dff4a48290344a46ec9b
54 | // see more (ru) https://gist.github.com/Prihod/ce52b1cb0e12ac9b5f14bc94dfcd03a5
55 | 'permissions' => [
56 | 'frames' => 1, // To use the MODX Manager UI at all.
57 | 'home' => 1, // To view the Welcome page.
58 | 'menu_user' => 1, // Show the top menu item "User".
59 | 'view_template' => 1, // To view any Templates.
60 | 'class_map' => 1, // To view a list of classes in the Class Map.
61 | 'change_password' => 1, // The user can change their password.
62 | 'change_profile' => 1, // The user can edit their profile.
63 | 'countries' => 1, // View the list of countries.
64 | 'create' => 1, // Ability to "create" new objects.
65 | 'delete_document' => 1, // Delete and move resources.
66 | 'delete_static_resource' => 1, // Permission "delete_document" is required to delete or unpublish a static resource.
67 | 'delete_symlink' => 1, // Permission "delete_document" is required to delete or unpublish a symbolic link.
68 | 'delete_user' => 1, // Disable and delete users.
69 | 'delete_weblink' => 1, // Permission "delete_document" is required to delete or unpublish a web link.
70 | 'directory_create' => 1, // Create directories in the file system.
71 | 'directory_list' => 1, // View the list of subdirectories in a file system directory.
72 | 'directory_remove' => 1, // Delete directories in the file system.
73 | 'directory_update' => 1, // Rename directories in the file system.
74 | 'edit_document' => 1, // Edit resources.
75 | 'edit_locked' => 1, // Allows the user to edit locked resources.
76 | 'edit_static_resource' => 1, // Permission "edit_document" is required to edit static resources.
77 | 'edit_symlink' => 1, // Permission "edit_document" is required to edit symbolic links.
78 | 'edit_user' => 1, // Edit users.
79 | 'edit_weblink' => 1, // Permission "edit_document" is required to edit web links.
80 | 'empty_cache' => 1, // Clear the site cache.
81 | 'file_create' => 1, // Create files.
82 | 'file_list' => 1, // View the list of files in folders.
83 | 'file_remove' => 1, // Delete files.
84 | 'file_tree' => 1, // View the file tree in the left navigation panel.
85 | 'file_update' => 1, // Modify files.
86 | 'file_upload' => 1, // Upload files to a folder.
87 | 'file_view' => 1, // View file content.
88 | 'list' => 1, // Ability to "list" any object. "List" means retrieving a collection of objects.
89 | 'load' => 1, // Ability to load objects or return them as object instances in general.
90 | 'logout' => 1, // Ability to log out as a user.
91 | 'menu_trash' => 1, // Display the "Deleted Resources Management" item in the top menu.
92 | 'new_document' => 1, // Create resources.
93 | 'new_document_in_root' => 1, // Create resources at the root level.
94 | 'new_static_resource' => 1, // Create static resources.
95 | 'new_symlink' => 1, // Create symbolic links.
96 | 'new_weblink' => 1, // Create new web links.
97 | 'publish_document' => 1, // Publish and unpublish resources.
98 | 'purge_deleted' => 1, // Empty the trash bin.
99 | 'remove' => 1, // Ability to delete objects.
100 | 'remove_locks' => 1, // Remove all locks on the site.
101 | 'resource_quick_create' => 1, // Use "Quick Create Resource" in the resource tree on the left.
102 | 'resource_quick_update' => 1, // Use "Quick Update Resource" in the resource tree on the left.
103 | 'resource_tree' => 1, // View the Resource Tree in the left navigation panel.
104 | 'save' => 1, // Ability to save objects.
105 | 'save_document' => 1, // Save resources.
106 | 'search' => 1, // Use the "Search" page.
107 | 'settings' => 0, // View and edit System Settings.
108 | 'source_view' => 1, // View file sources.
109 | 'tree_show_resource_ids' => 1, // Show IDs in the Resource Tree.
110 | 'undelete_document' => 1, // Ability to undelete resources.
111 | 'unpublish_document' => 1, // Unpublish resources.
112 | 'view' => 1, // Ability to "view" objects.
113 | 'view_document' => 1, // View resources.
114 | 'view_tv' => 1, // View TVs (Template Variables).
115 | 'view_unpublished' => 1, // View unpublished resources.
116 | 'view_user' => 1, // View users.
117 | ],
118 | 'media_source' => [
119 | 'name' => 'Manager',
120 | 'bind_tvs' => true,
121 | 'source_path' => 'assets/uploads/',
122 | 'access' => [
123 | 'authority' => 9,
124 | 'policy' => 8,
125 | 'context_key' => '',
126 | ],
127 | ]
128 | ],
129 | 'seo' => [
130 | 'users' => [[
131 | 'username' => 'seo',
132 | 'password' => '',
133 | 'email' => '',
134 | ]],
135 | 'context_key' => 'mgr',
136 | 'group_name' => 'Seo',
137 | 'access_role_authority' => 9,
138 | 'access_policy_template_inherit' => 'Manager',
139 | 'permissions' => [
140 | 'components' => 1, // View the "Packages" menu.
141 | 'delete_document' => 1, // Delete and move resources.
142 | 'view_snippet' => 1, // View snippets.
143 | 'new_snippet' => 0, // To create a new Snippet.
144 | 'edit_snippet' => 0, // To edit any Snippets.
145 | 'save_snippet' => 0, // To save any Snippets.
146 | 'view_chunk' => 1, // View chunks.
147 | 'edit_chunk' => 1, // Edit chunks.
148 | 'save_chunk' => 1, // To save any Chunks.
149 | 'edit_locked' => 1, // Allows the user to edit locked resources.
150 | 'edit_template' => 1, // Edit templates.
151 | 'save_template' => 1, // To save any Templates.
152 | 'edit_tv' => 1, // Edit TVs (Template Variables).
153 | 'element_tree' => 1, // View the element tree in the left navigation panel.
154 | 'error_log_view' => 1, // View the error log.
155 | 'events' => 1, // View system events.
156 | 'flush_sessions' => 1, // Reset all site sessions.
157 | 'lexicons' => 1, // View or edit "Lexicon Management."
158 | 'logs' => 1, // View the "System Management Log."
159 | 'menu_tools' => 1, // Display the "Tools" menu item in the top menu.
160 | 'menu_trash' => 1, // Display the "Deleted Resources Management" menu item in the top menu.
161 | 'remove_locks' => 1, // Remove all locks on the site.
162 | 'resourcegroup_resource_list' => 1, // View resources in a resource group.
163 | 'resourcegroup_view' => 1, // View resource groups.
164 | 'settings' => 0, // View and edit system settings.
165 | 'steal_locks' => 1, // "Steal" resource locks to gain control.
166 | 'tree_show_element_ids' => 1, // Show IDs in the element tree.
167 | 'usergroup_user_list' => 1, // View the list of users in a user group.
168 | 'usergroup_view' => 1, // View user groups.
169 | 'view_category' => 1, // View categories.
170 | 'view_context' => 1, // View contexts.
171 | 'view_eventlog' => 1, // View the event log.
172 | 'view_offline' => 1, // View the site when it is in offline mode.
173 | 'view_plugin' => 1, // View plugins.
174 | 'view_propertyset' => 1, // View property sets.
175 | 'view_tv' => 1, // View TVs (Template Variables).
176 | ],
177 | 'media_source' => [
178 | 'join' => 'Manager'
179 | ]
180 | ]
181 |
182 | ];
183 |
184 | $config['ms2'] = [
185 | 'demo' => [
186 | 'reset' => false,
187 | 'enable' => false,
188 | 'vendors' => true,
189 | 'products' => true,
190 | 'categories' => true,
191 | ],
192 | 'templates' => [
193 | 'cart',
194 | 'product',
195 | 'category',
196 | ],
197 | 'pages' => [
198 | 'category' => [
199 | 'pagetitle' => 'Category',
200 | 'template' => 'category',
201 | 'class_key' => 'msCategory',
202 | 'content' => '',
203 | 'hidemenu' => 0,
204 | 'publishedon' => 1,
205 | ],
206 | 'cart' => [
207 | 'pagetitle' => 'Cart',
208 | 'template' => 'cart',
209 | 'hidemenu' => 0,
210 | 'publishedon' => 1,
211 | ],
212 | ],
213 | ];
214 |
215 | return $config;
--------------------------------------------------------------------------------
/docker/modx/tools/configurator/example.config.inc.php:
--------------------------------------------------------------------------------
1 | [
14 | 'name' => 'modstore.pro',
15 | 'service_url' => 'https://modstore.pro/extras/',
16 | 'username' => '',
17 | 'api_key' => '',
18 | ],
19 | 'modxkit.com' => [
20 | 'name' => 'modxkit.com',
21 | 'service_url' => 'https://modxkit.com/extras/',
22 | 'username' => '',
23 | 'api_key' => '',
24 | ],
25 | ];
26 | $config['install_packages'] = [
27 | 'ace' => [
28 | 'name' => 'Ace',
29 | 'version' => '',
30 | 'provider' => 'modx.com',
31 | ],
32 | 'controlerrorlog' => [
33 | 'name' => 'controlErrorLog',
34 | ],
35 | 'console' => [
36 | 'name' => 'Console',
37 | ],
38 | 'VersionX' => [
39 | 'name' => 'versionx',
40 | ],
41 | 'clientconfig' => [
42 | 'name' => 'ClientConfig',
43 | ],
44 | 'debugparser' => [
45 | 'name' => 'debugParser',
46 | ],
47 | 'tagelementplugin' => [
48 | 'name' => 'tagElementPlugin',
49 | ],
50 | 'upgrademodx' => [
51 | 'name' => 'UpgradeMODX',
52 | ],
53 | 'translit' => [
54 | 'name' => 'translit',
55 | ],
56 | 'collections' => [
57 | 'name' => 'Collections',
58 | ],
59 | 'tinymcerte' => [
60 | 'name' => 'TinyMCE Rich Text Editor',
61 | ],
62 | 'admintools' => [
63 | 'name' => 'AdminTools',
64 | 'provider' => 'modstore.pro',
65 | ],
66 | 'moddevtools' => [
67 | 'name' => 'modDevTools',
68 | 'provider' => 'modstore.pro',
69 | ],
70 | 'frontendmanager' => [
71 | 'name' => 'frontendManager',
72 | 'provider' => 'modstore.pro',
73 | ],
74 | 'staticelementslive' => [
75 | 'name' => 'StaticElementsLive',
76 | 'provider' => 'modstore.pro',
77 | ],
78 | 'theme.bootstrap' => [
79 | 'name' => 'Theme.Bootstrap',
80 | 'provider' => 'modstore.pro',
81 | ],
82 | 'minishop2' => [
83 | 'name' => 'miniShop2',
84 | 'provider' => 'modstore.pro',
85 | ],
86 | ];
87 |
88 | $config['set_options'] = [
89 | 'friendly_urls' => 1,
90 | 'use_alias_path' => 1,
91 | 'friendly_alias_translit' => 'russian',
92 | ];
93 |
94 | $config['grant_access_user'] = [
95 | 'manager' => [
96 | 'users' => [[
97 | 'username' => 'manager',
98 | 'password' => '',
99 | 'email' => '',
100 | ]],
101 | 'context_key' => 'mgr',
102 | 'group_name' => 'Manager',
103 | 'access_role_name' => '',
104 | 'access_role_authority' => 9,
105 | 'access_policy_name' => '',
106 | 'access_policy_template_name' => '',
107 | 'access_policy_template_override' => 'AdministratorTemplate',
108 | // see more (en) https://gist.github.com/Prihod/09ff88088c67dff4a48290344a46ec9b
109 | // see more (ru) https://gist.github.com/Prihod/ce52b1cb0e12ac9b5f14bc94dfcd03a5
110 | 'permissions' => [
111 | 'frames' => 1, // To use the MODX Manager UI at all.
112 | 'home' => 1, // To view the Welcome page.
113 | 'menu_user' => 1, // Show the top menu item "User".
114 | 'view_template' => 1, // To view any Templates.
115 | 'class_map' => 1, // To view a list of classes in the Class Map.
116 | 'change_password' => 1, // The user can change their password.
117 | 'change_profile' => 1, // The user can edit their profile.
118 | 'countries' => 1, // View the list of countries.
119 | 'create' => 1, // Ability to "create" new objects.
120 | 'delete_document' => 1, // Delete and move resources.
121 | 'delete_static_resource' => 1, // Permission "delete_document" is required to delete or unpublish a static resource.
122 | 'delete_symlink' => 1, // Permission "delete_document" is required to delete or unpublish a symbolic link.
123 | 'delete_user' => 1, // Disable and delete users.
124 | 'delete_weblink' => 1, // Permission "delete_document" is required to delete or unpublish a web link.
125 | 'directory_create' => 1, // Create directories in the file system.
126 | 'directory_list' => 1, // View the list of subdirectories in a file system directory.
127 | 'directory_remove' => 1, // Delete directories in the file system.
128 | 'directory_update' => 1, // Rename directories in the file system.
129 | 'edit_document' => 1, // Edit resources.
130 | 'edit_locked' => 1, // Allows the user to edit locked resources.
131 | 'edit_static_resource' => 1, // Permission "edit_document" is required to edit static resources.
132 | 'edit_symlink' => 1, // Permission "edit_document" is required to edit symbolic links.
133 | 'edit_user' => 1, // Edit users.
134 | 'edit_weblink' => 1, // Permission "edit_document" is required to edit web links.
135 | 'empty_cache' => 1, // Clear the site cache.
136 | 'file_create' => 1, // Create files.
137 | 'file_list' => 1, // View the list of files in folders.
138 | 'file_remove' => 1, // Delete files.
139 | 'file_tree' => 1, // View the file tree in the left navigation panel.
140 | 'file_update' => 1, // Modify files.
141 | 'file_upload' => 1, // Upload files to a folder.
142 | 'file_view' => 1, // View file content.
143 | 'list' => 1, // Ability to "list" any object. "List" means retrieving a collection of objects.
144 | 'load' => 1, // Ability to load objects or return them as object instances in general.
145 | 'logout' => 1, // Ability to log out as a user.
146 | 'menu_trash' => 1, // Display the "Deleted Resources Management" item in the top menu.
147 | 'new_document' => 1, // Create resources.
148 | 'new_document_in_root' => 1, // Create resources at the root level.
149 | 'new_static_resource' => 1, // Create static resources.
150 | 'new_symlink' => 1, // Create symbolic links.
151 | 'new_weblink' => 1, // Create new web links.
152 | 'publish_document' => 1, // Publish and unpublish resources.
153 | 'purge_deleted' => 1, // Empty the trash bin.
154 | 'remove' => 1, // Ability to delete objects.
155 | 'remove_locks' => 1, // Remove all locks on the site.
156 | 'resource_quick_create' => 1, // Use "Quick Create Resource" in the resource tree on the left.
157 | 'resource_quick_update' => 1, // Use "Quick Update Resource" in the resource tree on the left.
158 | 'resource_tree' => 1, // View the Resource Tree in the left navigation panel.
159 | 'save' => 1, // Ability to save objects.
160 | 'save_document' => 1, // Save resources.
161 | 'search' => 1, // Use the "Search" page.
162 | 'settings' => 0, // View and edit System Settings.
163 | 'source_view' => 1, // View file sources.
164 | 'tree_show_resource_ids' => 1, // Show IDs in the Resource Tree.
165 | 'undelete_document' => 1, // Ability to undelete resources.
166 | 'unpublish_document' => 1, // Unpublish resources.
167 | 'view' => 1, // Ability to "view" objects.
168 | 'view_document' => 1, // View resources.
169 | 'view_tv' => 1, // View TVs (Template Variables).
170 | 'view_unpublished' => 1, // View unpublished resources.
171 | 'view_user' => 1, // View users.
172 | ],
173 | 'media_source' => [
174 | 'name' => 'Manager',
175 | 'bind_tvs' => true,
176 | 'source_path' => 'assets/uploads/',
177 | 'access' => [
178 | 'authority' => 9,
179 | 'policy' => 8,
180 | 'context_key' => '',
181 | ],
182 | ]
183 | ],
184 | 'seo' => [
185 | 'users' => [[
186 | 'username' => 'seo',
187 | 'password' => '',
188 | 'email' => '',
189 | ]],
190 | 'context_key' => 'mgr',
191 | 'group_name' => 'Seo',
192 | 'access_role_authority' => 9,
193 | 'access_policy_template_inherit' => 'Manager',
194 | 'permissions' => [
195 | 'components' => 1, // View the "Packages" menu.
196 | 'delete_document' => 1, // Delete and move resources.
197 | 'view_snippet' => 1, // View snippets.
198 | 'new_snippet' => 0, // To create a new Snippet.
199 | 'edit_snippet' => 0, // To edit any Snippets.
200 | 'save_snippet' => 0, // To save any Snippets.
201 | 'view_chunk' => 1, // View chunks.
202 | 'edit_chunk' => 1, // Edit chunks.
203 | 'save_chunk' => 1, // To save any Chunks.
204 | 'edit_locked' => 1, // Allows the user to edit locked resources.
205 | 'edit_template' => 1, // Edit templates.
206 | 'save_template' => 1, // To save any Templates.
207 | 'edit_tv' => 1, // Edit TVs (Template Variables).
208 | 'element_tree' => 1, // View the element tree in the left navigation panel.
209 | 'error_log_view' => 1, // View the error log.
210 | 'events' => 1, // View system events.
211 | 'flush_sessions' => 1, // Reset all site sessions.
212 | 'lexicons' => 1, // View or edit "Lexicon Management."
213 | 'logs' => 1, // View the "System Management Log."
214 | 'menu_tools' => 1, // Display the "Tools" menu item in the top menu.
215 | 'menu_trash' => 1, // Display the "Deleted Resources Management" menu item in the top menu.
216 | 'remove_locks' => 1, // Remove all locks on the site.
217 | 'resourcegroup_resource_list' => 1, // View resources in a resource group.
218 | 'resourcegroup_view' => 1, // View resource groups.
219 | 'settings' => 0, // View and edit system settings.
220 | 'steal_locks' => 1, // "Steal" resource locks to gain control.
221 | 'tree_show_element_ids' => 1, // Show IDs in the element tree.
222 | 'usergroup_user_list' => 1, // View the list of users in a user group.
223 | 'usergroup_view' => 1, // View user groups.
224 | 'view_category' => 1, // View categories.
225 | 'view_context' => 1, // View contexts.
226 | 'view_eventlog' => 1, // View the event log.
227 | 'view_offline' => 1, // View the site when it is in offline mode.
228 | 'view_plugin' => 1, // View plugins.
229 | 'view_propertyset' => 1, // View property sets.
230 | 'view_tv' => 1, // View TVs (Template Variables).
231 | ],
232 | 'media_source' => [
233 | 'join' => 'Manager'
234 | ]
235 | ]
236 |
237 | ];
238 |
239 | $config['ms2'] = [
240 | 'demo' => [
241 | 'reset' => false,
242 | 'enable' => true,
243 | 'vendors' => true,
244 | 'products' => true,
245 | 'categories' => true,
246 | ],
247 | 'templates' => [
248 | 'cart',
249 | 'product',
250 | 'category',
251 | ],
252 | 'pages' => [
253 | 'category' => [
254 | 'pagetitle' => 'Category',
255 | 'template' => 'category',
256 | 'class_key' => 'msCategory',
257 | 'content' => '',
258 | 'hidemenu' => 0,
259 | 'publishedon' => 1,
260 | ],
261 | 'cart' => [
262 | 'pagetitle' => 'Cart',
263 | 'template' => 'cart',
264 | 'hidemenu' => 0,
265 | 'publishedon' => 1,
266 | ],
267 | ],
268 | ];
269 |
270 | return $config;
--------------------------------------------------------------------------------
/docker/modx/tools/configurator/run.php:
--------------------------------------------------------------------------------
1 | getService('error', 'error.modError');
16 | $modx->setLogLevel(\modX::LOG_LEVEL_ERROR);
17 | $modx->setLogTarget('FILE');
18 |
19 | $config = require(__DIR__ . '/config.inc.php');
20 | $runner = new Runner($modx, $config);
21 | $runner->run();
--------------------------------------------------------------------------------
/docker/modx/tools/configurator/src/Runner/Runner.php:
--------------------------------------------------------------------------------
1 | initialize($modx, $properties);
20 | }
21 |
22 | public function run(): void
23 | {
24 | $this->loadTasks();
25 | if (empty($this->tasks)) {
26 | return;
27 | }
28 | Logger::info("Start configurator Modx");
29 | foreach ($this->tasks as $task) {
30 | $this->runTask($task);
31 | $this->modx->reloadConfig();
32 | }
33 | Logger::info("Finish configurator Modx");
34 | }
35 |
36 | protected function loadTasks(): array
37 | {
38 | $handlers = $this->getProperty('tasks', []);
39 |
40 | foreach ($handlers as $handler) {
41 | $this->addTask($handler);
42 | }
43 |
44 | return $this->tasks;
45 | }
46 |
47 | protected function addTask(string $handler): void
48 | {
49 | try {
50 | $fullClass = 'App\\Tasks\\' . $handler;
51 | if (!class_exists($fullClass)) {
52 | Logger::error("Class '{$fullClass}' not found.");
53 | return;
54 | }
55 | $task = new $fullClass($this->modx, $this->getProperties());
56 | if (!$task instanceof Task) {
57 | Logger::error("Task handler error: The handler '{$handler}' must be an instance of Task.");
58 | return;
59 | }
60 |
61 | $this->tasks[] = $task;
62 | } catch (\Exception $e) {
63 | Logger::error($e->getMessage());
64 | }
65 | }
66 |
67 | protected function runTask(Task $task): void
68 | {
69 | try {
70 | Logger::info("Start execute task: '{$task->getName()}'");
71 | $task->execute();
72 | Logger::info("Finish execute task: '{$task->getName()}'");
73 | } catch (\Exception $e) {
74 | Logger::error("Error in task '{$task->getName()}': " . $e->getMessage());
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/docker/modx/tools/configurator/src/Runner/RunnerInterface.php:
--------------------------------------------------------------------------------
1 | modx->lexicon->load('policy');
20 | $config = $this->getProperty('grant_access_user');
21 | if (empty($config)) {
22 | return;
23 | }
24 |
25 | foreach ($config as $key => $data) {
26 | Logger::info("Grant access for: {$key}");
27 | $users = $data['users'] ?? [];
28 | $groupName = $data['group_name'] ?? '';
29 | $permissions = $data['permissions'] ?? [];
30 | $contextKey = $data['context_key'] ?? null;
31 | $roleAuthority = $data['access_role_authority'] ?? 9;
32 | $roleName = empty($data['access_role_name']) ? $groupName : $data['access_role_name'];
33 | $policyName = empty($data['access_policy_name']) ? $groupName : $data['access_policy_name'];
34 | $templateName = empty($data['access_policy_template_name']) ? $groupName : $data['access_policy_template_name'];
35 | $mediaSourceOptions = $data['media_source'] ?? null;
36 | $sourceTemplate = $this->detectSourceAccessPolicyTemplate($data);
37 |
38 | if (!$contextKey || !$groupName || !$sourceTemplate) {
39 | continue;
40 | }
41 |
42 |
43 | $template = $this->getOrDuplicateAccessPolicyTemplate($templateName, $sourceTemplate->get('id'));
44 | if (!$template) {
45 | continue;
46 | }
47 |
48 |
49 | $permissions = $this->prepareTemplatePermissions($permissions, $sourceTemplate->get('id'), $data);
50 | $accessPolicy = $this->getOrCreateAccessPolicy($policyName, $template->get('id'), $permissions);
51 | if (!$accessPolicy) {
52 | continue;
53 | }
54 |
55 | $role = $this->getOrCreateUserGroupRole($roleName, $roleAuthority);
56 | if (!$role) {
57 | continue;
58 | }
59 |
60 | $userGroup = $this->getOrCreateUserGroup($groupName);
61 | if (!$userGroup) {
62 | continue;
63 | }
64 |
65 | $contextData = [
66 | 'target' => $contextKey,
67 | 'authority' => $roleAuthority,
68 | 'policy' => $accessPolicy->get('id'),
69 | 'principal' => $userGroup->get('id'),
70 | ];
71 |
72 | $context = $this->getOrCreateUserGroupAccessContext($contextData);
73 | if (!$context) {
74 | continue;
75 | }
76 |
77 | if ($contextKey === 'mgr') {
78 | $this->updateUserGroupAccessContext($userGroup->get('id'), 'web', [
79 | 'authority' => $roleAuthority,
80 | 'policy' => 2, // access policy - Administrator.
81 | ]);
82 | }
83 |
84 | $groupMember = array(
85 | 'user_group' => $userGroup->get('id'),
86 | 'role' => $role->get('id'),
87 | );
88 |
89 | foreach ($users as $user) {
90 | $this->getOrCreateUser($user, $groupMember);
91 | }
92 |
93 | if (!empty($mediaSourceOptions)) {
94 | if (empty($mediaSourceOptions['join'])) {
95 | $this->createMediaSource($mediaSourceOptions, $userGroup->get('id'));
96 | } else {
97 | $this->joinMediaSource($mediaSourceOptions['join'], $userGroup->get('id'), $mediaSourceOptions);
98 | }
99 | }
100 | }
101 |
102 | }
103 |
104 | protected function prepareTemplatePermissions(array $permissions, int $templateId = 0, array $options = []): ?array
105 | {
106 | if (!empty($options['access_policy_template_override'])) {
107 | $defaultPermissions = $this->getAccessPolicyTemplatePermissions($templateId, 0);
108 | } else {
109 | $defaultPermissions = $this->getAccessPolicyPermissions($templateId);
110 | }
111 | return array_merge($defaultPermissions, $permissions);
112 | }
113 |
114 | protected function detectSourceAccessPolicyTemplate(array $options = []): ?object
115 | {
116 | if (!empty($options['access_policy_template_override'])) {
117 | return $this->findAccessPolicyTemplate($options['access_policy_template_override']);
118 |
119 | } else if (!empty($options['access_policy_template_inherit'])) {
120 | return $this->findAccessPolicyTemplate($options['access_policy_template_inherit']);
121 | }
122 | return null;
123 | }
124 |
125 | protected function joinMediaSource(string $mediaSourceName, int $userGroupId, array $options = []): ?object
126 | {
127 | $mediaSource = $this->findMediaSource($mediaSourceName);
128 | if (!$mediaSource) {
129 | return null;
130 | }
131 |
132 | $access = $options['access'] ?? [];
133 | $access = array_merge([
134 | 'target' => $mediaSource->get('id'),
135 | 'authority' => 9,
136 | 'policy' => 8,
137 | 'principal_class' => 'modUserGroup',
138 | 'principal' => $userGroupId,
139 | ], $access);
140 |
141 | if (!$this->getOrCreateAccessMediaSource($access)) {
142 | return null;
143 | }
144 |
145 | return $mediaSource;
146 | }
147 |
148 | protected function createMediaSource(array $options, int $userGroupId): void
149 | {
150 |
151 | $name = $options['name'] ?? '';
152 | $access = $options['access'] ?? [];
153 | $isBindTvs = $options['bind_tvs'] ?? false;
154 | $sourcePath = $options['source_path'] ?? '';
155 |
156 | if ($sourcePath) {
157 | $mediaSource = $this->getOrCreateFileMediaSource($name, $sourcePath);
158 | if (!$mediaSource) {
159 | return;
160 | }
161 |
162 | $access = array_merge([
163 | 'target' => $mediaSource->get('id'),
164 | 'principal_class' => 'modUserGroup',
165 | 'principal' => $userGroupId,
166 | ], $access);
167 |
168 | $this->getOrCreateAccessMediaSource($access);
169 |
170 | $adminAccess = array(
171 | 'target' => 1,
172 | 'principal_class' => 'modUserGroup',
173 | 'principal' => 1,
174 | 'authority' => 0,
175 | 'policy' => 8,
176 | 'context_key' => '',
177 | );
178 | $this->getOrCreateAccessMediaSource($adminAccess);
179 |
180 | if ($isBindTvs) {
181 | $this->bindMediaSourceTvs($mediaSource->get('id'));
182 | }
183 | }
184 | }
185 | }
--------------------------------------------------------------------------------
/docker/modx/tools/configurator/src/Tasks/InstallPackagesTask.php:
--------------------------------------------------------------------------------
1 | getProperty('install_packages', []);
26 | if (empty($packages)) {
27 | return;
28 | }
29 |
30 | foreach ($packages as $data) {
31 | $name = $data['name'] ?? '';
32 | $version = $data['version'] ?? '';
33 | /** @var \modTransportPackage $package */
34 | $package = $this->getPackage($name);
35 | if ($package && $package->compareVersion($version, '<=')) {
36 | continue;
37 | }
38 |
39 | if ($this->installPackage($name, $data)) {
40 | Logger::info("Installed package '{$name}'");
41 | }
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/docker/modx/tools/configurator/src/Tasks/SetOptionsTask.php:
--------------------------------------------------------------------------------
1 | getProperty('set_options', []);
20 | if (empty($options)) {
21 | return;
22 | }
23 | foreach ($options as $key => $val) {
24 | if ($this->setOption($key, $val)) {
25 | Logger::info("Set option: '{$key}' value: '{$val}'");
26 | } else {
27 | Logger::error("Error set option: '{$key}' value: '{$val}'");
28 | }
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/docker/modx/tools/configurator/src/Tasks/Task.php:
--------------------------------------------------------------------------------
1 | initialize($modx, $properties);
18 | }
19 |
20 | protected function getStoragePath(): string
21 | {
22 | return dirname(__FILE__, 3) . '/storage/';
23 | }
24 |
25 | protected function getImagePath(): string
26 | {
27 | $path = MODX_ASSETS_PATH . 'images/';
28 | if (!file_exists($path)) {
29 | $this->modx->cacheManager->writeTree($path);
30 | }
31 | return $path;
32 | }
33 |
34 | protected function readCsv(string $file, callable $callback, string $delimiter = ";"): void
35 | {
36 | if (!file_exists($file) || !is_readable($file)) {
37 | throw new \Exception("File not found or not readable: $file");
38 | }
39 |
40 | if (($handle = fopen($file, 'r')) !== false) {
41 | while (($row = fgetcsv($handle, 0, ";", '"')) !== false) {
42 | $callback($row);
43 | }
44 | fclose($handle);
45 | } else {
46 | throw new \Exception("Failed to open file: $file");
47 | }
48 | }
49 |
50 | protected function saveArrayToCsv(string $file, array $data): void
51 | {
52 | if (($handle = fopen($file, 'w')) !== false) {
53 | foreach ($data as $row) {
54 | fputcsv($handle, $row, ";");
55 | }
56 | fclose($handle);
57 | return;
58 | }
59 | throw new \Exception("Failed to open file: $file");
60 | }
61 |
62 | }
--------------------------------------------------------------------------------
/docker/modx/tools/configurator/src/Tasks/TaskInterface.php:
--------------------------------------------------------------------------------
1 | getProperty('transport_providers', []);
21 | foreach ($providers as $provider) {
22 | if (
23 | empty($provider['username']) ||
24 | empty($provider['api_key']) ||
25 | $this->hasProvider($provider['name'])
26 | ) {
27 | continue;
28 | }
29 | if ($this->addProvider($provider)) {
30 | Logger::info("Added provider: '{$provider['name']}'");
31 | }
32 | }
33 | }
34 |
35 | }
--------------------------------------------------------------------------------
/docker/modx/tools/configurator/src/Traits/DocumentTrait.php:
--------------------------------------------------------------------------------
1 | findModDocument($name)) {
19 | $this->modx->error->reset();
20 | /** @var \modProcessorResponse $response */
21 | $response = $this->modx->runProcessor('resource/create', $params);
22 | if ($response->isError()) {
23 | Logger::error($response->getResponse());
24 | return null;
25 | }
26 | $obj = $response->getObject();
27 | $doc = $this->getModDocument($obj['id']);
28 | }
29 | return $doc;
30 | }
31 |
32 | protected function findModDocument(string $name): ?object
33 | {
34 | return $this->modx->getObject('modResource', ['pagetitle' => $name]);
35 | }
36 |
37 | protected function getModDocument(int $id): ?object
38 | {
39 | return $this->modx->getObject('modResource', $id);
40 | }
41 | }
--------------------------------------------------------------------------------
/docker/modx/tools/configurator/src/Traits/ElementsTrait.php:
--------------------------------------------------------------------------------
1 | findModTemplate($name)) {
13 | $template = $this->modx->newObject('modTemplate');
14 | $template->fromArray($params);
15 | $template->set('templatename', $name);
16 | $template->set('content', $content);
17 | $template->set('category', $categoryId);
18 | return $template->save() ? $template : null;
19 | }
20 | return $template;
21 | }
22 |
23 | protected function findModTemplate(string $name): ?object
24 | {
25 | return $this->modx->getObject('modTemplate', ['templatename' => $name]);
26 | }
27 |
28 | protected function getModTemplate(int $id): ?object
29 | {
30 | return $this->modx->getObject('modTemplate', $id);
31 | }
32 |
33 | protected function createModChunk(string $name, string $content = '', int $categoryId = 0, array $params = []):? object
34 | {
35 | if (!$chunk = $this->findModChunk($name)) {
36 | $chunk = $this->modx->newObject('modChunk');
37 | $chunk->fromArray($params);
38 | $chunk->set('name', $name);
39 | $chunk->set('snippet', $content);
40 | $chunk->set('category', $categoryId);
41 | return $chunk->save() ? $chunk : null;
42 | }
43 | return $chunk;
44 | }
45 |
46 | protected function findModChunk(string $name): ?object
47 | {
48 | return $this->modx->getObject('modChunk', ['name' => $name]);
49 | }
50 |
51 | protected function createModCategory(string $name, int $parent = 0, array $params = []):? object
52 | {
53 | if (!$category = $this->findModCategory($name)) {
54 | $category = $this->modx->newObject('modCategory');
55 | $category->fromArray($params);
56 | $category->set('name', $name);
57 | $category->set('parent', $parent);
58 | return $category->save() ? $category : null;
59 | }
60 | return $category;
61 | }
62 |
63 | protected function findModCategory(string $name): ?object
64 | {
65 | return $this->modx->getObject('modCategory', ['name' => $name]);
66 | }
67 |
68 | }
--------------------------------------------------------------------------------
/docker/modx/tools/configurator/src/Traits/InitializeTrait.php:
--------------------------------------------------------------------------------
1 | modx = $modx;
12 | if ($this->hasTrait('App\Traits\PropertiesTrait')) {
13 | $this->setProperties($properties);
14 | }
15 | }
16 |
17 | protected function hasTrait(string $trait): bool
18 | {
19 | $class = static::class;
20 | do {
21 | if (in_array($trait, class_uses($class))) {
22 | return true;
23 | }
24 | } while ($class = get_parent_class($class));
25 |
26 | return false;
27 | }
28 |
29 | }
--------------------------------------------------------------------------------
/docker/modx/tools/configurator/src/Traits/OptionTrait.php:
--------------------------------------------------------------------------------
1 | modx->getObject('modSystemSetting', ['key' => $key])) {
12 | return false;
13 | }
14 |
15 | $setting->set('value', $value);
16 | $saved = $setting->save();
17 | if ($saved) {
18 | $this->modx->setOption($key, $value);
19 | if ($clearCache) {
20 | $this->modx->cacheManager->refresh(array('system_settings' => array()));
21 | }
22 | }
23 |
24 | return $saved;
25 | }
26 |
27 | protected function getOption(string $key, $default = null)
28 | {
29 | if (!$setting = $this->modx->getObject('modSystemSetting', ['key' => $key])) {
30 | return $default;
31 | }
32 | $value = $setting->get('value');
33 | if (is_string($value)) {
34 | $value = $this->normalizePath($value);
35 | $value = $this->normalizeUrl($value);
36 | }
37 | return $value;
38 | }
39 |
40 | private function normalizePath(string $path): string
41 | {
42 | return str_replace(array(
43 | '{base_path}',
44 | '{core_path}',
45 | '{assets_path}',
46 | ), array(
47 | MODX_BASE_PATH,
48 | MODX_CORE_PATH,
49 | MODX_ASSETS_PATH,
50 | ), $path);
51 | }
52 |
53 | private function normalizeUrl(string $url): string
54 | {
55 | return str_replace(array(
56 | '{base_url}',
57 | '{core_url}',
58 | '{assets_url}',
59 | ), array(
60 | MODX_BASE_PATH,
61 | MODX_CORE_PATH,
62 | MODX_ASSETS_PATH,
63 | ), $url);
64 | }
65 |
66 | }
--------------------------------------------------------------------------------
/docker/modx/tools/configurator/src/Traits/PropertiesTrait.php:
--------------------------------------------------------------------------------
1 | properties[$key] = $value;
12 | }
13 |
14 | public function getProperty(string $key, $default = null, bool $skipEmpty = false)
15 | {
16 | $value = $this->properties[$key] ?? $default;
17 | return ($skipEmpty && empty($value)) ? $default : $value;
18 | }
19 |
20 | public function hasProperty(string $key): bool
21 | {
22 | return isset($this->properties[$key]);
23 | }
24 |
25 | public function unsetProperty(string $key): void
26 | {
27 | unset($this->properties[$key]);
28 | }
29 |
30 | public function getProperties(): array
31 | {
32 | return $this->properties;
33 | }
34 |
35 | public function setProperties(array $properties = []): void
36 | {
37 | $this->properties = array_merge($this->properties, $properties);
38 | }
39 |
40 | public function setDefaultProperties(array $properties = []): array
41 | {
42 | $this->properties = array_merge($properties, $this->properties);
43 | return $this->properties;
44 | }
45 | }
--------------------------------------------------------------------------------
/docker/modx/tools/configurator/src/Traits/TransportProviderTrait.php:
--------------------------------------------------------------------------------
1 | modx->newQuery('transport.modTransportPackage');
16 | $q->where([
17 | 'package_name:=' => $name,
18 | 'OR:package_name:=' => strtolower($name)
19 | ]);
20 | return $this->modx->getObject('transport.modTransportPackage', $q);
21 | }
22 |
23 | protected function installPackage(string $name, array $options = []): bool
24 | {
25 | $providerName = $options['provider'] ?? 'modx.com';
26 | $providers = $this->getTransportProviders();
27 | $provider = $providers[$providerName] ?? null;
28 | if (!$provider) {
29 | Logger::error("Provider '{$providerName}' for package '{$name}' not found!");
30 | return false;
31 | }
32 |
33 | $this->modx->getVersionData();
34 | $productVersion = $this->modx->version['code_name'] . '-' . $this->modx->version['full_version'];
35 | $response = $provider->request('package', 'GET', [
36 | 'supports' => $productVersion,
37 | 'query' => $name,
38 | ]);
39 |
40 | if (!empty($response)) {
41 | $foundPackages = simplexml_load_string($response->response);
42 | foreach ($foundPackages as $foundPackage) {
43 | /** @var \modTransportPackage $foundPackage */
44 | /** @noinspection PhpUndefinedFieldInspection */
45 | if (preg_match('#^' . $name . '\b#i', $foundPackage->name)) {
46 | $sig = explode('-', $foundPackage->signature);
47 | $versionSignature = explode('.', $sig[1]);
48 | /** @noinspection PhpUndefinedFieldInspection */
49 | $url = $foundPackage->location;
50 | $dst = $this->modx->getOption('core_path') . 'packages/' . $foundPackage->signature . '.transport.zip';
51 | if (!$this->downloadPackage($url, $dst)) {
52 | Logger::error("Could not download package '{$name}'!");
53 | return false;
54 | }
55 |
56 | $package = $this->modx->newObject('transport.modTransportPackage');
57 | $package->set('signature', $foundPackage->signature);
58 | /** @noinspection PhpUndefinedFieldInspection */
59 | $package->fromArray([
60 | 'created' => date('Y-m-d h:i:s'),
61 | 'updated' => null,
62 | 'state' => 1,
63 | 'workspace' => 1,
64 | 'provider' => $provider->get('id'),
65 | 'source' => $foundPackage->signature . '.transport.zip',
66 | 'package_name' => $name,
67 | 'version_major' => $versionSignature[0],
68 | 'version_minor' => !empty($versionSignature[1]) ? $versionSignature[1] : 0,
69 | 'version_patch' => !empty($versionSignature[2]) ? $versionSignature[2] : 0,
70 | ]);
71 |
72 | if (!empty($sig[2])) {
73 | $r = preg_split('/([0-9]+)/', $sig[2], -1, PREG_SPLIT_DELIM_CAPTURE);
74 | if (is_array($r) && !empty($r)) {
75 | $package->set('release', $r[0]);
76 | $package->set('release_index', ($r[1] ?? '0'));
77 | } else {
78 | $package->set('release', $sig[2]);
79 | }
80 | }
81 | if ($package->save() && $package->install()) {
82 | return true;
83 | } else {
84 | Logger::error("Could not install package '{$name}'!");
85 | }
86 | }
87 | }
88 | Logger::error("Could not find package '{$name}' in '{$providerName}' repository!");
89 | }
90 |
91 | return false;
92 | }
93 |
94 | protected function downloadPackage(string $url, string $dst): bool
95 | {
96 | try {
97 | $file = false;
98 | if (ini_get('allow_url_fopen')) {
99 | $file = @file_get_contents($url);
100 | } elseif (function_exists('curl_init')) {
101 | $ch = curl_init();
102 | curl_setopt($ch, CURLOPT_URL, $url);
103 | curl_setopt($ch, CURLOPT_HEADER, 0);
104 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
105 | curl_setopt($ch, CURLOPT_TIMEOUT, 180);
106 | $safeMode = @ini_get('safe_mode');
107 | $openBasedir = @ini_get('open_basedir');
108 | if (empty($safeMode) && empty($openBasedir)) {
109 | curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
110 | }
111 | $file = curl_exec($ch);
112 | curl_close($ch);
113 | }
114 |
115 | if ($file) {
116 | file_put_contents($dst, $file);
117 | return file_exists($dst);
118 | }
119 | } catch (\Exception $e) {
120 | Logger::error($e->getMessage());
121 | }
122 | return false;
123 | }
124 |
125 | protected function addProvider(array $data): bool
126 | {
127 | $this->modx->error->reset();
128 | /** @var \modProcessorResponse $response */
129 | $response = $this->modx->runProcessor('workspace/providers/create', $data);
130 | if ($response->isError()) {
131 | Logger::error($response->getResponse());
132 | return false;
133 | }
134 | return true;
135 | }
136 |
137 | protected function hasProvider(string $name): bool
138 | {
139 | $providers = $this->getTransportProviders();
140 | return isset($providers[$name]);
141 | }
142 |
143 | protected function getTransportProviders(): array
144 | {
145 | if ($this->transportProviders !== null) {
146 | return $this->transportProviders;
147 | }
148 |
149 | $this->transportProviders = [];
150 | /** @var \modTransportProvider $provider */
151 | $list = $this->modx->getCollection('transport.modTransportProvider');
152 | foreach ($list as $provider) {
153 | $this->transportProviders[$provider->get('name')] = $provider;
154 | }
155 | return $this->transportProviders;
156 | }
157 |
158 | }
--------------------------------------------------------------------------------
/docker/modx/tools/configurator/src/Utils/Logger.php:
--------------------------------------------------------------------------------
1 |
2 |
3 | [[!msCart]]
4 | [[!msOrder]]
5 | [[!msGetOrder]]
6 |
--------------------------------------------------------------------------------
/docker/modx/tools/configurator/storage/ms2/pages/category.tpl:
--------------------------------------------------------------------------------
1 |
2 | [[!pdoPage?
3 | &element=`msProducts`
4 | ]]
5 | [[!+page.nav]]
6 |
--------------------------------------------------------------------------------
/docker/modx/tools/configurator/storage/ms2/templates/cart.tpl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Prihod/docker-modx/4fa05bd11e002f3e867d46cfa59956c613a33d52/docker/modx/tools/configurator/storage/ms2/templates/cart.tpl
--------------------------------------------------------------------------------
/docker/modx/tools/configurator/storage/ms2/templates/category.tpl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Prihod/docker-modx/4fa05bd11e002f3e867d46cfa59956c613a33d52/docker/modx/tools/configurator/storage/ms2/templates/category.tpl
--------------------------------------------------------------------------------
/docker/modx/tools/configurator/storage/ms2/templates/product.tpl:
--------------------------------------------------------------------------------
1 |
2 | [[$msProduct.content]]
3 |
--------------------------------------------------------------------------------
/docker/nginx/default.conf.template:
--------------------------------------------------------------------------------
1 | server {
2 | listen 80;
3 | listen 443 ssl;
4 | http2 on;
5 | server_name ${SERVER_NAME};
6 | root ${ROOT_PATH};
7 | index index.php index.html;
8 |
9 | # Compression
10 | gzip on;
11 | gzip_vary on;
12 | gzip_static on;
13 | gzip_comp_level 6;
14 | gzip_min_length 1024;
15 | gzip_buffers 128 4k;
16 | gzip_http_version 1.1;
17 | gzip_types text/css text/javascript text/js text/plain text/richtext text/shtml text/x-component text/x-java-source text/x-markdown text/x-script text/xml image/bmp image/svg+xml image/vnd.microsoft.icon image/x-icon font/otf font/ttf font/x-woff multipart/bag multipart/mixed application/eot application/font application/font-sfnt application/font-woff application/javascript application/javascript-binast application/json application/ld+json application/manifest+json application/opentype application/otf application/rss+xml application/ttf application/truetype application/vnd.api+json application/vnd.ms-fontobject application/wasm application/xhtml+xml application/xml application/xml+rss application/x-httpd-cgi application/x-javascript application/x-opentype application/x-otf application/x-perl application/x-protobuf application/x-ttf;
18 | gzip_proxied any;
19 |
20 | client_max_body_size 100M;
21 |
22 | ssl_certificate ${SSL_PATH}/server.crt;
23 | ssl_certificate_key ${SSL_PATH}/server.key;
24 | ssl_prefer_server_ciphers on;
25 | ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:AES256-GCM-SHA384';
26 | ssl_protocols TLSv1.2 TLSv1.3;
27 |
28 | location = /favicon.ico {
29 | log_not_found off;
30 | access_log off;
31 | }
32 |
33 | location = /robots.txt {
34 | log_not_found off;
35 | access_log off;
36 | }
37 |
38 | location ~ /\.ht {
39 | deny all;
40 | }
41 |
42 | location ~ ^/config.core.php {
43 | return 404;
44 | }
45 |
46 | # Polylang language rewrite
47 | #location ~ "^/([a-z]{2})/" {
48 | # rewrite "^/([a-z]{2})/(.*)" /$2 last;
49 | #}
50 |
51 | location ~* ^.+\.(jpeg|jpg|png|webp|gif|bmp|ico|svg|css|js)$ {
52 | expires max;
53 | access_log off;
54 | log_not_found off;
55 | add_header Cache-Control "public, must-revalidate, proxy-revalidate";
56 | }
57 |
58 | location / {
59 | try_files $uri $uri/ @rewrite;
60 | }
61 |
62 | location @rewrite {
63 | rewrite ^/(.*)$ /index.php?q=$1;
64 | }
65 |
66 | location ~ \.php$ {
67 | try_files $uri =404;
68 | fastcgi_split_path_info ^(.+\.php)(.*)$;
69 | include fastcgi_params;
70 | fastcgi_pass php:9000;
71 | fastcgi_index index.php;
72 | fastcgi_buffers 16 16k;
73 | fastcgi_buffer_size 32k;
74 | fastcgi_param SERVER_NAME $http_host;
75 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
76 | fastcgi_param PATH_INFO $fastcgi_path_info;
77 | fastcgi_param PHP_VALUE "auto_prepend_file=/usr/local/php/xhprof/handler.php";
78 | }
79 | }
--------------------------------------------------------------------------------
/docker/nginx/ssl/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Prihod/docker-modx/4fa05bd11e002f3e867d46cfa59956c613a33d52/docker/nginx/ssl/.gitkeep
--------------------------------------------------------------------------------
/docker/php/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG PHP_VERSION=7.4
2 |
3 | ARG LOCALE=en_US.UTF-8
4 |
5 | ARG SMTP_PORT=1025
6 | ARG SMTP_HOST=mailhog
7 | ARG ROOT_PATH=/var/www/html
8 |
9 | ARG XDEBUG_ENABLE=0
10 | ARG XHPROF_ENABLE=0
11 | ARG BLACKFIRE_ENABLE=0
12 |
13 | ARG SSH_ENABLE=0
14 | ARG SSH_LOGIN=dev
15 | ARG SSH_PASSWORD=dev
16 |
17 | FROM php:${PHP_VERSION}-fpm
18 |
19 | ARG LOCALE
20 |
21 | ARG SMTP_HOST
22 | ARG SMTP_PORT
23 | ARG ROOT_PATH
24 |
25 | ARG XDEBUG_ENABLE
26 | ARG XHPROF_ENABLE
27 | ARG BLACKFIRE_ENABLE
28 |
29 | ARG SSH_ENABLE
30 | ARG SSH_LOGIN
31 | ARG SSH_PASSWORD
32 |
33 | ENV ENTRYPOINT_PATH=/usr/local/bin
34 | ENV MODX_TOOLS_PATH=/usr/local/modx/tools
35 | ENV XHPROF_PATH=/usr/local/php/xhprof
36 | ENV MODX_STORAGE_PATH=/usr/local/modx/storage
37 | ENV MODX_BACKUP_PATH=/usr/local/modx/storage/backup
38 | ENV MODX_CACHE_SOURCE_PATH=/usr/local/modx/storage/cache
39 |
40 | RUN apt-get update && apt-get install -y --no-install-recommends \
41 | libzip-dev \
42 | libpng-dev \
43 | libjpeg-dev \
44 | libfreetype6-dev \
45 | libmagickwand-dev \
46 | libmagic-dev \
47 | imagemagick \
48 | pkg-config \
49 | build-essential \
50 | msmtp \
51 | msmtp-mta \
52 | mariadb-client \
53 | git \
54 | make \
55 | zip \
56 | unzip \
57 | wget \
58 | curl \
59 | nano \
60 | locales \
61 | procps \
62 | openssl \
63 | openssh-server \
64 | telnet \
65 | && docker-php-ext-configure gd --with-freetype --with-jpeg \
66 | && docker-php-ext-install pcntl gd mysqli pdo pdo_mysql opcache fileinfo zip \
67 | && pecl install redis \
68 | && git clone https://github.com/Imagick/imagick.git /usr/src/php/ext/imagick \
69 | && cd /usr/src/php/ext/imagick \
70 | && docker-php-ext-install imagick \
71 | && docker-php-ext-enable imagick redis opcache \
72 | && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
73 |
74 | RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
75 |
76 | RUN { \
77 | echo "# msmtp configuration"; \
78 | echo "defaults"; \
79 | echo "auth off"; \
80 | echo "tls off"; \
81 | echo "host ${SMTP_HOST}"; \
82 | echo "port ${SMTP_PORT}"; \
83 | echo "logfile /proc/self/fd/2"; \
84 | echo "account default"; \
85 | echo "add_missing_date_header on"; \
86 | echo "from mail@example.local"; \
87 | } > /etc/msmtprc \
88 | && chmod 644 /etc/msmtprc
89 |
90 | RUN echo "[mail function]\n" \
91 | "SMTP=${SMTP_HOST}\n" \
92 | "smtp_port=${SMTP_PORT}\n" \
93 | "sendmail_path=/usr/bin/msmtp -t -i\n" \
94 | > /usr/local/etc/php/conf.d/mailhog.ini
95 |
96 | RUN if [ -n "$LOCALE" ]; then \
97 | echo "${LOCALE} UTF-8" >> /etc/locale.gen && \
98 | locale-gen && \
99 | echo "export LANG=${LOCALE}" >> /etc/profile.d/php_locale.sh && \
100 | echo "export LC_ALL=${LOCALE}" >> /etc/profile.d/php_locale.sh; \
101 | fi
102 |
103 | RUN if [ "${XDEBUG_ENABLE}" -eq 1 ]; then \
104 | if [ "${PHP_VERSION}" \< "8.0" ]; then \
105 | pecl install xdebug-2.9.8; \
106 | else \
107 | pecl install xdebug; \
108 | fi && \
109 | docker-php-ext-enable xdebug; \
110 | fi
111 |
112 | COPY xhprof/ $XHPROF_PATH/
113 | RUN if [ "${XHPROF_ENABLE}" -eq 1 ]; then \
114 | pecl install mongodb xhprof \
115 | && docker-php-ext-enable mongodb xhprof \
116 | && cd $XHPROF_PATH \
117 | && composer update \
118 | && chown -R www-data:www-data $XHPROF_PATH \
119 | && chmod -R 775 $XHPROF_PATH; \
120 | fi
121 |
122 | RUN if [ "$BLACKFIRE_ENABLE" -eq 1 ]; then \
123 | version=$(php -r "echo PHP_MAJOR_VERSION.PHP_MINOR_VERSION.(PHP_ZTS ? '-zts' : '');") \
124 | && architecture=$(uname -m) \
125 | && curl -A "Docker" -o /tmp/blackfire-probe.tar.gz -D - -L -s https://blackfire.io/api/v1/releases/probe/php/linux/$architecture/$version \
126 | && mkdir -p /tmp/blackfire \
127 | && tar zxpf /tmp/blackfire-probe.tar.gz -C /tmp/blackfire \
128 | && mv /tmp/blackfire/blackfire-*.so $(php -r "echo ini_get ('extension_dir');")/blackfire.so \
129 | && printf "extension=blackfire.so\nblackfire.agent_socket=tcp://blackfire:8307\n" > $PHP_INI_DIR/conf.d/blackfire.ini \
130 | && rm -rf /tmp/blackfire /tmp/blackfire-probe.tar.gz; \
131 | fi
132 |
133 | RUN if [ "$SSH_ENABLE" -eq 1 ]; then \
134 | mkdir /var/run/sshd \
135 | && sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config \
136 | && useradd -rm -d ${ROOT_PATH} -s /bin/bash -g root -G www-data -u 1000 ${SSH_LOGIN} \
137 | && echo "${SSH_LOGIN}:${SSH_PASSWORD}" | chpasswd; \
138 | fi
139 |
140 | COPY sh/modx-*.sh $ENTRYPOINT_PATH/
141 | RUN chmod 777 $ENTRYPOINT_PATH/modx-*.sh
142 |
143 | ENTRYPOINT ["/usr/local/bin/modx-docker-start.sh"]
144 |
145 | WORKDIR $ROOT_PATH
--------------------------------------------------------------------------------
/docker/php/conf/opcache.ini:
--------------------------------------------------------------------------------
1 | opcache.memory_consumption = 128
2 | opcache.interned_strings_buffer = 8
3 | opcache.max_accelerated_files = 4000
4 | opcache.fast_shutdown = 1
5 | opcache.enable_cli = 0
--------------------------------------------------------------------------------
/docker/php/conf/php.ini:
--------------------------------------------------------------------------------
1 | log_errors=On
2 | display_errors=On
3 | error_log= /var/log/php-fpm/error.log
4 | error_reporting=E_ALL & ~E_NOTICE
5 |
6 | max_execution_time=120
7 | upload_max_filesize=100M
8 | upload_tmp_dir=/tmp
--------------------------------------------------------------------------------
/docker/php/conf/xdebug.ini:
--------------------------------------------------------------------------------
1 | ; Xdebug 2.x:
2 | xdebug.remote_enable = 1
3 | xdebug.remote_autostart = 1
4 | xdebug.remote_port = 9000
5 | xdebug.remote_host = host.docker.internal
6 |
7 | ; Xdebug 3.x
8 | xdebug.mode = debug
9 | xdebug.client_host = host.docker.internal
10 | xdebug.start_start_with_request = yes
11 | xdebug.log_level = 0
--------------------------------------------------------------------------------
/docker/php/conf/xhprof.ini:
--------------------------------------------------------------------------------
1 | xhprof.collect_additional_info = 1
2 | xhprof.output_dir = /tmp/xhprof
--------------------------------------------------------------------------------
/docker/php/sh/modx-clear-db.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | echo "Start cleaning DB: ${MODX_DB_NAME}..."
4 | mysql -u"$MODX_DB_USER" -p"$MODX_DB_PASSWORD" -h"$MODX_DB_SERVER" -e "
5 | SET FOREIGN_KEY_CHECKS = 0;
6 | USE $MODX_DB_NAME;
7 | SET GROUP_CONCAT_MAX_LEN = 1000000;
8 | SET @tables = NULL;
9 | SELECT GROUP_CONCAT('\`', table_name, '\`') INTO @tables
10 | FROM information_schema.tables
11 | WHERE table_schema = '$MODX_DB_NAME';
12 | SET @sql = IFNULL(CONCAT('DROP TABLE ', @tables), 'SELECT \"No tables to drop\"');
13 | PREPARE stmt FROM @sql;
14 | EXECUTE stmt;
15 | DEALLOCATE PREPARE stmt;
16 | SET FOREIGN_KEY_CHECKS = 1;
17 | " || echo "Error when deleting tables from the database $MODX_DB_NAME"
18 | echo "Finish cleaning DB"
19 |
--------------------------------------------------------------------------------
/docker/php/sh/modx-clear-site.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | echo "Start cleaning site directory: ${ROOT_PATH} ..."
4 | find "${ROOT_PATH}" -mindepth 1 -delete
5 | echo "Finish cleaning site directory"
--------------------------------------------------------------------------------
/docker/php/sh/modx-configure.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | configurator_path="${MODX_CORE_PATH}configurator"
5 |
6 | echo "Copying files for Modx configurator..."
7 | mkdir -p "$configurator_path"
8 | cp -rf "${MODX_TOOLS_PATH}"/configurator/* "$configurator_path"
9 |
10 | echo "Set permissions for Modx configurator files..."
11 | chown -R www-data:www-data "$configurator_path"
12 | chmod -R 775 "$configurator_path"
13 |
14 | echo "Run composer update for Modx configurator..."
15 | cd "$configurator_path"
16 | composer update;
17 |
18 | php "$configurator_path"/run.php
19 |
20 | if [[ "$MODX_CONFIGURE_DEV_MODE" -eq 0 ]]; then
21 | rm -rf "$configurator_path"
22 | rm -rf "${MODX_CORE_PATH}cache/*"
23 | fi
24 |
25 | chown -R www-data:www-data "${ROOT_PATH}"
26 | chmod -R 775 "${ROOT_PATH}"
27 |
28 |
29 |
--------------------------------------------------------------------------------
/docker/php/sh/modx-docker-start.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | if [ "$SSH_ENABLE" -eq 1 ]; then
4 | /usr/sbin/sshd
5 | fi
6 |
7 | bash "${ENTRYPOINT_PATH}/docker-php-entrypoint"
8 |
9 | if [[ "$SSL_GENERATE" -eq 1 && ! -f "${SSL_PATH}/server.crt" ]]; then
10 | bash "${ENTRYPOINT_PATH}/modx-generate-ssl.sh";
11 | fi
12 |
13 | if [[ "$MODX_INSTALL_ENABLE" -eq 1 ]]; then
14 |
15 | version_file="${MODX_CORE_PATH}docs/version.inc.php"
16 | if [[ "$MODX_RESET" -eq 1 && -f "$version_file" ]]; then
17 | bash "${ENTRYPOINT_PATH}/modx-uninstall.sh";
18 | fi
19 |
20 | if [[ "$MODX_IMPORT" != "0" ]]; then
21 | bash "${ENTRYPOINT_PATH}/modx-import.sh";
22 | elif [ ! -f "$version_file" ]; then
23 | bash "${ENTRYPOINT_PATH}/modx-install.sh";
24 | if [ "$MODX_CONFIGURE_ENABLE" -eq 1 ]; then
25 | bash "${ENTRYPOINT_PATH}/modx-configure.sh";
26 | fi
27 | else
28 | echo "Starting check upgrade Modx version"
29 | installed_version=$(php -r "\$v = include '$version_file'; echo \$v['full_version'];")
30 |
31 | echo "Installed Modx version: $installed_version"
32 | echo "Required Modx version: $MODX_VERSION"
33 |
34 | is_less=$(php -r "echo version_compare('$installed_version','$MODX_VERSION', '<');")
35 |
36 | if [[ -n "$is_less" && "$is_less" -eq 1 ]]; then
37 | bash "${ENTRYPOINT_PATH}/modx-upgrade.sh";
38 | else
39 | echo "No need to upgrade the Modx version"
40 | fi
41 | fi
42 | fi
43 |
44 | if ! pgrep php-fpm; then
45 | php-fpm
46 | fi
--------------------------------------------------------------------------------
/docker/php/sh/modx-download.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | source_file="${MODX_CACHE_SOURCE_PATH}/modx-${MODX_VERSION}.zip"
5 | modx_download_url="https://modx.com/download/direct/modx-${MODX_VERSION}.zip"
6 |
7 | if [[ ! -f "$source_file" ]]; then
8 | echo "Downloading Modx ${MODX_VERSION} ..."
9 | echo "Download Modx URL ${modx_download_url}"
10 | curl -o "${MODX_CACHE_SOURCE_PATH}/modx-${MODX_VERSION}.zip" -L "${modx_download_url}"
11 | fi
12 |
13 |
14 | echo "Unzip Modx..."
15 | unzip -q "$source_file" -d "${ROOT_PATH}"
16 |
17 | echo "Moving extracted Modx files..."
18 | cp -rf "${ROOT_PATH}"/modx-"${MODX_VERSION}"/* "${ROOT_PATH}"
19 | #mv "${ROOT_PATH}"/modx-"${MODX_VERSION}"/* "${ROOT_PATH}"
20 |
21 | echo "Deleting temporary Modx files..."
22 | rm -rf "${ROOT_PATH}"/modx-"${MODX_VERSION}"
23 |
24 | if [[ "$MODX_USE_CACHE_SOURCE" -ne 1 && -f "$source_file" ]]; then
25 | rm "$source_file"
26 | fi
27 |
28 | echo "Set permissions Modx files..."
29 | chown -R www-data:www-data "${ROOT_PATH}"
30 | chmod -R 775 "${ROOT_PATH}"
--------------------------------------------------------------------------------
/docker/php/sh/modx-export.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | echo "Start export Modx"
5 |
6 | temp_dir=$(mktemp -d)
7 | main_config=${MODX_CORE_PATH}config/config.inc.php
8 |
9 | if [ "$MODX_EXPORT_DB" -eq 1 ]; then
10 | echo "Export DB: ${MODX_DB_NAME}..."
11 |
12 | db_file="db.dump.sql"
13 | table_prefix=$(grep -Po '\$table_prefix\s*=\s*'\''.*?'\''' "$main_config" | perl -pe "s/.*'(.*?)'.*/\1/")
14 | table_prefix="${table_prefix:-$MODX_TABLE_PREFIX}"
15 | session_table="${table_prefix}session"
16 |
17 | echo "Cleaning table: ${session_table}..."
18 | mysql -u"$MODX_DB_USER" -p"$MODX_DB_PASSWORD" -h"$MODX_DB_SERVER" "$MODX_DB_NAME" -e "TRUNCATE TABLE ${session_table};"
19 |
20 | echo "Creating a dump: ${MODX_DB_NAME}..."
21 | mysqldump -u"$MODX_DB_USER" -p"$MODX_DB_PASSWORD" -h"$MODX_DB_SERVER" "$MODX_DB_NAME" > "$temp_dir"/"$db_file"
22 | fi
23 |
24 | if [ "$MODX_EXPORT_SITE" -eq 1 ]; then
25 | echo "Export site directory: ${ROOT_PATH}..."
26 |
27 | cd "$ROOT_PATH"
28 | configs=(
29 | "$main_config"
30 | "${ROOT_PATH}"/config.core.php
31 | "${MODX_CONTEXT_MANAGER_PATH}"config.core.php
32 | "${MODX_CONTEXT_CONNECTORS_PATH}"config.core.php
33 | )
34 |
35 | echo "Cleaning Modx cache folder..."
36 | rm -rf "${MODX_CORE_PATH}"cache/*
37 |
38 | if [ "$MODX_EXPORT_OVERWRITE_CONFIG" -eq 1 ]; then
39 | echo "Creating a backup of Modx config files..."
40 | for file in "${configs[@]}"
41 | do
42 | if [ -f "$file" ]; then
43 | echo "Backuping file: ${file}.bak"
44 | cp "$file" "${file}.bak"
45 | fi
46 | done
47 |
48 | if [ -n "$MODX_EXPORT_DB_USER" ]; then
49 | sed -i "s|\(\$database_user\s*=\s*\)[\"'][^\"']*[\"'];|\1'${MODX_EXPORT_DB_USER}';|g" "$main_config"
50 | fi
51 |
52 | if [ -n "$MODX_EXPORT_DB_PASSWORD" ]; then
53 | sed -i "s|\(\$database_password\s*=\s*\)[\"'][^\"']*[\"'];|\1'${MODX_EXPORT_DB_PASSWORD}';|g" "$main_config"
54 | fi
55 |
56 | if [ -n "$MODX_EXPORT_DB_SERVER" ]; then
57 | sed -i "s|\(\$database_server\s*=\s*\)[\"'][^\"']*[\"'];|\1'${MODX_EXPORT_DB_SERVER}';|g" "$main_config"
58 | sed -i "s|\(\$database_dsn = '[^:]*:host=\)[^;]*|\1${MODX_EXPORT_DB_SERVER}|" "$main_config"
59 | fi
60 |
61 | if [ -n "$MODX_EXPORT_DB_NAME" ]; then
62 | sed -i "s|\(\$dbase\s*=\s*\)[\"'][^\"']*[\"'];|\1'${MODX_EXPORT_DB_NAME}';|g" "$main_config"
63 | sed -i "/^\$database_dsn =/s|\(dbname=\)[^;]*|\1${MODX_EXPORT_DB_NAME}|" "$main_config"
64 | fi
65 |
66 | if [ -n "$MODX_EXPORT_CORE_PATH" ]; then
67 | file=${ROOT_PATH}/config.core.php
68 | sed -i "s|^\(define('MODX_CORE_PATH', \).*);|\1'$MODX_EXPORT_CORE_PATH');|g" "$file"
69 |
70 | file=${MODX_CONNECTORS_PATH}config.core.php
71 | sed -i "s|^\(define('MODX_CORE_PATH', \).*);|\1'$MODX_EXPORT_CORE_PATH');|g" "$file"
72 |
73 | file=${MODX_MANAGER_PATH}config.core.php
74 | sed -i "s|^\(define('MODX_CORE_PATH', \).*);|\1'$MODX_EXPORT_CORE_PATH');|g" "$file"
75 |
76 | sed -i "s|\(\$modx_core_path\s*=\s*\)[\"'][^\"']*[\"'];|\1'${MODX_EXPORT_CORE_PATH}';|g" "$main_config"
77 | sed -i "s|\(\$modx_processors_path\s*=\s*\)[\"'][^\"']*[\"'];|\1'${MODX_EXPORT_CORE_PATH}model/modx/processors/';|g" "$main_config"
78 | fi
79 |
80 | if [ -n "$MODX_EXPORT_CONNECTORS_PATH" ]; then
81 | sed -i "s|\(\$modx_connectors_path\s*=\s*\)[\"'][^\"']*[\"'];|\1'${MODX_EXPORT_CONNECTORS_PATH}';|g" "$main_config"
82 | fi
83 |
84 | if [ -n "$MODX_EXPORT_CONNECTORS_URL" ]; then
85 | sed -i "s|\(\$modx_connectors_url\s*=\s*\)[\"'][^\"']*[\"'];|\1'${MODX_EXPORT_CONNECTORS_URL}';|g" "$main_config"
86 | fi
87 |
88 | if [ -n "$MODX_EXPORT_MANAGER_PATH" ]; then
89 | sed -i "s|\(\$modx_manager_path\s*=\s*\)[\"'][^\"']*[\"'];|\1'${MODX_EXPORT_MANAGER_PATH}';|g" "$main_config"
90 | fi
91 |
92 | if [ -n "$MODX_EXPORT_MANAGER_URL" ]; then
93 | sed -i "s|\(\$modx_manager_url\s*=\s*\)[\"'][^\"']*[\"'];|\1'${MODX_EXPORT_MANAGER_URL}';|g" "$main_config"
94 | fi
95 |
96 | if [ -n "$MODX_EXPORT_HTTP_HOST" ]; then
97 | sed -i "s|\(\$http_host\s*=\s*\)[\"'][^\"']*[\"'];|\1'${MODX_EXPORT_HTTP_HOST}';|g" "$main_config"
98 | sed -i "s|$MODX_HTTP_HOST|$MODX_EXPORT_HTTP_HOST|g" "$main_config"
99 | fi
100 |
101 | if [ -n "$MODX_EXPORT_BASE_PATH" ]; then
102 | sed -i "s|\(\$modx_base_path\s*=\s*\)[\"'][^\"']*[\"'];|\1'${MODX_EXPORT_BASE_PATH}';|g" "$main_config"
103 | sed -i "s|\(\$modx_assets_path\s*=\s*\)[\"'][^\"']*[\"'];|\1'${MODX_EXPORT_BASE_PATH}assets/';|g" "$main_config"
104 | fi
105 |
106 | if [ -n "$MODX_EXPORT_BASE_URL" ]; then
107 | sed -i "s|\(\$modx_base_url\s*=\s*\)[\"'][^\"']*[\"'];|\1'${MODX_EXPORT_BASE_URL}';|g" "$main_config"
108 | sed -i "s|\(\$modx_assets_url\s*=\s*\)[\"'][^\"']*[\"'];|\1'${MODX_EXPORT_BASE_URL}assets/';|g" "$main_config"
109 | fi
110 |
111 | if [ -n "$MODX_EXPORT_ASSETS_PATH" ]; then
112 | sed -i "s|\(\$modx_assets_path\s*=\s*\)[\"'][^\"']*[\"'];|\1'${MODX_EXPORT_ASSETS_PATH}';|g" "$main_config"
113 | fi
114 |
115 | if [ -n "$MODX_EXPORT_ASSETS_URL" ]; then
116 | sed -i "s|\(\$modx_assets_url\s*=\s*\)[\"'][^\"']*[\"'];|\1'${MODX_EXPORT_ASSETS_URL}';|g" "$main_config"
117 | fi
118 | fi
119 |
120 | archive_site="site.zip";
121 | echo "Compress site dir into: ${archive_site}"
122 | zip -q -r "$archive_site" ./ -x "./*.php.bak"
123 |
124 | if [ "$MODX_EXPORT_OVERWRITE_CONFIG" -eq 1 ]; then
125 | for file in "${configs[@]}"
126 | do
127 | file_bak="${file}.bak"
128 | if [ -f "$file_bak" ]; then
129 | mv "$file_bak" "$file"
130 | fi
131 | done
132 | fi
133 |
134 | echo "Moving ${archive_site} to ${temp_dir}"
135 | mv "$archive_site" "$temp_dir"
136 | fi
137 |
138 | if [ "$(ls -A "$temp_dir")" ]; then
139 | cd "$temp_dir"
140 | date=$(date +\%F_\%T)
141 | export_file="${date}.zip"
142 |
143 | echo "Compress all export into: ${export_file}"
144 | zip -r "$export_file" ./
145 |
146 | echo "Moving ${export_file} to ${MODX_BACKUP_PATH}"
147 | mv "$export_file" "$MODX_BACKUP_PATH"
148 | fi
149 |
150 | echo "Finish export Modx"
--------------------------------------------------------------------------------
/docker/php/sh/modx-generate-ssl.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | mkdir -p "$SSL_PATH"
5 |
6 | echo "Start generate SSL into ${SSL_PATH}"
7 | openssl req -x509 -nodes -days 365 \
8 | -newkey rsa:2048 \
9 | -keyout "$SSL_PATH"/server.key \
10 | -out "$SSL_PATH"/server.crt \
11 | -subj "/CN=${SSL_HOST:-$MODX_HTTP_HOST}";
--------------------------------------------------------------------------------
/docker/php/sh/modx-import.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | echo "Start Import Modx"
5 |
6 | if [ "$MODX_IMPORT" == "latest" ]; then
7 | archive_file=$(find "$MODX_BACKUP_PATH" -name "*.zip" -type f -printf '%T@ %p\n' | sort -nr | head -n 1 | cut -d' ' -f2-)
8 | else
9 | if [[ "$MODX_IMPORT" =~ \.zip$ ]]; then
10 | archive_file="${MODX_BACKUP_PATH}/${MODX_IMPORT}"
11 | else
12 | archive_file="${MODX_BACKUP_PATH}/${MODX_IMPORT}.zip"
13 | fi
14 | fi
15 |
16 | if [[ -z "$archive_file" || ! -f "$archive_file" ]]; then
17 | echo "Import zip file not found in directory: ${MODX_BACKUP_PATH}"
18 | exit 1
19 | fi
20 |
21 | temp_dir=$(mktemp -d)
22 | cd "$temp_dir"
23 |
24 | echo "Copy ${archive_file} to ${temp_dir}"
25 | cp "$archive_file" "$temp_dir"
26 |
27 | echo "Unzip ${archive_file}"
28 | unzip "$archive_file"
29 |
30 | if [[ "$MODX_IMPORT_SITE" -eq 1 ]]; then
31 | site_zip_file="${temp_dir}/site.zip"
32 | if [[ -f "$site_zip_file" ]]; then
33 | echo "Start site import from file: ${site_zip_file}"
34 | bash "${ENTRYPOINT_PATH}/modx-clear-site.sh";
35 |
36 | echo "Unzip ${site_zip_file}..."
37 | unzip -q "$site_zip_file" -d "$ROOT_PATH"
38 |
39 | echo "Finish site import"
40 | else
41 | echo "Site import zip file: ${site_zip_file} not found!"
42 | fi
43 | fi
44 |
45 | if [[ "$MODX_IMPORT_DB" -eq 1 ]]; then
46 | db_file="${temp_dir}/db.dump.sql"
47 | if [[ -f "$db_file" ]]; then
48 | bash "${ENTRYPOINT_PATH}/modx-clear-db.sh";
49 | echo "Start DB import from dump file: ${db_file}"
50 | mysql -u"$MODX_DB_USER" -p"$MODX_DB_PASSWORD" -h"$MODX_DB_SERVER" "$MODX_DB_NAME" < "$db_file"
51 | echo "Finish DB import"
52 | else
53 | echo "DB import dump file: ${db_file} not found!"
54 | fi
55 | fi
56 |
57 | echo "Finish Import Modx"
--------------------------------------------------------------------------------
/docker/php/sh/modx-install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 | prepare_table_prefix() {
4 | input=$1
5 | if [[ $input =~ ^random:([0-9]+)$ ]]; then
6 | length=${BASH_REMATCH[1]}
7 | random_string=$(head /dev/urandom | tr -dc 'A-Za-z0-9' | head -c "$length")
8 | echo "${random_string}_"
9 | else
10 | echo "$input"
11 | fi
12 | }
13 |
14 | bash "${ENTRYPOINT_PATH}/modx-download.sh"
15 |
16 | echo "Install MODX preparing..."
17 | install_config=$(cat "$ROOT_PATH/setup/config.dist.new.xml")
18 |
19 | table_prefix=$(prepare_table_prefix "$MODX_TABLE_PREFIX")
20 | install_config="${install_config//modx_/$table_prefix}"
21 | echo " Param table_prefix: $table_prefix"
22 |
23 | install_config=$(echo $install_config | sed "s/localhost/$MODX_DB_SERVER/g")
24 | install_config="${install_config//localhost/$MODX_DB_SERVER}"
25 | echo " Param database_server: $MODX_DB_SERVER"
26 |
27 | install_config="${install_config//modx_modx/$MODX_DB_NAME}"
28 | echo " Param database: $MODX_DB_NAME"
29 |
30 | install_config="${install_config//db_username/$MODX_DB_USER}"
31 | echo " Param database_user: $MODX_DB_USER"
32 |
33 | install_config="${install_config//db_password/$MODX_DB_PASSWORD}"
34 | echo " Param database_password: $MODX_DB_PASSWORD"
35 |
36 | install_config="${install_config//utf8/$MODX_DB_CONNECTION_CHARSET}"
37 | echo " Param database_connection_charset: $MODX_DB_CONNECTION_CHARSET"
38 |
39 | install_config="${install_config//utf8/$MODX_DB_CHARSET}"
40 | echo " Param database_charset: $MODX_DB_CHARSET"
41 |
42 | install_config="${install_config//utf8_general_ci/$MODX_DB_CHARSET_COLLATION}"
43 | echo " Param database_collation: $MODX_DB_CHARSET_COLLATION"
44 |
45 | install_config="${install_config//443/$MODX_HTTPS_PORT}"
46 | echo " Param https_port: $MODX_HTTPS_PORT"
47 |
48 | install_config="${install_config//localhost/$MODX_HTTP_HOST}"
49 | echo " Param http_host: $MODX_HTTP_HOST"
50 |
51 | install_config="${install_config//0/1}"
52 | echo " Param inplace: 1"
53 |
54 | install_config="${install_config//0/1}"
55 | echo " Param unpacked: 1"
56 |
57 | install_config="${install_config//en/$MODX_LANGUAGE}"
58 | echo " Param: language :$MODX_LANGUAGE"
59 |
60 | install_config="${install_config//username/$MODX_CMS_ADMIN}"
61 | echo " Param cmsadmin: $MODX_CMS_ADMIN"
62 |
63 | install_config="${install_config//password/$MODX_CMS_PASS}"
64 | echo " Param cmspassword: $MODX_CMS_PASS"
65 |
66 | install_config="${install_config//email@address.com/$MODX_CMS_EMAIL}"
67 | echo " Param cmsadminemail: $MODX_CMS_EMAIL"
68 |
69 | install_config="${install_config//1/$MODX_REMOVE_SETUP_DIRECTORY}"
70 | echo " Param remove_setup_directory: $MODX_REMOVE_SETUP_DIRECTORY"
71 |
72 | install_config="${install_config//\/www\/modx\/core\//$MODX_CORE_PATH}"
73 | echo " Param core_path: $MODX_CORE_PATH"
74 |
75 | install_config="${install_config//\/www\/modx\/connectors\//$MODX_CONNECTORS_PATH}"
76 | echo " Param context_connectors_path: $MODX_CONNECTORS_PATH"
77 |
78 | install_config="${install_config//\/modx\/connectors\//$MODX_CONNECTORS_URL}"
79 | echo " Param: context_connectors_url: $MODX_CONNECTORS_URL"
80 |
81 | install_config="${install_config//\/www\/modx\/manager\//$MODX_MANAGER_PATH}"
82 | echo " Param context_mgr_path: $MODX_MANAGER_PATH"
83 |
84 | install_config="${install_config//\/modx\/manager\//$MODX_MANAGER_URL}"
85 | echo " Param context_mgr_url: $MODX_MANAGER_URL"
86 |
87 | install_config="${install_config//\/www\/modx\//$MODX_BASE_PATH}"
88 | echo " Param context_web_path: $MODX_BASE_PATH"
89 |
90 | install_config="${install_config//\/modx\//$MODX_BASE_URL}"
91 | echo " Param context_web_url: $MODX_BASE_URL"
92 |
93 | echo "$install_config" > "$ROOT_PATH"/setup/config.xml
94 |
95 | echo "Start installation Modx..."
96 | php "$ROOT_PATH"/setup/index.php --installmode=new
97 |
98 | echo "Modx installation is complete!"
--------------------------------------------------------------------------------
/docker/php/sh/modx-uninstall.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | echo "Start uninstall Modx"
5 | bash "${ENTRYPOINT_PATH}/modx-clear-site.sh";
6 | bash "${ENTRYPOINT_PATH}/modx-clear-db.sh";
7 | echo "Finish uninstall Modx"
--------------------------------------------------------------------------------
/docker/php/sh/modx-upgrade.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | bash "${ENTRYPOINT_PATH}/modx-download.sh"
5 |
6 | echo "Upgrade MODX preparing..."
7 | upgrade_config=$(cat "$ROOT_PATH/setup/config.dist.upgrade.xml")
8 |
9 | upgrade_config="${upgrade_config//0/1}"
10 | echo " Param inplace: 1"
11 |
12 | upgrade_config="${upgrade_config//0/0}"
13 | echo " Param unpacked: 0"
14 |
15 | upgrade_config="${upgrade_config//en/$MODX_LANGUAGE}"
16 | echo " Param: language :$MODX_LANGUAGE"
17 |
18 | echo "$upgrade_config" > "$ROOT_PATH"/setup/config.xml
19 |
20 | echo "Start of modx upgrade..."
21 | php "$ROOT_PATH"/setup/index.php --installmode=upgrade
22 |
23 | echo "Modx upgrade is complete!"
24 |
--------------------------------------------------------------------------------
/docker/php/xhprof/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "require": {
3 | "mongodb/mongodb": "^1.20.0"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/docker/php/xhprof/handler.php:
--------------------------------------------------------------------------------
1 | selectCollection(getenv('XHGUI_MONGO_DATABASE'), 'results');
10 | $data = array(
11 | 'meta' => array(
12 | 'url' => $_SERVER['REQUEST_URI'],
13 | 'get' => $_GET,
14 | 'SERVER' => $_SERVER,
15 | // 'env' => $_ENV,
16 | 'simple_url' => parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH),
17 | 'request_ts' => new MongoDB\BSON\UTCDateTime(microtime(true) * 1000),
18 | 'request_date' => date('Y-m-d'),
19 | ),
20 | 'profile' => $xhprof_data
21 | );
22 | $collection->insertOne($data);
23 | });
24 | }
--------------------------------------------------------------------------------
/docker/volume/mariadb/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Prihod/docker-modx/4fa05bd11e002f3e867d46cfa59956c613a33d52/docker/volume/mariadb/.gitkeep
--------------------------------------------------------------------------------
/docker/xhgui/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.1-apache
2 |
3 | RUN apt-get update && apt-get install -y --no-install-recommends \
4 | git \
5 | unzip \
6 | libmongoc-1.0-0 \
7 | libssl-dev \
8 | && pecl install mongodb \
9 | && docker-php-ext-enable mongodb \
10 | && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
11 |
12 | RUN echo "date.timezone=UTC" > /usr/local/etc/php/conf.d/timezone.ini
13 |
14 | RUN echo "error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT" > /usr/local/etc/php/conf.d/error-reporting.ini
15 |
16 | RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
17 |
18 | WORKDIR /var/www/html
19 |
20 | RUN git clone https://github.com/perftools/xhgui.git . \
21 | && chmod -R 0777 cache \
22 | && composer install --no-dev
23 |
24 |
25 | RUN a2enmod rewrite
26 | COPY apache.conf /etc/apache2/sites-available/000-default.conf
27 |
28 | RUN chown -R www-data:www-data /var/www/html \
29 | && chmod -R 755 /var/www/html
30 |
31 | COPY config.php /var/www/html/config/config.default.php
32 |
33 | COPY templates/runs/view.twig /var/www/html/templates/custom/runs/view.twig
--------------------------------------------------------------------------------
/docker/xhgui/apache.conf:
--------------------------------------------------------------------------------
1 |
2 | ServerAdmin webmaster@localhost
3 | DocumentRoot /var/www/html/webroot
4 |
5 |
6 | Options Indexes FollowSymLinks
7 | AllowOverride All
8 | Require all granted
9 |
10 |
11 | ErrorLog ${APACHE_LOG_DIR}/error.log
12 | CustomLog ${APACHE_LOG_DIR}/access.log combined
13 |
--------------------------------------------------------------------------------
/docker/xhgui/config.php:
--------------------------------------------------------------------------------
1 | 'mongodb',
13 |
14 | 'mongodb' => [
15 | // 'hostname' and 'port' are used to build DSN for MongoClient
16 | 'hostname' => getenv('XHGUI_MONGO_HOSTNAME') ?: '127.0.0.1',
17 | 'port' => getenv('XHGUI_MONGO_PORT') ?: 27017,
18 | // The database name
19 | 'database' => getenv('XHGUI_MONGO_DATABASE') ?: 'xhprof',
20 | // Additional options for the MongoClient constructor,
21 | // for example 'username', 'password', or 'replicaSet'.
22 | // See .
23 | 'options' => [
24 | /*
25 | 'username' => getenv('XHGUI_MONGO_USERNAME') ?: null,
26 | 'password' => getenv('XHGUI_MONGO_PASSWORD') ?: null,
27 | */
28 | ],
29 | // An array of options for the MongoDB driver.
30 | // Options include setting connection context options for SSL or logging callbacks.
31 | // See .
32 | 'driverOptions' => [],
33 | ],
34 |
35 | 'run.view.filter.names' => [
36 | 'Zend*',
37 | 'Composer*',
38 | ],
39 |
40 | // If defined, add imports via upload (/run/import) must pass token parameter with this value
41 | 'upload.token' => getenv('XHGUI_UPLOAD_TOKEN') ?: '',
42 |
43 | // Add this path prefix to all links and resources
44 | // If this is not defined, auto-detection will try to find it itself
45 | // Example:
46 | // - prefix=null: use auto-detection from request
47 | // - prefix='': use '' for prefix
48 | // - prefix='/xhgui': use '/xhgui'
49 | 'path.prefix' => null,
50 |
51 | // Setup timezone for date formatting
52 | // Example: 'UTC', 'Europe/Tallinn'
53 | // If left empty, php default will be used (php.ini or compiled in default)
54 | 'timezone' => '',
55 |
56 | // Date format used when browsing XHGui pages.
57 | //
58 | // Must be a format supported by the PHP date() function.
59 | // See .
60 | 'date.format' => 'M jS H:i:s',
61 |
62 | // The number of items to show in "Top lists" with functions
63 | // using the most time or memory resources, on XHGui Run pages.
64 | 'detail.count' => 6,
65 |
66 | // The number of items to show per page, on XHGui list pages.
67 | 'page.limit' => 25,
68 |
69 | 'template_dir' => [
70 | '/var/www/html/templates/custom',
71 | '/var/www/html/templates',
72 | ],
73 | ];
74 |
--------------------------------------------------------------------------------
/docker/xhgui/mongo.init.d/xhgui.js:
--------------------------------------------------------------------------------
1 | db.results.ensureIndex( { 'meta.SERVER.REQUEST_TIME' : -1 } );
2 | db.results.ensureIndex( { 'profile.main().wt' : -1 } );
3 | db.results.ensureIndex( { 'profile.main().mu' : -1 } );
4 | db.results.ensureIndex( { 'profile.main().cpu' : -1 } );
5 | db.results.ensureIndex( { 'meta.url' : 1 } );
6 | db.results.ensureIndex( { 'meta.SERVER.SERVER_NAME' : 1 } );
--------------------------------------------------------------------------------
/docker/xhgui/templates/runs/view.twig:
--------------------------------------------------------------------------------
1 | {% extends 'layout/base.twig' %}
2 | {% import 'macros/helpers.twig' as helpers %}
3 |
4 | {% block title %}
5 | - Profile - {{ result.meta.url }}
6 | {% endblock %}
7 |
8 | {% block content %}
9 |
10 |
Profile data for {{ result.meta('SERVER.REQUEST_METHOD')}} {{ result.meta.SERVER.SERVER_NAME }}{{ result.meta.url }}
11 |
12 |
13 |
14 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | Compare this run
47 |
48 |
49 | View Callgraph
50 |
51 |
52 | Jump to functions
53 |
54 |
55 |
Watch Functions
56 |
57 |
58 |
59 |
60 | Function |
61 | Call Count |
62 | ewt |
63 | emu |
64 | epmu |
65 |
66 |
67 |
68 | {% for value in watches %}
69 |
70 |
71 | {{ helpers.tip_link(
72 | value.function,
73 | 65,
74 | 'run.symbol',
75 | {'id': result.id|trim, 'symbol': value.function}
76 | ) }}
77 | |
78 | {{ value.ct }} |
79 | {{ value.ewt|as_time }} |
80 | {{ value.emu|as_bytes }} |
81 | {{ value.epmu|as_bytes }} |
82 |
83 | {% else %}
84 |
85 | You have no watch functions setup.
86 | Add a watch function now.
87 | |
88 | {% endfor %}
89 |
90 |
91 |
92 |
93 |
94 |
95 |
Self Wall Time
96 |
97 |
98 | {% for value in wall_time %}
99 | - {{ value.name }}
100 | - {{ value.value|as_time }}
101 | {% endfor %}
102 |
103 |
104 |
105 |
106 |
Memory Hogs
107 |
108 |
109 | {% for value in memory %}
110 | - {{ value.name }}
111 | - {{ value.value|as_bytes }}
112 | {% endfor %}
113 |
114 |
115 |
116 |
117 |
118 |
119 |
124 |
125 |
126 |
127 |
128 |
129 |
130 | Function |
131 | Call Count |
132 | Self Wall Time |
133 | Self CPU |
134 | Self Memory Usage |
135 | Self Peak Memory Usage |
136 | Inclusive Wall Time |
137 | Inclusive CPU |
138 | Inclusive Memory Usage |
139 | Inclusive Peak Memory Usage |
140 |
141 |
142 |
143 | {% for key, value in profile %}
144 |
145 |
146 | {{ helpers.tip_link(
147 | key,
148 | 65,
149 | 'run.symbol',
150 | {'id': result.id|trim, 'symbol': key}
151 | ) }}
152 | |
153 | {{ value.ct }} |
154 | {{ value.ewt|as_time }} |
155 | {{ value.ecpu|as_time }} |
156 | {{ value.emu|as_bytes }} |
157 | {{ value.epmu|as_bytes }} |
158 | {{ value.wt|as_time }} |
159 | {{ value.cpu|as_time }} |
160 | {{ value.mu|as_bytes }} |
161 | {{ value.pmu|as_bytes }} |
162 |
163 | {% endfor %}
164 |
165 |
166 |
167 | {% endblock %}
168 |
169 | {% block jsfoot %}
170 |
200 | {% endblock %}
--------------------------------------------------------------------------------
/docs/images/video-cover.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Prihod/docker-modx/4fa05bd11e002f3e867d46cfa59956c613a33d52/docs/images/video-cover.jpg
--------------------------------------------------------------------------------
/www/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Prihod/docker-modx/4fa05bd11e002f3e867d46cfa59956c613a33d52/www/.gitkeep
--------------------------------------------------------------------------------