From 17df2ce6a92399b3e3f51533509d89426db34757 Mon Sep 17 00:00:00 2001 From: Kavalar Date: Wed, 24 Apr 2024 18:02:58 +0300 Subject: [PATCH] create project --- .bowerrc | 3 + .gitignore | 45 + LICENSE.md | 29 + README.md | 60 + Vagrantfile | 88 + backend/Dockerfile | 4 + backend/assets/AppAsset.php | 23 + backend/codeception.yml | 15 + backend/config/.gitignore | 4 + backend/config/bootstrap.php | 1 + backend/config/main.php | 54 + backend/config/params.php | 4 + backend/config/test.php | 15 + backend/controllers/SiteController.php | 104 + backend/models/.gitkeep | 1 + backend/modules/company/Company.php | 24 + .../company/controllers/CompanyController.php | 134 + .../company/controllers/DefaultController.php | 20 + backend/modules/company/models/Company.php | 8 + .../modules/company/models/CompanySearch.php | 73 + .../modules/company/views/company/_form.php | 33 + .../modules/company/views/company/_search.php | 39 + .../modules/company/views/company/create.php | 20 + .../modules/company/views/company/index.php | 49 + .../modules/company/views/company/update.php | 21 + .../modules/company/views/company/view.php | 42 + .../modules/company/views/default/index.php | 12 + backend/runtime/.gitignore | 2 + backend/tests/_bootstrap.php | 10 + backend/tests/_data/.gitignore | 0 backend/tests/_data/login_data.php | 13 + backend/tests/_output/.gitignore | 2 + backend/tests/_support/.gitignore | 1 + backend/tests/_support/FunctionalTester.php | 26 + backend/tests/_support/UnitTester.php | 26 + backend/tests/functional.suite.yml | 5 + backend/tests/functional/LoginCest.php | 44 + backend/tests/functional/_bootstrap.php | 16 + backend/tests/unit.suite.yml | 2 + backend/tests/unit/_bootstrap.php | 16 + backend/views/layouts/blank.php | 33 + backend/views/layouts/main.php | 81 + backend/views/site/error.php | 27 + backend/views/site/index.php | 53 + backend/views/site/login.php | 32 + backend/web/assets/.gitignore | 2 + backend/web/css/site.css | 90 + backend/web/favicon.ico | Bin 0 -> 318 bytes codeception.yml | 9 + common/classes/Debug.php | 20 + common/codeception.yml | 15 + common/config/.gitignore | 4 + common/config/__autocomplete.php | 33 + common/config/bootstrap.php | 5 + common/config/main.php | 13 + common/config/params.php | 9 + common/config/test.php | 11 + common/fixtures/UserFixture.php | 10 + common/mail/emailVerify-html.php | 16 + common/mail/emailVerify-text.php | 12 + common/mail/layouts/html.php | 24 + common/mail/layouts/text.php | 12 + common/mail/passwordResetToken-html.php | 16 + common/mail/passwordResetToken-text.php | 12 + common/models/Addresses.php | 73 + common/models/Check.php | 111 + common/models/CheckProduct.php | 72 + common/models/Company.php | 125 + common/models/LoginForm.php | 80 + common/models/Product.php | 97 + common/models/ProductCategory.php | 78 + common/models/User.php | 222 + common/services/CompanyService.php | 64 + common/tests/_bootstrap.php | 9 + common/tests/_data/user.php | 14 + common/tests/_output/.gitignore | 2 + common/tests/_support/.gitignore | 1 + common/tests/_support/UnitTester.php | 26 + common/tests/unit.suite.yml | 7 + common/tests/unit/models/LoginFormTest.php | 67 + common/widgets/Alert.php | 76 + composer.json | 58 + composer.lock | 5867 +++++++++++++++++ console/config/.gitignore | 3 + console/config/bootstrap.php | 1 + console/config/main.php | 36 + console/config/params.php | 5 + console/config/test.php | 4 + console/controllers/.gitkeep | 0 console/migrations/m130524_201442_init.php | 33 + ...erification_token_column_to_user_table.php | 16 + .../m240110_152351_create_company_table.php | 33 + .../m240110_153348_create_addresses_table.php | 52 + .../m240110_154916_create_product_table.php | 55 + .../m240110_155920_create_check_table.php | 75 + ...ion_table_for_check_and_product_tables.php | 92 + ...24_add_user_id_column_at_company_table.php | 44 + ...0_add_additional_column_at_check_table.php | 40 + ...205124_add_title_column_at_check_table.php | 40 + ...2_213157_create_product_category_table.php | 57 + console/models/.gitkeep | 1 + console/runtime/.gitignore | 2 + docker-compose.yml | 38 + .../dev/backend/config/codeception-local.php | 11 + .../dev/backend/config/main-local.php | 25 + .../dev/backend/config/params-local.php | 4 + .../dev/backend/config/test-local.php | 4 + environments/dev/backend/web/index-test.php | 27 + environments/dev/backend/web/index.php | 18 + environments/dev/backend/web/robots.txt | 2 + .../dev/common/config/codeception-local.php | 16 + environments/dev/common/config/main-local.php | 43 + .../dev/common/config/params-local.php | 4 + environments/dev/common/config/test-local.php | 9 + .../dev/console/config/main-local.php | 8 + .../dev/console/config/params-local.php | 4 + .../dev/console/config/test-local.php | 4 + .../dev/frontend/config/codeception-local.php | 11 + .../dev/frontend/config/main-local.php | 25 + .../dev/frontend/config/params-local.php | 4 + .../dev/frontend/config/test-local.php | 4 + environments/dev/frontend/web/index-test.php | 28 + environments/dev/frontend/web/index.php | 18 + environments/dev/frontend/web/robots.txt | 2 + environments/dev/yii | 24 + environments/dev/yii_test | 28 + environments/dev/yii_test.bat | 15 + environments/index.php | 68 + .../prod/backend/config/main-local.php | 10 + .../prod/backend/config/params-local.php | 4 + environments/prod/backend/web/index.php | 18 + environments/prod/backend/web/robots.txt | 2 + .../prod/common/config/main-local.php | 17 + .../prod/common/config/params-local.php | 4 + .../prod/console/config/main-local.php | 4 + .../prod/console/config/params-local.php | 4 + .../prod/frontend/config/main-local.php | 10 + .../prod/frontend/config/params-local.php | 4 + environments/prod/frontend/web/index.php | 18 + environments/prod/frontend/web/robots.txt | 2 + environments/prod/yii | 24 + frontend/Dockerfile | 4 + frontend/assets/AppAsset.php | 23 + frontend/codeception.yml | 15 + frontend/config/.gitignore | 4 + frontend/config/bootstrap.php | 1 + frontend/config/main.php | 67 + frontend/config/params.php | 4 + frontend/config/test.php | 18 + frontend/controllers/SiteController.php | 265 + frontend/models/ContactForm.php | 61 + frontend/models/PasswordResetRequestForm.php | 69 + .../models/ResendVerificationEmailForm.php | 61 + frontend/models/ResetPasswordForm.php | 67 + frontend/models/SignupForm.php | 80 + frontend/models/VerifyEmailForm.php | 52 + frontend/modules/addresses/Addresses.php | 24 + .../controllers/AddressesController.php | 140 + .../controllers/DefaultController.php | 20 + .../modules/addresses/models/Addresses.php | 8 + .../addresses/models/AddressesSearch.php | 70 + .../addresses/views/addresses/_form.php | 29 + .../addresses/views/addresses/_search.php | 36 + .../addresses/views/addresses/create.php | 30 + .../addresses/views/addresses/index.php | 62 + .../addresses/views/addresses/update.php | 30 + .../addresses/views/addresses/view.php | 53 + .../modules/addresses/views/default/index.php | 12 + frontend/modules/check/Check.php | 24 + .../check/controllers/CheckController.php | 127 + .../check/controllers/DefaultController.php | 20 + frontend/modules/check/models/Check.php | 8 + frontend/modules/check/models/CheckSearch.php | 72 + frontend/modules/check/views/check/_form.php | 27 + .../modules/check/views/check/_search.php | 40 + frontend/modules/check/views/check/create.php | 27 + frontend/modules/check/views/check/index.php | 58 + frontend/modules/check/views/check/update.php | 26 + frontend/modules/check/views/check/view.php | 49 + .../modules/check/views/default/index.php | 12 + frontend/modules/company/Company.php | 24 + .../company/controllers/CompanyController.php | 154 + .../company/controllers/DefaultController.php | 20 + frontend/modules/company/models/Company.php | 8 + .../modules/company/models/CompanySearch.php | 77 + .../modules/company/views/company/_form.php | 29 + .../modules/company/views/company/_search.php | 39 + .../modules/company/views/company/create.php | 18 + .../modules/company/views/company/index.php | 47 + .../modules/company/views/company/update.php | 19 + .../modules/company/views/company/view.php | 41 + .../modules/company/views/default/index.php | 12 + frontend/modules/product/Product.php | 24 + .../product/controllers/DefaultController.php | 20 + .../product/controllers/ProductController.php | 139 + frontend/modules/product/models/Product.php | 8 + .../modules/product/models/ProductSearch.php | 73 + .../modules/product/views/default/index.php | 12 + .../modules/product/views/product/_form.php | 34 + .../modules/product/views/product/_search.php | 42 + .../modules/product/views/product/create.php | 29 + .../modules/product/views/product/index.php | 58 + .../modules/product/views/product/update.php | 28 + .../modules/product/views/product/view.php | 62 + .../product_category/ProductCategory.php | 24 + .../controllers/DefaultController.php | 20 + .../controllers/ProductCategoryController.php | 132 + .../models/ProductCategory.php | 8 + .../models/ProductCategorySearch.php | 71 + .../product_category/views/default/index.php | 12 + .../views/product-category/_form.php | 32 + .../views/product-category/_search.php | 38 + .../views/product-category/create.php | 30 + .../views/product-category/index.php | 56 + .../views/product-category/update.php | 30 + .../views/product-category/view.php | 48 + frontend/runtime/.gitignore | 2 + frontend/tests/_bootstrap.php | 10 + frontend/tests/_data/login_data.php | 25 + frontend/tests/_data/user.php | 45 + frontend/tests/_output/.gitignore | 2 + frontend/tests/_support/.gitignore | 1 + frontend/tests/_support/FunctionalTester.php | 34 + frontend/tests/_support/UnitTester.php | 26 + frontend/tests/acceptance.suite.yml.example | 9 + frontend/tests/acceptance/HomeCest.php | 21 + frontend/tests/acceptance/_bootstrap.php | 16 + frontend/tests/functional.suite.yml | 7 + frontend/tests/functional/AboutCest.php | 14 + frontend/tests/functional/ContactCest.php | 60 + frontend/tests/functional/HomeCest.php | 17 + frontend/tests/functional/LoginCest.php | 66 + .../ResendVerificationEmailCest.php | 83 + frontend/tests/functional/SignupCest.php | 59 + frontend/tests/functional/VerifyEmailCest.php | 68 + frontend/tests/functional/_bootstrap.php | 16 + frontend/tests/unit.suite.yml | 7 + frontend/tests/unit/_bootstrap.php | 16 + .../tests/unit/models/ContactFormTest.php | 35 + .../models/PasswordResetRequestFormTest.php | 59 + .../ResendVerificationEmailFormTest.php | 85 + .../unit/models/ResetPasswordFormTest.php | 44 + frontend/tests/unit/models/SignupFormTest.php | 72 + .../tests/unit/models/VerifyEmailFormTest.php | 55 + frontend/views/layouts/content.php | 42 + frontend/views/layouts/control-sidebar.php | 5 + frontend/views/layouts/footer.php | 7 + frontend/views/layouts/main-login.php | 40 + frontend/views/layouts/main.php | 54 + frontend/views/layouts/navbar.php | 191 + frontend/views/layouts/sidebar.php | 87 + frontend/views/site/about.php | 16 + frontend/views/site/contact.php | 45 + frontend/views/site/error.php | 40 + frontend/views/site/index.php | 134 + frontend/views/site/login.php | 64 + .../views/site/requestPasswordResetToken.php | 31 + .../views/site/resendVerificationEmail.php | 31 + frontend/views/site/resetPassword.php | 31 + frontend/views/site/signup.php | 68 + frontend/web/assets/.gitignore | 2 + frontend/web/css/site.css | 103 + frontend/web/favicon.ico | Bin 0 -> 318 bytes init | 356 + init.bat | 15 + requirements.php | 155 + vagrant/config/.gitignore | 2 + vagrant/config/vagrant-local.example.yml | 22 + vagrant/nginx/app.conf | 77 + vagrant/nginx/log/.gitignore | 5 + vagrant/provision/always-as-root.sh | 12 + vagrant/provision/common.sh | 9 + vagrant/provision/once-as-root.sh | 74 + vagrant/provision/once-as-vagrant.sh | 32 + vagrant/provision/provision.awk | 70 + yii.bat | 15 + 276 files changed, 15932 insertions(+) create mode 100644 .bowerrc create mode 100644 .gitignore create mode 100644 LICENSE.md create mode 100644 README.md create mode 100644 Vagrantfile create mode 100644 backend/Dockerfile create mode 100644 backend/assets/AppAsset.php create mode 100644 backend/codeception.yml create mode 100644 backend/config/.gitignore create mode 100644 backend/config/bootstrap.php create mode 100644 backend/config/main.php create mode 100644 backend/config/params.php create mode 100644 backend/config/test.php create mode 100644 backend/controllers/SiteController.php create mode 100644 backend/models/.gitkeep create mode 100644 backend/modules/company/Company.php create mode 100644 backend/modules/company/controllers/CompanyController.php create mode 100644 backend/modules/company/controllers/DefaultController.php create mode 100644 backend/modules/company/models/Company.php create mode 100644 backend/modules/company/models/CompanySearch.php create mode 100644 backend/modules/company/views/company/_form.php create mode 100644 backend/modules/company/views/company/_search.php create mode 100644 backend/modules/company/views/company/create.php create mode 100644 backend/modules/company/views/company/index.php create mode 100644 backend/modules/company/views/company/update.php create mode 100644 backend/modules/company/views/company/view.php create mode 100644 backend/modules/company/views/default/index.php create mode 100644 backend/runtime/.gitignore create mode 100644 backend/tests/_bootstrap.php create mode 100644 backend/tests/_data/.gitignore create mode 100644 backend/tests/_data/login_data.php create mode 100644 backend/tests/_output/.gitignore create mode 100644 backend/tests/_support/.gitignore create mode 100644 backend/tests/_support/FunctionalTester.php create mode 100644 backend/tests/_support/UnitTester.php create mode 100644 backend/tests/functional.suite.yml create mode 100644 backend/tests/functional/LoginCest.php create mode 100644 backend/tests/functional/_bootstrap.php create mode 100644 backend/tests/unit.suite.yml create mode 100644 backend/tests/unit/_bootstrap.php create mode 100644 backend/views/layouts/blank.php create mode 100644 backend/views/layouts/main.php create mode 100644 backend/views/site/error.php create mode 100644 backend/views/site/index.php create mode 100644 backend/views/site/login.php create mode 100644 backend/web/assets/.gitignore create mode 100644 backend/web/css/site.css create mode 100644 backend/web/favicon.ico create mode 100644 codeception.yml create mode 100755 common/classes/Debug.php create mode 100644 common/codeception.yml create mode 100644 common/config/.gitignore create mode 100644 common/config/__autocomplete.php create mode 100644 common/config/bootstrap.php create mode 100644 common/config/main.php create mode 100644 common/config/params.php create mode 100644 common/config/test.php create mode 100644 common/fixtures/UserFixture.php create mode 100644 common/mail/emailVerify-html.php create mode 100644 common/mail/emailVerify-text.php create mode 100644 common/mail/layouts/html.php create mode 100644 common/mail/layouts/text.php create mode 100644 common/mail/passwordResetToken-html.php create mode 100644 common/mail/passwordResetToken-text.php create mode 100644 common/models/Addresses.php create mode 100644 common/models/Check.php create mode 100644 common/models/CheckProduct.php create mode 100644 common/models/Company.php create mode 100644 common/models/LoginForm.php create mode 100644 common/models/Product.php create mode 100644 common/models/ProductCategory.php create mode 100644 common/models/User.php create mode 100644 common/services/CompanyService.php create mode 100644 common/tests/_bootstrap.php create mode 100644 common/tests/_data/user.php create mode 100644 common/tests/_output/.gitignore create mode 100644 common/tests/_support/.gitignore create mode 100644 common/tests/_support/UnitTester.php create mode 100644 common/tests/unit.suite.yml create mode 100644 common/tests/unit/models/LoginFormTest.php create mode 100644 common/widgets/Alert.php create mode 100644 composer.json create mode 100644 composer.lock create mode 100644 console/config/.gitignore create mode 100644 console/config/bootstrap.php create mode 100644 console/config/main.php create mode 100644 console/config/params.php create mode 100644 console/config/test.php create mode 100644 console/controllers/.gitkeep create mode 100644 console/migrations/m130524_201442_init.php create mode 100644 console/migrations/m190124_110200_add_verification_token_column_to_user_table.php create mode 100644 console/migrations/m240110_152351_create_company_table.php create mode 100644 console/migrations/m240110_153348_create_addresses_table.php create mode 100644 console/migrations/m240110_154916_create_product_table.php create mode 100644 console/migrations/m240110_155920_create_check_table.php create mode 100644 console/migrations/m240110_161944_create_junction_table_for_check_and_product_tables.php create mode 100644 console/migrations/m240110_223124_add_user_id_column_at_company_table.php create mode 100644 console/migrations/m240117_203610_add_additional_column_at_check_table.php create mode 100644 console/migrations/m240117_205124_add_title_column_at_check_table.php create mode 100644 console/migrations/m240212_213157_create_product_category_table.php create mode 100644 console/models/.gitkeep create mode 100644 console/runtime/.gitignore create mode 100644 docker-compose.yml create mode 100644 environments/dev/backend/config/codeception-local.php create mode 100644 environments/dev/backend/config/main-local.php create mode 100644 environments/dev/backend/config/params-local.php create mode 100644 environments/dev/backend/config/test-local.php create mode 100644 environments/dev/backend/web/index-test.php create mode 100644 environments/dev/backend/web/index.php create mode 100644 environments/dev/backend/web/robots.txt create mode 100644 environments/dev/common/config/codeception-local.php create mode 100644 environments/dev/common/config/main-local.php create mode 100644 environments/dev/common/config/params-local.php create mode 100644 environments/dev/common/config/test-local.php create mode 100644 environments/dev/console/config/main-local.php create mode 100644 environments/dev/console/config/params-local.php create mode 100644 environments/dev/console/config/test-local.php create mode 100644 environments/dev/frontend/config/codeception-local.php create mode 100644 environments/dev/frontend/config/main-local.php create mode 100644 environments/dev/frontend/config/params-local.php create mode 100644 environments/dev/frontend/config/test-local.php create mode 100644 environments/dev/frontend/web/index-test.php create mode 100644 environments/dev/frontend/web/index.php create mode 100644 environments/dev/frontend/web/robots.txt create mode 100644 environments/dev/yii create mode 100644 environments/dev/yii_test create mode 100644 environments/dev/yii_test.bat create mode 100644 environments/index.php create mode 100644 environments/prod/backend/config/main-local.php create mode 100644 environments/prod/backend/config/params-local.php create mode 100644 environments/prod/backend/web/index.php create mode 100644 environments/prod/backend/web/robots.txt create mode 100644 environments/prod/common/config/main-local.php create mode 100644 environments/prod/common/config/params-local.php create mode 100644 environments/prod/console/config/main-local.php create mode 100644 environments/prod/console/config/params-local.php create mode 100644 environments/prod/frontend/config/main-local.php create mode 100644 environments/prod/frontend/config/params-local.php create mode 100644 environments/prod/frontend/web/index.php create mode 100644 environments/prod/frontend/web/robots.txt create mode 100644 environments/prod/yii create mode 100644 frontend/Dockerfile create mode 100644 frontend/assets/AppAsset.php create mode 100644 frontend/codeception.yml create mode 100644 frontend/config/.gitignore create mode 100644 frontend/config/bootstrap.php create mode 100644 frontend/config/main.php create mode 100644 frontend/config/params.php create mode 100644 frontend/config/test.php create mode 100644 frontend/controllers/SiteController.php create mode 100644 frontend/models/ContactForm.php create mode 100644 frontend/models/PasswordResetRequestForm.php create mode 100644 frontend/models/ResendVerificationEmailForm.php create mode 100644 frontend/models/ResetPasswordForm.php create mode 100644 frontend/models/SignupForm.php create mode 100644 frontend/models/VerifyEmailForm.php create mode 100644 frontend/modules/addresses/Addresses.php create mode 100644 frontend/modules/addresses/controllers/AddressesController.php create mode 100644 frontend/modules/addresses/controllers/DefaultController.php create mode 100644 frontend/modules/addresses/models/Addresses.php create mode 100644 frontend/modules/addresses/models/AddressesSearch.php create mode 100644 frontend/modules/addresses/views/addresses/_form.php create mode 100644 frontend/modules/addresses/views/addresses/_search.php create mode 100644 frontend/modules/addresses/views/addresses/create.php create mode 100644 frontend/modules/addresses/views/addresses/index.php create mode 100644 frontend/modules/addresses/views/addresses/update.php create mode 100644 frontend/modules/addresses/views/addresses/view.php create mode 100644 frontend/modules/addresses/views/default/index.php create mode 100644 frontend/modules/check/Check.php create mode 100644 frontend/modules/check/controllers/CheckController.php create mode 100644 frontend/modules/check/controllers/DefaultController.php create mode 100644 frontend/modules/check/models/Check.php create mode 100644 frontend/modules/check/models/CheckSearch.php create mode 100644 frontend/modules/check/views/check/_form.php create mode 100644 frontend/modules/check/views/check/_search.php create mode 100644 frontend/modules/check/views/check/create.php create mode 100644 frontend/modules/check/views/check/index.php create mode 100644 frontend/modules/check/views/check/update.php create mode 100644 frontend/modules/check/views/check/view.php create mode 100644 frontend/modules/check/views/default/index.php create mode 100644 frontend/modules/company/Company.php create mode 100644 frontend/modules/company/controllers/CompanyController.php create mode 100644 frontend/modules/company/controllers/DefaultController.php create mode 100644 frontend/modules/company/models/Company.php create mode 100644 frontend/modules/company/models/CompanySearch.php create mode 100644 frontend/modules/company/views/company/_form.php create mode 100644 frontend/modules/company/views/company/_search.php create mode 100644 frontend/modules/company/views/company/create.php create mode 100644 frontend/modules/company/views/company/index.php create mode 100644 frontend/modules/company/views/company/update.php create mode 100644 frontend/modules/company/views/company/view.php create mode 100644 frontend/modules/company/views/default/index.php create mode 100644 frontend/modules/product/Product.php create mode 100644 frontend/modules/product/controllers/DefaultController.php create mode 100644 frontend/modules/product/controllers/ProductController.php create mode 100644 frontend/modules/product/models/Product.php create mode 100644 frontend/modules/product/models/ProductSearch.php create mode 100644 frontend/modules/product/views/default/index.php create mode 100644 frontend/modules/product/views/product/_form.php create mode 100644 frontend/modules/product/views/product/_search.php create mode 100644 frontend/modules/product/views/product/create.php create mode 100644 frontend/modules/product/views/product/index.php create mode 100644 frontend/modules/product/views/product/update.php create mode 100644 frontend/modules/product/views/product/view.php create mode 100644 frontend/modules/product_category/ProductCategory.php create mode 100644 frontend/modules/product_category/controllers/DefaultController.php create mode 100644 frontend/modules/product_category/controllers/ProductCategoryController.php create mode 100644 frontend/modules/product_category/models/ProductCategory.php create mode 100644 frontend/modules/product_category/models/ProductCategorySearch.php create mode 100644 frontend/modules/product_category/views/default/index.php create mode 100644 frontend/modules/product_category/views/product-category/_form.php create mode 100644 frontend/modules/product_category/views/product-category/_search.php create mode 100644 frontend/modules/product_category/views/product-category/create.php create mode 100644 frontend/modules/product_category/views/product-category/index.php create mode 100644 frontend/modules/product_category/views/product-category/update.php create mode 100644 frontend/modules/product_category/views/product-category/view.php create mode 100644 frontend/runtime/.gitignore create mode 100644 frontend/tests/_bootstrap.php create mode 100644 frontend/tests/_data/login_data.php create mode 100644 frontend/tests/_data/user.php create mode 100644 frontend/tests/_output/.gitignore create mode 100644 frontend/tests/_support/.gitignore create mode 100644 frontend/tests/_support/FunctionalTester.php create mode 100644 frontend/tests/_support/UnitTester.php create mode 100644 frontend/tests/acceptance.suite.yml.example create mode 100644 frontend/tests/acceptance/HomeCest.php create mode 100644 frontend/tests/acceptance/_bootstrap.php create mode 100644 frontend/tests/functional.suite.yml create mode 100644 frontend/tests/functional/AboutCest.php create mode 100644 frontend/tests/functional/ContactCest.php create mode 100644 frontend/tests/functional/HomeCest.php create mode 100644 frontend/tests/functional/LoginCest.php create mode 100644 frontend/tests/functional/ResendVerificationEmailCest.php create mode 100644 frontend/tests/functional/SignupCest.php create mode 100644 frontend/tests/functional/VerifyEmailCest.php create mode 100644 frontend/tests/functional/_bootstrap.php create mode 100644 frontend/tests/unit.suite.yml create mode 100644 frontend/tests/unit/_bootstrap.php create mode 100644 frontend/tests/unit/models/ContactFormTest.php create mode 100644 frontend/tests/unit/models/PasswordResetRequestFormTest.php create mode 100644 frontend/tests/unit/models/ResendVerificationEmailFormTest.php create mode 100644 frontend/tests/unit/models/ResetPasswordFormTest.php create mode 100644 frontend/tests/unit/models/SignupFormTest.php create mode 100644 frontend/tests/unit/models/VerifyEmailFormTest.php create mode 100644 frontend/views/layouts/content.php create mode 100644 frontend/views/layouts/control-sidebar.php create mode 100644 frontend/views/layouts/footer.php create mode 100644 frontend/views/layouts/main-login.php create mode 100644 frontend/views/layouts/main.php create mode 100644 frontend/views/layouts/navbar.php create mode 100644 frontend/views/layouts/sidebar.php create mode 100644 frontend/views/site/about.php create mode 100644 frontend/views/site/contact.php create mode 100644 frontend/views/site/error.php create mode 100644 frontend/views/site/index.php create mode 100644 frontend/views/site/login.php create mode 100644 frontend/views/site/requestPasswordResetToken.php create mode 100644 frontend/views/site/resendVerificationEmail.php create mode 100644 frontend/views/site/resetPassword.php create mode 100644 frontend/views/site/signup.php create mode 100644 frontend/web/assets/.gitignore create mode 100644 frontend/web/css/site.css create mode 100644 frontend/web/favicon.ico create mode 100755 init create mode 100644 init.bat create mode 100644 requirements.php create mode 100644 vagrant/config/.gitignore create mode 100644 vagrant/config/vagrant-local.example.yml create mode 100644 vagrant/nginx/app.conf create mode 100644 vagrant/nginx/log/.gitignore create mode 100644 vagrant/provision/always-as-root.sh create mode 100644 vagrant/provision/common.sh create mode 100644 vagrant/provision/once-as-root.sh create mode 100644 vagrant/provision/once-as-vagrant.sh create mode 100644 vagrant/provision/provision.awk create mode 100644 yii.bat diff --git a/.bowerrc b/.bowerrc new file mode 100644 index 0000000..a39b5b0 --- /dev/null +++ b/.bowerrc @@ -0,0 +1,3 @@ +{ + "directory" : "vendor/bower-asset" +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2bc4788 --- /dev/null +++ b/.gitignore @@ -0,0 +1,45 @@ +# yii console commands +/yii +/yii_test +/yii_test.bat + +# phpstorm project files +.idea + +# netbeans project files +nbproject + +# zend studio for eclipse project files +.buildpath +.project +.settings + +# windows thumbnail cache +Thumbs.db + +# composer vendor dir +/vendor + +# composer itself is not needed +composer.phar + +# Mac DS_Store Files +.DS_Store + +# phpunit itself is not needed +phpunit.phar +# local phpunit config +/phpunit.xml + +# vagrant runtime +/.vagrant + +# ignore generated files +/frontend/web/index.php +/frontend/web/index-test.php +/frontend/web/robots.txt +/backend/web/index.php +/backend/web/index-test.php +/backend/web/robots.txt + +/log diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..ee872b9 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,29 @@ +Copyright © 2008 by Yii Software LLC (http://www.yiisoft.com) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Yii Software LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..ea3d192 --- /dev/null +++ b/README.md @@ -0,0 +1,60 @@ +

+ + + +

Yii 2 Advanced Project Template

+
+

+ +Yii 2 Advanced Project Template is a skeleton [Yii 2](https://www.yiiframework.com/) application best for +developing complex Web applications with multiple tiers. + +The template includes three tiers: front end, back end, and console, each of which +is a separate Yii application. + +The template is designed to work in a team development environment. It supports +deploying the application in different environments. + +Documentation is at [docs/guide/README.md](docs/guide/README.md). + +[![Latest Stable Version](https://img.shields.io/packagist/v/yiisoft/yii2-app-advanced.svg)](https://packagist.org/packages/yiisoft/yii2-app-advanced) +[![Total Downloads](https://img.shields.io/packagist/dt/yiisoft/yii2-app-advanced.svg)](https://packagist.org/packages/yiisoft/yii2-app-advanced) +[![build](https://github.com/yiisoft/yii2-app-advanced/workflows/build/badge.svg)](https://github.com/yiisoft/yii2-app-advanced/actions?query=workflow%3Abuild) + +DIRECTORY STRUCTURE +------------------- + +``` +common + config/ contains shared configurations + mail/ contains view files for e-mails + models/ contains model classes used in both backend and frontend + tests/ contains tests for common classes +console + config/ contains console configurations + controllers/ contains console controllers (commands) + migrations/ contains database migrations + models/ contains console-specific model classes + runtime/ contains files generated during runtime +backend + assets/ contains application assets such as JavaScript and CSS + config/ contains backend configurations + controllers/ contains Web controller classes + models/ contains backend-specific model classes + runtime/ contains files generated during runtime + tests/ contains tests for backend application + views/ contains view files for the Web application + web/ contains the entry script and Web resources +frontend + assets/ contains application assets such as JavaScript and CSS + config/ contains frontend configurations + controllers/ contains Web controller classes + models/ contains frontend-specific model classes + runtime/ contains files generated during runtime + tests/ contains tests for frontend application + views/ contains view files for the Web application + web/ contains the entry script and Web resources + widgets/ contains frontend widgets +vendor/ contains dependent 3rd-party packages +environments/ contains environment-based overrides +``` diff --git a/Vagrantfile b/Vagrantfile new file mode 100644 index 0000000..3940bfb --- /dev/null +++ b/Vagrantfile @@ -0,0 +1,88 @@ +require 'yaml' +require 'fileutils' + +required_plugins_installed = nil +required_plugins = %w( vagrant-hostmanager vagrant-vbguest ) +required_plugins.each do |plugin| + unless Vagrant.has_plugin? plugin + system "vagrant plugin install #{plugin}" + required_plugins_installed = true + end +end + +# IF plugin[s] was just installed - restart required +if required_plugins_installed + # Get CLI command[s] and call again + system 'vagrant' + ARGV.to_s.gsub(/\[\"|\", \"|\"\]/, ' ') + exit +end + +domains = { + frontend: 'y2aa-frontend.test', + backend: 'y2aa-backend.test' +} + +config = { + local: './vagrant/config/vagrant-local.yml', + example: './vagrant/config/vagrant-local.example.yml' +} + +# copy config from example if local config not exists +FileUtils.cp config[:example], config[:local] unless File.exist?(config[:local]) +# read config +options = YAML.load_file config[:local] + +# check github token +if options['github_token'].nil? || options['github_token'].to_s.length != 40 + puts "You must place REAL GitHub token into configuration:\n/yii2-app-advanced/vagrant/config/vagrant-local.yml" + exit +end + +# vagrant configurate +Vagrant.configure(2) do |config| + # select the box + config.vm.box = 'bento/ubuntu-18.04' + + # should we ask about box updates? + config.vm.box_check_update = options['box_check_update'] + + config.vm.provider 'virtualbox' do |vb| + # machine cpus count + vb.cpus = options['cpus'] + # machine memory size + vb.memory = options['memory'] + # machine name (for VirtualBox UI) + vb.name = options['machine_name'] + end + + # machine name (for vagrant console) + config.vm.define options['machine_name'] + + # machine name (for guest machine console) + config.vm.hostname = options['machine_name'] + + # network settings + config.vm.network 'private_network', ip: options['ip'] + + # sync: folder 'yii2-app-advanced' (host machine) -> folder '/app' (guest machine) + config.vm.synced_folder './', '/app', owner: 'vagrant', group: 'vagrant' + + # disable folder '/vagrant' (guest machine) + config.vm.synced_folder '.', '/vagrant', disabled: true + + # hosts settings (host machine) + config.vm.provision :hostmanager + config.hostmanager.enabled = true + config.hostmanager.manage_host = true + config.hostmanager.ignore_private_ip = false + config.hostmanager.include_offline = true + config.hostmanager.aliases = domains.values + + # provisioners + config.vm.provision 'shell', path: './vagrant/provision/once-as-root.sh', args: [options['timezone'], options['ip']] + config.vm.provision 'shell', path: './vagrant/provision/once-as-vagrant.sh', args: [options['github_token']], privileged: false + config.vm.provision 'shell', path: './vagrant/provision/always-as-root.sh', run: 'always' + + # post-install message (vagrant console) + config.vm.post_up_message = "Frontend URL: http://#{domains[:frontend]}\nBackend URL: http://#{domains[:backend]}" +end diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 0000000..0515d35 --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,4 @@ +FROM yiisoftware/yii2-php:8.1-apache + +# Change document root for Apache +RUN sed -i -e 's|/app/web|/app/backend/web|g' /etc/apache2/sites-available/000-default.conf diff --git a/backend/assets/AppAsset.php b/backend/assets/AppAsset.php new file mode 100644 index 0000000..7494859 --- /dev/null +++ b/backend/assets/AppAsset.php @@ -0,0 +1,23 @@ + 'app-backend', + 'basePath' => dirname(__DIR__), + 'controllerNamespace' => 'backend\controllers', + 'bootstrap' => ['log'], + 'modules' => [ + 'company' => [ + 'class' => 'backend\modules\company\Company', + ], + ], + 'components' => [ + 'request' => [ + 'csrfParam' => '_csrf-backend', + ], + 'user' => [ + 'identityClass' => 'common\models\User', + 'enableAutoLogin' => true, + 'identityCookie' => ['name' => '_identity-backend', 'httpOnly' => true], + ], + 'session' => [ + // this is the name of the session cookie used for login on the backend + 'name' => 'advanced-backend', + ], + 'log' => [ + 'traceLevel' => YII_DEBUG ? 3 : 0, + 'targets' => [ + [ + 'class' => \yii\log\FileTarget::class, + 'levels' => ['error', 'warning'], + ], + ], + ], + 'errorHandler' => [ + 'errorAction' => 'site/error', + ], + + 'urlManager' => [ + 'enablePrettyUrl' => true, + 'showScriptName' => false, + 'rules' => [ + ], + ], + + ], + 'params' => $params, +]; diff --git a/backend/config/params.php b/backend/config/params.php new file mode 100644 index 0000000..7f754b9 --- /dev/null +++ b/backend/config/params.php @@ -0,0 +1,4 @@ + 'admin@example.com', +]; diff --git a/backend/config/test.php b/backend/config/test.php new file mode 100644 index 0000000..411b05f --- /dev/null +++ b/backend/config/test.php @@ -0,0 +1,15 @@ + 'app-backend-tests', + 'components' => [ + 'assetManager' => [ + 'basePath' => __DIR__ . '/../web/assets', + ], + 'urlManager' => [ + 'showScriptName' => true, + ], + 'request' => [ + 'cookieValidationKey' => 'test', + ], + ], +]; diff --git a/backend/controllers/SiteController.php b/backend/controllers/SiteController.php new file mode 100644 index 0000000..45101d0 --- /dev/null +++ b/backend/controllers/SiteController.php @@ -0,0 +1,104 @@ + [ + 'class' => AccessControl::class, + 'rules' => [ + [ + 'actions' => ['login', 'error'], + 'allow' => true, + ], + [ + 'actions' => ['logout', 'index'], + 'allow' => true, + 'roles' => ['@'], + ], + ], + ], + 'verbs' => [ + 'class' => VerbFilter::class, + 'actions' => [ + 'logout' => ['post'], + ], + ], + ]; + } + + /** + * {@inheritdoc} + */ + public function actions() + { + return [ + 'error' => [ + 'class' => \yii\web\ErrorAction::class, + ], + ]; + } + + /** + * Displays homepage. + * + * @return string + */ + public function actionIndex() + { + return $this->render('index'); + } + + /** + * Login action. + * + * @return string|Response + */ + public function actionLogin() + { + if (!Yii::$app->user->isGuest) { + return $this->goHome(); + } + + $this->layout = 'blank'; + + $model = new LoginForm(); + if ($model->load(Yii::$app->request->post()) && $model->login()) { + return $this->goBack(); + } + + $model->password = ''; + + return $this->render('login', [ + 'model' => $model, + ]); + } + + /** + * Logout action. + * + * @return Response + */ + public function actionLogout() + { + Yii::$app->user->logout(); + + return $this->goHome(); + } +} diff --git a/backend/models/.gitkeep b/backend/models/.gitkeep new file mode 100644 index 0000000..72e8ffc --- /dev/null +++ b/backend/models/.gitkeep @@ -0,0 +1 @@ +* diff --git a/backend/modules/company/Company.php b/backend/modules/company/Company.php new file mode 100644 index 0000000..966135c --- /dev/null +++ b/backend/modules/company/Company.php @@ -0,0 +1,24 @@ + [ + 'class' => VerbFilter::className(), + 'actions' => [ + 'delete' => ['POST'], + ], + ], + ] + ); + } + + /** + * Lists all Company models. + * + * @return string + */ + public function actionIndex() + { + $searchModel = new CompanySearch(); + $dataProvider = $searchModel->search($this->request->queryParams); + + return $this->render('index', [ + 'searchModel' => $searchModel, + 'dataProvider' => $dataProvider, + ]); + } + + /** + * Displays a single Company model. + * @param int $id ID + * @return string + * @throws NotFoundHttpException if the model cannot be found + */ + public function actionView($id) + { + return $this->render('view', [ + 'model' => $this->findModel($id), + ]); + } + + /** + * Creates a new Company model. + * If creation is successful, the browser will be redirected to the 'view' page. + * @return string|\yii\web\Response + */ + public function actionCreate() + { + $model = new Company(); + + if ($this->request->isPost) { + if ($model->load($this->request->post()) && $model->save()) { + return $this->redirect(['view', 'id' => $model->id]); + } + } else { + $model->loadDefaultValues(); + } + + return $this->render('create', [ + 'model' => $model, + ]); + } + + /** + * Updates an existing Company model. + * If update is successful, the browser will be redirected to the 'view' page. + * @param int $id ID + * @return string|\yii\web\Response + * @throws NotFoundHttpException if the model cannot be found + */ + public function actionUpdate($id) + { + $model = $this->findModel($id); + + if ($this->request->isPost && $model->load($this->request->post()) && $model->save()) { + return $this->redirect(['view', 'id' => $model->id]); + } + + return $this->render('update', [ + 'model' => $model, + ]); + } + + /** + * Deletes an existing Company model. + * If deletion is successful, the browser will be redirected to the 'index' page. + * @param int $id ID + * @return \yii\web\Response + * @throws NotFoundHttpException if the model cannot be found + */ + public function actionDelete($id) + { + $this->findModel($id)->delete(); + + return $this->redirect(['index']); + } + + /** + * Finds the Company model based on its primary key value. + * If the model is not found, a 404 HTTP exception will be thrown. + * @param int $id ID + * @return Company the loaded model + * @throws NotFoundHttpException if the model cannot be found + */ + protected function findModel($id) + { + if (($model = Company::findOne(['id' => $id])) !== null) { + return $model; + } + + throw new NotFoundHttpException('The requested page does not exist.'); + } +} diff --git a/backend/modules/company/controllers/DefaultController.php b/backend/modules/company/controllers/DefaultController.php new file mode 100644 index 0000000..0e338d3 --- /dev/null +++ b/backend/modules/company/controllers/DefaultController.php @@ -0,0 +1,20 @@ +render('index'); + } +} diff --git a/backend/modules/company/models/Company.php b/backend/modules/company/models/Company.php new file mode 100644 index 0000000..5d1705e --- /dev/null +++ b/backend/modules/company/models/Company.php @@ -0,0 +1,8 @@ + $query, + ]); + + $this->load($params); + + if (!$this->validate()) { + // uncomment the following line if you do not want to return any records when validation fails + // $query->where('0=1'); + return $dataProvider; + } + + // grid filtering conditions + $query->andFilterWhere([ + 'id' => $this->id, + 'inn' => $this->inn, + 'created_at' => $this->created_at, + 'updated_at' => $this->updated_at, + 'status' => $this->status, + ]); + + $query->andFilterWhere(['like', 'name', $this->name]) + ->andFilterWhere(['like', 'address', $this->address]); + + return $dataProvider; + } +} diff --git a/backend/modules/company/views/company/_form.php b/backend/modules/company/views/company/_form.php new file mode 100644 index 0000000..653c3ba --- /dev/null +++ b/backend/modules/company/views/company/_form.php @@ -0,0 +1,33 @@ + + +
+ + + + field($model, 'inn')->textInput() ?> + + field($model, 'name')->textInput(['maxlength' => true]) ?> + + field($model, 'address')->textInput(['maxlength' => true]) ?> + + field($model, 'created_at')->textInput() ?> + + field($model, 'updated_at')->textInput() ?> + + field($model, 'status')->textInput() ?> + +
+ 'btn btn-success']) ?> +
+ + + +
diff --git a/backend/modules/company/views/company/_search.php b/backend/modules/company/views/company/_search.php new file mode 100644 index 0000000..81cc9fc --- /dev/null +++ b/backend/modules/company/views/company/_search.php @@ -0,0 +1,39 @@ + + + diff --git a/backend/modules/company/views/company/create.php b/backend/modules/company/views/company/create.php new file mode 100644 index 0000000..ef3fb10 --- /dev/null +++ b/backend/modules/company/views/company/create.php @@ -0,0 +1,20 @@ +title = 'Create Company'; +$this->params['breadcrumbs'][] = ['label' => 'Companies', 'url' => ['index']]; +$this->params['breadcrumbs'][] = $this->title; +?> +
+ +

title) ?>

+ + render('_form', [ + 'model' => $model, + ]) ?> + +
diff --git a/backend/modules/company/views/company/index.php b/backend/modules/company/views/company/index.php new file mode 100644 index 0000000..862620f --- /dev/null +++ b/backend/modules/company/views/company/index.php @@ -0,0 +1,49 @@ +title = 'Companies'; +$this->params['breadcrumbs'][] = $this->title; +?> +
+ +

title) ?>

+ +

+ 'btn btn-success']) ?> +

+ + render('_search', ['model' => $searchModel]); ?> + + $dataProvider, + 'filterModel' => $searchModel, + 'columns' => [ + ['class' => 'yii\grid\SerialColumn'], + + 'id', + 'inn', + 'name', + 'address', + 'created_at', + //'updated_at', + //'status', + [ + 'class' => ActionColumn::className(), + 'urlCreator' => function ($action, Company $model, $key, $index, $column) { + return Url::toRoute([$action, 'id' => $model->id]); + } + ], + ], + ]); ?> + + +
diff --git a/backend/modules/company/views/company/update.php b/backend/modules/company/views/company/update.php new file mode 100644 index 0000000..d883a38 --- /dev/null +++ b/backend/modules/company/views/company/update.php @@ -0,0 +1,21 @@ +title = 'Update Company: ' . $model->name; +$this->params['breadcrumbs'][] = ['label' => 'Companies', 'url' => ['index']]; +$this->params['breadcrumbs'][] = ['label' => $model->name, 'url' => ['view', 'id' => $model->id]]; +$this->params['breadcrumbs'][] = 'Update'; +?> +
+ +

title) ?>

+ + render('_form', [ + 'model' => $model, + ]) ?> + +
diff --git a/backend/modules/company/views/company/view.php b/backend/modules/company/views/company/view.php new file mode 100644 index 0000000..a96d085 --- /dev/null +++ b/backend/modules/company/views/company/view.php @@ -0,0 +1,42 @@ +title = $model->name; +$this->params['breadcrumbs'][] = ['label' => 'Companies', 'url' => ['index']]; +$this->params['breadcrumbs'][] = $this->title; +\yii\web\YiiAsset::register($this); +?> +
+ +

title) ?>

+ +

+ $model->id], ['class' => 'btn btn-primary']) ?> + $model->id], [ + 'class' => 'btn btn-danger', + 'data' => [ + 'confirm' => 'Are you sure you want to delete this item?', + 'method' => 'post', + ], + ]) ?> +

+ + $model, + 'attributes' => [ + 'id', + 'inn', + 'name', + 'address', + 'created_at', + 'updated_at', + 'status', + ], + ]) ?> + +
diff --git a/backend/modules/company/views/default/index.php b/backend/modules/company/views/default/index.php new file mode 100644 index 0000000..9b6a7bf --- /dev/null +++ b/backend/modules/company/views/default/index.php @@ -0,0 +1,12 @@ +
+

context->action->uniqueId ?>

+

+ This is the view content for action "context->action->id ?>". + The action belongs to the controller "context) ?>" + in the "context->module->id ?>" module. +

+

+ You may customize this page by editing the following file:
+ +

+
diff --git a/backend/runtime/.gitignore b/backend/runtime/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/backend/runtime/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/backend/tests/_bootstrap.php b/backend/tests/_bootstrap.php new file mode 100644 index 0000000..637ce14 --- /dev/null +++ b/backend/tests/_bootstrap.php @@ -0,0 +1,10 @@ + 'erau', + 'auth_key' => 'tUu1qHcde0diwUol3xeI-18MuHkkprQI', + // password_0 + 'password_hash' => '$2y$13$nJ1WDlBaGcbCdbNC5.5l4.sgy.OMEKCqtDQOdQ2OWpgiKRWYyzzne', + 'password_reset_token' => 'RkD_Jw0_8HEedzLk7MM-ZKEFfYR7VbMr_1392559490', + 'created_at' => '1392559490', + 'updated_at' => '1392559490', + 'email' => 'sfriesen@jenkins.info', + ], +]; diff --git a/backend/tests/_output/.gitignore b/backend/tests/_output/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/backend/tests/_output/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/backend/tests/_support/.gitignore b/backend/tests/_support/.gitignore new file mode 100644 index 0000000..36e264c --- /dev/null +++ b/backend/tests/_support/.gitignore @@ -0,0 +1 @@ +_generated diff --git a/backend/tests/_support/FunctionalTester.php b/backend/tests/_support/FunctionalTester.php new file mode 100644 index 0000000..a2bb8cb --- /dev/null +++ b/backend/tests/_support/FunctionalTester.php @@ -0,0 +1,26 @@ + [ + 'class' => UserFixture::class, + 'dataFile' => codecept_data_dir() . 'login_data.php' + ] + ]; + } + + /** + * @param FunctionalTester $I + */ + public function loginUser(FunctionalTester $I) + { + $I->amOnRoute('/site/login'); + $I->fillField('Username', 'erau'); + $I->fillField('Password', 'password_0'); + $I->click('login-button'); + + $I->see('Logout (erau)', 'form button[type=submit]'); + $I->dontSeeLink('Login'); + $I->dontSeeLink('Signup'); + } +} diff --git a/backend/tests/functional/_bootstrap.php b/backend/tests/functional/_bootstrap.php new file mode 100644 index 0000000..30ed54b --- /dev/null +++ b/backend/tests/functional/_bootstrap.php @@ -0,0 +1,16 @@ + 'davert']); + * ``` + * + * In Cests + * + * ```php + * \Codeception\Util\Fixtures::get('user1'); + * ``` + */ \ No newline at end of file diff --git a/backend/tests/unit.suite.yml b/backend/tests/unit.suite.yml new file mode 100644 index 0000000..f90030f --- /dev/null +++ b/backend/tests/unit.suite.yml @@ -0,0 +1,2 @@ +suite_namespace: backend\tests\unit +actor: UnitTester diff --git a/backend/tests/unit/_bootstrap.php b/backend/tests/unit/_bootstrap.php new file mode 100644 index 0000000..e432ce5 --- /dev/null +++ b/backend/tests/unit/_bootstrap.php @@ -0,0 +1,16 @@ + 'davert']); + * ``` + * + * In Tests + * + * ```php + * \Codeception\Util\Fixtures::get('user1'); + * ``` + */ diff --git a/backend/views/layouts/blank.php b/backend/views/layouts/blank.php new file mode 100644 index 0000000..c843320 --- /dev/null +++ b/backend/views/layouts/blank.php @@ -0,0 +1,33 @@ + +beginPage() ?> + + + + + + registerCsrfMetaTags() ?> + <?= Html::encode($this->title) ?> + head() ?> + + +beginBody() ?> + +
+
+ +
+
+ +endBody() ?> + + +endPage(); diff --git a/backend/views/layouts/main.php b/backend/views/layouts/main.php new file mode 100644 index 0000000..9cdb6c7 --- /dev/null +++ b/backend/views/layouts/main.php @@ -0,0 +1,81 @@ + +beginPage() ?> + + + + + + registerCsrfMetaTags() ?> + <?= Html::encode($this->title) ?> + head() ?> + + +beginBody() ?> + +
+ Yii::$app->name, + 'brandUrl' => Yii::$app->homeUrl, + 'options' => [ + 'class' => 'navbar navbar-expand-md navbar-dark bg-dark fixed-top', + ], + ]); + $menuItems = [ + ['label' => 'Home', 'url' => ['/site/index']], + ]; + if (Yii::$app->user->isGuest) { + $menuItems[] = ['label' => 'Login', 'url' => ['/site/login']]; + } + echo Nav::widget([ + 'options' => ['class' => 'navbar-nav me-auto mb-2 mb-md-0'], + 'items' => $menuItems, + ]); + if (Yii::$app->user->isGuest) { + echo Html::tag('div',Html::a('Login',['/site/login'],['class' => ['btn btn-link login text-decoration-none']]),['class' => ['d-flex']]); + } else { + echo Html::beginForm(['/site/logout'], 'post', ['class' => 'd-flex']) + . Html::submitButton( + 'Logout (' . Yii::$app->user->identity->username . ')', + ['class' => 'btn btn-link logout text-decoration-none'] + ) + . Html::endForm(); + } + NavBar::end(); + ?> +
+ +
+
+ isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [], + ]) ?> + + +
+
+ + + +endBody() ?> + + +endPage(); diff --git a/backend/views/site/error.php b/backend/views/site/error.php new file mode 100644 index 0000000..e0f8b65 --- /dev/null +++ b/backend/views/site/error.php @@ -0,0 +1,27 @@ +title = $name; +?> +
+ +

title) ?>

+ +
+ +
+ +

+ The above error occurred while the Web server was processing your request. +

+

+ Please contact us if you think this is a server error. Thank you. +

+ +
diff --git a/backend/views/site/index.php b/backend/views/site/index.php new file mode 100644 index 0000000..4ced35c --- /dev/null +++ b/backend/views/site/index.php @@ -0,0 +1,53 @@ +title = 'My Yii Application'; +?> +
+ +
+

Congratulations!

+ +

You have successfully created your Yii-powered application.

+ +

Get started with Yii

+
+ +
+ +
+
+

Heading

+ +

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et + dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip + ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu + fugiat nulla pariatur.

+ +

Yii Documentation »

+
+
+

Heading

+ +

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et + dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip + ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu + fugiat nulla pariatur.

+ +

Yii Forum »

+
+
+

Heading

+ +

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et + dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip + ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu + fugiat nulla pariatur.

+ +

Yii Extensions »

+
+
+ +
+
diff --git a/backend/views/site/login.php b/backend/views/site/login.php new file mode 100644 index 0000000..d4b5a3b --- /dev/null +++ b/backend/views/site/login.php @@ -0,0 +1,32 @@ +title = 'Login'; +?> +
+
+

title) ?>

+ +

Please fill out the following fields to login:

+ + 'login-form']); ?> + + field($model, 'username')->textInput(['autofocus' => true]) ?> + + field($model, 'password')->passwordInput() ?> + + field($model, 'rememberMe')->checkbox() ?> + +
+ 'btn btn-primary btn-block', 'name' => 'login-button']) ?> +
+ + +
+
diff --git a/backend/web/assets/.gitignore b/backend/web/assets/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/backend/web/assets/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/backend/web/css/site.css b/backend/web/css/site.css new file mode 100644 index 0000000..34c35c6 --- /dev/null +++ b/backend/web/css/site.css @@ -0,0 +1,90 @@ +main > .container { + padding: 70px 15px 20px; +} + +.footer { + background-color: #f5f5f5; + font-size: .9em; + height: 60px; +} + +.footer > .container { + padding-right: 15px; + padding-left: 15px; +} + +.not-set { + color: #c55; + font-style: italic; +} + +/* add sorting icons to gridview sort links */ +a.asc:after, a.desc:after { + content: ''; + left: 3px; + display: inline-block; + width: 0; + height: 0; + border: solid 5px transparent; + margin: 4px 4px 2px 4px; + background: transparent; +} + +a.asc:after { + border-bottom: solid 7px #212529; + border-top-width: 0; +} + +a.desc:after { + border-top: solid 7px #212529; + border-bottom-width: 0; +} + +.grid-view th, +.grid-view td:last-child { + white-space: nowrap; +} + +.grid-view .filters input, +.grid-view .filters select { + min-width: 50px; +} + +.hint-block { + display: block; + margin-top: 5px; + color: #999; +} + +.error-summary { + color: #a94442; + background: #fdf7f7; + border-left: 3px solid #eed3d7; + padding: 10px 20px; + margin: 0 0 15px 0; +} + +/* align the logout "link" (button in form) of the navbar */ +.nav li > form > button.logout { + padding-top: 7px; + color: rgba(255, 255, 255, 0.5); +} + +@media(max-width:767px) { + .nav li > form > button.logout { + display:block; + text-align: left; + width: 100%; + padding: 10px 0; + } +} + +.nav > li > form > button.logout:focus, +.nav > li > form > button.logout:hover { + text-decoration: none; + color: rgba(255, 255, 255, 0.75); +} + +.nav > li > form > button.logout:focus { + outline: none; +} diff --git a/backend/web/favicon.ico b/backend/web/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..580ed732e86556ec57f3f3395a210246d679c076 GIT binary patch literal 318 zcmZQzU<5(|0RbS%!l1#(z#zuJz@P!d0zj+)#2|4HXaJKC0wf0lAEr2iX{M9K3=BR0 y!E90pK{x=K$Oz&POT#sS8N$ZKhC)h8ip0_|-T#43{vnSYgXBQCu@O54$pHYIza?e> literal 0 HcmV?d00001 diff --git a/codeception.yml b/codeception.yml new file mode 100644 index 0000000..c6f0143 --- /dev/null +++ b/codeception.yml @@ -0,0 +1,9 @@ +# global codeception file to run tests from all apps +include: + - common + - frontend + - backend +paths: + output: console/runtime/output +settings: + colors: true \ No newline at end of file diff --git a/common/classes/Debug.php b/common/classes/Debug.php new file mode 100755 index 0000000..24e49b0 --- /dev/null +++ b/common/classes/Debug.php @@ -0,0 +1,20 @@ +'; + print_r($content); + echo ''; + } + public static function dd($content) + { + echo '
';
+        print_r($content);
+        echo '
'; + die(); + } +} \ No newline at end of file diff --git a/common/codeception.yml b/common/codeception.yml new file mode 100644 index 0000000..1dfaf97 --- /dev/null +++ b/common/codeception.yml @@ -0,0 +1,15 @@ +namespace: common\tests +actor_suffix: Tester +paths: + tests: tests + output: tests/_output + data: tests/_data + support: tests/_support +bootstrap: _bootstrap.php +settings: + colors: true + memory_limit: 1024M +modules: + config: + Yii2: + configFile: 'config/codeception-local.php' diff --git a/common/config/.gitignore b/common/config/.gitignore new file mode 100644 index 0000000..7c090d2 --- /dev/null +++ b/common/config/.gitignore @@ -0,0 +1,4 @@ +codeception-local.php +main-local.php +params-local.php +test-local.php diff --git a/common/config/__autocomplete.php b/common/config/__autocomplete.php new file mode 100644 index 0000000..d99dea5 --- /dev/null +++ b/common/config/__autocomplete.php @@ -0,0 +1,33 @@ + [ + '@bower' => '@vendor/bower-asset', + '@npm' => '@vendor/npm-asset', + ], + 'vendorPath' => dirname(dirname(__DIR__)) . '/vendor', + 'components' => [ + 'cache' => [ + 'class' => \yii\caching\FileCache::class, + ], + ], +]; diff --git a/common/config/params.php b/common/config/params.php new file mode 100644 index 0000000..9361512 --- /dev/null +++ b/common/config/params.php @@ -0,0 +1,9 @@ + 'admin@example.com', + 'supportEmail' => 'support@example.com', + 'senderEmail' => 'noreply@example.com', + 'senderName' => 'Example.com mailer', + 'user.passwordResetTokenExpire' => 3600, + 'user.passwordMinLength' => 8, +]; diff --git a/common/config/test.php b/common/config/test.php new file mode 100644 index 0000000..c50955f --- /dev/null +++ b/common/config/test.php @@ -0,0 +1,11 @@ + 'app-common-tests', + 'basePath' => dirname(__DIR__), + 'components' => [ + 'user' => [ + 'class' => \yii\web\User::class, + 'identityClass' => 'common\models\User', + ], + ], +]; diff --git a/common/fixtures/UserFixture.php b/common/fixtures/UserFixture.php new file mode 100644 index 0000000..6df7a98 --- /dev/null +++ b/common/fixtures/UserFixture.php @@ -0,0 +1,10 @@ +urlManager->createAbsoluteUrl(['site/verify-email', 'token' => $user->verification_token]); +?> +
+

Hello username) ?>,

+ +

Follow the link below to verify your email:

+ +

+
diff --git a/common/mail/emailVerify-text.php b/common/mail/emailVerify-text.php new file mode 100644 index 0000000..48a68fc --- /dev/null +++ b/common/mail/emailVerify-text.php @@ -0,0 +1,12 @@ +urlManager->createAbsoluteUrl(['site/verify-email', 'token' => $user->verification_token]); +?> +Hello username ?>, + +Follow the link below to verify your email: + + diff --git a/common/mail/layouts/html.php b/common/mail/layouts/html.php new file mode 100644 index 0000000..8560d47 --- /dev/null +++ b/common/mail/layouts/html.php @@ -0,0 +1,24 @@ + +beginPage() ?> + + + + + <?= Html::encode($this->title) ?> + head() ?> + + + beginBody() ?> + + endBody() ?> + + +endPage(); diff --git a/common/mail/layouts/text.php b/common/mail/layouts/text.php new file mode 100644 index 0000000..9b4c548 --- /dev/null +++ b/common/mail/layouts/text.php @@ -0,0 +1,12 @@ + +beginPage() ?> +beginBody() ?> + +endBody() ?> +endPage() ?> diff --git a/common/mail/passwordResetToken-html.php b/common/mail/passwordResetToken-html.php new file mode 100644 index 0000000..9f6e470 --- /dev/null +++ b/common/mail/passwordResetToken-html.php @@ -0,0 +1,16 @@ +urlManager->createAbsoluteUrl(['site/reset-password', 'token' => $user->password_reset_token]); +?> +
+

Hello username) ?>,

+ +

Follow the link below to reset your password:

+ +

+
diff --git a/common/mail/passwordResetToken-text.php b/common/mail/passwordResetToken-text.php new file mode 100644 index 0000000..6a5120f --- /dev/null +++ b/common/mail/passwordResetToken-text.php @@ -0,0 +1,12 @@ +urlManager->createAbsoluteUrl(['site/reset-password', 'token' => $user->password_reset_token]); +?> +Hello username ?>, + +Follow the link below to reset your password: + + diff --git a/common/models/Addresses.php b/common/models/Addresses.php new file mode 100644 index 0000000..9a433e9 --- /dev/null +++ b/common/models/Addresses.php @@ -0,0 +1,73 @@ + 255], + [['company_id'], 'exist', 'skipOnError' => true, 'targetClass' => Company::class, 'targetAttribute' => ['company_id' => 'id']], + ]; + } + + /** + * {@inheritdoc} + */ + public function attributeLabels() + { + return [ + 'id' => 'ID', + 'address' => 'Адрес', + 'company_id' => 'Компания', + 'name' => 'Название', + ]; + } + + /** + * Gets query for [[Checks]]. + * + * @return \yii\db\ActiveQuery + */ + public function getChecks() + { + return $this->hasMany(Check::class, ['addresses_id' => 'id']); + } + + /** + * Gets query for [[Company]]. + * + * @return \yii\db\ActiveQuery + */ + public function getCompany() + { + return $this->hasOne(Company::class, ['id' => 'company_id']); + } +} diff --git a/common/models/Check.php b/common/models/Check.php new file mode 100644 index 0000000..6ad9a2a --- /dev/null +++ b/common/models/Check.php @@ -0,0 +1,111 @@ + 'Новый', + self::STATUS_PRINTED => 'Напечатан', + self::STATUS_PAID => 'Оплачен', + ]; + } + + /** + * @return string[] + */ + public static function getStatusColor(): array + { + return [ + self::STATUS_NEW => '#FFA500', + self::STATUS_PRINTED => '#008080', + self::STATUS_PAID => '#32CD32', + ]; + } + + /** + * {@inheritdoc} + */ + public static function tableName() + { + return 'check'; + } + + /** + * {@inheritdoc} + */ + public function rules() + { + return [ + [['number', 'company_id', 'addresses_id'], 'required'], + [['company_id', 'addresses_id', 'status'], 'integer'], + [['number', 'title'], 'string', 'max' => 255], + [['additional'], 'string'], + [['addresses_id'], 'exist', 'skipOnError' => true, 'targetClass' => Addresses::class, 'targetAttribute' => ['addresses_id' => 'id']], + [['company_id'], 'exist', 'skipOnError' => true, 'targetClass' => Company::class, 'targetAttribute' => ['company_id' => 'id']], + ]; + } + + /** + * {@inheritdoc} + */ + public function attributeLabels() + { + return [ + 'id' => 'ID', + 'number' => 'Номер', + 'company_id' => 'Компания', + 'additional' => 'Дополнительная информация', + 'title' => 'Заголовок', + 'addresses_id' => 'Отделение', + 'status' => 'Статус', + ]; + } + + /** + * Gets query for [[Addresses]]. + * + * @return \yii\db\ActiveQuery + */ + public function getAddresses(): \yii\db\ActiveQuery + { + return $this->hasOne(Addresses::class, ['id' => 'addresses_id']); + } + + /** + * Gets query for [[Company]]. + * + * @return \yii\db\ActiveQuery + */ + public function getCompany(): \yii\db\ActiveQuery + { + return $this->hasOne(Company::class, ['id' => 'company_id']); + } +} diff --git a/common/models/CheckProduct.php b/common/models/CheckProduct.php new file mode 100644 index 0000000..ddb9146 --- /dev/null +++ b/common/models/CheckProduct.php @@ -0,0 +1,72 @@ + ['check_id', 'product_id']], + [['check_id'], 'exist', 'skipOnError' => true, 'targetClass' => Check::class, 'targetAttribute' => ['check_id' => 'id']], + [['product_id'], 'exist', 'skipOnError' => true, 'targetClass' => Product::class, 'targetAttribute' => ['product_id' => 'id']], + ]; + } + + /** + * {@inheritdoc} + */ + public function attributeLabels() + { + return [ + 'check_id' => 'Check ID', + 'product_id' => 'Product ID', + 'quantity' => 'Quantity', + ]; + } + + /** + * Gets query for [[Check]]. + * + * @return \yii\db\ActiveQuery + */ + public function getCheck() + { + return $this->hasOne(Check::class, ['id' => 'check_id']); + } + + /** + * Gets query for [[Product]]. + * + * @return \yii\db\ActiveQuery + */ + public function getProduct() + { + return $this->hasOne(Product::class, ['id' => 'product_id']); + } +} diff --git a/common/models/Company.php b/common/models/Company.php new file mode 100644 index 0000000..1a9f1e2 --- /dev/null +++ b/common/models/Company.php @@ -0,0 +1,125 @@ + 'Активна', + self::STATUS_INACTIVE => 'Не активна', + ]; + } + + /** + * {@inheritdoc} + */ + public static function tableName() + { + return 'company'; + } + + public function behaviors() + { + return [ + [ + 'class' => TimestampBehavior::class, + 'createdAtAttribute' => 'created_at', + 'updatedAtAttribute' => 'updated_at', + 'value' => new Expression('NOW()'), + ], + ]; + } + + /** + * {@inheritdoc} + */ + public function rules() + { + return [ + [['inn', 'name', 'user_id'], 'required'], + [['created_at', 'updated_at'], 'safe'], + [['status', 'user_id'], 'integer'], + [['name', 'address', 'inn'], 'string', 'max' => 255], + ]; + } + + /** + * {@inheritdoc} + */ + public function attributeLabels() + { + return [ + 'id' => 'ID', + 'inn' => 'ИНН', + 'name' => 'Название', + 'address' => 'Адрес', + 'created_at' => 'Дата создания', + 'updated_at' => 'Дата редактирования', + 'status' => 'Статус', + 'user_id' => 'Пользователь', + ]; + } + + /** + * Gets query for [[Addresses]]. + * + * @return \yii\db\ActiveQuery + */ + public function getAddresses() + { + return $this->hasMany(Addresses::class, ['company_id' => 'id']); + } + + /** + * Gets query for [[Checks]]. + * + * @return \yii\db\ActiveQuery + */ + public function getChecks() + { + return $this->hasMany(Check::class, ['company_id' => 'id']); + } + + /** + * Gets query for [[Products]]. + * + * @return \yii\db\ActiveQuery + */ + public function getProducts() + { + return $this->hasMany(Product::class, ['company_id' => 'id']); + } + + public static function getMyCompany() + { + $companies = self::find()->where(['user_id' => Yii::$app->user->id])->all(); + } +} diff --git a/common/models/LoginForm.php b/common/models/LoginForm.php new file mode 100644 index 0000000..2a37c89 --- /dev/null +++ b/common/models/LoginForm.php @@ -0,0 +1,80 @@ +hasErrors()) { + $user = $this->getUser(); + if (!$user || !$user->validatePassword($this->password)) { + $this->addError($attribute, 'Incorrect username or password.'); + } + } + } + + /** + * Logs in a user using the provided username and password. + * + * @return bool whether the user is logged in successfully + */ + public function login() + { + if ($this->validate()) { + return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600 * 24 * 30 : 0); + } + + return false; + } + + /** + * Finds user by [[username]] + * + * @return User|null + */ + protected function getUser() + { + if ($this->_user === null) { + $this->_user = User::findByUsername($this->username); + } + + return $this->_user; + } +} diff --git a/common/models/Product.php b/common/models/Product.php new file mode 100644 index 0000000..d7172c9 --- /dev/null +++ b/common/models/Product.php @@ -0,0 +1,97 @@ + 'шт.', + self::TYPE_WEIGHT => 'кг.', + ]; + } + + /** + * @return string[] + */ + public static function getStatus(): array + { + return [ + self::STATUS_ACTIVE => 'Активна', + self::STATUS_INACTIVE => 'Не активна', + ]; + } + + /** + * {@inheritdoc} + */ + public static function tableName() + { + return 'product'; + } + + /** + * {@inheritdoc} + */ + public function rules() + { + return [ + [['title', 'article', 'company_id'], 'required'], + [['company_id', 'type', 'price', 'status'], 'integer'], + [['title', 'article'], 'string', 'max' => 255], + [['company_id'], 'exist', 'skipOnError' => true, 'targetClass' => Company::class, 'targetAttribute' => ['company_id' => 'id']], + ]; + } + + /** + * {@inheritdoc} + */ + public function attributeLabels() + { + return [ + 'id' => 'ID', + 'title' => 'Название', + 'article' => 'Артикул', + 'company_id' => 'Компания', + 'type' => 'Тип', + 'price' => 'Цена', + 'status' => 'Статус', + ]; + } + + /** + * Gets query for [[Company]]. + * + * @return \yii\db\ActiveQuery + */ + public function getCompany() + { + return $this->hasOne(Company::class, ['id' => 'company_id']); + } +} diff --git a/common/models/ProductCategory.php b/common/models/ProductCategory.php new file mode 100644 index 0000000..1f4fdec --- /dev/null +++ b/common/models/ProductCategory.php @@ -0,0 +1,78 @@ + 255], + [['company_id'], 'exist', 'skipOnError' => true, 'targetClass' => Company::class, 'targetAttribute' => ['company_id' => 'id']], + ]; + } + + /** + * {@inheritdoc} + */ + public function attributeLabels() + { + return [ + 'id' => 'ID', + 'title' => 'Название', + 'parent_id' => 'Родительская категория', + 'company_id' => 'Компания', + 'status' => 'Статус', + ]; + } + + /** + * @return string[] + */ + public static function getStatus(): array + { + return [ + self::STATUS_ACTIVE => "Активна", + self::STATUS_NOACTIVE => "Не активна" + ]; + } + + /** + * Gets query for [[Company]]. + * + * @return \yii\db\ActiveQuery + */ + public function getCompany() + { + return $this->hasOne(Company::class, ['id' => 'company_id']); + } +} diff --git a/common/models/User.php b/common/models/User.php new file mode 100644 index 0000000..8104569 --- /dev/null +++ b/common/models/User.php @@ -0,0 +1,222 @@ + self::STATUS_ACTIVE], + ['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_INACTIVE, self::STATUS_DELETED]], + ]; + } + + /** + * {@inheritdoc} + */ + public static function findIdentity($id) + { + return static::findOne(['id' => $id, 'status' => self::STATUS_ACTIVE]); + } + + /** + * {@inheritdoc} + */ + public static function findIdentityByAccessToken($token, $type = null) + { + throw new NotSupportedException('"findIdentityByAccessToken" is not implemented.'); + } + + /** + * Finds user by username + * + * @param string $username + * @return static|null + */ + public static function findByUsername($username) + { + return static::findOne(['username' => $username, 'status' => self::STATUS_ACTIVE]); + } + + /** + * Finds user by password reset token + * + * @param string $token password reset token + * @return static|null + */ + public static function findByPasswordResetToken($token) + { + if (!static::isPasswordResetTokenValid($token)) { + return null; + } + + return static::findOne([ + 'password_reset_token' => $token, + 'status' => self::STATUS_ACTIVE, + ]); + } + + /** + * Finds user by verification email token + * + * @param string $token verify email token + * @return static|null + */ + public static function findByVerificationToken($token) + { + return static::findOne([ + 'verification_token' => $token, + 'status' => self::STATUS_INACTIVE + ]); + } + + /** + * Finds out if password reset token is valid + * + * @param string $token password reset token + * @return bool + */ + public static function isPasswordResetTokenValid($token) + { + if (empty($token)) { + return false; + } + + $timestamp = (int)substr($token, strrpos($token, '_') + 1); + $expire = Yii::$app->params['user.passwordResetTokenExpire']; + return $timestamp + $expire >= time(); + } + + /** + * {@inheritdoc} + */ + public function getId() + { + return $this->getPrimaryKey(); + } + + /** + * {@inheritdoc} + */ + public function getAuthKey() + { + return $this->auth_key; + } + + /** + * {@inheritdoc} + */ + public function validateAuthKey($authKey) + { + return $this->getAuthKey() === $authKey; + } + + /** + * Validates password + * + * @param string $password password to validate + * @return bool if password provided is valid for current user + */ + public function validatePassword($password) + { + return Yii::$app->security->validatePassword($password, $this->password_hash); + } + + /** + * Generates password hash from password and sets it to the model + * + * @param string $password + */ + public function setPassword($password) + { + $this->password_hash = Yii::$app->security->generatePasswordHash($password); + } + + /** + * Generates "remember me" authentication key + */ + public function generateAuthKey() + { + $this->auth_key = Yii::$app->security->generateRandomString(); + } + + /** + * Generates new password reset token + */ + public function generatePasswordResetToken() + { + $this->password_reset_token = Yii::$app->security->generateRandomString() . '_' . time(); + } + + /** + * Generates new token for email verification + */ + public function generateEmailVerificationToken() + { + $this->verification_token = Yii::$app->security->generateRandomString() . '_' . time(); + } + + /** + * Removes password reset token + */ + public function removePasswordResetToken() + { + $this->password_reset_token = null; + } + + /** + * @return \yii\db\ActiveQuery + */ + public function getMyCompany(): \yii\db\ActiveQuery + { + return $this->hasMany(Company::class, ['user_id' => 'id']); + } +} diff --git a/common/services/CompanyService.php b/common/services/CompanyService.php new file mode 100644 index 0000000..0e76fe3 --- /dev/null +++ b/common/services/CompanyService.php @@ -0,0 +1,64 @@ +model = new Company(); + } + + /** + * @param int|null $id + * @return array + */ + public function getCompaniesByUser(int $id = null): array + { + return $this->model->find()->where(['user_id' => $id ?? Yii::$app->user->id])->all(); + } + + /** + * @param int|null $id + * @return array + */ + public function getCompaniesByUserArr(int $id = null): array + { + return ArrayHelper::map($this->getCompaniesByUser($id), 'id', 'name'); + } + + /** + * @param int $id + * @return Company|null + */ + public function getCompany(int $id): ?Company + { + return $this->model->findOne($id); + } + + /** + * @param int|null $id + * @return array + */ + public function getAddressesByUser(int $id = null): array + { + $companies = $this->getCompaniesByUser($id); + return $this->model->find()->where(['id' => ArrayHelper::getColumn($companies, 'id')])->all(); + } + + /** + * @param int|null $id + * @return array + */ + public function getAddressesByUserArr(int $id = null): array + { + return ArrayHelper::map($this->getAddressesByUser($id), 'id', 'address'); + } + +} \ No newline at end of file diff --git a/common/tests/_bootstrap.php b/common/tests/_bootstrap.php new file mode 100644 index 0000000..9915cc3 --- /dev/null +++ b/common/tests/_bootstrap.php @@ -0,0 +1,9 @@ + 'bayer.hudson', + 'auth_key' => 'HP187Mvq7Mmm3CTU80dLkGmni_FUH_lR', + //password_0 + 'password_hash' => '$2y$13$EjaPFBnZOQsHdGuHI.xvhuDp1fHpo8hKRSk6yshqa9c5EG8s3C3lO', + 'password_reset_token' => 'ExzkCOaYc1L8IOBs4wdTGGbgNiG3Wz1I_1402312317', + 'created_at' => '1402312317', + 'updated_at' => '1402312317', + 'email' => 'nicole.paucek@schultz.info', + ], +]; diff --git a/common/tests/_output/.gitignore b/common/tests/_output/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/common/tests/_output/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/common/tests/_support/.gitignore b/common/tests/_support/.gitignore new file mode 100644 index 0000000..36e264c --- /dev/null +++ b/common/tests/_support/.gitignore @@ -0,0 +1 @@ +_generated diff --git a/common/tests/_support/UnitTester.php b/common/tests/_support/UnitTester.php new file mode 100644 index 0000000..a0cc7a7 --- /dev/null +++ b/common/tests/_support/UnitTester.php @@ -0,0 +1,26 @@ + [ + 'class' => UserFixture::class, + 'dataFile' => codecept_data_dir() . 'user.php' + ] + ]; + } + + public function testLoginNoUser() + { + $model = new LoginForm([ + 'username' => 'not_existing_username', + 'password' => 'not_existing_password', + ]); + + verify($model->login())->false(); + verify(Yii::$app->user->isGuest)->true(); + } + + public function testLoginWrongPassword() + { + $model = new LoginForm([ + 'username' => 'bayer.hudson', + 'password' => 'wrong_password', + ]); + + verify($model->login())->false(); + verify( $model->errors)->arrayHasKey('password'); + verify(Yii::$app->user->isGuest)->true(); + } + + public function testLoginCorrect() + { + $model = new LoginForm([ + 'username' => 'bayer.hudson', + 'password' => 'password_0', + ]); + + verify($model->login())->true(); + verify($model->errors)->arrayHasNotKey('password'); + verify(Yii::$app->user->isGuest)->false(); + } +} diff --git a/common/widgets/Alert.php b/common/widgets/Alert.php new file mode 100644 index 0000000..4ac3d15 --- /dev/null +++ b/common/widgets/Alert.php @@ -0,0 +1,76 @@ +session->setFlash('error', 'This is the message'); + * Yii::$app->session->setFlash('success', 'This is the message'); + * Yii::$app->session->setFlash('info', 'This is the message'); + * ``` + * + * Multiple messages could be set as follows: + * + * ```php + * Yii::$app->session->setFlash('error', ['Error 1', 'Error 2']); + * ``` + * + * @author Kartik Visweswaran + * @author Alexander Makarov + */ +class Alert extends \yii\bootstrap5\Widget +{ + /** + * @var array the alert types configuration for the flash messages. + * This array is setup as $key => $value, where: + * - key: the name of the session flash variable + * - value: the bootstrap alert type (i.e. danger, success, info, warning) + */ + public $alertTypes = [ + 'error' => 'alert-danger', + 'danger' => 'alert-danger', + 'success' => 'alert-success', + 'info' => 'alert-info', + 'warning' => 'alert-warning' + ]; + /** + * @var array the options for rendering the close button tag. + * Array will be passed to [[\yii\bootstrap\Alert::closeButton]]. + */ + public $closeButton = []; + + + /** + * {@inheritdoc} + */ + public function run() + { + $session = Yii::$app->session; + $flashes = $session->getAllFlashes(); + $appendClass = isset($this->options['class']) ? ' ' . $this->options['class'] : ''; + + foreach ($flashes as $type => $flash) { + if (!isset($this->alertTypes[$type])) { + continue; + } + + foreach ((array) $flash as $i => $message) { + echo \yii\bootstrap5\Alert::widget([ + 'body' => $message, + 'closeButton' => $this->closeButton, + 'options' => array_merge($this->options, [ + 'id' => $this->getId() . '-' . $type . '-' . $i, + 'class' => $this->alertTypes[$type] . $appendClass, + ]), + ]); + } + + $session->removeFlash($type); + } + } +} diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..f47f179 --- /dev/null +++ b/composer.json @@ -0,0 +1,58 @@ +{ + "name": "yiisoft/yii2-app-advanced", + "description": "Yii 2 Advanced Project Template", + "keywords": ["yii2", "framework", "advanced", "project template"], + "homepage": "https://www.yiiframework.com/", + "type": "project", + "license": "BSD-3-Clause", + "support": { + "issues": "https://github.com/yiisoft/yii2/issues?state=open", + "forum": "https://www.yiiframework.com/forum/", + "wiki": "https://www.yiiframework.com/wiki/", + "irc": "ircs://irc.libera.chat:6697/yii", + "source": "https://github.com/yiisoft/yii2" + }, + "minimum-stability": "stable", + "require": { + "php": ">=7.4.0", + "yiisoft/yii2": "~2.0.45", + "yiisoft/yii2-bootstrap5": "~2.0.2", + "yiisoft/yii2-symfonymailer": "~2.0.3", + "hail812/yii2-adminlte3": "~1.1" + }, + "require-dev": { + "yiisoft/yii2-debug": "~2.1.0", + "yiisoft/yii2-gii": "~2.2.0", + "yiisoft/yii2-faker": "~2.0.0", + "phpunit/phpunit": "~9.5.0", + "codeception/codeception": "^5.0.0 || ^4.0", + "codeception/lib-innerbrowser": "^4.0 || ^3.0 || ^1.1", + "codeception/module-asserts": "^3.0 || ^1.1", + "codeception/module-yii2": "^1.1", + "codeception/module-filesystem": "^3.0 || ^2.0 || ^1.1", + "codeception/verify": "^3.0 || ^2.2", + "symfony/browser-kit": "^6.0 || >=2.7 <=4.2.4" + }, + "autoload-dev": { + "psr-4": { + "common\\tests\\": ["common/tests/", "common/tests/_support"], + "backend\\tests\\": ["backend/tests/", "backend/tests/_support"], + "frontend\\tests\\": ["frontend/tests/", "frontend/tests/_support"] + } + }, + "config": { + "allow-plugins": { + "yiisoft/yii2-composer" : true + }, + "process-timeout": 1800, + "fxp-asset": { + "enabled": false + } + }, + "repositories": [ + { + "type": "composer", + "url": "https://asset-packagist.org" + } + ] +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..fd69d6d --- /dev/null +++ b/composer.lock @@ -0,0 +1,5867 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "825cc56cf0c423874be51a9d82a526fe", + "packages": [ + { + "name": "almasaeed2010/adminlte", + "version": "v3.2.0", + "source": { + "type": "git", + "url": "https://github.com/ColorlibHQ/AdminLTE.git", + "reference": "bd4d9c72931f1dd28601b6bfb387554a381ad540" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ColorlibHQ/AdminLTE/zipball/bd4d9c72931f1dd28601b6bfb387554a381ad540", + "reference": "bd4d9c72931f1dd28601b6bfb387554a381ad540", + "shasum": "" + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Colorlib" + } + ], + "description": "AdminLTE - admin control panel and dashboard that's based on Bootstrap 4", + "homepage": "https://adminlte.io/", + "keywords": [ + "JS", + "admin", + "back-end", + "css", + "less", + "responsive", + "template", + "theme", + "web" + ], + "support": { + "issues": "https://github.com/ColorlibHQ/AdminLTE/issues", + "source": "https://github.com/ColorlibHQ/AdminLTE/tree/v3.2.0" + }, + "time": "2022-02-07T20:33:09+00:00" + }, + { + "name": "bower-asset/bootstrap", + "version": "v5.2.3", + "source": { + "type": "git", + "url": "git@github.com:twbs/bootstrap.git", + "reference": "cb021439c683d9805e2864c58095b92d405e9b11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twbs/bootstrap/zipball/cb021439c683d9805e2864c58095b92d405e9b11", + "reference": "cb021439c683d9805e2864c58095b92d405e9b11" + }, + "type": "bower-asset" + }, + { + "name": "bower-asset/inputmask", + "version": "3.3.11", + "source": { + "type": "git", + "url": "https://github.com/RobinHerbots/Inputmask.git", + "reference": "5e670ad62f50c738388d4dcec78d2888505ad77b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/RobinHerbots/Inputmask/zipball/5e670ad62f50c738388d4dcec78d2888505ad77b", + "reference": "5e670ad62f50c738388d4dcec78d2888505ad77b" + }, + "require": { + "bower-asset/jquery": ">=1.7" + }, + "type": "bower-asset", + "license": [ + "http://opensource.org/licenses/mit-license.php" + ] + }, + { + "name": "bower-asset/jquery", + "version": "3.7.1", + "source": { + "type": "git", + "url": "https://github.com/jquery/jquery-dist.git", + "reference": "fde1f76e2799dd877c176abde0ec836553246991" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jquery/jquery-dist/zipball/fde1f76e2799dd877c176abde0ec836553246991", + "reference": "fde1f76e2799dd877c176abde0ec836553246991" + }, + "type": "bower-asset", + "license": [ + "MIT" + ] + }, + { + "name": "bower-asset/punycode", + "version": "v1.3.2", + "source": { + "type": "git", + "url": "https://github.com/mathiasbynens/punycode.js.git", + "reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mathiasbynens/punycode.js/zipball/38c8d3131a82567bfef18da09f7f4db68c84f8a3", + "reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3" + }, + "type": "bower-asset" + }, + { + "name": "bower-asset/yii2-pjax", + "version": "2.0.8", + "source": { + "type": "git", + "url": "git@github.com:yiisoft/jquery-pjax.git", + "reference": "a9298d57da63d14a950f1b94366a864bc62264fb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/yiisoft/jquery-pjax/zipball/a9298d57da63d14a950f1b94366a864bc62264fb", + "reference": "a9298d57da63d14a950f1b94366a864bc62264fb" + }, + "require": { + "bower-asset/jquery": ">=1.8" + }, + "type": "bower-asset", + "license": [ + "MIT" + ] + }, + { + "name": "cebe/markdown", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/cebe/markdown.git", + "reference": "9bac5e971dd391e2802dca5400bbeacbaea9eb86" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cebe/markdown/zipball/9bac5e971dd391e2802dca5400bbeacbaea9eb86", + "reference": "9bac5e971dd391e2802dca5400bbeacbaea9eb86", + "shasum": "" + }, + "require": { + "lib-pcre": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "cebe/indent": "*", + "facebook/xhprof": "*@dev", + "phpunit/phpunit": "4.1.*" + }, + "bin": [ + "bin/markdown" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "cebe\\markdown\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Carsten Brandt", + "email": "mail@cebe.cc", + "homepage": "http://cebe.cc/", + "role": "Creator" + } + ], + "description": "A super fast, highly extensible markdown parser for PHP", + "homepage": "https://github.com/cebe/markdown#readme", + "keywords": [ + "extensible", + "fast", + "gfm", + "markdown", + "markdown-extra" + ], + "support": { + "issues": "https://github.com/cebe/markdown/issues", + "source": "https://github.com/cebe/markdown" + }, + "time": "2018-03-26T11:24:36+00:00" + }, + { + "name": "doctrine/lexer", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "84a527db05647743d50373e0ec53a152f2cde568" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/84a527db05647743d50373e0ec53a152f2cde568", + "reference": "84a527db05647743d50373e0ec53a152f2cde568", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "doctrine/coding-standard": "^10", + "phpstan/phpstan": "^1.9", + "phpunit/phpunit": "^9.5", + "psalm/plugin-phpunit": "^0.18.3", + "vimeo/psalm": "^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Lexer\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "https://www.doctrine-project.org/projects/lexer.html", + "keywords": [ + "annotations", + "docblock", + "lexer", + "parser", + "php" + ], + "support": { + "issues": "https://github.com/doctrine/lexer/issues", + "source": "https://github.com/doctrine/lexer/tree/3.0.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", + "type": "tidelift" + } + ], + "time": "2022-12-15T16:57:16+00:00" + }, + { + "name": "egulias/email-validator", + "version": "4.0.2", + "source": { + "type": "git", + "url": "https://github.com/egulias/EmailValidator.git", + "reference": "ebaaf5be6c0286928352e054f2d5125608e5405e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/ebaaf5be6c0286928352e054f2d5125608e5405e", + "reference": "ebaaf5be6c0286928352e054f2d5125608e5405e", + "shasum": "" + }, + "require": { + "doctrine/lexer": "^2.0 || ^3.0", + "php": ">=8.1", + "symfony/polyfill-intl-idn": "^1.26" + }, + "require-dev": { + "phpunit/phpunit": "^10.2", + "vimeo/psalm": "^5.12" + }, + "suggest": { + "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Egulias\\EmailValidator\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Eduardo Gulias Davis" + } + ], + "description": "A library for validating emails against several RFCs", + "homepage": "https://github.com/egulias/EmailValidator", + "keywords": [ + "email", + "emailvalidation", + "emailvalidator", + "validation", + "validator" + ], + "support": { + "issues": "https://github.com/egulias/EmailValidator/issues", + "source": "https://github.com/egulias/EmailValidator/tree/4.0.2" + }, + "funding": [ + { + "url": "https://github.com/egulias", + "type": "github" + } + ], + "time": "2023-10-06T06:47:41+00:00" + }, + { + "name": "ezyang/htmlpurifier", + "version": "v4.17.0", + "source": { + "type": "git", + "url": "https://github.com/ezyang/htmlpurifier.git", + "reference": "bbc513d79acf6691fa9cf10f192c90dd2957f18c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/bbc513d79acf6691fa9cf10f192c90dd2957f18c", + "reference": "bbc513d79acf6691fa9cf10f192c90dd2957f18c", + "shasum": "" + }, + "require": { + "php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0" + }, + "require-dev": { + "cerdic/css-tidy": "^1.7 || ^2.0", + "simpletest/simpletest": "dev-master" + }, + "suggest": { + "cerdic/css-tidy": "If you want to use the filter 'Filter.ExtractStyleBlocks'.", + "ext-bcmath": "Used for unit conversion and imagecrash protection", + "ext-iconv": "Converts text to and from non-UTF-8 encodings", + "ext-tidy": "Used for pretty-printing HTML" + }, + "type": "library", + "autoload": { + "files": [ + "library/HTMLPurifier.composer.php" + ], + "psr-0": { + "HTMLPurifier": "library/" + }, + "exclude-from-classmap": [ + "/library/HTMLPurifier/Language/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "Edward Z. Yang", + "email": "admin@htmlpurifier.org", + "homepage": "http://ezyang.com" + } + ], + "description": "Standards compliant HTML filter written in PHP", + "homepage": "http://htmlpurifier.org/", + "keywords": [ + "html" + ], + "support": { + "issues": "https://github.com/ezyang/htmlpurifier/issues", + "source": "https://github.com/ezyang/htmlpurifier/tree/v4.17.0" + }, + "time": "2023-11-17T15:01:25+00:00" + }, + { + "name": "hail812/yii2-adminlte-widgets", + "version": "v1.0.5", + "source": { + "type": "git", + "url": "https://github.com/hail812/yii2-adminlte-widgets.git", + "reference": "bc942430d7a5f5636f6c492553b5f444bf4a6df6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hail812/yii2-adminlte-widgets/zipball/bc942430d7a5f5636f6c492553b5f444bf4a6df6", + "reference": "bc942430d7a5f5636f6c492553b5f444bf4a6df6", + "shasum": "" + }, + "require": { + "yiisoft/yii2": "~2.0.0", + "yiisoft/yii2-bootstrap4": "~2.0.8" + }, + "type": "yii2-extension", + "autoload": { + "psr-4": { + "hail812\\adminlte\\widgets\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "hail", + "email": "hail812@163.com" + } + ], + "description": "yii2 adminlte widgets", + "keywords": [ + "extension", + "yii2" + ], + "support": { + "issues": "https://github.com/hail812/yii2-adminlte-widgets/issues", + "source": "https://github.com/hail812/yii2-adminlte-widgets/tree/v1.0.5" + }, + "time": "2022-05-25T05:58:29+00:00" + }, + { + "name": "hail812/yii2-adminlte3", + "version": "v1.1.9", + "source": { + "type": "git", + "url": "https://github.com/hail812/yii2-adminlte3.git", + "reference": "bcdec8f5e2f9caf7f3a34fad8cdfdd5dbc3a9c31" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hail812/yii2-adminlte3/zipball/bcdec8f5e2f9caf7f3a34fad8cdfdd5dbc3a9c31", + "reference": "bcdec8f5e2f9caf7f3a34fad8cdfdd5dbc3a9c31", + "shasum": "" + }, + "require": { + "almasaeed2010/adminlte": "~3.1", + "hail812/yii2-adminlte-widgets": "~1.0.2", + "php": ">=7.0", + "yiisoft/yii2": "~2.0.0", + "yiisoft/yii2-bootstrap4": "~2.0.8" + }, + "type": "yii2-extension", + "autoload": { + "psr-4": { + "hail812\\adminlte3\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "hail", + "email": "hail812@163.com" + } + ], + "description": "adminlte3 for yii2", + "keywords": [ + "AdminLTE", + "extension", + "yii2" + ], + "support": { + "issues": "https://github.com/hail812/yii2-adminlte3/issues", + "source": "https://github.com/hail812/yii2-adminlte3/tree/v1.1.9" + }, + "time": "2023-10-23T05:58:30+00:00" + }, + { + "name": "npm-asset/bootstrap", + "version": "4.6.2", + "dist": { + "type": "tar", + "url": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.2.tgz" + }, + "type": "npm-asset", + "license": [ + "MIT" + ] + }, + { + "name": "paragonie/random_compat", + "version": "v9.99.100", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a", + "shasum": "" + }, + "require": { + "php": ">= 7" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*", + "vimeo/psalm": "^1" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "polyfill", + "pseudorandom", + "random" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/random_compat/issues", + "source": "https://github.com/paragonie/random_compat" + }, + "time": "2020-10-15T08:29:30+00:00" + }, + { + "name": "psr/container", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/2.0.2" + }, + "time": "2021-11-05T16:47:00+00:00" + }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, + "time": "2019-01-08T18:20:26+00:00" + }, + { + "name": "psr/log", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.0" + }, + "time": "2021-07-14T16:46:02+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.4.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", + "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.4-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.4.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-05-23T14:45:45+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v6.4.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "d76d2632cfc2206eecb5ad2b26cd5934082941b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/d76d2632cfc2206eecb5ad2b26cd5934082941b6", + "reference": "d76d2632cfc2206eecb5ad2b26cd5934082941b6", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/event-dispatcher-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/dependency-injection": "<5.4", + "symfony/service-contracts": "<2.5" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/error-handler": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^5.4|^6.0|^7.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/stopwatch": "^5.4|^6.0|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v6.4.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-07-27T06:52:43+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v3.4.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "a76aed96a42d2b521153fb382d418e30d18b59df" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/a76aed96a42d2b521153fb382d418e30d18b59df", + "reference": "a76aed96a42d2b521153fb382d418e30d18b59df", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/event-dispatcher": "^1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.4-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.4.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-05-23T14:45:45+00:00" + }, + { + "name": "symfony/mailer", + "version": "v6.4.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/mailer.git", + "reference": "ca8dcf8892cdc5b4358ecf2528429bb5e706f7ba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mailer/zipball/ca8dcf8892cdc5b4358ecf2528429bb5e706f7ba", + "reference": "ca8dcf8892cdc5b4358ecf2528429bb5e706f7ba", + "shasum": "" + }, + "require": { + "egulias/email-validator": "^2.1.10|^3|^4", + "php": ">=8.1", + "psr/event-dispatcher": "^1", + "psr/log": "^1|^2|^3", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/mime": "^6.2|^7.0", + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/http-client-contracts": "<2.5", + "symfony/http-kernel": "<5.4", + "symfony/messenger": "<6.2", + "symfony/mime": "<6.2", + "symfony/twig-bridge": "<6.2.1" + }, + "require-dev": { + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/http-client": "^5.4|^6.0|^7.0", + "symfony/messenger": "^6.2|^7.0", + "symfony/twig-bridge": "^6.2|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mailer\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Helps sending emails", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/mailer/tree/v6.4.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-11-12T18:02:22+00:00" + }, + { + "name": "symfony/mime", + "version": "v6.4.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/mime.git", + "reference": "ca4f58b2ef4baa8f6cecbeca2573f88cd577d205" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mime/zipball/ca4f58b2ef4baa8f6cecbeca2573f88cd577d205", + "reference": "ca4f58b2ef4baa8f6cecbeca2573f88cd577d205", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0" + }, + "conflict": { + "egulias/email-validator": "~3.0.0", + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/mailer": "<5.4", + "symfony/serializer": "<6.3.2" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10|^3.1|^4", + "league/html-to-markdown": "^5.0", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/property-access": "^5.4|^6.0|^7.0", + "symfony/property-info": "^5.4|^6.0|^7.0", + "symfony/serializer": "^6.3.2|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mime\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows manipulating MIME messages", + "homepage": "https://symfony.com", + "keywords": [ + "mime", + "mime-type" + ], + "support": { + "source": "https://github.com/symfony/mime/tree/v6.4.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-10-17T11:49:05+00:00" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.28.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "ecaafce9f77234a6a449d29e49267ba10499116d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/ecaafce9f77234a6a449d29e49267ba10499116d", + "reference": "ecaafce9f77234a6a449d29e49267ba10499116d", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "symfony/polyfill-intl-normalizer": "^1.10", + "symfony/polyfill-php72": "^1.10" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.28.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-01-26T09:30:37+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.28.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", + "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.28.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-01-26T09:26:14+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.28.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "42292d99c55abe617799667f454222c54c60e229" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229", + "reference": "42292d99c55abe617799667f454222c54c60e229", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-07-28T09:04:16+00:00" + }, + { + "name": "symfony/polyfill-php72", + "version": "v1.28.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "70f4aebd92afca2f865444d30a4d2151c13c3179" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/70f4aebd92afca2f865444d30a4d2151c13c3179", + "reference": "70f4aebd92afca2f865444d30a4d2151c13c3179", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php72/tree/v1.28.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-01-26T09:26:14+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v3.4.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "b3313c2dbffaf71c8de2934e2ea56ed2291a3838" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/b3313c2dbffaf71c8de2934e2ea56ed2291a3838", + "reference": "b3313c2dbffaf71c8de2934e2ea56ed2291a3838", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/container": "^2.0" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.4-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v3.4.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-07-30T20:28:31+00:00" + }, + { + "name": "yiisoft/yii2", + "version": "2.0.49.3", + "source": { + "type": "git", + "url": "https://github.com/yiisoft/yii2-framework.git", + "reference": "783f65c9a743dfd7484b6026f1aa6f25e37159d9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/yiisoft/yii2-framework/zipball/783f65c9a743dfd7484b6026f1aa6f25e37159d9", + "reference": "783f65c9a743dfd7484b6026f1aa6f25e37159d9", + "shasum": "" + }, + "require": { + "bower-asset/inputmask": "~3.2.2 | ~3.3.5", + "bower-asset/jquery": "3.7.*@stable | 3.6.*@stable | 3.5.*@stable | 3.4.*@stable | 3.3.*@stable | 3.2.*@stable | 3.1.*@stable | 2.2.*@stable | 2.1.*@stable | 1.11.*@stable | 1.12.*@stable", + "bower-asset/punycode": "1.3.*", + "bower-asset/yii2-pjax": "~2.0.1", + "cebe/markdown": "~1.0.0 | ~1.1.0 | ~1.2.0", + "ext-ctype": "*", + "ext-mbstring": "*", + "ezyang/htmlpurifier": "^4.6", + "lib-pcre": "*", + "paragonie/random_compat": ">=1", + "php": ">=5.4.0", + "yiisoft/yii2-composer": "~2.0.4" + }, + "bin": [ + "yii" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "yii\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Qiang Xue", + "email": "qiang.xue@gmail.com", + "homepage": "https://www.yiiframework.com/", + "role": "Founder and project lead" + }, + { + "name": "Alexander Makarov", + "email": "sam@rmcreative.ru", + "homepage": "https://rmcreative.ru/", + "role": "Core framework development" + }, + { + "name": "Maurizio Domba", + "homepage": "http://mdomba.info/", + "role": "Core framework development" + }, + { + "name": "Carsten Brandt", + "email": "mail@cebe.cc", + "homepage": "https://www.cebe.cc/", + "role": "Core framework development" + }, + { + "name": "Timur Ruziev", + "email": "resurtm@gmail.com", + "homepage": "http://resurtm.com/", + "role": "Core framework development" + }, + { + "name": "Paul Klimov", + "email": "klimov.paul@gmail.com", + "role": "Core framework development" + }, + { + "name": "Dmitry Naumenko", + "email": "d.naumenko.a@gmail.com", + "role": "Core framework development" + }, + { + "name": "Boudewijn Vahrmeijer", + "email": "info@dynasource.eu", + "homepage": "http://dynasource.eu", + "role": "Core framework development" + } + ], + "description": "Yii PHP Framework Version 2", + "homepage": "https://www.yiiframework.com/", + "keywords": [ + "framework", + "yii2" + ], + "support": { + "forum": "https://forum.yiiframework.com/", + "irc": "ircs://irc.libera.chat:6697/yii", + "issues": "https://github.com/yiisoft/yii2/issues?state=open", + "source": "https://github.com/yiisoft/yii2", + "wiki": "https://www.yiiframework.com/wiki" + }, + "funding": [ + { + "url": "https://github.com/yiisoft", + "type": "github" + }, + { + "url": "https://opencollective.com/yiisoft", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/yiisoft/yii2", + "type": "tidelift" + } + ], + "time": "2023-10-31T15:39:08+00:00" + }, + { + "name": "yiisoft/yii2-bootstrap4", + "version": "2.0.11", + "source": { + "type": "git", + "url": "https://github.com/yiisoft/yii2-bootstrap4.git", + "reference": "6681a7ca2319499c1c35f09e803c5337e56b3dae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/yiisoft/yii2-bootstrap4/zipball/6681a7ca2319499c1c35f09e803c5337e56b3dae", + "reference": "6681a7ca2319499c1c35f09e803c5337e56b3dae", + "shasum": "" + }, + "require": { + "npm-asset/bootstrap": "^4.3", + "yiisoft/yii2": "^2.0.43" + }, + "require-dev": { + "cweagans/composer-patches": "^1.7", + "phpunit/phpunit": "4.8.34", + "yiisoft/yii2-coding-standards": "~2.0" + }, + "type": "yii2-extension", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + }, + "patches": { + "phpunit/phpunit-mock-objects": { + "Fix PHP 7 and 8 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_mock_objects.patch" + }, + "phpunit/phpunit": { + "Fix PHP 7 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_php7.patch", + "Fix PHP 8 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_php8.patch" + } + } + }, + "autoload": { + "psr-4": { + "yii\\bootstrap4\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Qiang Xue", + "email": "qiang.xue@gmail.com", + "homepage": "https://www.yiiframework.com/" + }, + { + "name": "Alexander Makarov", + "email": "sam@rmcreative.ru", + "homepage": "https://rmcreative.ru/" + }, + { + "name": "Antonio Ramirez", + "email": "amigo.cobos@gmail.com" + }, + { + "name": "Paul Klimov", + "email": "klimov.paul@gmail.com" + }, + { + "name": "Simon Karlen", + "email": "simi.albi@outlook.com" + } + ], + "description": "The Twitter Bootstrap extension for the Yii framework", + "keywords": [ + "bootstrap", + "bootstrap4", + "yii2" + ], + "support": { + "forum": "https://www.yiiframework.com/forum/", + "irc": "irc://irc.freenode.net/yii", + "issues": "https://github.com/yiisoft/yii2-bootstrap4/issues", + "source": "https://github.com/yiisoft/yii2-bootstrap4", + "wiki": "https://www.yiiframework.com/wiki/" + }, + "funding": [ + { + "url": "https://github.com/yiisoft", + "type": "github" + }, + { + "url": "https://opencollective.com/yiisoft", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/yiisoft/yii2-bootstrap4", + "type": "tidelift" + } + ], + "time": "2023-05-22T18:39:25+00:00" + }, + { + "name": "yiisoft/yii2-bootstrap5", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/yiisoft/yii2-bootstrap5.git", + "reference": "0ce35f80ca07763fa2c6f38d1c0a1aaf65c76d2e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/yiisoft/yii2-bootstrap5/zipball/0ce35f80ca07763fa2c6f38d1c0a1aaf65c76d2e", + "reference": "0ce35f80ca07763fa2c6f38d1c0a1aaf65c76d2e", + "shasum": "" + }, + "require": { + "bower-asset/bootstrap": "^5.1.0", + "ext-json": "*", + "php": ">=7.0", + "yiisoft/yii2": "^2.0.42" + }, + "require-dev": { + "phpunit/phpunit": "^6.5.14", + "twbs/bootstrap-icons": "^1.7.2", + "yiisoft/yii2-coding-standards": "~2.0" + }, + "suggest": { + "twbs/bootstrap-icons": "Add this package to the `require` section of your `composer.json` if you'd like to use the bootstrap icon asset." + }, + "type": "yii2-extension", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + }, + "bootstrap": "yii\\bootstrap5\\i18n\\TranslationBootstrap" + }, + "autoload": { + "psr-4": { + "yii\\bootstrap5\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sergey Zhukovskiy", + "email": "mylistryx@gmail.com", + "homepage": "https://net23.ru/" + }, + { + "name": "Simon Karlen", + "email": "simi.albi@outlook.com" + } + ], + "description": "The Twitter Bootstrap v5 extension for the Yii framework", + "keywords": [ + "bootstrap", + "bootstrap5", + "yii2" + ], + "support": { + "issues": "https://github.com/yiisoft/yii2-bootstrap5/issues", + "source": "https://github.com/yiisoft/yii2-bootstrap5" + }, + "funding": [ + { + "url": "https://github.com/yiisoft", + "type": "github" + }, + { + "url": "https://opencollective.com/yiisoft", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/yiisoft/yii2-bootstrap5", + "type": "tidelift" + } + ], + "time": "2022-11-30T08:25:21+00:00" + }, + { + "name": "yiisoft/yii2-composer", + "version": "2.0.10", + "source": { + "type": "git", + "url": "https://github.com/yiisoft/yii2-composer.git", + "reference": "94bb3f66e779e2774f8776d6e1bdeab402940510" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/yiisoft/yii2-composer/zipball/94bb3f66e779e2774f8776d6e1bdeab402940510", + "reference": "94bb3f66e779e2774f8776d6e1bdeab402940510", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0 | ^2.0" + }, + "require-dev": { + "composer/composer": "^1.0 | ^2.0@dev", + "phpunit/phpunit": "<7" + }, + "type": "composer-plugin", + "extra": { + "class": "yii\\composer\\Plugin", + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "yii\\composer\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Qiang Xue", + "email": "qiang.xue@gmail.com" + }, + { + "name": "Carsten Brandt", + "email": "mail@cebe.cc" + } + ], + "description": "The composer plugin for Yii extension installer", + "keywords": [ + "composer", + "extension installer", + "yii2" + ], + "support": { + "forum": "http://www.yiiframework.com/forum/", + "irc": "irc://irc.freenode.net/yii", + "issues": "https://github.com/yiisoft/yii2-composer/issues", + "source": "https://github.com/yiisoft/yii2-composer", + "wiki": "http://www.yiiframework.com/wiki/" + }, + "funding": [ + { + "url": "https://github.com/yiisoft", + "type": "github" + }, + { + "url": "https://opencollective.com/yiisoft", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/yiisoft/yii2-composer", + "type": "tidelift" + } + ], + "time": "2020-06-24T00:04:01+00:00" + }, + { + "name": "yiisoft/yii2-symfonymailer", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/yiisoft/yii2-symfonymailer.git", + "reference": "82f5902551a160633c4734b5096977ce76a809d9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/yiisoft/yii2-symfonymailer/zipball/82f5902551a160633c4734b5096977ce76a809d9", + "reference": "82f5902551a160633c4734b5096977ce76a809d9", + "shasum": "" + }, + "require": { + "php": ">=7.4.0", + "symfony/mailer": ">=5.4.0", + "yiisoft/yii2": ">=2.0.4" + }, + "require-dev": { + "phpunit/phpunit": "9.5.10" + }, + "type": "yii2-extension", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "yii\\symfonymailer\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kirill Petrov", + "email": "archibeardrinker@gmail.com" + } + ], + "description": "The SymfonyMailer integration for the Yii framework", + "keywords": [ + "email", + "mail", + "mailer", + "symfony", + "symfonymailer", + "yii2" + ], + "support": { + "forum": "http://www.yiiframework.com/forum/", + "irc": "irc://irc.freenode.net/yii", + "issues": "https://github.com/yiisoft/yii2-symfonymailer/issues", + "source": "https://github.com/yiisoft/yii2-symfonymailer", + "wiki": "http://www.yiiframework.com/wiki/" + }, + "funding": [ + { + "url": "https://github.com/yiisoft", + "type": "github" + }, + { + "url": "https://opencollective.com/yiisoft", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/yiisoft/yii2-symfonymailer", + "type": "tidelift" + } + ], + "time": "2022-09-04T10:48:21+00:00" + } + ], + "packages-dev": [ + { + "name": "behat/gherkin", + "version": "v4.9.0", + "source": { + "type": "git", + "url": "https://github.com/Behat/Gherkin.git", + "reference": "0bc8d1e30e96183e4f36db9dc79caead300beff4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Behat/Gherkin/zipball/0bc8d1e30e96183e4f36db9dc79caead300beff4", + "reference": "0bc8d1e30e96183e4f36db9dc79caead300beff4", + "shasum": "" + }, + "require": { + "php": "~7.2|~8.0" + }, + "require-dev": { + "cucumber/cucumber": "dev-gherkin-22.0.0", + "phpunit/phpunit": "~8|~9", + "symfony/yaml": "~3|~4|~5" + }, + "suggest": { + "symfony/yaml": "If you want to parse features, represented in YAML files" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.x-dev" + } + }, + "autoload": { + "psr-0": { + "Behat\\Gherkin": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + } + ], + "description": "Gherkin DSL parser for PHP", + "homepage": "http://behat.org/", + "keywords": [ + "BDD", + "Behat", + "Cucumber", + "DSL", + "gherkin", + "parser" + ], + "support": { + "issues": "https://github.com/Behat/Gherkin/issues", + "source": "https://github.com/Behat/Gherkin/tree/v4.9.0" + }, + "time": "2021-10-12T13:05:09+00:00" + }, + { + "name": "codeception/codeception", + "version": "5.0.13", + "source": { + "type": "git", + "url": "https://github.com/Codeception/Codeception.git", + "reference": "713a90195efa2926566e24bfc623da703ff42bba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/Codeception/zipball/713a90195efa2926566e24bfc623da703ff42bba", + "reference": "713a90195efa2926566e24bfc623da703ff42bba", + "shasum": "" + }, + "require": { + "behat/gherkin": "^4.6.2", + "codeception/lib-asserts": "^2.0", + "codeception/stub": "^4.1", + "ext-curl": "*", + "ext-json": "*", + "ext-mbstring": "*", + "php": "^8.0", + "phpunit/php-code-coverage": "^9.2 || ^10.0", + "phpunit/php-text-template": "^2.0 || ^3.0", + "phpunit/php-timer": "^5.0.3 || ^6.0", + "phpunit/phpunit": "^9.5.20 || ^10.0", + "psy/psysh": "^0.11.2 || ^0.12", + "sebastian/comparator": "^4.0.5 || ^5.0", + "sebastian/diff": "^4.0.3 || ^5.0", + "symfony/console": ">=4.4.24 <8.0", + "symfony/css-selector": ">=4.4.24 <8.0", + "symfony/event-dispatcher": ">=4.4.24 <8.0", + "symfony/finder": ">=4.4.24 <8.0", + "symfony/var-dumper": ">=4.4.24 <8.0", + "symfony/yaml": ">=4.4.24 <8.0" + }, + "conflict": { + "codeception/lib-innerbrowser": "<3.1.3", + "codeception/module-filesystem": "<3.0", + "codeception/module-phpbrowser": "<2.5" + }, + "replace": { + "codeception/phpunit-wrapper": "*" + }, + "require-dev": { + "codeception/lib-innerbrowser": "*@dev", + "codeception/lib-web": "^1.0", + "codeception/module-asserts": "*@dev", + "codeception/module-cli": "*@dev", + "codeception/module-db": "*@dev", + "codeception/module-filesystem": "*@dev", + "codeception/module-phpbrowser": "*@dev", + "codeception/util-universalframework": "*@dev", + "ext-simplexml": "*", + "jetbrains/phpstorm-attributes": "^1.0", + "symfony/dotenv": ">=4.4.24 <8.0", + "symfony/process": ">=4.4.24 <8.0", + "vlucas/phpdotenv": "^5.1" + }, + "suggest": { + "codeception/specify": "BDD-style code blocks", + "codeception/verify": "BDD-style assertions", + "ext-simplexml": "For loading params from XML files", + "stecman/symfony-console-completion": "For BASH autocompletion", + "symfony/dotenv": "For loading params from .env files", + "symfony/phpunit-bridge": "For phpunit-bridge support", + "vlucas/phpdotenv": "For loading params from .env files" + }, + "bin": [ + "codecept" + ], + "type": "library", + "autoload": { + "files": [ + "functions.php" + ], + "psr-4": { + "Codeception\\": "src/Codeception", + "Codeception\\Extension\\": "ext" + }, + "classmap": [ + "src/PHPUnit/TestCase.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Bodnarchuk", + "email": "davert.ua@gmail.com", + "homepage": "https://codeception.com" + } + ], + "description": "BDD-style testing framework", + "homepage": "https://codeception.com/", + "keywords": [ + "BDD", + "TDD", + "acceptance testing", + "functional testing", + "unit testing" + ], + "support": { + "issues": "https://github.com/Codeception/Codeception/issues", + "source": "https://github.com/Codeception/Codeception/tree/5.0.13" + }, + "funding": [ + { + "url": "https://opencollective.com/codeception", + "type": "open_collective" + } + ], + "time": "2023-12-22T19:32:40+00:00" + }, + { + "name": "codeception/lib-asserts", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/Codeception/lib-asserts.git", + "reference": "b8c7dff552249e560879c682ba44a4b963af91bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/lib-asserts/zipball/b8c7dff552249e560879c682ba44a4b963af91bc", + "reference": "b8c7dff552249e560879c682ba44a4b963af91bc", + "shasum": "" + }, + "require": { + "codeception/phpunit-wrapper": "^7.7.1 | ^8.0.3 | ^9.0", + "ext-dom": "*", + "php": "^7.4 | ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Bodnarchuk", + "email": "davert@mail.ua", + "homepage": "http://codegyre.com" + }, + { + "name": "Gintautas Miselis" + }, + { + "name": "Gustavo Nieves", + "homepage": "https://medium.com/@ganieves" + } + ], + "description": "Assertion methods used by Codeception core and Asserts module", + "homepage": "https://codeception.com/", + "keywords": [ + "codeception" + ], + "support": { + "issues": "https://github.com/Codeception/lib-asserts/issues", + "source": "https://github.com/Codeception/lib-asserts/tree/2.1.0" + }, + "time": "2023-02-10T18:36:23+00:00" + }, + { + "name": "codeception/lib-innerbrowser", + "version": "3.1.3", + "source": { + "type": "git", + "url": "https://github.com/Codeception/lib-innerbrowser.git", + "reference": "10482f7e34c0537bf5b87bc82a3d65a1842a8b4f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/lib-innerbrowser/zipball/10482f7e34c0537bf5b87bc82a3d65a1842a8b4f", + "reference": "10482f7e34c0537bf5b87bc82a3d65a1842a8b4f", + "shasum": "" + }, + "require": { + "codeception/codeception": "^5.0", + "codeception/lib-web": "^1.0.1", + "ext-dom": "*", + "ext-json": "*", + "ext-mbstring": "*", + "php": "^8.0", + "phpunit/phpunit": "^9.5", + "symfony/browser-kit": "^4.4.24 || ^5.4 || ^6.0", + "symfony/dom-crawler": "^4.4.30 || ^5.4 || ^6.0" + }, + "require-dev": { + "codeception/util-universalframework": "dev-master" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Bodnarchuk", + "email": "davert@mail.ua", + "homepage": "https://codegyre.com" + }, + { + "name": "Gintautas Miselis" + } + ], + "description": "Parent library for all Codeception framework modules and PhpBrowser", + "homepage": "https://codeception.com/", + "keywords": [ + "codeception" + ], + "support": { + "issues": "https://github.com/Codeception/lib-innerbrowser/issues", + "source": "https://github.com/Codeception/lib-innerbrowser/tree/3.1.3" + }, + "time": "2022-10-03T15:33:34+00:00" + }, + { + "name": "codeception/lib-web", + "version": "1.0.4", + "source": { + "type": "git", + "url": "https://github.com/Codeception/lib-web.git", + "reference": "28cb2ed1169de18e720bec758015aadc37d8344c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/lib-web/zipball/28cb2ed1169de18e720bec758015aadc37d8344c", + "reference": "28cb2ed1169de18e720bec758015aadc37d8344c", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "guzzlehttp/psr7": "^2.0", + "php": "^8.0", + "symfony/css-selector": ">=4.4.24 <8.0" + }, + "conflict": { + "codeception/codeception": "<5.0.0-alpha3" + }, + "require-dev": { + "php-webdriver/webdriver": "^1.12", + "phpunit/phpunit": "^9.5 | ^10.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gintautas Miselis" + } + ], + "description": "Library containing files used by module-webdriver and lib-innerbrowser or module-phpbrowser", + "homepage": "https://codeception.com/", + "keywords": [ + "codeception" + ], + "support": { + "issues": "https://github.com/Codeception/lib-web/issues", + "source": "https://github.com/Codeception/lib-web/tree/1.0.4" + }, + "time": "2023-12-01T11:38:22+00:00" + }, + { + "name": "codeception/module-asserts", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/Codeception/module-asserts.git", + "reference": "1b6b150b30586c3614e7e5761b31834ed7968603" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/module-asserts/zipball/1b6b150b30586c3614e7e5761b31834ed7968603", + "reference": "1b6b150b30586c3614e7e5761b31834ed7968603", + "shasum": "" + }, + "require": { + "codeception/codeception": "*@dev", + "codeception/lib-asserts": "^2.0", + "php": "^8.0" + }, + "conflict": { + "codeception/codeception": "<5.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Bodnarchuk" + }, + { + "name": "Gintautas Miselis" + }, + { + "name": "Gustavo Nieves", + "homepage": "https://medium.com/@ganieves" + } + ], + "description": "Codeception module containing various assertions", + "homepage": "https://codeception.com/", + "keywords": [ + "assertions", + "asserts", + "codeception" + ], + "support": { + "issues": "https://github.com/Codeception/module-asserts/issues", + "source": "https://github.com/Codeception/module-asserts/tree/3.0.0" + }, + "time": "2022-02-16T19:48:08+00:00" + }, + { + "name": "codeception/module-filesystem", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/Codeception/module-filesystem.git", + "reference": "0fd78cf941cb72dc2a650c6132c5999c26ad4f9a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/module-filesystem/zipball/0fd78cf941cb72dc2a650c6132c5999c26ad4f9a", + "reference": "0fd78cf941cb72dc2a650c6132c5999c26ad4f9a", + "shasum": "" + }, + "require": { + "codeception/codeception": "*@dev", + "php": "^8.0", + "symfony/finder": "^4.4 || ^5.4 || ^6.0 || ^7.0" + }, + "conflict": { + "codeception/codeception": "<5.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Bodnarchuk" + }, + { + "name": "Gintautas Miselis" + } + ], + "description": "Codeception module for testing local filesystem", + "homepage": "https://codeception.com/", + "keywords": [ + "codeception", + "filesystem" + ], + "support": { + "issues": "https://github.com/Codeception/module-filesystem/issues", + "source": "https://github.com/Codeception/module-filesystem/tree/3.0.1" + }, + "time": "2023-12-08T19:23:28+00:00" + }, + { + "name": "codeception/module-yii2", + "version": "1.1.9", + "source": { + "type": "git", + "url": "https://github.com/Codeception/module-yii2.git", + "reference": "70ad7544fc256363acd082b4ef9e7220a18017a0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/module-yii2/zipball/70ad7544fc256363acd082b4ef9e7220a18017a0", + "reference": "70ad7544fc256363acd082b4ef9e7220a18017a0", + "shasum": "" + }, + "require": { + "codeception/codeception": "^5.0.8", + "codeception/lib-innerbrowser": "^3.0 | ^4.0", + "php": "^8.0" + }, + "require-dev": { + "codeception/module-asserts": "^3.0", + "codeception/module-filesystem": "^3.0", + "codeception/verify": "^3.0", + "codemix/yii2-localeurls": "^1.7", + "yiisoft/yii2": "dev-master", + "yiisoft/yii2-app-advanced": "dev-master" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alexander Makarov" + }, + { + "name": "Sam Mouse" + }, + { + "name": "Michael Bodnarchuk" + } + ], + "description": "Codeception module for Yii2 framework", + "homepage": "https://codeception.com/", + "keywords": [ + "codeception", + "yii2" + ], + "support": { + "issues": "https://github.com/Codeception/module-yii2/issues", + "source": "https://github.com/Codeception/module-yii2/tree/1.1.9" + }, + "time": "2023-06-16T03:48:50+00:00" + }, + { + "name": "codeception/stub", + "version": "4.1.2", + "source": { + "type": "git", + "url": "https://github.com/Codeception/Stub.git", + "reference": "f6bc56e33e3f5ba7a831dfb968c49b27cf1676ad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/Stub/zipball/f6bc56e33e3f5ba7a831dfb968c49b27cf1676ad", + "reference": "f6bc56e33e3f5ba7a831dfb968c49b27cf1676ad", + "shasum": "" + }, + "require": { + "php": "^7.4 | ^8.0", + "phpunit/phpunit": "^8.4 | ^9.0 | ^10.0 | 10.0.x-dev" + }, + "conflict": { + "codeception/codeception": "<5.0.6" + }, + "require-dev": { + "consolidation/robo": "^3.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Codeception\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Flexible Stub wrapper for PHPUnit's Mock Builder", + "support": { + "issues": "https://github.com/Codeception/Stub/issues", + "source": "https://github.com/Codeception/Stub/tree/4.1.2" + }, + "time": "2023-10-07T19:22:36+00:00" + }, + { + "name": "codeception/verify", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/Codeception/Verify.git", + "reference": "25b84a96f0fe7dcf28e8021f02b57643b751a707" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Codeception/Verify/zipball/25b84a96f0fe7dcf28e8021f02b57643b751a707", + "reference": "25b84a96f0fe7dcf28e8021f02b57643b751a707", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "php": "^7.4 || ^8.0", + "phpunit/phpunit": "^9.5 | ^10.0" + }, + "type": "library", + "autoload": { + "files": [ + "src/Codeception/bootstrap.php" + ], + "psr-4": { + "Codeception\\": "src\\Codeception" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Bodnarchuk", + "email": "davert@codeception.com" + }, + { + "name": "Gustavo Nieves", + "homepage": "https://medium.com/@ganieves" + } + ], + "description": "BDD assertion library for PHPUnit", + "support": { + "issues": "https://github.com/Codeception/Verify/issues", + "source": "https://github.com/Codeception/Verify/tree/3.0.0" + }, + "time": "2023-02-09T07:33:00+00:00" + }, + { + "name": "doctrine/instantiator", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "doctrine/coding-standard": "^11", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^1.2", + "phpstan/phpstan": "^1.9.4", + "phpstan/phpstan-phpunit": "^1.3", + "phpunit/phpunit": "^9.5.27", + "vimeo/psalm": "^5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "https://ocramius.github.io/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", + "keywords": [ + "constructor", + "instantiate" + ], + "support": { + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/2.0.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", + "type": "tidelift" + } + ], + "time": "2022-12-30T00:23:10+00:00" + }, + { + "name": "fakerphp/faker", + "version": "v1.23.0", + "source": { + "type": "git", + "url": "https://github.com/FakerPHP/Faker.git", + "reference": "e3daa170d00fde61ea7719ef47bb09bb8f1d9b01" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/e3daa170d00fde61ea7719ef47bb09bb8f1d9b01", + "reference": "e3daa170d00fde61ea7719ef47bb09bb8f1d9b01", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "psr/container": "^1.0 || ^2.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "conflict": { + "fzaninotto/faker": "*" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4.1", + "doctrine/persistence": "^1.3 || ^2.0", + "ext-intl": "*", + "phpunit/phpunit": "^9.5.26", + "symfony/phpunit-bridge": "^5.4.16" + }, + "suggest": { + "doctrine/orm": "Required to use Faker\\ORM\\Doctrine", + "ext-curl": "Required by Faker\\Provider\\Image to download images.", + "ext-dom": "Required by Faker\\Provider\\HtmlLorem for generating random HTML.", + "ext-iconv": "Required by Faker\\Provider\\ru_RU\\Text::realText() for generating real Russian text.", + "ext-mbstring": "Required for multibyte Unicode string functionality." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "v1.21-dev" + } + }, + "autoload": { + "psr-4": { + "Faker\\": "src/Faker/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "François Zaninotto" + } + ], + "description": "Faker is a PHP library that generates fake data for you.", + "keywords": [ + "data", + "faker", + "fixtures" + ], + "support": { + "issues": "https://github.com/FakerPHP/Faker/issues", + "source": "https://github.com/FakerPHP/Faker/tree/v1.23.0" + }, + "time": "2023-06-12T08:44:38+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.6.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/45b30f99ac27b5ca93cb4831afe16285f57b8221", + "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "http-interop/http-factory-tests": "^0.9", + "phpunit/phpunit": "^8.5.36 || ^9.6.15" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.6.2" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2023-12-03T20:05:35+00:00" + }, + { + "name": "masterminds/html5", + "version": "2.8.1", + "source": { + "type": "git", + "url": "https://github.com/Masterminds/html5-php.git", + "reference": "f47dcf3c70c584de14f21143c55d9939631bc6cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/f47dcf3c70c584de14f21143c55d9939631bc6cf", + "reference": "f47dcf3c70c584de14f21143c55d9939631bc6cf", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Masterminds\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matt Butcher", + "email": "technosophos@gmail.com" + }, + { + "name": "Matt Farina", + "email": "matt@mattfarina.com" + }, + { + "name": "Asmir Mustafic", + "email": "goetas@gmail.com" + } + ], + "description": "An HTML5 parser and serializer.", + "homepage": "http://masterminds.github.io/html5-php", + "keywords": [ + "HTML5", + "dom", + "html", + "parser", + "querypath", + "serializer", + "xml" + ], + "support": { + "issues": "https://github.com/Masterminds/html5-php/issues", + "source": "https://github.com/Masterminds/html5-php/tree/2.8.1" + }, + "time": "2023-05-10T11:58:31+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.11.1", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3,<3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2023-03-08T13:26:56+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v4.18.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999", + "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=7.0" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v4.18.0" + }, + "time": "2023-12-10T21:03:43+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.3" + }, + "time": "2021-07-20T11:28:43+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phpspec/php-diff", + "version": "v1.1.3", + "source": { + "type": "git", + "url": "https://github.com/phpspec/php-diff.git", + "reference": "fc1156187f9f6c8395886fe85ed88a0a245d72e9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/php-diff/zipball/fc1156187f9f6c8395886fe85ed88a0a245d72e9", + "reference": "fc1156187f9f6c8395886fe85ed88a0a245d72e9", + "shasum": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Diff": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Chris Boulton", + "homepage": "http://github.com/chrisboulton" + } + ], + "description": "A comprehensive library for generating differences between two hashable objects (strings or arrays).", + "support": { + "source": "https://github.com/phpspec/php-diff/tree/v1.1.3" + }, + "time": "2020-09-18T13:47:07+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "9.2.30", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca2bd87d2f9215904682a9cb9bb37dda98e76089", + "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0.3", + "phpunit/php-text-template": "^2.0.2", + "sebastian/code-unit-reverse-lookup": "^2.0.2", + "sebastian/complexity": "^2.0", + "sebastian/environment": "^5.1.2", + "sebastian/lines-of-code": "^1.0.3", + "sebastian/version": "^3.0.1", + "theseer/tokenizer": "^1.2.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.30" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-12-22T06:47:57+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "3.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2021-12-02T12:48:52+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:58:55+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T05:33:50+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "5.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:16:10+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "9.5.28", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "954ca3113a03bf780d22f07bf055d883ee04b65e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/954ca3113a03bf780d22f07bf055d883ee04b65e", + "reference": "954ca3113a03bf780d22f07bf055d883ee04b65e", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.3.1 || ^2", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.10.1", + "phar-io/manifest": "^2.0.3", + "phar-io/version": "^3.0.2", + "php": ">=7.3", + "phpunit/php-code-coverage": "^9.2.13", + "phpunit/php-file-iterator": "^3.0.5", + "phpunit/php-invoker": "^3.1.1", + "phpunit/php-text-template": "^2.0.3", + "phpunit/php-timer": "^5.0.2", + "sebastian/cli-parser": "^1.0.1", + "sebastian/code-unit": "^1.0.6", + "sebastian/comparator": "^4.0.8", + "sebastian/diff": "^4.0.3", + "sebastian/environment": "^5.1.3", + "sebastian/exporter": "^4.0.5", + "sebastian/global-state": "^5.0.1", + "sebastian/object-enumerator": "^4.0.3", + "sebastian/resource-operations": "^3.0.3", + "sebastian/type": "^3.2", + "sebastian/version": "^3.0.2" + }, + "suggest": { + "ext-soap": "*", + "ext-xdebug": "*" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.5-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.28" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2023-01-14T12:32:24+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "e616d01114759c4c489f93b099585439f795fe35" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35", + "reference": "e616d01114759c4c489f93b099585439f795fe35", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory/tree/1.0.2" + }, + "time": "2023-04-10T20:10:41+00:00" + }, + { + "name": "psr/http-message", + "version": "2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/2.0" + }, + "time": "2023-04-04T09:54:51+00:00" + }, + { + "name": "psy/psysh", + "version": "v0.12.0", + "source": { + "type": "git", + "url": "https://github.com/bobthecow/psysh.git", + "reference": "750bf031a48fd07c673dbe3f11f72362ea306d0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/750bf031a48fd07c673dbe3f11f72362ea306d0d", + "reference": "750bf031a48fd07c673dbe3f11f72362ea306d0d", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-tokenizer": "*", + "nikic/php-parser": "^5.0 || ^4.0", + "php": "^8.0 || ^7.4", + "symfony/console": "^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4", + "symfony/var-dumper": "^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4" + }, + "conflict": { + "symfony/console": "4.4.37 || 5.3.14 || 5.3.15 || 5.4.3 || 5.4.4 || 6.0.3 || 6.0.4" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.2" + }, + "suggest": { + "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)", + "ext-pdo-sqlite": "The doc command requires SQLite to work.", + "ext-posix": "If you have PCNTL, you'll want the POSIX extension as well." + }, + "bin": [ + "bin/psysh" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "0.12.x-dev" + }, + "bamarni-bin": { + "bin-links": false, + "forward-command": false + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Psy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Justin Hileman", + "email": "justin@justinhileman.info", + "homepage": "http://justinhileman.com" + } + ], + "description": "An interactive shell for modern PHP.", + "homepage": "http://psysh.org", + "keywords": [ + "REPL", + "console", + "interactive", + "shell" + ], + "support": { + "issues": "https://github.com/bobthecow/psysh/issues", + "source": "https://github.com/bobthecow/psysh/tree/v0.12.0" + }, + "time": "2023-12-20T15:28:09+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:08:49+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:08:54+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:30:19+00:00" + }, + { + "name": "sebastian/comparator", + "version": "4.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/diff": "^4.0", + "sebastian/exporter": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-09-14T12:41:17+00:00" + }, + { + "name": "sebastian/complexity", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a", + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-12-22T06:19:30+00:00" + }, + { + "name": "sebastian/diff", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-05-07T05:35:17+00:00" + }, + { + "name": "sebastian/environment", + "version": "5.1.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:03:51+00:00" + }, + { + "name": "sebastian/exporter", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-09-14T06:03:37+00:00" + }, + { + "name": "sebastian/global-state", + "version": "5.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "bde739e7565280bda77be70044ac1047bc007e34" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34", + "reference": "bde739e7565280bda77be70044ac1047bc007e34", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-08-02T09:26:13+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "1.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5", + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-12-22T06:20:34+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:12:34+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:14:26+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:07:39+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "support": { + "issues": "https://github.com/sebastianbergmann/resource-operations/issues", + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:45:17+00:00" + }, + { + "name": "sebastian/type", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:13:03+00:00" + }, + { + "name": "sebastian/version", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c6c1022351a901512170118436c764e473f6de8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", + "reference": "c6c1022351a901512170118436c764e473f6de8c", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:39:44+00:00" + }, + { + "name": "symfony/browser-kit", + "version": "v6.4.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/browser-kit.git", + "reference": "a3bb210e001580ec75e1d02b27fae3452e6bf502" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/a3bb210e001580ec75e1d02b27fae3452e6bf502", + "reference": "a3bb210e001580ec75e1d02b27fae3452e6bf502", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/dom-crawler": "^5.4|^6.0|^7.0" + }, + "require-dev": { + "symfony/css-selector": "^5.4|^6.0|^7.0", + "symfony/http-client": "^5.4|^6.0|^7.0", + "symfony/mime": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.0|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\BrowserKit\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/browser-kit/tree/v6.4.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-10-31T08:18:17+00:00" + }, + { + "name": "symfony/console", + "version": "v6.4.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "a550a7c99daeedef3f9d23fb82e3531525ff11fd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/a550a7c99daeedef3f9d23fb82e3531525ff11fd", + "reference": "a550a7c99daeedef3f9d23fb82e3531525ff11fd", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/string": "^5.4|^6.0|^7.0" + }, + "conflict": { + "symfony/dependency-injection": "<5.4", + "symfony/dotenv": "<5.4", + "symfony/event-dispatcher": "<5.4", + "symfony/lock": "<5.4", + "symfony/process": "<5.4" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/lock": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/stopwatch": "^5.4|^6.0|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command-line", + "console", + "terminal" + ], + "support": { + "source": "https://github.com/symfony/console/tree/v6.4.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-11-30T10:54:28+00:00" + }, + { + "name": "symfony/css-selector", + "version": "v6.4.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "d036c6c0d0b09e24a14a35f8292146a658f986e4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/d036c6c0d0b09e24a14a35f8292146a658f986e4", + "reference": "d036c6c0d0b09e24a14a35f8292146a658f986e4", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Converts CSS selectors to XPath expressions", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/css-selector/tree/v6.4.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-10-31T08:40:20+00:00" + }, + { + "name": "symfony/dom-crawler", + "version": "v6.4.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "14ff4fd2a5c8969d6158dbe7ef5b17d6a9c6ba33" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/14ff4fd2a5c8969d6158dbe7ef5b17d6a9c6ba33", + "reference": "14ff4fd2a5c8969d6158dbe7ef5b17d6a9c6ba33", + "shasum": "" + }, + "require": { + "masterminds/html5": "^2.6", + "php": ">=8.1", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0" + }, + "require-dev": { + "symfony/css-selector": "^5.4|^6.0|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\DomCrawler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases DOM navigation for HTML and XML documents", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/dom-crawler/tree/v6.4.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-11-20T16:41:16+00:00" + }, + { + "name": "symfony/finder", + "version": "v6.4.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "11d736e97f116ac375a81f96e662911a34cd50ce" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/11d736e97f116ac375a81f96e662911a34cd50ce", + "reference": "11d736e97f116ac375a81f96e662911a34cd50ce", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "symfony/filesystem": "^6.0|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v6.4.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-10-31T17:30:12+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.28.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", + "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-01-26T09:26:14+00:00" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.28.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "875e90aeea2777b6f135677f618529449334a612" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/875e90aeea2777b6f135677f618529449334a612", + "reference": "875e90aeea2777b6f135677f618529449334a612", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.28.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-01-26T09:26:14+00:00" + }, + { + "name": "symfony/string", + "version": "v6.4.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "b45fcf399ea9c3af543a92edf7172ba21174d809" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/b45fcf399ea9c3af543a92edf7172ba21174d809", + "reference": "b45fcf399ea9c3af543a92edf7172ba21174d809", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/translation-contracts": "<2.5" + }, + "require-dev": { + "symfony/error-handler": "^5.4|^6.0|^7.0", + "symfony/http-client": "^5.4|^6.0|^7.0", + "symfony/intl": "^6.2|^7.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^5.4|^6.0|^7.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v6.4.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-11-28T20:41:49+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v6.4.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "c40f7d17e91d8b407582ed51a2bbf83c52c367f6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/c40f7d17e91d8b407582ed51a2bbf83c52c367f6", + "reference": "c40f7d17e91d8b407582ed51a2bbf83c52c367f6", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/console": "<5.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/error-handler": "^6.3|^7.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/uid": "^5.4|^6.0|^7.0", + "twig/twig": "^2.13|^3.0.4" + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides mechanisms for walking through any arbitrary PHP variable", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "support": { + "source": "https://github.com/symfony/var-dumper/tree/v6.4.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-11-09T08:28:32+00:00" + }, + { + "name": "symfony/yaml", + "version": "v6.4.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "4f9237a1bb42455d609e6687d2613dde5b41a587" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/4f9237a1bb42455d609e6687d2613dde5b41a587", + "reference": "4f9237a1bb42455d609e6687d2613dde5b41a587", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "symfony/console": "<5.4" + }, + "require-dev": { + "symfony/console": "^5.4|^6.0|^7.0" + }, + "bin": [ + "Resources/bin/yaml-lint" + ], + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Loads and dumps YAML files", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/yaml/tree/v6.4.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-11-06T11:00:25+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.2.2", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96", + "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.2.2" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2023-11-20T00:12:19+00:00" + }, + { + "name": "yiisoft/yii2-debug", + "version": "2.1.25", + "source": { + "type": "git", + "url": "https://github.com/yiisoft/yii2-debug.git", + "reference": "4d011b9bfc83bde71cde43c9f6837f5a74685ea7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/yiisoft/yii2-debug/zipball/4d011b9bfc83bde71cde43c9f6837f5a74685ea7", + "reference": "4d011b9bfc83bde71cde43c9f6837f5a74685ea7", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=5.4", + "yiisoft/yii2": "~2.0.13" + }, + "require-dev": { + "cweagans/composer-patches": "^1.7", + "phpunit/phpunit": "4.8.34", + "yiisoft/yii2-coding-standards": "~2.0", + "yiisoft/yii2-swiftmailer": "*" + }, + "type": "yii2-extension", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + }, + "composer-exit-on-patch-failure": true, + "patches": { + "phpunit/phpunit-mock-objects": { + "Fix PHP 7 and 8 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_mock_objects.patch" + }, + "phpunit/phpunit": { + "Fix PHP 7 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_php7.patch", + "Fix PHP 8 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_php8.patch", + "Fix PHP 8.1 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_php81.patch" + } + } + }, + "autoload": { + "psr-4": { + "yii\\debug\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Qiang Xue", + "email": "qiang.xue@gmail.com" + }, + { + "name": "Simon Karlen", + "email": "simi.albi@outlook.com" + } + ], + "description": "The debugger extension for the Yii framework", + "keywords": [ + "debug", + "debugger", + "yii2" + ], + "support": { + "forum": "http://www.yiiframework.com/forum/", + "irc": "irc://irc.freenode.net/yii", + "issues": "https://github.com/yiisoft/yii2-debug/issues", + "source": "https://github.com/yiisoft/yii2-debug", + "wiki": "http://www.yiiframework.com/wiki/" + }, + "funding": [ + { + "url": "https://github.com/yiisoft", + "type": "github" + }, + { + "url": "https://opencollective.com/yiisoft", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/yiisoft/yii2-debug", + "type": "tidelift" + } + ], + "time": "2023-09-26T15:50:00+00:00" + }, + { + "name": "yiisoft/yii2-faker", + "version": "2.0.5", + "source": { + "type": "git", + "url": "https://github.com/yiisoft/yii2-faker.git", + "reference": "8c361657143bfaea58ff7dcc9bf51f1991a46f5d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/yiisoft/yii2-faker/zipball/8c361657143bfaea58ff7dcc9bf51f1991a46f5d", + "reference": "8c361657143bfaea58ff7dcc9bf51f1991a46f5d", + "shasum": "" + }, + "require": { + "fakerphp/faker": "~1.9|~1.10", + "yiisoft/yii2": "~2.0.0" + }, + "require-dev": { + "cweagans/composer-patches": "^1.7", + "phpunit/phpunit": "4.8.34" + }, + "type": "yii2-extension", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + }, + "composer-exit-on-patch-failure": true, + "patches": { + "phpunit/phpunit-mock-objects": { + "Fix PHP 7 and 8 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_mock_objects.patch" + }, + "phpunit/phpunit": { + "Fix PHP 7 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_php7.patch", + "Fix PHP 8 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_php8.patch" + } + } + }, + "autoload": { + "psr-4": { + "yii\\faker\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Mark Jebri", + "email": "mark.github@yandex.ru" + } + ], + "description": "Fixture generator. The Faker integration for the Yii framework.", + "keywords": [ + "Fixture", + "faker", + "yii2" + ], + "support": { + "forum": "http://www.yiiframework.com/forum/", + "irc": "irc://irc.freenode.net/yii", + "issues": "https://github.com/yiisoft/yii2-faker/issues", + "source": "https://github.com/yiisoft/yii2-faker", + "wiki": "http://www.yiiframework.com/wiki/" + }, + "funding": [ + { + "url": "https://github.com/yiisoft", + "type": "github" + }, + { + "url": "https://opencollective.com/yiisoft", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/yiisoft/yii2-faker", + "type": "tidelift" + } + ], + "time": "2020-11-10T12:27:35+00:00" + }, + { + "name": "yiisoft/yii2-gii", + "version": "2.2.6", + "source": { + "type": "git", + "url": "https://github.com/yiisoft/yii2-gii.git", + "reference": "ac574e7e2c29fd865145c8688719f252d19aae23" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/yiisoft/yii2-gii/zipball/ac574e7e2c29fd865145c8688719f252d19aae23", + "reference": "ac574e7e2c29fd865145c8688719f252d19aae23", + "shasum": "" + }, + "require": { + "phpspec/php-diff": "^1.1.0", + "yiisoft/yii2": "~2.0.46" + }, + "require-dev": { + "cweagans/composer-patches": "^1.7", + "phpunit/phpunit": "4.8.34", + "yiisoft/yii2-coding-standards": "~2.0" + }, + "type": "yii2-extension", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + }, + "composer-exit-on-patch-failure": true, + "patches": { + "phpunit/phpunit-mock-objects": { + "Fix PHP 7 and 8 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_mock_objects.patch" + }, + "phpunit/php-file-iterator": { + "Fix PHP 8.1 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_path_file_iterator.patch" + }, + "phpunit/phpunit": { + "Fix PHP 7 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_php7.patch", + "Fix PHP 8 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_php8.patch", + "Fix PHP 8.1 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_php81.patch" + } + } + }, + "autoload": { + "psr-4": { + "yii\\gii\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Qiang Xue", + "email": "qiang.xue@gmail.com" + } + ], + "description": "The Gii extension for the Yii framework", + "keywords": [ + "code generator", + "gii", + "yii2" + ], + "support": { + "forum": "https://www.yiiframework.com/forum/", + "irc": "irc://irc.freenode.net/yii", + "issues": "https://github.com/yiisoft/yii2-gii/issues", + "source": "https://github.com/yiisoft/yii2-gii", + "wiki": "https://www.yiiframework.com/wiki/" + }, + "funding": [ + { + "url": "https://github.com/yiisoft", + "type": "github" + }, + { + "url": "https://opencollective.com/yiisoft", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/yiisoft/yii2-gii", + "type": "tidelift" + } + ], + "time": "2023-05-22T20:55:37+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=7.4.0" + }, + "platform-dev": [], + "plugin-api-version": "2.3.0" +} diff --git a/console/config/.gitignore b/console/config/.gitignore new file mode 100644 index 0000000..42799dd --- /dev/null +++ b/console/config/.gitignore @@ -0,0 +1,3 @@ +main-local.php +params-local.php +test-local.php diff --git a/console/config/bootstrap.php b/console/config/bootstrap.php new file mode 100644 index 0000000..b3d9bbc --- /dev/null +++ b/console/config/bootstrap.php @@ -0,0 +1 @@ + 'app-console', + 'basePath' => dirname(__DIR__), + 'bootstrap' => ['log'], + 'controllerNamespace' => 'console\controllers', + 'aliases' => [ + '@bower' => '@vendor/bower-asset', + '@npm' => '@vendor/npm-asset', + ], + 'controllerMap' => [ + 'fixture' => [ + 'class' => \yii\console\controllers\FixtureController::class, + 'namespace' => 'common\fixtures', + ], + ], + 'components' => [ + 'log' => [ + 'targets' => [ + [ + 'class' => \yii\log\FileTarget::class, + 'levels' => ['error', 'warning'], + ], + ], + ], + ], + 'params' => $params, +]; diff --git a/console/config/params.php b/console/config/params.php new file mode 100644 index 0000000..6ebf279 --- /dev/null +++ b/console/config/params.php @@ -0,0 +1,5 @@ + 'admin@example.com', +]; diff --git a/console/config/test.php b/console/config/test.php new file mode 100644 index 0000000..b625128 --- /dev/null +++ b/console/config/test.php @@ -0,0 +1,4 @@ +db->driverName === 'mysql') { + // https://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci + $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB'; + } + + $this->createTable('{{%user}}', [ + 'id' => $this->primaryKey(), + 'username' => $this->string()->notNull()->unique(), + 'auth_key' => $this->string(32)->notNull(), + 'password_hash' => $this->string()->notNull(), + 'password_reset_token' => $this->string()->unique(), + 'email' => $this->string()->notNull()->unique(), + + 'status' => $this->smallInteger()->notNull()->defaultValue(10), + 'created_at' => $this->integer()->notNull(), + 'updated_at' => $this->integer()->notNull(), + ], $tableOptions); + } + + public function down() + { + $this->dropTable('{{%user}}'); + } +} diff --git a/console/migrations/m190124_110200_add_verification_token_column_to_user_table.php b/console/migrations/m190124_110200_add_verification_token_column_to_user_table.php new file mode 100644 index 0000000..4a20dc7 --- /dev/null +++ b/console/migrations/m190124_110200_add_verification_token_column_to_user_table.php @@ -0,0 +1,16 @@ +addColumn('{{%user}}', 'verification_token', $this->string()->defaultValue(null)); + } + + public function down() + { + $this->dropColumn('{{%user}}', 'verification_token'); + } +} diff --git a/console/migrations/m240110_152351_create_company_table.php b/console/migrations/m240110_152351_create_company_table.php new file mode 100644 index 0000000..f1f91cb --- /dev/null +++ b/console/migrations/m240110_152351_create_company_table.php @@ -0,0 +1,33 @@ +createTable('{{%company}}', [ + 'id' => $this->primaryKey(), + 'inn' => $this->string(255)->notNull(), + 'name' => $this->string(255)->notNull(), + 'address' => $this->string(255), + 'created_at' => $this->dateTime(), + 'updated_at' => $this->dateTime(), + 'status' => $this->integer(1)->defaultValue(1) + ]); + } + + /** + * {@inheritdoc} + */ + public function safeDown() + { + $this->dropTable('{{%company}}'); + } +} diff --git a/console/migrations/m240110_153348_create_addresses_table.php b/console/migrations/m240110_153348_create_addresses_table.php new file mode 100644 index 0000000..34e6bfc --- /dev/null +++ b/console/migrations/m240110_153348_create_addresses_table.php @@ -0,0 +1,52 @@ +createTable('{{%addresses}}', [ + 'id' => $this->primaryKey(), + 'address' => $this->string(255)->notNull(), + 'company_id' => $this->integer(11)->notNull(), + 'name' => $this->string(255), + ]); + + $this->createIndex('idx-addresses-company_id', 'addresses', 'company_id'); + + $this->addForeignKey( + 'fk-addresses-company_id', + 'addresses', + 'company_id', + 'company', + 'id', + 'CASCADE' + ); + } + + /** + * {@inheritdoc} + */ + public function safeDown() + { + $this->dropForeignKey( + 'fk-addresses-company_id', + 'addresses' + ); + + // drops index for column `author_id` + $this->dropIndex( + 'idx-addresses-company_id', + 'addresses' + ); + + $this->dropTable('{{%addresses}}'); + } +} diff --git a/console/migrations/m240110_154916_create_product_table.php b/console/migrations/m240110_154916_create_product_table.php new file mode 100644 index 0000000..4bae1ff --- /dev/null +++ b/console/migrations/m240110_154916_create_product_table.php @@ -0,0 +1,55 @@ +createTable('{{%product}}', [ + 'id' => $this->primaryKey(), + 'title' => $this->string(255)->notNull(), + 'article' => $this->string(255)->notNull(), + 'company_id' => $this->integer(11)->notNull(), + 'type' => $this->integer(1)->defaultValue(1), + 'price' => $this->integer(11)->defaultValue(0), + 'status' => $this->integer(1)->defaultValue(1), + ]); + + $this->createIndex('idx-product-company_id', 'product', 'company_id'); + + $this->addForeignKey( + 'fk-product-company_id', + 'product', + 'company_id', + 'company', + 'id', + 'CASCADE' + ); + } + + /** + * {@inheritdoc} + */ + public function safeDown() + { + $this->dropForeignKey( + 'fk-product-company_id', + 'product' + ); + + // drops index for column `author_id` + $this->dropIndex( + 'idx-product-company_id', + 'product' + ); + + $this->dropTable('{{%product}}'); + } +} diff --git a/console/migrations/m240110_155920_create_check_table.php b/console/migrations/m240110_155920_create_check_table.php new file mode 100644 index 0000000..999a919 --- /dev/null +++ b/console/migrations/m240110_155920_create_check_table.php @@ -0,0 +1,75 @@ +createTable('{{%check}}', [ + 'id' => $this->primaryKey(), + 'number' => $this->string(255)->notNull(), + 'company_id' => $this->integer(11)->notNull(), + 'addresses_id' => $this->integer(11)->notNull(), + 'status' => $this->integer(1)->defaultValue(1), + ]); + + $this->createIndex('idx-check-company_id', 'check', 'company_id'); + + $this->addForeignKey( + 'fk-check-company_id', + 'check', + 'company_id', + 'company', + 'id', + 'CASCADE' + ); + + $this->createIndex('idx-check-addresses_id', 'check', 'addresses_id'); + + $this->addForeignKey( + 'fk-check-addresses_id', + 'check', + 'addresses_id', + 'addresses', + 'id', + 'CASCADE' + ); + } + + /** + * {@inheritdoc} + */ + public function safeDown() + { + $this->dropForeignKey( + 'fk-check-company_id', + 'check' + ); + + // drops index for column `author_id` + $this->dropIndex( + 'idx-check-company_id', + 'check' + ); + + $this->dropForeignKey( + 'fk-check-addresses_id', + 'check' + ); + + // drops index for column `author_id` + $this->dropIndex( + 'idx-check-addresses_id', + 'check' + ); + + $this->dropTable('{{%check}}'); + } +} diff --git a/console/migrations/m240110_161944_create_junction_table_for_check_and_product_tables.php b/console/migrations/m240110_161944_create_junction_table_for_check_and_product_tables.php new file mode 100644 index 0000000..46ad836 --- /dev/null +++ b/console/migrations/m240110_161944_create_junction_table_for_check_and_product_tables.php @@ -0,0 +1,92 @@ +createTable('{{%check_product}}', [ + 'check_id' => $this->integer(11)->notNull(), + 'product_id' => $this->integer(11)->notNull(), + 'quantity' => $this->integer(11)->defaultValue(1), + 'PRIMARY KEY(check_id, product_id)', + ]); + + // creates index for column `check_id` + $this->createIndex( + '{{%idx-check_product-check_id}}', + '{{%check_product}}', + 'check_id' + ); + + // add foreign key for table `{{%check}}` + $this->addForeignKey( + '{{%fk-check_product-check_id}}', + '{{%check_product}}', + 'check_id', + '{{%check}}', + 'id', + 'CASCADE' + ); + + // creates index for column `product_id` + $this->createIndex( + '{{%idx-check_product-product_id}}', + '{{%check_product}}', + 'product_id' + ); + + // add foreign key for table `{{%product}}` + $this->addForeignKey( + '{{%fk-check_product-product_id}}', + '{{%check_product}}', + 'product_id', + '{{%product}}', + 'id', + 'CASCADE' + ); + } + + /** + * {@inheritdoc} + */ + public function safeDown() + { + // drops foreign key for table `{{%check}}` + $this->dropForeignKey( + '{{%fk-check_product-check_id}}', + '{{%check_product}}' + ); + + // drops index for column `check_id` + $this->dropIndex( + '{{%idx-check_product-check_id}}', + '{{%check_product}}' + ); + + // drops foreign key for table `{{%product}}` + $this->dropForeignKey( + '{{%fk-check_product-product_id}}', + '{{%check_product}}' + ); + + // drops index for column `product_id` + $this->dropIndex( + '{{%idx-check_product-product_id}}', + '{{%check_product}}' + ); + + $this->dropTable('{{%check_product}}'); + } +} diff --git a/console/migrations/m240110_223124_add_user_id_column_at_company_table.php b/console/migrations/m240110_223124_add_user_id_column_at_company_table.php new file mode 100644 index 0000000..4cd30f7 --- /dev/null +++ b/console/migrations/m240110_223124_add_user_id_column_at_company_table.php @@ -0,0 +1,44 @@ +addColumn('company', 'user_id', $this->integer(11)->notNull()); + + } + + /** + * {@inheritdoc} + */ + public function safeDown() + { + + $this->dropColumn('company', 'user_id'); + + } + + /* + // Use up()/down() to run migration code without a transaction. + public function up() + { + + } + + public function down() + { + echo "m240110_223124_add_user_id_column_at_company_table cannot be reverted.\n"; + + return false; + } + */ +} diff --git a/console/migrations/m240117_203610_add_additional_column_at_check_table.php b/console/migrations/m240117_203610_add_additional_column_at_check_table.php new file mode 100644 index 0000000..2169d02 --- /dev/null +++ b/console/migrations/m240117_203610_add_additional_column_at_check_table.php @@ -0,0 +1,40 @@ +addColumn('check', 'additional', $this->text()->after('company_id')); + } + + /** + * {@inheritdoc} + */ + public function safeDown() + { + $this->dropColumn('check', 'additional'); + } + + /* + // Use up()/down() to run migration code without a transaction. + public function up() + { + + } + + public function down() + { + echo "m240117_203610_add_additional_column_at_check_table cannot be reverted.\n"; + + return false; + } + */ +} diff --git a/console/migrations/m240117_205124_add_title_column_at_check_table.php b/console/migrations/m240117_205124_add_title_column_at_check_table.php new file mode 100644 index 0000000..e4fa66e --- /dev/null +++ b/console/migrations/m240117_205124_add_title_column_at_check_table.php @@ -0,0 +1,40 @@ +addColumn('check', 'title', $this->text()->after('company_id')); + } + + /** + * {@inheritdoc} + */ + public function safeDown() + { + $this->dropColumn('check', 'title'); + } + + /* + // Use up()/down() to run migration code without a transaction. + public function up() + { + + } + + public function down() + { + echo "m240117_205124_add_title_column_at_check_table cannot be reverted.\n"; + + return false; + } + */ +} diff --git a/console/migrations/m240212_213157_create_product_category_table.php b/console/migrations/m240212_213157_create_product_category_table.php new file mode 100644 index 0000000..6bbd57f --- /dev/null +++ b/console/migrations/m240212_213157_create_product_category_table.php @@ -0,0 +1,57 @@ +createTable('{{%product_category}}', [ + 'id' => $this->primaryKey(), + 'title' => $this->string('255')->notNull(), + 'parent_id' => $this->integer(11)->defaultValue(0), + 'company_id' => $this->integer(11)->notNull(), + 'status' => $this->integer(1)->defaultValue(1), + ]); + + $this->createIndex( + 'idx-product_category-company_id', + 'product_category', + 'company_id' + ); + + // add foreign key for table `user` + $this->addForeignKey( + 'fk-product_category-company_id', + 'product_category', + 'company_id', + 'company', + 'id', + 'CASCADE' + ); + } + + /** + * {@inheritdoc} + */ + public function safeDown() + { + $this->dropForeignKey( + 'fk-product_category-company_id', + 'product_category' + ); + + // drops index for column `author_id` + $this->dropIndex( + 'idx-product_category-company_id', + 'product_category' + ); + $this->dropTable('{{%product_category}}'); + } +} diff --git a/console/models/.gitkeep b/console/models/.gitkeep new file mode 100644 index 0000000..72e8ffc --- /dev/null +++ b/console/models/.gitkeep @@ -0,0 +1 @@ +* diff --git a/console/runtime/.gitignore b/console/runtime/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/console/runtime/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..c8ad750 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,38 @@ +version: '3.2' + +services: + + frontend: + build: frontend + ports: + - 20080:80 + volumes: + # Re-use local composer cache via host-volume + - ~/.composer-docker/cache:/root/.composer/cache:delegated + # Mount source-code for development + - ./:/app + + backend: + build: backend + ports: + - 21080:80 + volumes: + # Re-use local composer cache via host-volume + - ~/.composer-docker/cache:/root/.composer/cache:delegated + # Mount source-code for development + - ./:/app + + mysql: + image: mysql:5.7 + environment: + - MYSQL_ROOT_PASSWORD=verysecret + - MYSQL_DATABASE=yii2advanced + - MYSQL_USER=yii2advanced + - MYSQL_PASSWORD=secret + + #pgsql: + # image: postgres:9.5 + # environment: + # - POSTGRES_DB=yii2advanced + # - POSTGRES_USER=yii2advanced + # - POSTGRES_PASSWORD=secret \ No newline at end of file diff --git a/environments/dev/backend/config/codeception-local.php b/environments/dev/backend/config/codeception-local.php new file mode 100644 index 0000000..2d875dd --- /dev/null +++ b/environments/dev/backend/config/codeception-local.php @@ -0,0 +1,11 @@ + [ + 'request' => [ + // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation + 'cookieValidationKey' => '', + ], + ], +]; + +if (!YII_ENV_TEST) { + // configuration adjustments for 'dev' environment + $config['bootstrap'][] = 'debug'; + $config['modules']['debug'] = [ + 'class' => \yii\debug\Module::class, + ]; + + $config['bootstrap'][] = 'gii'; + $config['modules']['gii'] = [ + 'class' => \yii\gii\Module::class, + ]; +} + +return $config; diff --git a/environments/dev/backend/config/params-local.php b/environments/dev/backend/config/params-local.php new file mode 100644 index 0000000..b625128 --- /dev/null +++ b/environments/dev/backend/config/params-local.php @@ -0,0 +1,4 @@ +run(); diff --git a/environments/dev/backend/web/index.php b/environments/dev/backend/web/index.php new file mode 100644 index 0000000..d0b6601 --- /dev/null +++ b/environments/dev/backend/web/index.php @@ -0,0 +1,18 @@ +run(); diff --git a/environments/dev/backend/web/robots.txt b/environments/dev/backend/web/robots.txt new file mode 100644 index 0000000..77470cb --- /dev/null +++ b/environments/dev/backend/web/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: / \ No newline at end of file diff --git a/environments/dev/common/config/codeception-local.php b/environments/dev/common/config/codeception-local.php new file mode 100644 index 0000000..654f801 --- /dev/null +++ b/environments/dev/common/config/codeception-local.php @@ -0,0 +1,16 @@ + [ + 'request' => [ + // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation + 'cookieValidationKey' => '', + ], + ], + ] +); diff --git a/environments/dev/common/config/main-local.php b/environments/dev/common/config/main-local.php new file mode 100644 index 0000000..d00db3e --- /dev/null +++ b/environments/dev/common/config/main-local.php @@ -0,0 +1,43 @@ + [ + 'db' => [ + 'class' => \yii\db\Connection::class, + 'dsn' => 'mysql:host=localhost;dbname=yii2advanced', + 'username' => 'root', + 'password' => '', + 'charset' => 'utf8', + ], + 'mailer' => [ + 'class' => \yii\symfonymailer\Mailer::class, + 'viewPath' => '@common/mail', + // send all mails to a file by default. + 'useFileTransport' => true, + // You have to set + // + // 'useFileTransport' => false, + // + // and configure a transport for the mailer to send real emails. + // + // SMTP server example: + // 'transport' => [ + // 'scheme' => 'smtps', + // 'host' => '', + // 'username' => '', + // 'password' => '', + // 'port' => 465, + // 'dsn' => 'native://default', + // ], + // + // DSN example: + // 'transport' => [ + // 'dsn' => 'smtp://user:pass@smtp.example.com:25', + // ], + // + // See: https://symfony.com/doc/current/mailer.html#using-built-in-transports + // Or if you use a 3rd party service, see: + // https://symfony.com/doc/current/mailer.html#using-a-3rd-party-transport + ], + ], +]; diff --git a/environments/dev/common/config/params-local.php b/environments/dev/common/config/params-local.php new file mode 100644 index 0000000..b625128 --- /dev/null +++ b/environments/dev/common/config/params-local.php @@ -0,0 +1,4 @@ + [ + 'db' => [ + 'dsn' => 'mysql:host=localhost;dbname=yii2advanced_test', + ], + ], +]; diff --git a/environments/dev/console/config/main-local.php b/environments/dev/console/config/main-local.php new file mode 100644 index 0000000..a3246e0 --- /dev/null +++ b/environments/dev/console/config/main-local.php @@ -0,0 +1,8 @@ + ['gii'], + 'modules' => [ + 'gii' => 'yii\gii\Module', + ], +]; diff --git a/environments/dev/console/config/params-local.php b/environments/dev/console/config/params-local.php new file mode 100644 index 0000000..b625128 --- /dev/null +++ b/environments/dev/console/config/params-local.php @@ -0,0 +1,4 @@ + [ + 'request' => [ + // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation + 'cookieValidationKey' => '', + ], + ], +]; + +if (!YII_ENV_TEST) { + // configuration adjustments for 'dev' environment + $config['bootstrap'][] = 'debug'; + $config['modules']['debug'] = [ + 'class' => \yii\debug\Module::class, + ]; + + $config['bootstrap'][] = 'gii'; + $config['modules']['gii'] = [ + 'class' => \yii\gii\Module::class, + ]; +} + +return $config; diff --git a/environments/dev/frontend/config/params-local.php b/environments/dev/frontend/config/params-local.php new file mode 100644 index 0000000..b625128 --- /dev/null +++ b/environments/dev/frontend/config/params-local.php @@ -0,0 +1,4 @@ +run(); diff --git a/environments/dev/frontend/web/index.php b/environments/dev/frontend/web/index.php new file mode 100644 index 0000000..d0b6601 --- /dev/null +++ b/environments/dev/frontend/web/index.php @@ -0,0 +1,18 @@ +run(); diff --git a/environments/dev/frontend/web/robots.txt b/environments/dev/frontend/web/robots.txt new file mode 100644 index 0000000..77470cb --- /dev/null +++ b/environments/dev/frontend/web/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: / \ No newline at end of file diff --git a/environments/dev/yii b/environments/dev/yii new file mode 100644 index 0000000..b93b5cf --- /dev/null +++ b/environments/dev/yii @@ -0,0 +1,24 @@ +#!/usr/bin/env php +run(); +exit($exitCode); diff --git a/environments/dev/yii_test b/environments/dev/yii_test new file mode 100644 index 0000000..63a4e7a --- /dev/null +++ b/environments/dev/yii_test @@ -0,0 +1,28 @@ +#!/usr/bin/env php +run(); +exit($exitCode); diff --git a/environments/dev/yii_test.bat b/environments/dev/yii_test.bat new file mode 100644 index 0000000..29fbbea --- /dev/null +++ b/environments/dev/yii_test.bat @@ -0,0 +1,15 @@ +@echo off + +rem ------------------------------------------------------------- +rem Yii command line bootstrap script for Windows. +rem ------------------------------------------------------------- + +@setlocal + +set YII_PATH=%~dp0 + +if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe + +"%PHP_COMMAND%" "%YII_PATH%yii_test" %* + +@endlocal diff --git a/environments/index.php b/environments/index.php new file mode 100644 index 0000000..1083c32 --- /dev/null +++ b/environments/index.php @@ -0,0 +1,68 @@ + [ + * 'path' => 'directory storing the local files', + * 'skipFiles' => [ + * // list of files that should only be copied once and skipped if they already exist + * ], + * 'setWritable' => [ + * // list of directories that should be set writable + * ], + * 'setExecutable' => [ + * // list of files that should be set executable + * ], + * 'setCookieValidationKey' => [ + * // list of config files that need to be inserted with automatically generated cookie validation keys + * ], + * 'createSymlink' => [ + * // list of symlinks to be created. Keys are symlinks, and values are the targets. + * ], + * ], + * ]; + * ``` + */ +return [ + 'Development' => [ + 'path' => 'dev', + 'setWritable' => [ + 'backend/runtime', + 'backend/web/assets', + 'console/runtime', + 'frontend/runtime', + 'frontend/web/assets', + ], + 'setExecutable' => [ + 'yii', + 'yii_test', + ], + 'setCookieValidationKey' => [ + 'backend/config/main-local.php', + 'common/config/codeception-local.php', + 'frontend/config/main-local.php', + ], + ], + 'Production' => [ + 'path' => 'prod', + 'setWritable' => [ + 'backend/runtime', + 'backend/web/assets', + 'console/runtime', + 'frontend/runtime', + 'frontend/web/assets', + ], + 'setExecutable' => [ + 'yii', + ], + 'setCookieValidationKey' => [ + 'backend/config/main-local.php', + 'frontend/config/main-local.php', + ], + ], +]; diff --git a/environments/prod/backend/config/main-local.php b/environments/prod/backend/config/main-local.php new file mode 100644 index 0000000..babe4a4 --- /dev/null +++ b/environments/prod/backend/config/main-local.php @@ -0,0 +1,10 @@ + [ + 'request' => [ + // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation + 'cookieValidationKey' => '', + ], + ], +]; diff --git a/environments/prod/backend/config/params-local.php b/environments/prod/backend/config/params-local.php new file mode 100644 index 0000000..b625128 --- /dev/null +++ b/environments/prod/backend/config/params-local.php @@ -0,0 +1,4 @@ +run(); diff --git a/environments/prod/backend/web/robots.txt b/environments/prod/backend/web/robots.txt new file mode 100644 index 0000000..77470cb --- /dev/null +++ b/environments/prod/backend/web/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: / \ No newline at end of file diff --git a/environments/prod/common/config/main-local.php b/environments/prod/common/config/main-local.php new file mode 100644 index 0000000..da5a6d3 --- /dev/null +++ b/environments/prod/common/config/main-local.php @@ -0,0 +1,17 @@ + [ + 'db' => [ + 'class' => \yii\db\Connection::class, + 'dsn' => 'mysql:host=localhost;dbname=yii2advanced', + 'username' => 'root', + 'password' => '', + 'charset' => 'utf8', + ], + 'mailer' => [ + 'class' => \yii\symfonymailer\Mailer::class, + 'viewPath' => '@common/mail', + ], + ], +]; diff --git a/environments/prod/common/config/params-local.php b/environments/prod/common/config/params-local.php new file mode 100644 index 0000000..b625128 --- /dev/null +++ b/environments/prod/common/config/params-local.php @@ -0,0 +1,4 @@ + [ + 'request' => [ + // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation + 'cookieValidationKey' => '', + ], + ], +]; diff --git a/environments/prod/frontend/config/params-local.php b/environments/prod/frontend/config/params-local.php new file mode 100644 index 0000000..b625128 --- /dev/null +++ b/environments/prod/frontend/config/params-local.php @@ -0,0 +1,4 @@ +run(); diff --git a/environments/prod/frontend/web/robots.txt b/environments/prod/frontend/web/robots.txt new file mode 100644 index 0000000..14267e9 --- /dev/null +++ b/environments/prod/frontend/web/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Allow: / \ No newline at end of file diff --git a/environments/prod/yii b/environments/prod/yii new file mode 100644 index 0000000..5b0d890 --- /dev/null +++ b/environments/prod/yii @@ -0,0 +1,24 @@ +#!/usr/bin/env php +run(); +exit($exitCode); diff --git a/frontend/Dockerfile b/frontend/Dockerfile new file mode 100644 index 0000000..a0487d2 --- /dev/null +++ b/frontend/Dockerfile @@ -0,0 +1,4 @@ +FROM yiisoftware/yii2-php:8.1-apache + +# Change document root for Apache +RUN sed -i -e 's|/app/web|/app/frontend/web|g' /etc/apache2/sites-available/000-default.conf diff --git a/frontend/assets/AppAsset.php b/frontend/assets/AppAsset.php new file mode 100644 index 0000000..f8478f6 --- /dev/null +++ b/frontend/assets/AppAsset.php @@ -0,0 +1,23 @@ + 'app-frontend', + 'basePath' => dirname(__DIR__), + 'bootstrap' => ['log'], + 'controllerNamespace' => 'frontend\controllers', + 'modules' => [ + 'company' => [ + 'class' => 'frontend\modules\company\Company', + ], + 'product' => [ + 'class' => 'frontend\modules\product\Product', + ], + 'addresses' => [ + 'class' => 'frontend\modules\addresses\Addresses', + ], + 'check' => [ + 'class' => 'frontend\modules\check\Check', + ], + 'product_category' => [ + 'class' => 'frontend\modules\product_category\ProductCategory', + ], + ], + 'components' => [ + 'request' => [ + 'csrfParam' => '_csrf-frontend', + ], + 'user' => [ + 'identityClass' => 'common\models\User', + 'enableAutoLogin' => true, + 'identityCookie' => ['name' => '_identity-frontend', 'httpOnly' => true], + ], + 'session' => [ + // this is the name of the session cookie used for login on the frontend + 'name' => 'advanced-frontend', + ], + 'view' => [ + + ], + 'log' => [ + 'traceLevel' => YII_DEBUG ? 3 : 0, + 'targets' => [ + [ + 'class' => \yii\log\FileTarget::class, + 'levels' => ['error', 'warning'], + ], + ], + ], + 'errorHandler' => [ + 'errorAction' => 'site/error', + ], + 'urlManager' => [ + 'enablePrettyUrl' => true, + 'showScriptName' => false, + 'rules' => [ + ], + ], + ], + 'params' => $params, +]; diff --git a/frontend/config/params.php b/frontend/config/params.php new file mode 100644 index 0000000..7f754b9 --- /dev/null +++ b/frontend/config/params.php @@ -0,0 +1,4 @@ + 'admin@example.com', +]; diff --git a/frontend/config/test.php b/frontend/config/test.php new file mode 100644 index 0000000..55d820c --- /dev/null +++ b/frontend/config/test.php @@ -0,0 +1,18 @@ + 'app-frontend-tests', + 'components' => [ + 'assetManager' => [ + 'basePath' => __DIR__ . '/../web/assets', + ], + 'urlManager' => [ + 'showScriptName' => true, + ], + 'request' => [ + 'cookieValidationKey' => 'test', + ], + 'mailer' => [ + 'messageClass' => \yii\symfonymailer\Message::class + ] + ], +]; diff --git a/frontend/controllers/SiteController.php b/frontend/controllers/SiteController.php new file mode 100644 index 0000000..e29f15e --- /dev/null +++ b/frontend/controllers/SiteController.php @@ -0,0 +1,265 @@ + [ + 'class' => AccessControl::class, + 'only' => ['logout', 'signup'], + 'rules' => [ + [ + 'actions' => ['signup'], + 'allow' => true, + 'roles' => ['?'], + ], + [ + 'actions' => ['logout'], + 'allow' => true, + 'roles' => ['@'], + ], + ], + ], + 'verbs' => [ + 'class' => VerbFilter::class, + 'actions' => [ + 'logout' => ['post'], + ], + ], + ]; + } + + /** + * {@inheritdoc} + */ + public function actions() + { + return [ + 'error' => [ + 'class' => \yii\web\ErrorAction::class, + ], + 'captcha' => [ + 'class' => \yii\captcha\CaptchaAction::class, + 'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null, + ], + ]; + } + + /** + * Displays homepage. + * + * @return mixed + */ + public function actionIndex() + { + return $this->render('index'); + } + + /** + * Logs in a user. + * + * @return mixed + */ + public function actionLogin() + { + $this->layout = 'main-login'; + + if (!Yii::$app->user->isGuest) { + return $this->goHome(); + } + + $model = new LoginForm(); + if ($model->load(Yii::$app->request->post()) && $model->login()) { + return $this->goBack(); + } + + $model->password = ''; + + return $this->render('login', [ + 'model' => $model, + ]); + } + + /** + * Logs out the current user. + * + * @return mixed + */ + public function actionLogout() + { + Yii::$app->user->logout(); + + return $this->goHome(); + } + + /** + * Displays contact page. + * + * @return mixed + */ + public function actionContact() + { + $model = new ContactForm(); + if ($model->load(Yii::$app->request->post()) && $model->validate()) { + if ($model->sendEmail(Yii::$app->params['adminEmail'])) { + Yii::$app->session->setFlash('success', 'Thank you for contacting us. We will respond to you as soon as possible.'); + } else { + Yii::$app->session->setFlash('error', 'There was an error sending your message.'); + } + + return $this->refresh(); + } + + return $this->render('contact', [ + 'model' => $model, + ]); + } + + /** + * Displays about page. + * + * @return mixed + */ + public function actionAbout() + { + return $this->render('about'); + } + + /** + * Signs user up. + * + * @return mixed + */ + public function actionSignup() + { + $this->layout = 'main-login'; + + $model = new SignupForm(); + if ($model->load(Yii::$app->request->post()) && $model->signup()) { + Yii::$app->session->setFlash('success', 'Спасиюо за регистрацию'); + return $this->goHome(); + } + + return $this->render('signup', [ + 'model' => $model, + ]); + } + + /** + * Requests password reset. + * + * @return mixed + */ + public function actionRequestPasswordReset() + { + $model = new PasswordResetRequestForm(); + if ($model->load(Yii::$app->request->post()) && $model->validate()) { + if ($model->sendEmail()) { + Yii::$app->session->setFlash('success', 'Check your email for further instructions.'); + + return $this->goHome(); + } + + Yii::$app->session->setFlash('error', 'Sorry, we are unable to reset password for the provided email address.'); + } + + return $this->render('requestPasswordResetToken', [ + 'model' => $model, + ]); + } + + /** + * Resets password. + * + * @param string $token + * @return mixed + * @throws BadRequestHttpException + */ + public function actionResetPassword($token) + { + try { + $model = new ResetPasswordForm($token); + } catch (InvalidArgumentException $e) { + throw new BadRequestHttpException($e->getMessage()); + } + + if ($model->load(Yii::$app->request->post()) && $model->validate() && $model->resetPassword()) { + Yii::$app->session->setFlash('success', 'New password saved.'); + + return $this->goHome(); + } + + return $this->render('resetPassword', [ + 'model' => $model, + ]); + } + + /** + * Verify email address + * + * @param string $token + * @throws BadRequestHttpException + * @return yii\web\Response + */ + public function actionVerifyEmail($token) + { + try { + $model = new VerifyEmailForm($token); + } catch (InvalidArgumentException $e) { + throw new BadRequestHttpException($e->getMessage()); + } + if (($user = $model->verifyEmail()) && Yii::$app->user->login($user)) { + Yii::$app->session->setFlash('success', 'Your email has been confirmed!'); + return $this->goHome(); + } + + Yii::$app->session->setFlash('error', 'Sorry, we are unable to verify your account with provided token.'); + return $this->goHome(); + } + + /** + * Resend verification email + * + * @return mixed + */ + public function actionResendVerificationEmail() + { + $model = new ResendVerificationEmailForm(); + if ($model->load(Yii::$app->request->post()) && $model->validate()) { + if ($model->sendEmail()) { + Yii::$app->session->setFlash('success', 'Check your email for further instructions.'); + return $this->goHome(); + } + Yii::$app->session->setFlash('error', 'Sorry, we are unable to resend verification email for the provided email address.'); + } + + return $this->render('resendVerificationEmail', [ + 'model' => $model + ]); + } +} diff --git a/frontend/models/ContactForm.php b/frontend/models/ContactForm.php new file mode 100644 index 0000000..1dd419c --- /dev/null +++ b/frontend/models/ContactForm.php @@ -0,0 +1,61 @@ + 'Verification Code', + ]; + } + + /** + * Sends an email to the specified email address using the information collected by this model. + * + * @param string $email the target email address + * @return bool whether the email was sent + */ + public function sendEmail($email) + { + return Yii::$app->mailer->compose() + ->setTo($email) + ->setFrom([Yii::$app->params['senderEmail'] => Yii::$app->params['senderName']]) + ->setReplyTo([$this->email => $this->name]) + ->setSubject($this->subject) + ->setTextBody($this->body) + ->send(); + } +} diff --git a/frontend/models/PasswordResetRequestForm.php b/frontend/models/PasswordResetRequestForm.php new file mode 100644 index 0000000..db963e3 --- /dev/null +++ b/frontend/models/PasswordResetRequestForm.php @@ -0,0 +1,69 @@ + '\common\models\User', + 'filter' => ['status' => User::STATUS_ACTIVE], + 'message' => 'There is no user with this email address.' + ], + ]; + } + + /** + * Sends an email with a link, for resetting the password. + * + * @return bool whether the email was send + */ + public function sendEmail() + { + /* @var $user User */ + $user = User::findOne([ + 'status' => User::STATUS_ACTIVE, + 'email' => $this->email, + ]); + + if (!$user) { + return false; + } + + if (!User::isPasswordResetTokenValid($user->password_reset_token)) { + $user->generatePasswordResetToken(); + if (!$user->save()) { + return false; + } + } + + return Yii::$app + ->mailer + ->compose( + ['html' => 'passwordResetToken-html', 'text' => 'passwordResetToken-text'], + ['user' => $user] + ) + ->setFrom([Yii::$app->params['supportEmail'] => Yii::$app->name . ' robot']) + ->setTo($this->email) + ->setSubject('Password reset for ' . Yii::$app->name) + ->send(); + } +} diff --git a/frontend/models/ResendVerificationEmailForm.php b/frontend/models/ResendVerificationEmailForm.php new file mode 100644 index 0000000..8fb265b --- /dev/null +++ b/frontend/models/ResendVerificationEmailForm.php @@ -0,0 +1,61 @@ + '\common\models\User', + 'filter' => ['status' => User::STATUS_INACTIVE], + 'message' => 'There is no user with this email address.' + ], + ]; + } + + /** + * Sends confirmation email to user + * + * @return bool whether the email was sent + */ + public function sendEmail() + { + $user = User::findOne([ + 'email' => $this->email, + 'status' => User::STATUS_INACTIVE + ]); + + if ($user === null) { + return false; + } + + return Yii::$app + ->mailer + ->compose( + ['html' => 'emailVerify-html', 'text' => 'emailVerify-text'], + ['user' => $user] + ) + ->setFrom([Yii::$app->params['supportEmail'] => Yii::$app->name . ' robot']) + ->setTo($this->email) + ->setSubject('Account registration at ' . Yii::$app->name) + ->send(); + } +} diff --git a/frontend/models/ResetPasswordForm.php b/frontend/models/ResetPasswordForm.php new file mode 100644 index 0000000..31c786f --- /dev/null +++ b/frontend/models/ResetPasswordForm.php @@ -0,0 +1,67 @@ +_user = User::findByPasswordResetToken($token); + if (!$this->_user) { + throw new InvalidArgumentException('Wrong password reset token.'); + } + parent::__construct($config); + } + + /** + * {@inheritdoc} + */ + public function rules() + { + return [ + ['password', 'required'], + ['password', 'string', 'min' => Yii::$app->params['user.passwordMinLength']], + ]; + } + + /** + * Resets password. + * + * @return bool if password was reset. + */ + public function resetPassword() + { + $user = $this->_user; + $user->setPassword($this->password); + $user->removePasswordResetToken(); + $user->generateAuthKey(); + + return $user->save(false); + } +} diff --git a/frontend/models/SignupForm.php b/frontend/models/SignupForm.php new file mode 100644 index 0000000..e42a8ca --- /dev/null +++ b/frontend/models/SignupForm.php @@ -0,0 +1,80 @@ + '\common\models\User', 'message' => 'This username has already been taken.'], + ['username', 'string', 'min' => 2, 'max' => 255], + + ['email', 'trim'], + ['email', 'required'], + ['email', 'email'], + ['email', 'string', 'max' => 255], + ['email', 'unique', 'targetClass' => '\common\models\User', 'message' => 'This email address has already been taken.'], + + ['password', 'required'], + ['password', 'string', 'min' => Yii::$app->params['user.passwordMinLength']], + ]; + } + + /** + * Signs user up. + * + * @return bool whether the creating new account was successful and email was sent + */ + public function signup() + { + if (!$this->validate()) { + return null; + } + + $user = new User(); + $user->username = $this->username; + $user->email = $this->email; + $user->setPassword($this->password); + $user->generateAuthKey(); + $user->generateEmailVerificationToken(); + + return $user->save() && $this->sendEmail($user); + } + + /** + * Sends confirmation email to user + * @param User $user user model to with email should be send + * @return bool whether the email was sent + */ + protected function sendEmail($user) + { + return Yii::$app + ->mailer + ->compose( + ['html' => 'emailVerify-html', 'text' => 'emailVerify-text'], + ['user' => $user] + ) + ->setFrom([Yii::$app->params['supportEmail'] => Yii::$app->name . ' robot']) + ->setTo($this->email) + ->setSubject('Account registration at ' . Yii::$app->name) + ->send(); + } +} diff --git a/frontend/models/VerifyEmailForm.php b/frontend/models/VerifyEmailForm.php new file mode 100644 index 0000000..0740746 --- /dev/null +++ b/frontend/models/VerifyEmailForm.php @@ -0,0 +1,52 @@ +_user = User::findByVerificationToken($token); + if (!$this->_user) { + throw new InvalidArgumentException('Wrong verify email token.'); + } + parent::__construct($config); + } + + /** + * Verify email + * + * @return User|null the saved model or null if saving fails + */ + public function verifyEmail() + { + $user = $this->_user; + $user->status = User::STATUS_ACTIVE; + return $user->save(false) ? $user : null; + } +} diff --git a/frontend/modules/addresses/Addresses.php b/frontend/modules/addresses/Addresses.php new file mode 100644 index 0000000..c67af94 --- /dev/null +++ b/frontend/modules/addresses/Addresses.php @@ -0,0 +1,24 @@ +companyService = new CompanyService(); + } + + /** + * {@inheritdoc} + */ + public function behaviors() + { + return [ + 'verbs' => [ + 'class' => VerbFilter::className(), + 'actions' => [ + 'delete' => ['POST'], + ], + ], + ]; + } + + /** + * Lists all Addresses models. + * @return mixed + */ + public function actionIndex() + { + $searchModel = new AddressesSearch(); + $dataProvider = $searchModel->search(Yii::$app->request->queryParams); + + return $this->render('index', [ + 'searchModel' => $searchModel, + 'dataProvider' => $dataProvider, + 'companyService' => $this->companyService, + ]); + } + + /** + * Displays a single Addresses model. + * @param int $id ID + * @return mixed + * @throws NotFoundHttpException if the model cannot be found + */ + public function actionView($id) + { + return $this->render('view', [ + 'model' => $this->findModel($id), + 'companyService' => $this->companyService, + ]); + } + + /** + * Creates a new Addresses model. + * If creation is successful, the browser will be redirected to the 'view' page. + * @return mixed + */ + public function actionCreate() + { + $model = new Addresses(); + + if ($model->load(Yii::$app->request->post()) && $model->save()) { + return $this->redirect(['view', 'id' => $model->id]); + } + + return $this->render('create', [ + 'model' => $model, + 'companyService' => $this->companyService, + ]); + } + + /** + * Updates an existing Addresses model. + * If update is successful, the browser will be redirected to the 'view' page. + * @param int $id ID + * @return mixed + * @throws NotFoundHttpException if the model cannot be found + */ + public function actionUpdate($id) + { + $model = $this->findModel($id); + + if ($model->load(Yii::$app->request->post()) && $model->save()) { + return $this->redirect(['view', 'id' => $model->id]); + } + + return $this->render('update', [ + 'model' => $model, + 'companyService' => $this->companyService + ]); + } + + /** + * Deletes an existing Addresses model. + * If deletion is successful, the browser will be redirected to the 'index' page. + * @param int $id ID + * @return mixed + * @throws NotFoundHttpException if the model cannot be found + */ + public function actionDelete($id) + { + $this->findModel($id)->delete(); + + return $this->redirect(['index']); + } + + /** + * Finds the Addresses model based on its primary key value. + * If the model is not found, a 404 HTTP exception will be thrown. + * @param int $id ID + * @return Addresses the loaded model + * @throws NotFoundHttpException if the model cannot be found + */ + protected function findModel($id) + { + if (($model = Addresses::findOne($id)) !== null) { + return $model; + } + + throw new NotFoundHttpException('The requested page does not exist.'); + } +} diff --git a/frontend/modules/addresses/controllers/DefaultController.php b/frontend/modules/addresses/controllers/DefaultController.php new file mode 100644 index 0000000..fed8c20 --- /dev/null +++ b/frontend/modules/addresses/controllers/DefaultController.php @@ -0,0 +1,20 @@ +render('index'); + } +} diff --git a/frontend/modules/addresses/models/Addresses.php b/frontend/modules/addresses/models/Addresses.php new file mode 100644 index 0000000..7decac8 --- /dev/null +++ b/frontend/modules/addresses/models/Addresses.php @@ -0,0 +1,8 @@ + $query, + ]); + + $this->load($params); + + if (!$this->validate()) { + // uncomment the following line if you do not want to return any records when validation fails + // $query->where('0=1'); + return $dataProvider; + } + + // grid filtering conditions + $query->andFilterWhere([ + 'id' => $this->id, + 'company_id' => $this->company_id, + ]); + + $query->andFilterWhere(['like', 'address', $this->address]) + ->andFilterWhere(['like', 'name', $this->name]); + + return $dataProvider; + } +} diff --git a/frontend/modules/addresses/views/addresses/_form.php b/frontend/modules/addresses/views/addresses/_form.php new file mode 100644 index 0000000..c26f675 --- /dev/null +++ b/frontend/modules/addresses/views/addresses/_form.php @@ -0,0 +1,29 @@ + + +
+ + + + field($model, 'address')->textInput(['maxlength' => true]) ?> + + field($model, 'company_id')->dropDownList($companyService->getCompaniesByUserArr()) ?> + + field($model, 'name')->textInput(['maxlength' => true]) ?> + +
+ 'btn btn-success']) ?> +
+ + + +
diff --git a/frontend/modules/addresses/views/addresses/_search.php b/frontend/modules/addresses/views/addresses/_search.php new file mode 100644 index 0000000..d0f6134 --- /dev/null +++ b/frontend/modules/addresses/views/addresses/_search.php @@ -0,0 +1,36 @@ + + +
+
+ + ['index'], + 'method' => 'get', + ]); ?> + + field($model, 'id') ?> + + field($model, 'address') ?> + + field($model, 'company_id') ?> + + field($model, 'name') ?> + +
+ 'btn btn-primary']) ?> + 'btn btn-outline-secondary']) ?> +
+ + + +
+ +
diff --git a/frontend/modules/addresses/views/addresses/create.php b/frontend/modules/addresses/views/addresses/create.php new file mode 100644 index 0000000..c4d7191 --- /dev/null +++ b/frontend/modules/addresses/views/addresses/create.php @@ -0,0 +1,30 @@ +title = 'Добавить отделение'; +$this->params['breadcrumbs'][] = ['label' => 'Отделения', 'url' => ['index']]; +$this->params['breadcrumbs'][] = $this->title; +?> + +
+
+
+
+
+ render('_form', [ + 'model' => $model, + 'companyService' => $companyService, + ]) ?> +
+
+
+ +
+ +
\ No newline at end of file diff --git a/frontend/modules/addresses/views/addresses/index.php b/frontend/modules/addresses/views/addresses/index.php new file mode 100644 index 0000000..1be0843 --- /dev/null +++ b/frontend/modules/addresses/views/addresses/index.php @@ -0,0 +1,62 @@ +title = 'Отделения'; +$this->params['breadcrumbs'][] = $this->title; +?> +
+
+
+
+
+
+
+ 'btn btn-success']) ?> +
+
+ + + render('_search', ['model' => $searchModel]); ?> + + $dataProvider, + 'filterModel' => $searchModel, + 'columns' => [ + ['class' => 'yii\grid\SerialColumn'], + + 'id', + 'address', + [ + 'attribute' => 'company_id', + 'value' => function($model) use ($companyService){ + return $companyService->getCompany($model->company_id)->name ?? null; + } + ], + 'name', + + ['class' => 'hail812\adminlte3\yii\grid\ActionColumn'], + ], + 'summaryOptions' => ['class' => 'summary mb-2'], + 'pager' => [ + 'class' => 'yii\bootstrap4\LinkPager', + ] + ]); ?> + + +
+ +
+ +
+ +
+ +
diff --git a/frontend/modules/addresses/views/addresses/update.php b/frontend/modules/addresses/views/addresses/update.php new file mode 100644 index 0000000..89c6683 --- /dev/null +++ b/frontend/modules/addresses/views/addresses/update.php @@ -0,0 +1,30 @@ +title = 'Update Addresses: ' . $model->name; +$this->params['breadcrumbs'][] = ['label' => 'Addresses', 'url' => ['index']]; +$this->params['breadcrumbs'][] = ['label' => $model->name, 'url' => ['view', 'id' => $model->id]]; +$this->params['breadcrumbs'][] = 'Update'; +?> + +
+
+
+
+
+ render('_form', [ + 'model' => $model, + 'companyService' => $companyService, + ]) ?> +
+
+
+ +
+ +
\ No newline at end of file diff --git a/frontend/modules/addresses/views/addresses/view.php b/frontend/modules/addresses/views/addresses/view.php new file mode 100644 index 0000000..f102c7a --- /dev/null +++ b/frontend/modules/addresses/views/addresses/view.php @@ -0,0 +1,53 @@ +title = $model->name; +$this->params['breadcrumbs'][] = ['label' => 'Addresses', 'url' => ['index']]; +$this->params['breadcrumbs'][] = $this->title; +\yii\web\YiiAsset::register($this); +?> + +
+
+
+
+
+

+ 'btn btn-primary']) ?> + $model->id], ['class' => 'btn btn-primary']) ?> + $model->id], [ + 'class' => 'btn btn-danger', + 'data' => [ + 'confirm' => 'Are you sure you want to delete this item?', + 'method' => 'post', + ], + ]) ?> +

+ $model, + 'attributes' => [ + 'id', + 'address', + [ + 'attribute' => 'company_id', + 'value' => $companyService->getCompany($model->company_id)->name ?? null, + ], + 'name', + ], + ]) ?> +
+ +
+ +
+ +
+ +
\ No newline at end of file diff --git a/frontend/modules/addresses/views/default/index.php b/frontend/modules/addresses/views/default/index.php new file mode 100644 index 0000000..f891fb1 --- /dev/null +++ b/frontend/modules/addresses/views/default/index.php @@ -0,0 +1,12 @@ +
+

context->action->uniqueId ?>

+

+ This is the view content for action "context->action->id ?>". + The action belongs to the controller "context) ?>" + in the "context->module->id ?>" module. +

+

+ You may customize this page by editing the following file:
+ +

+
diff --git a/frontend/modules/check/Check.php b/frontend/modules/check/Check.php new file mode 100644 index 0000000..049c5fe --- /dev/null +++ b/frontend/modules/check/Check.php @@ -0,0 +1,24 @@ + [ + 'class' => VerbFilter::className(), + 'actions' => [ + 'delete' => ['POST'], + ], + ], + ]; + } + + /** + * Lists all Check models. + * @return mixed + */ + public function actionIndex() + { + $searchModel = new CheckSearch(); + $dataProvider = $searchModel->search(Yii::$app->request->queryParams); + + return $this->render('index', [ + 'searchModel' => $searchModel, + 'dataProvider' => $dataProvider, + ]); + } + + /** + * Displays a single Check model. + * @param int $id ID + * @return mixed + * @throws NotFoundHttpException if the model cannot be found + */ + public function actionView($id) + { + return $this->render('view', [ + 'model' => $this->findModel($id), + ]); + } + + /** + * Creates a new Check model. + * If creation is successful, the browser will be redirected to the 'view' page. + * @return mixed + */ + public function actionCreate() + { + $model = new Check(); + + if ($model->load(Yii::$app->request->post()) && $model->save()) { + return $this->redirect(['view', 'id' => $model->id]); + } + + return $this->render('create', [ + 'model' => $model, + ]); + } + + /** + * Updates an existing Check model. + * If update is successful, the browser will be redirected to the 'view' page. + * @param int $id ID + * @return mixed + * @throws NotFoundHttpException if the model cannot be found + */ + public function actionUpdate($id) + { + $model = $this->findModel($id); + + if ($model->load(Yii::$app->request->post()) && $model->save()) { + return $this->redirect(['view', 'id' => $model->id]); + } + + return $this->render('update', [ + 'model' => $model, + ]); + } + + /** + * Deletes an existing Check model. + * If deletion is successful, the browser will be redirected to the 'index' page. + * @param int $id ID + * @return mixed + * @throws NotFoundHttpException if the model cannot be found + */ + public function actionDelete($id) + { + $this->findModel($id)->delete(); + + return $this->redirect(['index']); + } + + /** + * Finds the Check model based on its primary key value. + * If the model is not found, a 404 HTTP exception will be thrown. + * @param int $id ID + * @return Check the loaded model + * @throws NotFoundHttpException if the model cannot be found + */ + protected function findModel($id) + { + if (($model = Check::findOne($id)) !== null) { + return $model; + } + + throw new NotFoundHttpException('The requested page does not exist.'); + } +} diff --git a/frontend/modules/check/controllers/DefaultController.php b/frontend/modules/check/controllers/DefaultController.php new file mode 100644 index 0000000..a22b4fb --- /dev/null +++ b/frontend/modules/check/controllers/DefaultController.php @@ -0,0 +1,20 @@ +render('index'); + } +} diff --git a/frontend/modules/check/models/Check.php b/frontend/modules/check/models/Check.php new file mode 100644 index 0000000..3201843 --- /dev/null +++ b/frontend/modules/check/models/Check.php @@ -0,0 +1,8 @@ + $query, + ]); + + $this->load($params); + + if (!$this->validate()) { + // uncomment the following line if you do not want to return any records when validation fails + // $query->where('0=1'); + return $dataProvider; + } + + // grid filtering conditions + $query->andFilterWhere([ + 'id' => $this->id, + 'company_id' => $this->company_id, + 'addresses_id' => $this->addresses_id, + 'status' => $this->status, + ]); + + $query->andFilterWhere(['like', 'number', $this->number]) + ->andFilterWhere(['like', 'additional', $this->additional]); + + return $dataProvider; + } +} diff --git a/frontend/modules/check/views/check/_form.php b/frontend/modules/check/views/check/_form.php new file mode 100644 index 0000000..79f8add --- /dev/null +++ b/frontend/modules/check/views/check/_form.php @@ -0,0 +1,27 @@ + + +
+ + + + field($model, 'addresses_id')->dropDownList($companyService->getAddressesByUserArr()) ?> + + field($model, 'status')->dropDownList(\common\models\Check::getStatus()) ?> + +
+ 'btn btn-success']) ?> +
+ + + +
diff --git a/frontend/modules/check/views/check/_search.php b/frontend/modules/check/views/check/_search.php new file mode 100644 index 0000000..edcc7e9 --- /dev/null +++ b/frontend/modules/check/views/check/_search.php @@ -0,0 +1,40 @@ + + +
+
+ + ['index'], + 'method' => 'get', + ]); ?> + + field($model, 'id') ?> + + field($model, 'number') ?> + + field($model, 'company_id') ?> + + field($model, 'additional') ?> + + field($model, 'addresses_id') ?> + + field($model, 'status') ?> + +
+ 'btn btn-primary']) ?> + 'btn btn-outline-secondary']) ?> +
+ + + +
+ +
diff --git a/frontend/modules/check/views/check/create.php b/frontend/modules/check/views/check/create.php new file mode 100644 index 0000000..2395414 --- /dev/null +++ b/frontend/modules/check/views/check/create.php @@ -0,0 +1,27 @@ +title = 'Создать чек'; +$this->params['breadcrumbs'][] = ['label' => 'Чеки', 'url' => ['index']]; +$this->params['breadcrumbs'][] = $this->title; +?> + +
+
+
+
+
+ render('_form', [ + 'model' => $model + ]) ?> +
+
+
+ +
+ +
\ No newline at end of file diff --git a/frontend/modules/check/views/check/index.php b/frontend/modules/check/views/check/index.php new file mode 100644 index 0000000..34420f7 --- /dev/null +++ b/frontend/modules/check/views/check/index.php @@ -0,0 +1,58 @@ +title = 'Чеки'; +$this->params['breadcrumbs'][] = $this->title; +?> +
+
+
+
+
+
+
+ 'btn btn-success']) ?> +
+
+ + + render('_search', ['model' => $searchModel]); ?> + + $dataProvider, + 'filterModel' => $searchModel, + 'columns' => [ + ['class' => 'yii\grid\SerialColumn'], + +// 'id', + 'title', + 'number', + 'company_id', + 'additional:ntext', + //'addresses_id', + //'status', + + ['class' => 'hail812\adminlte3\yii\grid\ActionColumn'], + ], + 'summaryOptions' => ['class' => 'summary mb-2'], + 'pager' => [ + 'class' => 'yii\bootstrap4\LinkPager', + ] + ]); ?> + + +
+ +
+ +
+ +
+ +
diff --git a/frontend/modules/check/views/check/update.php b/frontend/modules/check/views/check/update.php new file mode 100644 index 0000000..63ed140 --- /dev/null +++ b/frontend/modules/check/views/check/update.php @@ -0,0 +1,26 @@ +title = 'Update Check: ' . $model->id; +$this->params['breadcrumbs'][] = ['label' => 'Checks', 'url' => ['index']]; +$this->params['breadcrumbs'][] = ['label' => $model->id, 'url' => ['view', 'id' => $model->id]]; +$this->params['breadcrumbs'][] = 'Update'; +?> + +
+
+
+
+
+ render('_form', [ + 'model' => $model + ]) ?> +
+
+
+ +
+ +
\ No newline at end of file diff --git a/frontend/modules/check/views/check/view.php b/frontend/modules/check/views/check/view.php new file mode 100644 index 0000000..f08b15a --- /dev/null +++ b/frontend/modules/check/views/check/view.php @@ -0,0 +1,49 @@ +title = $model->id; +$this->params['breadcrumbs'][] = ['label' => 'Checks', 'url' => ['index']]; +$this->params['breadcrumbs'][] = $this->title; +\yii\web\YiiAsset::register($this); +?> + +
+
+
+
+
+

+ $model->id], ['class' => 'btn btn-primary']) ?> + $model->id], [ + 'class' => 'btn btn-danger', + 'data' => [ + 'confirm' => 'Are you sure you want to delete this item?', + 'method' => 'post', + ], + ]) ?> +

+ $model, + 'attributes' => [ + 'id', + 'number', + 'company_id', + 'additional:ntext', + 'addresses_id', + 'status', + ], + ]) ?> +
+ +
+ +
+ +
+ +
\ No newline at end of file diff --git a/frontend/modules/check/views/default/index.php b/frontend/modules/check/views/default/index.php new file mode 100644 index 0000000..9c7f0dc --- /dev/null +++ b/frontend/modules/check/views/default/index.php @@ -0,0 +1,12 @@ +
+

context->action->uniqueId ?>

+

+ This is the view content for action "context->action->id ?>". + The action belongs to the controller "context) ?>" + in the "context->module->id ?>" module. +

+

+ You may customize this page by editing the following file:
+ +

+
diff --git a/frontend/modules/company/Company.php b/frontend/modules/company/Company.php new file mode 100644 index 0000000..dc775fc --- /dev/null +++ b/frontend/modules/company/Company.php @@ -0,0 +1,24 @@ +service = new CompanyService(); + } + + /** + * @inheritDoc + */ + public function behaviors() + { + return array_merge( + parent::behaviors(), + [ + 'verbs' => [ + 'class' => VerbFilter::className(), + 'actions' => [ + 'delete' => ['POST'], + ], + ], + 'access' => [ + 'class' => \yii\filters\AccessControl::className(), + 'rules' => [ + [ + 'allow' => true, + 'roles' => ['@'], + ], + ], + ], + ] + ); + } + + /** + * Lists all Company models. + * + * @return string + */ + public function actionIndex() + { + $searchModel = new CompanySearch(); + $dataProvider = $searchModel->search($this->request->queryParams); + + return $this->render('index', [ + 'searchModel' => $searchModel, + 'dataProvider' => $dataProvider, + ]); + } + + /** + * Displays a single Company model. + * @param int $id ID + * @return string + * @throws NotFoundHttpException if the model cannot be found + */ + public function actionView($id) + { + return $this->render('view', [ + 'model' => $this->findModel($id), + ]); + } + + /** + * Creates a new Company model. + * If creation is successful, the browser will be redirected to the 'view' page. + * @return string|\yii\web\Response + */ + public function actionCreate() + { + $model = new Company(); + $model->user_id = \Yii::$app->user->id; + + if ($this->request->isPost) { + if ($model->load($this->request->post()) && $model->save()) { + return $this->redirect(['view', 'id' => $model->id]); + } + } else { + $model->loadDefaultValues(); + } + + return $this->render('create', [ + 'model' => $model, + 'companies' => $this->service->getCompaniesByUserArr(), + ]); + } + + /** + * Updates an existing Company model. + * If update is successful, the browser will be redirected to the 'view' page. + * @param int $id ID + * @return string|\yii\web\Response + * @throws NotFoundHttpException if the model cannot be found + */ + public function actionUpdate(int $id) + { + $model = $this->findModel($id); + + if ($this->request->isPost && $model->load($this->request->post()) && $model->save()) { + return $this->redirect(['view', 'id' => $model->id]); + } + + return $this->render('update', [ + 'model' => $model, + ]); + } + + /** + * Deletes an existing Company model. + * If deletion is successful, the browser will be redirected to the 'index' page. + * @param int $id ID + * @return \yii\web\Response + * @throws NotFoundHttpException if the model cannot be found + */ + public function actionDelete($id) + { + $this->findModel($id)->delete(); + + return $this->redirect(['index']); + } + + /** + * Finds the Company model based on its primary key value. + * If the model is not found, a 404 HTTP exception will be thrown. + * @param int $id ID + * @return Company the loaded model + * @throws NotFoundHttpException if the model cannot be found + */ + protected function findModel($id) + { + if (($model = Company::findOne(['id' => $id])) !== null) { + return $model; + } + + throw new NotFoundHttpException('The requested page does not exist.'); + } +} diff --git a/frontend/modules/company/controllers/DefaultController.php b/frontend/modules/company/controllers/DefaultController.php new file mode 100644 index 0000000..e527435 --- /dev/null +++ b/frontend/modules/company/controllers/DefaultController.php @@ -0,0 +1,20 @@ +render('index'); + } +} diff --git a/frontend/modules/company/models/Company.php b/frontend/modules/company/models/Company.php new file mode 100644 index 0000000..ef6da03 --- /dev/null +++ b/frontend/modules/company/models/Company.php @@ -0,0 +1,8 @@ + $query, + ]); + + $this->load($params); + + if (!$this->validate()) { + // uncomment the following line if you do not want to return any records when validation fails + // $query->where('0=1'); + return $dataProvider; + } + + $query->where(['user_id' => \Yii::$app->user->id]); + + // grid filtering conditions + $query->andFilterWhere([ + 'id' => $this->id, + 'inn' => $this->inn, + 'created_at' => $this->created_at, + 'updated_at' => $this->updated_at, + 'status' => $this->status, + ]); + + $query->andFilterWhere(['like', 'name', $this->name]) + ->andFilterWhere(['like', 'address', $this->address]); + + $query->orderBy("id DESC"); + + return $dataProvider; + } +} diff --git a/frontend/modules/company/views/company/_form.php b/frontend/modules/company/views/company/_form.php new file mode 100644 index 0000000..3958f16 --- /dev/null +++ b/frontend/modules/company/views/company/_form.php @@ -0,0 +1,29 @@ + + +
+ + + + field($model, 'inn')->textInput() ?> + + field($model, 'name')->textInput(['maxlength' => true]) ?> + + field($model, 'address')->textInput(['maxlength' => true]) ?> + + field($model, 'status')->dropDownList(\common\models\Company::getStatus()) ?> + +
+ 'btn btn-success']) ?> +
+ + + +
diff --git a/frontend/modules/company/views/company/_search.php b/frontend/modules/company/views/company/_search.php new file mode 100644 index 0000000..2e9a1a5 --- /dev/null +++ b/frontend/modules/company/views/company/_search.php @@ -0,0 +1,39 @@ + + + diff --git a/frontend/modules/company/views/company/create.php b/frontend/modules/company/views/company/create.php new file mode 100644 index 0000000..3cdbc7f --- /dev/null +++ b/frontend/modules/company/views/company/create.php @@ -0,0 +1,18 @@ +title = 'Добавить'; +$this->params['breadcrumbs'][] = ['label' => 'Компании', 'url' => ['index']]; +$this->params['breadcrumbs'][] = $this->title; +?> +
+ + render('_form', [ + 'model' => $model, + ]) ?> + +
diff --git a/frontend/modules/company/views/company/index.php b/frontend/modules/company/views/company/index.php new file mode 100644 index 0000000..cad38f9 --- /dev/null +++ b/frontend/modules/company/views/company/index.php @@ -0,0 +1,47 @@ +title = 'Компании'; +$this->params['breadcrumbs'][] = $this->title; +?> +
+ +

+ 'btn btn-success']) ?> +

+ + render('_search', ['model' => $searchModel]); ?> + + $dataProvider, + 'filterModel' => $searchModel, + 'columns' => [ + ['class' => 'yii\grid\SerialColumn'], + + 'id', + 'inn', + 'name', + 'address', + 'created_at', + //'updated_at', + //'status', + [ + 'class' => ActionColumn::className(), + 'urlCreator' => function ($action, Company $model, $key, $index, $column) { + return Url::toRoute([$action, 'id' => $model->id]); + } + ], + ], + ]); ?> + + +
diff --git a/frontend/modules/company/views/company/update.php b/frontend/modules/company/views/company/update.php new file mode 100644 index 0000000..9c8f38a --- /dev/null +++ b/frontend/modules/company/views/company/update.php @@ -0,0 +1,19 @@ +title = 'Редактировать: ' . $model->name; +$this->params['breadcrumbs'][] = ['label' => 'Компании', 'url' => ['index']]; +$this->params['breadcrumbs'][] = ['label' => $model->name, 'url' => ['view', 'id' => $model->id]]; +$this->params['breadcrumbs'][] = 'Редактировать'; +?> +
+ + render('_form', [ + 'model' => $model, + ]) ?> + +
diff --git a/frontend/modules/company/views/company/view.php b/frontend/modules/company/views/company/view.php new file mode 100644 index 0000000..d7a091c --- /dev/null +++ b/frontend/modules/company/views/company/view.php @@ -0,0 +1,41 @@ +title = $model->name; +$this->params['breadcrumbs'][] = ['label' => 'Компании', 'url' => ['index']]; +$this->params['breadcrumbs'][] = $this->title; +\yii\web\YiiAsset::register($this); +?> +
+ +

+ 'btn btn-primary']) ?> + $model->id], ['class' => 'btn btn-primary']) ?> + $model->id], [ + 'class' => 'btn btn-danger', + 'data' => [ + 'confirm' => 'Are you sure you want to delete this item?', + 'method' => 'post', + ], + ]) ?> +

+ + $model, + 'attributes' => [ + 'id', + 'inn', + 'name', + 'address', + 'created_at', + 'updated_at', + 'status', + ], + ]) ?> + +
diff --git a/frontend/modules/company/views/default/index.php b/frontend/modules/company/views/default/index.php new file mode 100644 index 0000000..9b6a7bf --- /dev/null +++ b/frontend/modules/company/views/default/index.php @@ -0,0 +1,12 @@ +
+

context->action->uniqueId ?>

+

+ This is the view content for action "context->action->id ?>". + The action belongs to the controller "context) ?>" + in the "context->module->id ?>" module. +

+

+ You may customize this page by editing the following file:
+ +

+
diff --git a/frontend/modules/product/Product.php b/frontend/modules/product/Product.php new file mode 100644 index 0000000..eb8e8a5 --- /dev/null +++ b/frontend/modules/product/Product.php @@ -0,0 +1,24 @@ +render('index'); + } +} diff --git a/frontend/modules/product/controllers/ProductController.php b/frontend/modules/product/controllers/ProductController.php new file mode 100644 index 0000000..1b33516 --- /dev/null +++ b/frontend/modules/product/controllers/ProductController.php @@ -0,0 +1,139 @@ +companyService = new CompanyService(); + } + + /** + * {@inheritdoc} + */ + public function behaviors() + { + return [ + 'verbs' => [ + 'class' => VerbFilter::className(), + 'actions' => [ + 'delete' => ['POST'], + ], + ], + ]; + } + + /** + * Lists all Product models. + * @return mixed + */ + public function actionIndex() + { + $searchModel = new ProductSearch(); + $dataProvider = $searchModel->search(Yii::$app->request->queryParams); + + return $this->render('index', [ + 'searchModel' => $searchModel, + 'dataProvider' => $dataProvider, + ]); + } + + /** + * Displays a single Product model. + * @param int $id ID + * @return mixed + * @throws NotFoundHttpException if the model cannot be found + */ + public function actionView($id) + { + return $this->render('view', [ + 'model' => $this->findModel($id), + 'companyService' => $this->companyService, + ]); + } + + /** + * Creates a new Product model. + * If creation is successful, the browser will be redirected to the 'view' page. + * @return mixed + */ + public function actionCreate() + { + $model = new Product(); + + if ($model->load(Yii::$app->request->post()) && $model->save()) { + return $this->redirect(['view', 'id' => $model->id]); + } + + return $this->render('create', [ + 'model' => $model, + 'companies' => $this->companyService->getCompaniesByUserArr(), + ]); + } + + /** + * Updates an existing Product model. + * If update is successful, the browser will be redirected to the 'view' page. + * @param int $id ID + * @return mixed + * @throws NotFoundHttpException if the model cannot be found + */ + public function actionUpdate($id) + { + $model = $this->findModel($id); + + if ($model->load(Yii::$app->request->post()) && $model->save()) { + return $this->redirect(['view', 'id' => $model->id]); + } + + return $this->render('update', [ + 'model' => $model, + 'companies' => $this->companyService->getCompaniesByUserArr(), + ]); + } + + /** + * Deletes an existing Product model. + * If deletion is successful, the browser will be redirected to the 'index' page. + * @param int $id ID + * @return mixed + * @throws NotFoundHttpException if the model cannot be found + */ + public function actionDelete($id) + { + $this->findModel($id)->delete(); + + return $this->redirect(['index']); + } + + /** + * Finds the Product model based on its primary key value. + * If the model is not found, a 404 HTTP exception will be thrown. + * @param int $id ID + * @return Product the loaded model + * @throws NotFoundHttpException if the model cannot be found + */ + protected function findModel($id) + { + if (($model = Product::findOne($id)) !== null) { + return $model; + } + + throw new NotFoundHttpException('The requested page does not exist.'); + } +} diff --git a/frontend/modules/product/models/Product.php b/frontend/modules/product/models/Product.php new file mode 100644 index 0000000..e162c4d --- /dev/null +++ b/frontend/modules/product/models/Product.php @@ -0,0 +1,8 @@ + $query, + ]); + + $this->load($params); + + if (!$this->validate()) { + // uncomment the following line if you do not want to return any records when validation fails + // $query->where('0=1'); + return $dataProvider; + } + + // grid filtering conditions + $query->andFilterWhere([ + 'id' => $this->id, + 'company_id' => $this->company_id, + 'type' => $this->type, + 'price' => $this->price, + 'status' => $this->status, + ]); + + $query->andFilterWhere(['like', 'title', $this->title]) + ->andFilterWhere(['like', 'article', $this->article]); + + return $dataProvider; + } +} diff --git a/frontend/modules/product/views/default/index.php b/frontend/modules/product/views/default/index.php new file mode 100644 index 0000000..218cc44 --- /dev/null +++ b/frontend/modules/product/views/default/index.php @@ -0,0 +1,12 @@ +
+

context->action->uniqueId ?>

+

+ This is the view content for action "context->action->id ?>". + The action belongs to the controller "context) ?>" + in the "context->module->id ?>" module. +

+

+ You may customize this page by editing the following file:
+ +

+
diff --git a/frontend/modules/product/views/product/_form.php b/frontend/modules/product/views/product/_form.php new file mode 100644 index 0000000..aeca88c --- /dev/null +++ b/frontend/modules/product/views/product/_form.php @@ -0,0 +1,34 @@ + + +
+ + + + field($model, 'title')->textInput(['maxlength' => true]) ?> + + field($model, 'article')->textInput(['maxlength' => true]) ?> + + field($model, 'company_id')->dropDownList($companies) ?> + + field($model, 'type')->dropDownList(\common\models\Product::getType()) ?> + + field($model, 'price')->textInput() ?> + + field($model, 'status')->dropDownList(\common\models\Product::getStatus(), ['prompt' => 'Выберите статус']) ?> + +
+ 'btn btn-success']) ?> +
+ + + +
diff --git a/frontend/modules/product/views/product/_search.php b/frontend/modules/product/views/product/_search.php new file mode 100644 index 0000000..69c1a50 --- /dev/null +++ b/frontend/modules/product/views/product/_search.php @@ -0,0 +1,42 @@ + + +
+
+ + ['index'], + 'method' => 'get', + ]); ?> + + field($model, 'id') ?> + + field($model, 'title') ?> + + field($model, 'article') ?> + + field($model, 'company_id') ?> + + field($model, 'type') ?> + + field($model, 'price') ?> + + field($model, 'status') ?> + +
+ 'btn btn-primary']) ?> + 'btn btn-outline-secondary']) ?> +
+ + + +
+ +
diff --git a/frontend/modules/product/views/product/create.php b/frontend/modules/product/views/product/create.php new file mode 100644 index 0000000..b272e64 --- /dev/null +++ b/frontend/modules/product/views/product/create.php @@ -0,0 +1,29 @@ +title = 'Добавить продукт'; +$this->params['breadcrumbs'][] = ['label' => 'Продукты', 'url' => ['index']]; +$this->params['breadcrumbs'][] = $this->title; +?> + +
+
+
+
+
+ render('_form', [ + 'model' => $model, + 'companies' => $companies, + ]) ?> +
+
+
+ +
+ +
\ No newline at end of file diff --git a/frontend/modules/product/views/product/index.php b/frontend/modules/product/views/product/index.php new file mode 100644 index 0000000..c061d8e --- /dev/null +++ b/frontend/modules/product/views/product/index.php @@ -0,0 +1,58 @@ +title = 'Товары'; +$this->params['breadcrumbs'][] = $this->title; +?> +
+
+
+
+
+
+
+ 'btn btn-success']) ?> +
+
+ + + render('_search', ['model' => $searchModel]); ?> + + $dataProvider, + 'filterModel' => $searchModel, + 'columns' => [ + ['class' => 'yii\grid\SerialColumn'], + + //'id', + 'title', + 'article', + //'company_id', + //'type', + //'price', + //'status', + + ['class' => 'hail812\adminlte3\yii\grid\ActionColumn'], + ], + 'summaryOptions' => ['class' => 'summary mb-2'], + 'pager' => [ + 'class' => 'yii\bootstrap4\LinkPager', + ] + ]); ?> + + +
+ +
+ +
+ +
+ +
diff --git a/frontend/modules/product/views/product/update.php b/frontend/modules/product/views/product/update.php new file mode 100644 index 0000000..5778165 --- /dev/null +++ b/frontend/modules/product/views/product/update.php @@ -0,0 +1,28 @@ +title = 'Редактировать: ' . $model->title; +$this->params['breadcrumbs'][] = ['label' => 'Товары', 'url' => ['index']]; +$this->params['breadcrumbs'][] = ['label' => $model->title, 'url' => ['view', 'id' => $model->id]]; +$this->params['breadcrumbs'][] = 'Редактировать'; +?> + +
+
+
+
+
+ render('_form', [ + 'model' => $model, + 'companies' => $companies, + ]) ?> +
+
+
+ +
+ +
\ No newline at end of file diff --git a/frontend/modules/product/views/product/view.php b/frontend/modules/product/views/product/view.php new file mode 100644 index 0000000..86e2e40 --- /dev/null +++ b/frontend/modules/product/views/product/view.php @@ -0,0 +1,62 @@ +title = $model->title; +$this->params['breadcrumbs'][] = ['label' => 'Продукты', 'url' => ['index']]; +$this->params['breadcrumbs'][] = $this->title; +\yii\web\YiiAsset::register($this); +?> + +
+
+
+
+
+

+ 'btn btn-primary']) ?> + $model->id], ['class' => 'btn btn-primary']) ?> + $model->id], [ + 'class' => 'btn btn-danger', + 'data' => [ + 'confirm' => 'Are you sure you want to delete this item?', + 'method' => 'post', + ], + ]) ?> +

+ $model, + 'attributes' => [ + 'id', + 'title', + 'article', + [ + 'attribute' => 'company_id', + 'value' => $companyService->getCompany($model->company_id)->name ?? null + ], + [ + 'attribute' => 'type', + 'value' => \common\models\Product::getType()[$model->type] + ], + 'price', + [ + 'attribute' => 'status', + 'value' => \common\models\Product::getStatus()[$model->status] + ], + ], + ]) ?> +
+ +
+ +
+ +
+ +
\ No newline at end of file diff --git a/frontend/modules/product_category/ProductCategory.php b/frontend/modules/product_category/ProductCategory.php new file mode 100644 index 0000000..3b6005f --- /dev/null +++ b/frontend/modules/product_category/ProductCategory.php @@ -0,0 +1,24 @@ +render('index'); + } +} diff --git a/frontend/modules/product_category/controllers/ProductCategoryController.php b/frontend/modules/product_category/controllers/ProductCategoryController.php new file mode 100644 index 0000000..9c09e16 --- /dev/null +++ b/frontend/modules/product_category/controllers/ProductCategoryController.php @@ -0,0 +1,132 @@ + [ + 'class' => VerbFilter::className(), + 'actions' => [ + 'delete' => ['POST'], + ], + ], + ]; + } + + /** + * Lists all ProductCategory models. + * @return mixed + */ + public function actionIndex() + { + $searchModel = new ProductCategorySearch(); + $dataProvider = $searchModel->search(Yii::$app->request->queryParams); + + return $this->render('index', [ + 'searchModel' => $searchModel, + 'dataProvider' => $dataProvider, + ]); + } + + /** + * Displays a single ProductCategory model. + * @param int $id ID + * @return mixed + * @throws NotFoundHttpException if the model cannot be found + */ + public function actionView($id) + { + return $this->render('view', [ + 'model' => $this->findModel($id), + ]); + } + + /** + * Creates a new ProductCategory model. + * If creation is successful, the browser will be redirected to the 'view' page. + * @return mixed + */ + public function actionCreate() + { + $model = new ProductCategory(); + $user = User::findOne(Yii::$app->user->id); + + if ($model->load(Yii::$app->request->post()) && $model->save()) { + return $this->redirect(['view', 'id' => $model->id]); + } + + return $this->render('create', [ + 'model' => $model, + 'user' => $user, + ]); + } + + /** + * Updates an existing ProductCategory model. + * If update is successful, the browser will be redirected to the 'view' page. + * @param int $id ID + * @return mixed + * @throws NotFoundHttpException if the model cannot be found + */ + public function actionUpdate($id) + { + $model = $this->findModel($id); + + if ($model->load(Yii::$app->request->post()) && $model->save()) { + return $this->redirect(['view', 'id' => $model->id]); + } + + return $this->render('update', [ + 'model' => $model, + ]); + } + + /** + * Deletes an existing ProductCategory model. + * If deletion is successful, the browser will be redirected to the 'index' page. + * @param int $id ID + * @return mixed + * @throws NotFoundHttpException if the model cannot be found + */ + public function actionDelete($id) + { + $this->findModel($id)->delete(); + + return $this->redirect(['index']); + } + + /** + * Finds the ProductCategory model based on its primary key value. + * If the model is not found, a 404 HTTP exception will be thrown. + * @param int $id ID + * @return ProductCategory the loaded model + * @throws NotFoundHttpException if the model cannot be found + */ + protected function findModel($id) + { + if (($model = ProductCategory::findOne($id)) !== null) { + return $model; + } + + throw new NotFoundHttpException('The requested page does not exist.'); + } +} diff --git a/frontend/modules/product_category/models/ProductCategory.php b/frontend/modules/product_category/models/ProductCategory.php new file mode 100644 index 0000000..d2b5af7 --- /dev/null +++ b/frontend/modules/product_category/models/ProductCategory.php @@ -0,0 +1,8 @@ + $query, + ]); + + $this->load($params); + + if (!$this->validate()) { + // uncomment the following line if you do not want to return any records when validation fails + // $query->where('0=1'); + return $dataProvider; + } + + // grid filtering conditions + $query->andFilterWhere([ + 'id' => $this->id, + 'parent_id' => $this->parent_id, + 'company_id' => $this->company_id, + 'status' => $this->status, + ]); + + $query->andFilterWhere(['like', 'title', $this->title]); + + return $dataProvider; + } +} diff --git a/frontend/modules/product_category/views/default/index.php b/frontend/modules/product_category/views/default/index.php new file mode 100644 index 0000000..7cc0ca0 --- /dev/null +++ b/frontend/modules/product_category/views/default/index.php @@ -0,0 +1,12 @@ +
+

context->action->uniqueId ?>

+

+ This is the view content for action "context->action->id ?>". + The action belongs to the controller "context) ?>" + in the "context->module->id ?>" module. +

+

+ You may customize this page by editing the following file:
+ +

+
diff --git a/frontend/modules/product_category/views/product-category/_form.php b/frontend/modules/product_category/views/product-category/_form.php new file mode 100644 index 0000000..8a8304e --- /dev/null +++ b/frontend/modules/product_category/views/product-category/_form.php @@ -0,0 +1,32 @@ + + +
+ + + + field($model, 'title')->textInput(['maxlength' => true]) ?> + + field($model, 'company_id')->dropDownList(ArrayHelper::map($user->getMyCompany()->asArray()->all(), 'id', 'name')) ?> + + field($model, 'parent_id')->textInput() ?> + + field($model, 'status')->dropDownList(\common\models\ProductCategory::getStatus()) ?> + +
+ 'btn btn-success']) ?> +
+ + + +
diff --git a/frontend/modules/product_category/views/product-category/_search.php b/frontend/modules/product_category/views/product-category/_search.php new file mode 100644 index 0000000..f5496f3 --- /dev/null +++ b/frontend/modules/product_category/views/product-category/_search.php @@ -0,0 +1,38 @@ + + +
+
+ + ['index'], + 'method' => 'get', + ]); ?> + + field($model, 'id') ?> + + field($model, 'title') ?> + + field($model, 'parent_id') ?> + + field($model, 'company_id') ?> + + field($model, 'status') ?> + +
+ 'btn btn-primary']) ?> + 'btn btn-outline-secondary']) ?> +
+ + + +
+ +
diff --git a/frontend/modules/product_category/views/product-category/create.php b/frontend/modules/product_category/views/product-category/create.php new file mode 100644 index 0000000..0c95871 --- /dev/null +++ b/frontend/modules/product_category/views/product-category/create.php @@ -0,0 +1,30 @@ +title = 'Добавить категорию'; +$this->params['breadcrumbs'][] = ['label' => 'Категории товаров', 'url' => ['index']]; +$this->params['breadcrumbs'][] = $this->title; +?> + +
+
+
+
+
+ render('_form', [ + 'model' => $model, + 'user' => $user, + ]) ?> +
+
+
+ +
+ +
\ No newline at end of file diff --git a/frontend/modules/product_category/views/product-category/index.php b/frontend/modules/product_category/views/product-category/index.php new file mode 100644 index 0000000..5b40cc2 --- /dev/null +++ b/frontend/modules/product_category/views/product-category/index.php @@ -0,0 +1,56 @@ +title = 'Категории товаров'; +$this->params['breadcrumbs'][] = $this->title; +?> +
+
+
+
+
+
+
+ 'btn btn-success']) ?> +
+
+ + + render('_search', ['model' => $searchModel]); ?> + + $dataProvider, + 'filterModel' => $searchModel, + 'columns' => [ + ['class' => 'yii\grid\SerialColumn'], + + 'id', + 'title', + //'parent_id', + 'company_id', + 'status', + + ['class' => 'hail812\adminlte3\yii\grid\ActionColumn'], + ], + 'summaryOptions' => ['class' => 'summary mb-2'], + 'pager' => [ + 'class' => 'yii\bootstrap4\LinkPager', + ] + ]); ?> + + +
+ +
+ +
+ +
+ +
diff --git a/frontend/modules/product_category/views/product-category/update.php b/frontend/modules/product_category/views/product-category/update.php new file mode 100644 index 0000000..894b3a6 --- /dev/null +++ b/frontend/modules/product_category/views/product-category/update.php @@ -0,0 +1,30 @@ +title = 'Update Product Category: ' . $model->title; +$this->params['breadcrumbs'][] = ['label' => 'Product Categories', 'url' => ['index']]; +$this->params['breadcrumbs'][] = ['label' => $model->title, 'url' => ['view', 'id' => $model->id]]; +$this->params['breadcrumbs'][] = 'Update'; +?> + +
+
+
+
+
+ render('_form', [ + 'model' => $model, + 'user' => $user, + ]) ?> +
+
+
+ +
+ +
\ No newline at end of file diff --git a/frontend/modules/product_category/views/product-category/view.php b/frontend/modules/product_category/views/product-category/view.php new file mode 100644 index 0000000..8dc5a28 --- /dev/null +++ b/frontend/modules/product_category/views/product-category/view.php @@ -0,0 +1,48 @@ +title = $model->title; +$this->params['breadcrumbs'][] = ['label' => 'Product Categories', 'url' => ['index']]; +$this->params['breadcrumbs'][] = $this->title; +\yii\web\YiiAsset::register($this); +?> + +
+
+
+
+
+

+ $model->id], ['class' => 'btn btn-primary']) ?> + $model->id], [ + 'class' => 'btn btn-danger', + 'data' => [ + 'confirm' => 'Are you sure you want to delete this item?', + 'method' => 'post', + ], + ]) ?> +

+ $model, + 'attributes' => [ + 'id', + 'title', + 'parent_id', + 'company_id', + 'status', + ], + ]) ?> +
+ +
+ +
+ +
+ +
\ No newline at end of file diff --git a/frontend/runtime/.gitignore b/frontend/runtime/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/frontend/runtime/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/frontend/tests/_bootstrap.php b/frontend/tests/_bootstrap.php new file mode 100644 index 0000000..637ce14 --- /dev/null +++ b/frontend/tests/_bootstrap.php @@ -0,0 +1,10 @@ + 'erau', + 'auth_key' => 'tUu1qHcde0diwUol3xeI-18MuHkkprQI', + // password_0 + 'password_hash' => '$2y$13$nJ1WDlBaGcbCdbNC5.5l4.sgy.OMEKCqtDQOdQ2OWpgiKRWYyzzne', + 'password_reset_token' => 'RkD_Jw0_8HEedzLk7MM-ZKEFfYR7VbMr_1392559490', + 'created_at' => '1392559490', + 'updated_at' => '1392559490', + 'email' => 'sfriesen@jenkins.info', + ], + [ + 'username' => 'test.test', + 'auth_key' => 'O87GkY3_UfmMHYkyezZ7QLfmkKNsllzT', + // Test1234 + 'password_hash' => 'O87GkY3_UfmMHYkyezZ7QLfmkKNsllzT', + 'email' => 'test@mail.com', + 'status' => '9', + 'created_at' => '1548675330', + 'updated_at' => '1548675330', + 'verification_token' => '4ch0qbfhvWwkcuWqjN8SWRq72SOw1KYT_1548675330', + ], +]; diff --git a/frontend/tests/_data/user.php b/frontend/tests/_data/user.php new file mode 100644 index 0000000..0b94332 --- /dev/null +++ b/frontend/tests/_data/user.php @@ -0,0 +1,45 @@ + 'okirlin', + 'auth_key' => 'iwTNae9t34OmnK6l4vT4IeaTk-YWI2Rv', + 'password_hash' => '$2y$13$CXT0Rkle1EMJ/c1l5bylL.EylfmQ39O5JlHJVFpNn618OUS1HwaIi', + 'password_reset_token' => 't5GU9NwpuGYSfb7FEZMAxqtuz2PkEvv_' . time(), + 'created_at' => '1391885313', + 'updated_at' => '1391885313', + 'email' => 'brady.renner@rutherford.com', + ], + [ + 'username' => 'troy.becker', + 'auth_key' => 'EdKfXrx88weFMV0vIxuTMWKgfK2tS3Lp', + 'password_hash' => '$2y$13$g5nv41Px7VBqhS3hVsVN2.MKfgT3jFdkXEsMC4rQJLfaMa7VaJqL2', + 'password_reset_token' => '4BSNyiZNAuxjs5Mty990c47sVrgllIi_' . time(), + 'created_at' => '1391885313', + 'updated_at' => '1391885313', + 'email' => 'nicolas.dianna@hotmail.com', + 'status' => '0', + ], + [ + 'username' => 'test.test', + 'auth_key' => 'O87GkY3_UfmMHYkyezZ7QLfmkKNsllzT', + //Test1234 + 'password_hash' => '$2y$13$d17z0w/wKC4LFwtzBcmx6up4jErQuandJqhzKGKczfWuiEhLBtQBK', + 'email' => 'test@mail.com', + 'status' => '9', + 'created_at' => '1548675330', + 'updated_at' => '1548675330', + 'verification_token' => '4ch0qbfhvWwkcuWqjN8SWRq72SOw1KYT_1548675330', + ], + [ + 'username' => 'test2.test', + 'auth_key' => '4XXdVqi3rDpa_a6JH6zqVreFxUPcUPvJ', + //Test1234 + 'password_hash' => '$2y$13$d17z0w/wKC4LFwtzBcmx6up4jErQuandJqhzKGKczfWuiEhLBtQBK', + 'email' => 'test2@mail.com', + 'status' => '10', + 'created_at' => '1548675330', + 'updated_at' => '1548675330', + 'verification_token' => 'already_used_token_1548675330', + ], +]; diff --git a/frontend/tests/_output/.gitignore b/frontend/tests/_output/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/frontend/tests/_output/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/frontend/tests/_support/.gitignore b/frontend/tests/_support/.gitignore new file mode 100644 index 0000000..36e264c --- /dev/null +++ b/frontend/tests/_support/.gitignore @@ -0,0 +1 @@ +_generated diff --git a/frontend/tests/_support/FunctionalTester.php b/frontend/tests/_support/FunctionalTester.php new file mode 100644 index 0000000..77ad9c5 --- /dev/null +++ b/frontend/tests/_support/FunctionalTester.php @@ -0,0 +1,34 @@ +see($message, '.invalid-feedback'); + } + + public function dontSeeValidationError($message) + { + $this->dontSee($message, '.invalid-feedback'); + } +} diff --git a/frontend/tests/_support/UnitTester.php b/frontend/tests/_support/UnitTester.php new file mode 100644 index 0000000..91557de --- /dev/null +++ b/frontend/tests/_support/UnitTester.php @@ -0,0 +1,26 @@ +amOnRoute(Url::toRoute('/site/index')); + $I->see('My Application'); + + $I->seeLink('About'); + $I->click('About'); + $I->wait(2); // wait for page to be opened + + $I->see('This is the About page.'); + } +} diff --git a/frontend/tests/acceptance/_bootstrap.php b/frontend/tests/acceptance/_bootstrap.php new file mode 100644 index 0000000..47716f0 --- /dev/null +++ b/frontend/tests/acceptance/_bootstrap.php @@ -0,0 +1,16 @@ + 'davert']); + * ``` + * + * In Cept + * + * ```php + * \Codeception\Util\Fixtures::get('user1'); + * ``` + */ \ No newline at end of file diff --git a/frontend/tests/functional.suite.yml b/frontend/tests/functional.suite.yml new file mode 100644 index 0000000..d66644d --- /dev/null +++ b/frontend/tests/functional.suite.yml @@ -0,0 +1,7 @@ +suite_namespace: frontend\tests\functional +actor: FunctionalTester +modules: + enabled: + - Filesystem + - Yii2 + - Asserts diff --git a/frontend/tests/functional/AboutCest.php b/frontend/tests/functional/AboutCest.php new file mode 100644 index 0000000..1bcce2b --- /dev/null +++ b/frontend/tests/functional/AboutCest.php @@ -0,0 +1,14 @@ +amOnRoute('site/about'); + $I->see('About', 'h1'); + } +} diff --git a/frontend/tests/functional/ContactCest.php b/frontend/tests/functional/ContactCest.php new file mode 100644 index 0000000..9b5f90b --- /dev/null +++ b/frontend/tests/functional/ContactCest.php @@ -0,0 +1,60 @@ +amOnRoute('site/contact'); + } + + public function checkContact(FunctionalTester $I) + { + $I->see('Contact', 'h1'); + } + + public function checkContactSubmitNoData(FunctionalTester $I) + { + $I->submitForm('#contact-form', []); + $I->see('Contact', 'h1'); + $I->seeValidationError('Name cannot be blank'); + $I->seeValidationError('Email cannot be blank'); + $I->seeValidationError('Subject cannot be blank'); + $I->seeValidationError('Body cannot be blank'); + $I->seeValidationError('The verification code is incorrect'); + } + + public function checkContactSubmitNotCorrectEmail(FunctionalTester $I) + { + $I->submitForm('#contact-form', [ + 'ContactForm[name]' => 'tester', + 'ContactForm[email]' => 'tester.email', + 'ContactForm[subject]' => 'test subject', + 'ContactForm[body]' => 'test content', + 'ContactForm[verifyCode]' => 'testme', + ]); + $I->seeValidationError('Email is not a valid email address.'); + $I->dontSeeValidationError('Name cannot be blank'); + $I->dontSeeValidationError('Subject cannot be blank'); + $I->dontSeeValidationError('Body cannot be blank'); + $I->dontSeeValidationError('The verification code is incorrect'); + } + + public function checkContactSubmitCorrectData(FunctionalTester $I) + { + $I->submitForm('#contact-form', [ + 'ContactForm[name]' => 'tester', + 'ContactForm[email]' => 'tester@example.com', + 'ContactForm[subject]' => 'test subject', + 'ContactForm[body]' => 'test content', + 'ContactForm[verifyCode]' => 'testme', + ]); + $I->seeEmailIsSent(); + $I->see('Thank you for contacting us. We will respond to you as soon as possible.'); + } +} diff --git a/frontend/tests/functional/HomeCest.php b/frontend/tests/functional/HomeCest.php new file mode 100644 index 0000000..99048af --- /dev/null +++ b/frontend/tests/functional/HomeCest.php @@ -0,0 +1,17 @@ +amOnRoute(\Yii::$app->homeUrl); + $I->see('My Application'); + $I->seeLink('About'); + $I->click('About'); + $I->see('This is the About page.'); + } +} \ No newline at end of file diff --git a/frontend/tests/functional/LoginCest.php b/frontend/tests/functional/LoginCest.php new file mode 100644 index 0000000..ee160b6 --- /dev/null +++ b/frontend/tests/functional/LoginCest.php @@ -0,0 +1,66 @@ + [ + 'class' => UserFixture::class, + 'dataFile' => codecept_data_dir() . 'login_data.php', + ], + ]; + } + + public function _before(FunctionalTester $I) + { + $I->amOnRoute('site/login'); + } + + protected function formParams($login, $password) + { + return [ + 'LoginForm[username]' => $login, + 'LoginForm[password]' => $password, + ]; + } + + public function checkEmpty(FunctionalTester $I) + { + $I->submitForm('#login-form', $this->formParams('', '')); + $I->seeValidationError('Username cannot be blank.'); + $I->seeValidationError('Password cannot be blank.'); + } + + public function checkWrongPassword(FunctionalTester $I) + { + $I->submitForm('#login-form', $this->formParams('admin', 'wrong')); + $I->seeValidationError('Incorrect username or password.'); + } + + public function checkInactiveAccount(FunctionalTester $I) + { + $I->submitForm('#login-form', $this->formParams('test.test', 'Test1234')); + $I->seeValidationError('Incorrect username or password'); + } + + public function checkValidLogin(FunctionalTester $I) + { + $I->submitForm('#login-form', $this->formParams('erau', 'password_0')); + $I->see('Logout (erau)', 'form button[type=submit]'); + $I->dontSeeLink('Login'); + $I->dontSeeLink('Signup'); + } +} diff --git a/frontend/tests/functional/ResendVerificationEmailCest.php b/frontend/tests/functional/ResendVerificationEmailCest.php new file mode 100644 index 0000000..8ecaeac --- /dev/null +++ b/frontend/tests/functional/ResendVerificationEmailCest.php @@ -0,0 +1,83 @@ + [ + 'class' => UserFixture::class, + 'dataFile' => codecept_data_dir() . 'user.php', + ], + ]; + } + + public function _before(FunctionalTester $I) + { + $I->amOnRoute('/site/resend-verification-email'); + } + + protected function formParams($email) + { + return [ + 'ResendVerificationEmailForm[email]' => $email + ]; + } + + public function checkPage(FunctionalTester $I) + { + $I->see('Resend verification email', 'h1'); + $I->see('Please fill out your email. A verification email will be sent there.'); + } + + public function checkEmptyField(FunctionalTester $I) + { + $I->submitForm($this->formId, $this->formParams('')); + $I->seeValidationError('Email cannot be blank.'); + } + + public function checkWrongEmailFormat(FunctionalTester $I) + { + $I->submitForm($this->formId, $this->formParams('abcd.com')); + $I->seeValidationError('Email is not a valid email address.'); + } + + public function checkWrongEmail(FunctionalTester $I) + { + $I->submitForm($this->formId, $this->formParams('wrong@email.com')); + $I->seeValidationError('There is no user with this email address.'); + } + + public function checkAlreadyVerifiedEmail(FunctionalTester $I) + { + $I->submitForm($this->formId, $this->formParams('test2@mail.com')); + $I->seeValidationError('There is no user with this email address.'); + } + + public function checkSendSuccessfully(FunctionalTester $I) + { + $I->submitForm($this->formId, $this->formParams('test@mail.com')); + $I->canSeeEmailIsSent(); + $I->seeRecord('common\models\User', [ + 'email' => 'test@mail.com', + 'username' => 'test.test', + 'status' => \common\models\User::STATUS_INACTIVE + ]); + $I->see('Check your email for further instructions.'); + } +} diff --git a/frontend/tests/functional/SignupCest.php b/frontend/tests/functional/SignupCest.php new file mode 100644 index 0000000..b83b795 --- /dev/null +++ b/frontend/tests/functional/SignupCest.php @@ -0,0 +1,59 @@ +amOnRoute('site/signup'); + } + + public function signupWithEmptyFields(FunctionalTester $I) + { + $I->see('Signup', 'h1'); + $I->see('Please fill out the following fields to signup:'); + $I->submitForm($this->formId, []); + $I->seeValidationError('Username cannot be blank.'); + $I->seeValidationError('Email cannot be blank.'); + $I->seeValidationError('Password cannot be blank.'); + + } + + public function signupWithWrongEmail(FunctionalTester $I) + { + $I->submitForm( + $this->formId, [ + 'SignupForm[username]' => 'tester', + 'SignupForm[email]' => 'ttttt', + 'SignupForm[password]' => 'tester_password', + ] + ); + $I->dontSee('Username cannot be blank.', '.invalid-feedback'); + $I->dontSee('Password cannot be blank.', '.invalid-feedback'); + $I->see('Email is not a valid email address.', '.invalid-feedback'); + } + + public function signupSuccessfully(FunctionalTester $I) + { + $I->submitForm($this->formId, [ + 'SignupForm[username]' => 'tester', + 'SignupForm[email]' => 'tester.email@example.com', + 'SignupForm[password]' => 'tester_password', + ]); + + $I->seeRecord('common\models\User', [ + 'username' => 'tester', + 'email' => 'tester.email@example.com', + 'status' => \common\models\User::STATUS_INACTIVE + ]); + + $I->seeEmailIsSent(); + $I->see('Thank you for registration. Please check your inbox for verification email.'); + } +} diff --git a/frontend/tests/functional/VerifyEmailCest.php b/frontend/tests/functional/VerifyEmailCest.php new file mode 100644 index 0000000..b227426 --- /dev/null +++ b/frontend/tests/functional/VerifyEmailCest.php @@ -0,0 +1,68 @@ + [ + 'class' => UserFixture::class, + 'dataFile' => codecept_data_dir() . 'user.php', + ], + ]; + } + + public function checkEmptyToken(FunctionalTester $I) + { + $I->amOnRoute('site/verify-email', ['token' => '']); + $I->canSee('Bad Request', 'h1'); + $I->canSee('Verify email token cannot be blank.'); + } + + public function checkInvalidToken(FunctionalTester $I) + { + $I->amOnRoute('site/verify-email', ['token' => 'wrong_token']); + $I->canSee('Bad Request', 'h1'); + $I->canSee('Wrong verify email token.'); + } + + public function checkNoToken(FunctionalTester $I) + { + $I->amOnRoute('site/verify-email'); + $I->canSee('Bad Request', 'h1'); + $I->canSee('Missing required parameters: token'); + } + + public function checkAlreadyActivatedToken(FunctionalTester $I) + { + $I->amOnRoute('site/verify-email', ['token' => 'already_used_token_1548675330']); + $I->canSee('Bad Request', 'h1'); + $I->canSee('Wrong verify email token.'); + } + + public function checkSuccessVerification(FunctionalTester $I) + { + $I->amOnRoute('site/verify-email', ['token' => '4ch0qbfhvWwkcuWqjN8SWRq72SOw1KYT_1548675330']); + $I->canSee('Your email has been confirmed!'); + $I->canSee('Congratulations!', 'h1'); + $I->see('Logout (test.test)', 'form button[type=submit]'); + + $I->seeRecord('common\models\User', [ + 'username' => 'test.test', + 'email' => 'test@mail.com', + 'status' => \common\models\User::STATUS_ACTIVE + ]); + } +} diff --git a/frontend/tests/functional/_bootstrap.php b/frontend/tests/functional/_bootstrap.php new file mode 100644 index 0000000..30ed54b --- /dev/null +++ b/frontend/tests/functional/_bootstrap.php @@ -0,0 +1,16 @@ + 'davert']); + * ``` + * + * In Cests + * + * ```php + * \Codeception\Util\Fixtures::get('user1'); + * ``` + */ \ No newline at end of file diff --git a/frontend/tests/unit.suite.yml b/frontend/tests/unit.suite.yml new file mode 100644 index 0000000..23ea63b --- /dev/null +++ b/frontend/tests/unit.suite.yml @@ -0,0 +1,7 @@ +suite_namespace: frontend\tests\unit +actor: UnitTester +modules: + enabled: + - Yii2: + part: [orm, email, fixtures] + - Asserts diff --git a/frontend/tests/unit/_bootstrap.php b/frontend/tests/unit/_bootstrap.php new file mode 100644 index 0000000..e432ce5 --- /dev/null +++ b/frontend/tests/unit/_bootstrap.php @@ -0,0 +1,16 @@ + 'davert']); + * ``` + * + * In Tests + * + * ```php + * \Codeception\Util\Fixtures::get('user1'); + * ``` + */ diff --git a/frontend/tests/unit/models/ContactFormTest.php b/frontend/tests/unit/models/ContactFormTest.php new file mode 100644 index 0000000..1fb4525 --- /dev/null +++ b/frontend/tests/unit/models/ContactFormTest.php @@ -0,0 +1,35 @@ +attributes = [ + 'name' => 'Tester', + 'email' => 'tester@example.com', + 'subject' => 'very important letter subject', + 'body' => 'body of current message', + ]; + + verify($model->sendEmail('admin@example.com'))->notEmpty(); + + // using Yii2 module actions to check email was sent + $this->tester->seeEmailIsSent(); + + /** @var MessageInterface $emailMessage */ + $emailMessage = $this->tester->grabLastSentEmail(); + verify($emailMessage)->instanceOf('yii\mail\MessageInterface'); + verify($emailMessage->getTo())->arrayHasKey('admin@example.com'); + verify($emailMessage->getFrom())->arrayHasKey('noreply@example.com'); + verify($emailMessage->getReplyTo())->arrayHasKey('tester@example.com'); + verify($emailMessage->getSubject())->equals('very important letter subject'); + verify($emailMessage->toString())->stringContainsString('body of current message'); + } +} diff --git a/frontend/tests/unit/models/PasswordResetRequestFormTest.php b/frontend/tests/unit/models/PasswordResetRequestFormTest.php new file mode 100644 index 0000000..8492fba --- /dev/null +++ b/frontend/tests/unit/models/PasswordResetRequestFormTest.php @@ -0,0 +1,59 @@ +tester->haveFixtures([ + 'user' => [ + 'class' => UserFixture::class, + 'dataFile' => codecept_data_dir() . 'user.php' + ] + ]); + } + + public function testSendMessageWithWrongEmailAddress() + { + $model = new PasswordResetRequestForm(); + $model->email = 'not-existing-email@example.com'; + verify($model->sendEmail())->false(); + } + + public function testNotSendEmailsToInactiveUser() + { + $user = $this->tester->grabFixture('user', 1); + $model = new PasswordResetRequestForm(); + $model->email = $user['email']; + verify($model->sendEmail())->false(); + } + + public function testSendEmailSuccessfully() + { + $userFixture = $this->tester->grabFixture('user', 0); + + $model = new PasswordResetRequestForm(); + $model->email = $userFixture['email']; + $user = User::findOne(['password_reset_token' => $userFixture['password_reset_token']]); + + verify($model->sendEmail())->notEmpty(); + verify($user->password_reset_token)->notEmpty(); + + $emailMessage = $this->tester->grabLastSentEmail(); + verify($emailMessage)->instanceOf('yii\mail\MessageInterface'); + verify($emailMessage->getTo())->arrayHasKey($model->email); + verify($emailMessage->getFrom())->arrayHasKey(Yii::$app->params['supportEmail']); + } +} diff --git a/frontend/tests/unit/models/ResendVerificationEmailFormTest.php b/frontend/tests/unit/models/ResendVerificationEmailFormTest.php new file mode 100644 index 0000000..af3548a --- /dev/null +++ b/frontend/tests/unit/models/ResendVerificationEmailFormTest.php @@ -0,0 +1,85 @@ +tester->haveFixtures([ + 'user' => [ + 'class' => UserFixture::class, + 'dataFile' => codecept_data_dir() . 'user.php' + ] + ]); + } + + public function testWrongEmailAddress() + { + $model = new ResendVerificationEmailForm(); + $model->attributes = [ + 'email' => 'aaa@bbb.cc' + ]; + + verify($model->validate())->false(); + verify($model->hasErrors())->true(); + verify($model->getFirstError('email'))->equals('There is no user with this email address.'); + } + + public function testEmptyEmailAddress() + { + $model = new ResendVerificationEmailForm(); + $model->attributes = [ + 'email' => '' + ]; + + verify($model->validate())->false(); + verify($model->hasErrors())->true(); + verify($model->getFirstError('email'))->equals('Email cannot be blank.'); + } + + public function testResendToActiveUser() + { + $model = new ResendVerificationEmailForm(); + $model->attributes = [ + 'email' => 'test2@mail.com' + ]; + + verify($model->validate())->false(); + verify($model->hasErrors())->true(); + verify($model->getFirstError('email'))->equals('There is no user with this email address.'); + } + + public function testSuccessfullyResend() + { + $model = new ResendVerificationEmailForm(); + $model->attributes = [ + 'email' => 'test@mail.com' + ]; + + verify($model->validate())->true(); + verify($model->hasErrors())->false(); + + verify($model->sendEmail())->true(); + $this->tester->seeEmailIsSent(); + + $mail = $this->tester->grabLastSentEmail(); + + verify($mail)->instanceOf('yii\mail\MessageInterface'); + verify($mail->getTo())->arrayHasKey('test@mail.com'); + verify($mail->getFrom())->arrayHasKey(\Yii::$app->params['supportEmail']); + verify($mail->getSubject())->equals('Account registration at ' . \Yii::$app->name); + verify($mail->toString())->stringContainsString('4ch0qbfhvWwkcuWqjN8SWRq72SOw1KYT_1548675330'); + } +} diff --git a/frontend/tests/unit/models/ResetPasswordFormTest.php b/frontend/tests/unit/models/ResetPasswordFormTest.php new file mode 100644 index 0000000..8d969a6 --- /dev/null +++ b/frontend/tests/unit/models/ResetPasswordFormTest.php @@ -0,0 +1,44 @@ +tester->haveFixtures([ + 'user' => [ + 'class' => UserFixture::class, + 'dataFile' => codecept_data_dir() . 'user.php' + ], + ]); + } + + public function testResetWrongToken() + { + $this->tester->expectThrowable('\yii\base\InvalidArgumentException', function() { + new ResetPasswordForm(''); + }); + + $this->tester->expectThrowable('\yii\base\InvalidArgumentException', function() { + new ResetPasswordForm('notexistingtoken_1391882543'); + }); + } + + public function testResetCorrectToken() + { + $user = $this->tester->grabFixture('user', 0); + $form = new ResetPasswordForm($user['password_reset_token']); + verify($form->resetPassword())->notEmpty(); + } + +} diff --git a/frontend/tests/unit/models/SignupFormTest.php b/frontend/tests/unit/models/SignupFormTest.php new file mode 100644 index 0000000..332ba6b --- /dev/null +++ b/frontend/tests/unit/models/SignupFormTest.php @@ -0,0 +1,72 @@ +tester->haveFixtures([ + 'user' => [ + 'class' => UserFixture::class, + 'dataFile' => codecept_data_dir() . 'user.php' + ] + ]); + } + + public function testCorrectSignup() + { + $model = new SignupForm([ + 'username' => 'some_username', + 'email' => 'some_email@example.com', + 'password' => 'some_password', + ]); + + $user = $model->signup(); + verify($user)->notEmpty(); + + /** @var \common\models\User $user */ + $user = $this->tester->grabRecord('common\models\User', [ + 'username' => 'some_username', + 'email' => 'some_email@example.com', + 'status' => \common\models\User::STATUS_INACTIVE + ]); + + $this->tester->seeEmailIsSent(); + + $mail = $this->tester->grabLastSentEmail(); + + verify($mail)->instanceOf('yii\mail\MessageInterface'); + verify($mail->getTo())->arrayHasKey('some_email@example.com'); + verify($mail->getFrom())->arrayHasKey(\Yii::$app->params['supportEmail']); + verify($mail->getSubject())->equals('Account registration at ' . \Yii::$app->name); + verify($mail->toString())->stringContainsString($user->verification_token); + } + + public function testNotCorrectSignup() + { + $model = new SignupForm([ + 'username' => 'troy.becker', + 'email' => 'nicolas.dianna@hotmail.com', + 'password' => 'some_password', + ]); + + verify($model->signup())->empty(); + verify($model->getErrors('username'))->notEmpty(); + verify($model->getErrors('email'))->notEmpty(); + + verify($model->getFirstError('username')) + ->equals('This username has already been taken.'); + verify($model->getFirstError('email')) + ->equals('This email address has already been taken.'); + } +} diff --git a/frontend/tests/unit/models/VerifyEmailFormTest.php b/frontend/tests/unit/models/VerifyEmailFormTest.php new file mode 100644 index 0000000..e0fe2e4 --- /dev/null +++ b/frontend/tests/unit/models/VerifyEmailFormTest.php @@ -0,0 +1,55 @@ +tester->haveFixtures([ + 'user' => [ + 'class' => UserFixture::class, + 'dataFile' => codecept_data_dir() . 'user.php' + ] + ]); + } + + public function testVerifyWrongToken() + { + $this->tester->expectThrowable('\yii\base\InvalidArgumentException', function() { + new VerifyEmailForm(''); + }); + + $this->tester->expectThrowable('\yii\base\InvalidArgumentException', function() { + new VerifyEmailForm('notexistingtoken_1391882543'); + }); + } + + public function testAlreadyActivatedToken() + { + $this->tester->expectThrowable('\yii\base\InvalidArgumentException', function() { + new VerifyEmailForm('already_used_token_1548675330'); + }); + } + + public function testVerifyCorrectToken() + { + $model = new VerifyEmailForm('4ch0qbfhvWwkcuWqjN8SWRq72SOw1KYT_1548675330'); + $user = $model->verifyEmail(); + verify($user)->instanceOf('common\models\User'); + + verify($user->username)->equals('test.test'); + verify($user->email)->equals('test@mail.com'); + verify($user->status)->equals(\common\models\User::STATUS_ACTIVE); + verify($user->validatePassword('Test1234'))->true(); + } +} diff --git a/frontend/views/layouts/content.php b/frontend/views/layouts/content.php new file mode 100644 index 0000000..adba668 --- /dev/null +++ b/frontend/views/layouts/content.php @@ -0,0 +1,42 @@ + +
+ +
+
+
+
+

+ title)) { + echo \yii\helpers\Html::encode($this->title); + } else { + echo \yii\helpers\Inflector::camelize($this->context->id); + } + ?> +

+
+
+ isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [], + 'options' => [ + 'class' => 'breadcrumb float-sm-right' + ] + ]); + ?> +
+
+
+
+ + + +
+ +
+ +
\ No newline at end of file diff --git a/frontend/views/layouts/control-sidebar.php b/frontend/views/layouts/control-sidebar.php new file mode 100644 index 0000000..addd3b1 --- /dev/null +++ b/frontend/views/layouts/control-sidebar.php @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/frontend/views/layouts/footer.php b/frontend/views/layouts/footer.php new file mode 100644 index 0000000..f335ebd --- /dev/null +++ b/frontend/views/layouts/footer.php @@ -0,0 +1,7 @@ +
+ Copyright © 2014-2021 AdminLTE.io. + All rights reserved. +
+ Version 3.1.0 +
+
\ No newline at end of file diff --git a/frontend/views/layouts/main-login.php b/frontend/views/layouts/main-login.php new file mode 100644 index 0000000..6ed35ef --- /dev/null +++ b/frontend/views/layouts/main-login.php @@ -0,0 +1,40 @@ +registerCssFile('https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700'); +$this->registerCssFile('https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css'); +\hail812\adminlte3\assets\PluginAsset::register($this)->add(['fontawesome', 'icheck-bootstrap']); +?> +beginPage() ?> + + + + + + + + registerCsrfMetaTags() ?> + <?= Html::encode($this->title) ?> + head() ?> + + +beginBody() ?> + + + +endBody() ?> + + +endPage() ?> \ No newline at end of file diff --git a/frontend/views/layouts/main.php b/frontend/views/layouts/main.php new file mode 100644 index 0000000..80ca4b5 --- /dev/null +++ b/frontend/views/layouts/main.php @@ -0,0 +1,54 @@ +registerCssFile('https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700&display=fallback'); + +$assetDir = Yii::$app->assetManager->getPublishedUrl('@vendor/almasaeed2010/adminlte/dist'); + +$publishedRes = Yii::$app->assetManager->publish('@vendor/hail812/yii2-adminlte3/src/web/js'); +$this->registerJsFile($publishedRes[1].'/control_sidebar.js', ['depends' => '\hail812\adminlte3\assets\AdminLteAsset']); +?> +beginPage() ?> + + + + + + + registerCsrfMetaTags() ?> + <?= Html::encode($this->title) ?> + head() ?> + + +beginBody() ?> + +
+ + render('navbar', ['assetDir' => $assetDir]) ?> + + + + render('sidebar', ['assetDir' => $assetDir]) ?> + + + render('content', ['content' => $content, 'assetDir' => $assetDir]) ?> + + + + render('control-sidebar') ?> + + + + render('footer') ?> +
+ +endBody() ?> + + +endPage() ?> diff --git a/frontend/views/layouts/navbar.php b/frontend/views/layouts/navbar.php new file mode 100644 index 0000000..880fab4 --- /dev/null +++ b/frontend/views/layouts/navbar.php @@ -0,0 +1,191 @@ + + + + \ No newline at end of file diff --git a/frontend/views/layouts/sidebar.php b/frontend/views/layouts/sidebar.php new file mode 100644 index 0000000..7efb794 --- /dev/null +++ b/frontend/views/layouts/sidebar.php @@ -0,0 +1,87 @@ + \ No newline at end of file diff --git a/frontend/views/site/about.php b/frontend/views/site/about.php new file mode 100644 index 0000000..b40ea44 --- /dev/null +++ b/frontend/views/site/about.php @@ -0,0 +1,16 @@ +title = 'About'; +$this->params['breadcrumbs'][] = $this->title; +?> +
+

title) ?>

+ +

This is the About page. You may modify the following file to customize its content:

+ + +
diff --git a/frontend/views/site/contact.php b/frontend/views/site/contact.php new file mode 100644 index 0000000..6e6b8ac --- /dev/null +++ b/frontend/views/site/contact.php @@ -0,0 +1,45 @@ +title = 'Contact'; +$this->params['breadcrumbs'][] = $this->title; +?> +
+

title) ?>

+ +

+ If you have business inquiries or other questions, please fill out the following form to contact us. Thank you. +

+ +
+
+ 'contact-form']); ?> + + field($model, 'name')->textInput(['autofocus' => true]) ?> + + field($model, 'email') ?> + + field($model, 'subject') ?> + + field($model, 'body')->textarea(['rows' => 6]) ?> + + field($model, 'verifyCode')->widget(Captcha::class, [ + 'template' => '
{image}
{input}
', + ]) ?> + +
+ 'btn btn-primary', 'name' => 'contact-button']) ?> +
+ + +
+
+ +
diff --git a/frontend/views/site/error.php b/frontend/views/site/error.php new file mode 100644 index 0000000..b4d9932 --- /dev/null +++ b/frontend/views/site/error.php @@ -0,0 +1,40 @@ +title = $name; +$this->params['breadcrumbs'] = [['label' => $this->title]]; +?> +
+
+

+ +

+ +

+ +

+ The above error occurred while the Web server was processing your request. + Please contact us if you think this is a server error. Thank you. + Meanwhile, you may homeUrl); ?> + or try using the search form. +

+ +
+
+ + +
+ +
+
+
+
+
+ diff --git a/frontend/views/site/index.php b/frontend/views/site/index.php new file mode 100644 index 0000000..b98184a --- /dev/null +++ b/frontend/views/site/index.php @@ -0,0 +1,134 @@ +title = 'Starter Page'; +$this->params['breadcrumbs'] = [['label' => $this->title]]; +?> +
+
+
+ 'success', + 'body' => '

Congratulations!

', + ]) ?> + 'danger', + 'head' => 'I am a danger callout!', + 'body' => 'There is a problem that we need to fix. A wonderful serenity has taken possession of my entire soul, like these sweet mornings of spring which I enjoy with my whole heart.' + ]) ?> +
+
+ +
+
+ 'CPU Traffic', + 'number' => '10 %', + 'icon' => 'fas fa-cog', + ]) ?> +
+
+ +
+
+ 'Messages', + 'number' => '1,410', + 'icon' => 'far fa-envelope', + ]) ?> +
+
+ 'Bookmarks', + 'number' => '410', + 'theme' => 'success', + 'icon' => 'far fa-flag', + ]) ?> +
+
+ 'Uploads', + 'number' => '13,648', + 'theme' => 'gradient-warning', + 'icon' => 'far fa-copy', + ]) ?> +
+
+ +
+
+ 'Bookmarks', + 'number' => '41,410', + 'icon' => 'far fa-bookmark', + 'progress' => [ + 'width' => '70%', + 'description' => '70% Increase in 30 Days' + ] + ]) ?> +
+
+ 'Likes', + 'number' => '41,410', + 'theme' => 'success', + 'icon' => 'far fa-thumbs-up', + 'progress' => [ + 'width' => '70%', + 'description' => '70% Increase in 30 Days' + ] + ]) ?> + $infoBox->id.'-ribbon', + 'text' => 'Ribbon', + ]) ?> + +
+
+ 'Events', + 'number' => '41,410', + 'theme' => 'gradient-warning', + 'icon' => 'far fa-calendar-alt', + 'progress' => [ + 'width' => '70%', + 'description' => '70% Increase in 30 Days' + ], + 'loadingStyle' => true + ]) ?> +
+
+ +
+
+ '150', + 'text' => 'New Orders', + 'icon' => 'fas fa-shopping-cart', + ]) ?> +
+
+ '150', + 'text' => 'New Orders', + 'icon' => 'fas fa-shopping-cart', + 'theme' => 'success' + ]) ?> + $smallBox->id.'-ribbon', + 'text' => 'Ribbon', + 'theme' => 'warning', + 'size' => 'lg', + 'textSize' => 'lg' + ]) ?> + +
+
+ '44', + 'text' => 'User Registrations', + 'icon' => 'fas fa-user-plus', + 'theme' => 'gradient-success', + 'loadingStyle' => true + ]) ?> +
+
+
\ No newline at end of file diff --git a/frontend/views/site/login.php b/frontend/views/site/login.php new file mode 100644 index 0000000..1380361 --- /dev/null +++ b/frontend/views/site/login.php @@ -0,0 +1,64 @@ + +
+ + +
\ No newline at end of file diff --git a/frontend/views/site/requestPasswordResetToken.php b/frontend/views/site/requestPasswordResetToken.php new file mode 100644 index 0000000..72f1693 --- /dev/null +++ b/frontend/views/site/requestPasswordResetToken.php @@ -0,0 +1,31 @@ +title = 'Request password reset'; +$this->params['breadcrumbs'][] = $this->title; +?> +
+

title) ?>

+ +

Please fill out your email. A link to reset password will be sent there.

+ +
+
+ 'request-password-reset-form']); ?> + + field($model, 'email')->textInput(['autofocus' => true]) ?> + +
+ 'btn btn-primary']) ?> +
+ + +
+
+
diff --git a/frontend/views/site/resendVerificationEmail.php b/frontend/views/site/resendVerificationEmail.php new file mode 100644 index 0000000..23f5666 --- /dev/null +++ b/frontend/views/site/resendVerificationEmail.php @@ -0,0 +1,31 @@ +title = 'Resend verification email'; +$this->params['breadcrumbs'][] = $this->title; +?> +
+

title) ?>

+ +

Please fill out your email. A verification email will be sent there.

+ +
+
+ 'resend-verification-email-form']); ?> + + field($model, 'email')->textInput(['autofocus' => true]) ?> + +
+ 'btn btn-primary']) ?> +
+ + +
+
+
diff --git a/frontend/views/site/resetPassword.php b/frontend/views/site/resetPassword.php new file mode 100644 index 0000000..61e15b4 --- /dev/null +++ b/frontend/views/site/resetPassword.php @@ -0,0 +1,31 @@ +title = 'Reset password'; +$this->params['breadcrumbs'][] = $this->title; +?> +
+

title) ?>

+ +

Please choose your new password:

+ +
+
+ 'reset-password-form']); ?> + + field($model, 'password')->passwordInput(['autofocus' => true]) ?> + +
+ 'btn btn-primary']) ?> +
+ + +
+
+
diff --git a/frontend/views/site/signup.php b/frontend/views/site/signup.php new file mode 100644 index 0000000..fa74af1 --- /dev/null +++ b/frontend/views/site/signup.php @@ -0,0 +1,68 @@ +title = 'Регистрация'; +$this->params['breadcrumbs'][] = $this->title; +?> + +
+ + +
diff --git a/frontend/web/assets/.gitignore b/frontend/web/assets/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/frontend/web/assets/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/frontend/web/css/site.css b/frontend/web/css/site.css new file mode 100644 index 0000000..4a65ca7 --- /dev/null +++ b/frontend/web/css/site.css @@ -0,0 +1,103 @@ +main > .container, main > .container-fluid +{ + padding: 70px 15px 20px; +} + +.footer { + background-color: #f5f5f5; + font-size: .9em; + height: 60px; +} + +.footer > .container, .footer > .container-fluid { + padding-right: 15px; + padding-left: 15px; +} + +.not-set { + color: #c55; + font-style: italic; +} + +/* add sorting icons to gridview sort links */ +a.asc:after, a.desc:after { + content: ''; + left: 3px; + display: inline-block; + width: 0; + height: 0; + border: solid 5px transparent; + margin: 4px 4px 2px 4px; + background: transparent; +} + +a.asc:after { + border-bottom: solid 7px #212529; + border-top-width: 0; +} + +a.desc:after { + border-top: solid 7px #212529; + border-bottom-width: 0; +} + +.grid-view th, +.grid-view td:last-child { + white-space: nowrap; +} + +.grid-view .filters input, +.grid-view .filters select { + min-width: 50px; +} + +.hint-block { + display: block; + margin-top: 5px; + color: #999; +} + +.error-summary { + color: #a94442; + background: #fdf7f7; + border-left: 3px solid #eed3d7; + padding: 10px 20px; + margin: 0 0 15px 0; +} + +/* align the logout "link" (button in form) of the navbar */ +.navbar form > button.logout { + padding-top: 7px; + color: rgba(255, 255, 255, 0.5); +} + +@media(max-width:767px) { + .navbar form > button.logout { + display:block; + text-align: left; + width: 100%; + padding: 10px 0; + } +} + +.navbar form > button.logout:focus, +.navbar form > button.logout:hover { + text-decoration: none; + color: rgba(255, 255, 255, 0.75); +} + +.navbar form > button.logout:focus { + outline: none; +} + +/* style breadcrumb widget as in previous bootstrap versions */ +.breadcrumb { + background-color: var(--bs-gray-200); + border-radius: .25rem; + padding: .75rem 1rem; +} + +.breadcrumb-item > a +{ + text-decoration: none; +} \ No newline at end of file diff --git a/frontend/web/favicon.ico b/frontend/web/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..580ed732e86556ec57f3f3395a210246d679c076 GIT binary patch literal 318 zcmZQzU<5(|0RbS%!l1#(z#zuJz@P!d0zj+)#2|4HXaJKC0wf0lAEr2iX{M9K3=BR0 y!E90pK{x=K$Oz&POT#sS8N$ZKhC)h8ip0_|-T#43{vnSYgXBQCu@O54$pHYIza?e> literal 0 HcmV?d00001 diff --git a/init b/init new file mode 100755 index 0000000..cf472c9 --- /dev/null +++ b/init @@ -0,0 +1,356 @@ +#!/usr/bin/env php + $name) { + echo " [$i] $name\n"; + } + echo "\n Your choice [0-" . (count($envs) - 1) . ', or "q" to quit] '; + $answer = trim(fgets(STDIN)); + + if (!ctype_digit($answer) || !in_array($answer, range(0, count($envs) - 1))) { + echo "\n Quit initialization.\n"; + exit(0); + } + + if (isset($envNames[$answer])) { + $envName = $envNames[$answer]; + } +} else { + $envName = $params['env']; +} + +if (!in_array($envName, $envNames, true)) { + $envsList = implode(', ', $envNames); + echo "\n $envName is not a valid environment. Try one of the following: $envsList. \n"; + exit(2); +} + +$env = $envs[$envName]; + +if (empty($params['env'])) { + echo "\n Initialize the application under '{$envNames[$answer]}' environment? [yes|no] "; + $answer = trim(fgets(STDIN)); + if (strncasecmp($answer, 'y', 1)) { + echo "\n Quit initialization.\n"; + exit(0); + } +} + +$rootPath = "$root/environments/{$env['path']}"; +if (!is_dir($rootPath)) { + printError("$rootPath directory does not exist. Check path in $envName environment."); + exit(3); +} + +echo "\n Start initialization ...\n\n"; + +$files = getFileList($rootPath); +if (isset($env['skipFiles'])) { + $skipFiles = $env['skipFiles']; + array_walk($skipFiles, function(&$value) use($env, $root) { $value = "$root/$value"; }); + $files = array_diff($files, array_intersect_key($env['skipFiles'], array_filter($skipFiles, 'file_exists'))); +} +$all = false; +foreach ($files as $file) { + if (!copyFile($root, "environments/{$env['path']}/$file", $file, $all, $params)) { + break; + } +} + +$filesToRemove = []; +$skipFiles = !empty($env['skipFiles']) ? $env['skipFiles'] : []; +foreach(array_column($envs, 'path') as $envPath) { + if ($env['path'] === $envPath) continue; + + $filesToRemove = + array_merge( + $filesToRemove, + array_diff(getFileList("$root/environments/{$envPath}"), $files, $filesToRemove, $skipFiles) + ); +} +$filesToRemove = array_filter($filesToRemove, 'file_exists'); +if ($filesToRemove) { + echo "\n Remove files from other environments ...\n\n"; + + $all = false; + foreach ($filesToRemove as $file) { + if (!removeFile($root, $file, $all, $params)) { + break; + } + } + echo "\n"; +} + +$callbacks = ['setCookieValidationKey', 'setWritable', 'setExecutable', 'createSymlink']; +foreach ($callbacks as $callback) { + if (!empty($env[$callback])) { + $callback($root, $env[$callback]); + } +} + +echo "\n ... initialization completed.\n\n"; + +function getFileList($root, $basePath = '') +{ + $files = []; + $handle = opendir($root); + while (($path = readdir($handle)) !== false) { + if ($path === '.git' || $path === '.svn' || $path === '.' || $path === '..') { + continue; + } + $fullPath = "$root/$path"; + $relativePath = $basePath === '' ? $path : "$basePath/$path"; + if (is_dir($fullPath)) { + $files = array_merge($files, getFileList($fullPath, $relativePath)); + } else { + $files[] = $relativePath; + } + } + closedir($handle); + return $files; +} + +function copyFile($root, $source, $target, &$all, $params) +{ + if (!is_file($root . '/' . $source)) { + echo " skip $target ($source not exist)\n"; + return true; + } + if (is_file($root . '/' . $target)) { + if (file_get_contents($root . '/' . $source) === file_get_contents($root . '/' . $target)) { + echo " unchanged $target\n"; + return true; + } + if ($all) { + echo " overwrite $target\n"; + } else { + echo " exist $target\n"; + echo " ...overwrite? [Yes|No|All|Quit] "; + + + $answer = !empty($params['overwrite']) ? $params['overwrite'] : trim(fgets(STDIN)); + if (!strncasecmp($answer, 'q', 1)) { + return false; + } else { + if (!strncasecmp($answer, 'y', 1)) { + echo " overwrite $target\n"; + } else { + if (!strncasecmp($answer, 'a', 1)) { + echo " overwrite $target\n"; + $all = true; + } else { + echo " skip $target\n"; + return true; + } + } + } + } + file_put_contents($root . '/' . $target, file_get_contents($root . '/' . $source)); + return true; + } + echo " generate $target\n"; + @mkdir(dirname($root . '/' . $target), 0777, true); + file_put_contents($root . '/' . $target, file_get_contents($root . '/' . $source)); + return true; +} + +function removeFile($root, $target, &$all, $params) +{ + if (is_file($root . '/' . $target)) { + if ($all) { + echo " delete $target\n"; + } else { + echo " delete $target\n"; + echo " ...confirm? [Yes|No|All|Quit] "; + + $answer = !empty($params['delete']) ? $params['delete'] : trim(fgets(STDIN)); + if (!strncasecmp($answer, 'q', 1)) { + return false; + } else { + if (!strncasecmp($answer, 'y', 1)) { + echo " delete $target\n"; + } else { + if (!strncasecmp($answer, 'a', 1)) { + echo " delete $target\n"; + $all = true; + } else { + echo " skip $target\n"; + return true; + } + } + } + } + return unlink($root . '/' . $target); + } + + return true; +} + +function getParams() +{ + $rawParams = []; + if (isset($_SERVER['argv'])) { + $rawParams = $_SERVER['argv']; + array_shift($rawParams); + } + + $params = []; + foreach ($rawParams as $param) { + if (preg_match('/^--([\w-]*\w)(=(.*))?$/', $param, $matches)) { + $name = $matches[1]; + $params[$name] = isset($matches[3]) ? $matches[3] : true; + } else { + $params[] = $param; + } + } + return $params; +} + +function setWritable($root, $paths) +{ + foreach ($paths as $writable) { + if (is_dir("$root/$writable")) { + if (@chmod("$root/$writable", 0777)) { + echo " chmod 0777 $writable\n"; + } else { + printError("Operation chmod not permitted for directory $writable."); + } + } else { + printError("Directory $writable does not exist."); + } + } +} + +function setExecutable($root, $paths) +{ + foreach ($paths as $executable) { + if (file_exists("$root/$executable")) { + if (@chmod("$root/$executable", 0755)) { + echo " chmod 0755 $executable\n"; + } else { + printError("Operation chmod not permitted for $executable."); + } + } else { + printError("$executable does not exist."); + } + } +} + +function setCookieValidationKey($root, $paths) +{ + foreach ($paths as $file) { + echo " generate cookie validation key in $file\n"; + $file = $root . '/' . $file; + $length = 32; + $bytes = openssl_random_pseudo_bytes($length); + $key = strtr(substr(base64_encode($bytes), 0, $length), '+/=', '_-.'); + $content = preg_replace('/(("|\')cookieValidationKey("|\')\s*=>\s*)(""|\'\')/', "\\1'$key'", file_get_contents($file)); + file_put_contents($file, $content); + } +} + +function createSymlink($root, $links) +{ + foreach ($links as $link => $target) { + //first removing folders to avoid errors if the folder already exists + @rmdir($root . "/" . $link); + //next removing existing symlink in order to update the target + if (is_link($root . "/" . $link)) { + @unlink($root . "/" . $link); + } + if (@symlink($root . "/" . $target, $root . "/" . $link)) { + echo " symlink $root/$target $root/$link\n"; + } else { + printError("Cannot create symlink $root/$target $root/$link."); + } + } +} + +/** + * Prints error message. + * @param string $message message + */ +function printError($message) +{ + echo "\n " . formatMessage("Error. $message", ['fg-red']) . " \n"; +} + +/** + * Returns true if the stream supports colorization. ANSI colors are disabled if not supported by the stream. + * + * - windows without ansicon + * - not tty consoles + * + * @return boolean true if the stream supports ANSI colors, otherwise false. + */ +function ansiColorsSupported() +{ + return DIRECTORY_SEPARATOR === '\\' + ? getenv('ANSICON') !== false || getenv('ConEmuANSI') === 'ON' + : function_exists('posix_isatty') && @posix_isatty(STDOUT); +} + +/** + * Get ANSI code of style. + * @param string $name style name + * @return integer ANSI code of style. + */ +function getStyleCode($name) +{ + $styles = [ + 'bold' => 1, + 'fg-black' => 30, + 'fg-red' => 31, + 'fg-green' => 32, + 'fg-yellow' => 33, + 'fg-blue' => 34, + 'fg-magenta' => 35, + 'fg-cyan' => 36, + 'fg-white' => 37, + 'bg-black' => 40, + 'bg-red' => 41, + 'bg-green' => 42, + 'bg-yellow' => 43, + 'bg-blue' => 44, + 'bg-magenta' => 45, + 'bg-cyan' => 46, + 'bg-white' => 47, + ]; + return $styles[$name]; +} + +/** + * Formats message using styles if STDOUT supports it. + * @param string $message message + * @param string[] $styles styles + * @return string formatted message. + */ +function formatMessage($message, $styles) +{ + if (empty($styles) || !ansiColorsSupported()) { + return $message; + } + + return sprintf("\x1b[%sm", implode(';', array_map('getStyleCode', $styles))) . $message . "\x1b[0m"; +} diff --git a/init.bat b/init.bat new file mode 100644 index 0000000..1b92c19 --- /dev/null +++ b/init.bat @@ -0,0 +1,15 @@ +@echo off + +rem ------------------------------------------------------------- +rem Yii command line init script for Windows. +rem ------------------------------------------------------------- + +@setlocal + +set YII_PATH=%~dp0 + +if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe + +"%PHP_COMMAND%" "%YII_PATH%init" %* + +@endlocal diff --git a/requirements.php b/requirements.php new file mode 100644 index 0000000..2859da7 --- /dev/null +++ b/requirements.php @@ -0,0 +1,155 @@ +Error\n\n" + . "

The path to yii framework seems to be incorrect.

\n" + . '

You need to install Yii framework via composer or adjust the framework path in file ' . basename(__FILE__) . ".

\n" + . '

Please refer to the README on how to install Yii.

\n"; + if (!empty($_SERVER['argv'])) { + // do not print HTML when used in console mode + echo strip_tags($message); + } else { + echo $message; + } + exit(1); +} + +require_once $frameworkPath . '/requirements/YiiRequirementChecker.php'; +$requirementsChecker = new YiiRequirementChecker(); + +$gdMemo = $imagickMemo = 'Either GD PHP extension with FreeType support or ImageMagick PHP extension with PNG support is required for image CAPTCHA.'; +$gdOK = $imagickOK = false; + +if (extension_loaded('imagick')) { + $imagick = new Imagick(); + $imagickFormats = $imagick->queryFormats('PNG'); + if (in_array('PNG', $imagickFormats)) { + $imagickOK = true; + } else { + $imagickMemo = 'Imagick extension should be installed with PNG support in order to be used for image CAPTCHA.'; + } +} + +if (extension_loaded('gd')) { + $gdInfo = gd_info(); + if (!empty($gdInfo['FreeType Support'])) { + $gdOK = true; + } else { + $gdMemo = 'GD extension should be installed with FreeType support in order to be used for image CAPTCHA.'; + } +} + +/** + * Adjust requirements according to your application specifics. + */ +$requirements = array( + // Database : + array( + 'name' => 'PDO extension', + 'mandatory' => true, + 'condition' => extension_loaded('pdo'), + 'by' => 'All DB-related classes', + ), + array( + 'name' => 'PDO SQLite extension', + 'mandatory' => false, + 'condition' => extension_loaded('pdo_sqlite'), + 'by' => 'All DB-related classes', + 'memo' => 'Required for SQLite database.', + ), + array( + 'name' => 'PDO MySQL extension', + 'mandatory' => false, + 'condition' => extension_loaded('pdo_mysql'), + 'by' => 'All DB-related classes', + 'memo' => 'Required for MySQL database.', + ), + array( + 'name' => 'PDO PostgreSQL extension', + 'mandatory' => false, + 'condition' => extension_loaded('pdo_pgsql'), + 'by' => 'All DB-related classes', + 'memo' => 'Required for PostgreSQL database.', + ), + // Cache : + array( + 'name' => 'Memcache extension', + 'mandatory' => false, + 'condition' => extension_loaded('memcache') || extension_loaded('memcached'), + 'by' => 'MemCache', + 'memo' => extension_loaded('memcached') ? 'To use memcached set MemCache::useMemcached to true.' : '' + ), + array( + 'name' => 'APC extension', + 'mandatory' => false, + 'condition' => extension_loaded('apc'), + 'by' => 'ApcCache', + ), + // CAPTCHA: + array( + 'name' => 'GD PHP extension with FreeType support', + 'mandatory' => false, + 'condition' => $gdOK, + 'by' => 'Captcha', + 'memo' => $gdMemo, + ), + array( + 'name' => 'ImageMagick PHP extension with PNG support', + 'mandatory' => false, + 'condition' => $imagickOK, + 'by' => 'Captcha', + 'memo' => $imagickMemo, + ), + // PHP ini : + 'phpExposePhp' => array( + 'name' => 'Expose PHP', + 'mandatory' => false, + 'condition' => $requirementsChecker->checkPhpIniOff("expose_php"), + 'by' => 'Security reasons', + 'memo' => '"expose_php" should be disabled at php.ini', + ), + 'phpAllowUrlInclude' => array( + 'name' => 'PHP allow url include', + 'mandatory' => false, + 'condition' => $requirementsChecker->checkPhpIniOff("allow_url_include"), + 'by' => 'Security reasons', + 'memo' => '"allow_url_include" should be disabled at php.ini', + ), + 'phpSmtp' => array( + 'name' => 'PHP mail SMTP', + 'mandatory' => false, + 'condition' => strlen(ini_get('SMTP')) > 0, + 'by' => 'Email sending', + 'memo' => 'PHP mail SMTP server required', + ), +); + +$result = $requirementsChecker->checkYii()->check($requirements)->getResult(); +$requirementsChecker->render(); + +exit($result['summary']['errors'] === 0 ? 0 : 1); diff --git a/vagrant/config/.gitignore b/vagrant/config/.gitignore new file mode 100644 index 0000000..0685a56 --- /dev/null +++ b/vagrant/config/.gitignore @@ -0,0 +1,2 @@ +# local configuration +vagrant-local.yml \ No newline at end of file diff --git a/vagrant/config/vagrant-local.example.yml b/vagrant/config/vagrant-local.example.yml new file mode 100644 index 0000000..7b36400 --- /dev/null +++ b/vagrant/config/vagrant-local.example.yml @@ -0,0 +1,22 @@ +# Your personal GitHub token +github_token: +# Read more: https://github.com/blog/1509-personal-api-tokens +# You can generate it here: https://github.com/settings/tokens + +# Guest OS timezone +timezone: Europe/London + +# Are we need check box updates for every 'vagrant up'? +box_check_update: false + +# Virtual machine name +machine_name: y2aa + +# Virtual machine IP +ip: 192.168.83.137 + +# Virtual machine CPU cores number +cpus: 1 + +# Virtual machine RAM +memory: 1024 diff --git a/vagrant/nginx/app.conf b/vagrant/nginx/app.conf new file mode 100644 index 0000000..0462830 --- /dev/null +++ b/vagrant/nginx/app.conf @@ -0,0 +1,77 @@ +server { + charset utf-8; + client_max_body_size 128M; + sendfile off; + + listen 80; ## listen for ipv4 + #listen [::]:80 default_server ipv6only=on; ## listen for ipv6 + + server_name y2aa-frontend.test; + root /app/frontend/web/; + index index.php; + + access_log /app/vagrant/nginx/log/frontend-access.log; + error_log /app/vagrant/nginx/log/frontend-error.log; + + location / { + # Redirect everything that isn't a real file to index.php + try_files $uri $uri/ /index.php$is_args$args; + } + + # uncomment to avoid processing of calls to non-existing static files by Yii + #location ~ \.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar)$ { + # try_files $uri =404; + #} + #error_page 404 /404.html; + + location ~ \.php$ { + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + #fastcgi_pass 127.0.0.1:9000; + fastcgi_pass unix:/var/run/php/php7.4-fpm.sock; + try_files $uri =404; + } + + location ~ /\.(ht|svn|git) { + deny all; + } +} + +server { + charset utf-8; + client_max_body_size 128M; + sendfile off; + + listen 80; ## listen for ipv4 + #listen [::]:80 default_server ipv6only=on; ## listen for ipv6 + + server_name y2aa-backend.test; + root /app/backend/web/; + index index.php; + + access_log /app/vagrant/nginx/log/backend-access.log; + error_log /app/vagrant/nginx/log/backend-error.log; + + location / { + # Redirect everything that isn't a real file to index.php + try_files $uri $uri/ /index.php$is_args$args; + } + + # uncomment to avoid processing of calls to non-existing static files by Yii + #location ~ \.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar)$ { + # try_files $uri =404; + #} + #error_page 404 /404.html; + + location ~ \.php$ { + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + #fastcgi_pass 127.0.0.1:9000; + fastcgi_pass unix:/var/run/php/php7.4-fpm.sock; + try_files $uri =404; + } + + location ~ /\.(ht|svn|git) { + deny all; + } +} diff --git a/vagrant/nginx/log/.gitignore b/vagrant/nginx/log/.gitignore new file mode 100644 index 0000000..c15cedd --- /dev/null +++ b/vagrant/nginx/log/.gitignore @@ -0,0 +1,5 @@ +# nginx logs +backend-access.log +backend-error.log +frontend-access.log +frontend-error.log \ No newline at end of file diff --git a/vagrant/provision/always-as-root.sh b/vagrant/provision/always-as-root.sh new file mode 100644 index 0000000..cca9cfb --- /dev/null +++ b/vagrant/provision/always-as-root.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +source /app/vagrant/provision/common.sh + +#== Provision script == + +info "Provision-script user: `whoami`" + +info "Restart web-stack" +service php7.4-fpm restart +service nginx restart +service mysql restart \ No newline at end of file diff --git a/vagrant/provision/common.sh b/vagrant/provision/common.sh new file mode 100644 index 0000000..ab5e1e0 --- /dev/null +++ b/vagrant/provision/common.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +#== Bash helpers == + +function info { + echo " " + echo "--> $1" + echo " " +} diff --git a/vagrant/provision/once-as-root.sh b/vagrant/provision/once-as-root.sh new file mode 100644 index 0000000..4542a43 --- /dev/null +++ b/vagrant/provision/once-as-root.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash + +source /app/vagrant/provision/common.sh + +#== Import script args == + +timezone=$(echo "$1") +readonly IP=$2 + +#== Provision script == + +info "Provision-script user: `whoami`" + +export DEBIAN_FRONTEND=noninteractive + +info "Configure timezone" +timedatectl set-timezone ${timezone} --no-ask-password + +info "AWK initial replacement work" +awk -v ip=$IP -f /app/vagrant/provision/provision.awk /app/environments/dev/*end/config/main-local.php + +info "Prepare root password for MySQL" +debconf-set-selections <<< "mysql-community-server mysql-community-server/root-pass password \"''\"" +debconf-set-selections <<< "mysql-community-server mysql-community-server/re-root-pass password \"''\"" +echo "Done!" + +info "Update OS software" +apt-get update +apt-get upgrade -y + +info "Add ppa:ondrej/php" +apt-get install -y python-software-properties +apt-get update && apt-get upgrade -y +add-apt-repository -y ppa:ondrej/php + +info "Install additional software" +apt-get install -y php7.4-curl php7.4-cli php7.4-intl php7.4-mysqlnd php7.4-gd php7.4-fpm php7.4-mbstring php7.4-xml unzip nginx mysql-server-5.7 php7.4-xdebug + +info "Configure MySQL" +sed -i "s/.*bind-address.*/bind-address = 0.0.0.0/" /etc/mysql/mysql.conf.d/mysqld.cnf +mysql -uroot <<< "CREATE USER 'root'@'%' IDENTIFIED BY ''" +mysql -uroot <<< "GRANT ALL PRIVILEGES ON *.* TO 'root'@'%'" +mysql -uroot <<< "DROP USER 'root'@'localhost'" +mysql -uroot <<< "FLUSH PRIVILEGES" +echo "Done!" + +info "Configure PHP-FPM" +sed -i 's/user = www-data/user = vagrant/g' /etc/php/7.4/fpm/pool.d/www.conf +sed -i 's/group = www-data/group = vagrant/g' /etc/php/7.4/fpm/pool.d/www.conf +sed -i 's/owner = www-data/owner = vagrant/g' /etc/php/7.4/fpm/pool.d/www.conf +cat << EOF > /etc/php/7.4/mods-available/xdebug.ini +zend_extension=xdebug.so +xdebug.remote_enable=1 +xdebug.remote_connect_back=1 +xdebug.remote_port=9000 +xdebug.remote_autostart=1 +EOF +echo "Done!" + +info "Configure NGINX" +sed -i 's/user www-data/user vagrant/g' /etc/nginx/nginx.conf +echo "Done!" + +info "Enabling site configuration" +ln -s /app/vagrant/nginx/app.conf /etc/nginx/sites-enabled/app.conf +echo "Done!" + +info "Initailize databases for MySQL" +mysql -uroot <<< "CREATE DATABASE yii2advanced" +mysql -uroot <<< "CREATE DATABASE yii2advanced_test" +echo "Done!" + +info "Install composer" +curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \ No newline at end of file diff --git a/vagrant/provision/once-as-vagrant.sh b/vagrant/provision/once-as-vagrant.sh new file mode 100644 index 0000000..ffaa898 --- /dev/null +++ b/vagrant/provision/once-as-vagrant.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +source /app/vagrant/provision/common.sh + +#== Import script args == + +github_token=$(echo "$1") + +#== Provision script == + +info "Provision-script user: `whoami`" + +info "Configure composer" +composer config --global github-oauth.github.com ${github_token} +echo "Done!" + +info "Install project dependencies" +cd /app +composer --no-progress --prefer-dist install + +info "Init project" +./init --env=Development --overwrite=y + +info "Apply migrations" +./yii migrate --interactive=0 +./yii_test migrate --interactive=0 + +info "Create bash-alias 'app' for vagrant user" +echo 'alias app="cd /app"' | tee /home/vagrant/.bash_aliases + +info "Enabling colorized prompt for guest console" +sed -i "s/#force_color_prompt=yes/force_color_prompt=yes/" /home/vagrant/.bashrc diff --git a/vagrant/provision/provision.awk b/vagrant/provision/provision.awk new file mode 100644 index 0000000..65e9bde --- /dev/null +++ b/vagrant/provision/provision.awk @@ -0,0 +1,70 @@ +### +# Modifying Yii2's files for initialize Vagrant VM +# +# @author HA3IK +# @version 1.0.0 + +BEGIN { + print "AWK BEGINs its work:" + IGNORECASE = 1 + # Correct IP - wildcard last octet + match(ip, /(([0-9]+\.)+)/, arr) + ip = arr[1] "*" +} +BEGINFILE { + msg = "- Work with: " FILENAME + # Define array index for the file + switch (FILENAME) { + case /environments\/dev\/(back|front)end\/config\/main\-local\.php$/: + isFile["IsMainLocConf"] = 1 + msg = msg " - allow VM IP for Gii and debug toolbar" + break + } + # Print the final message + print msg +} +# BODY +{ + # IF environments/dev/(back|front)end/config/main-local.php + if (isFile["IsMainLocConf"]) { + # IF the line[s] after yii\(debug|gii)\Module + if (FNR == nextLine["nubmer"]) { + # Prepare for next line + ++nextLine["nubmer"] + # IF line has "allowedIPs" + if (index($0, "allowedIPs")) { + # IF our IP is not there + if (!index($0, ip)) { + # Add it + match($0, /([^\]]+)(.+)/, arr) + $0 = sprintf("%s, '%s'%s", arr[1], ip, arr[2]) + } + # Delete next line + delete nextLine + # IF "allowedIPs" are not set - search for the end of an array structure + } else if ($0 ~ /\];$/) { + # Rewrite line + $0 = nextLine["indent"] "'allowedIPs' => ['127.0.0.1', '::1', '" ip "'],\n" $0 + delete nextLine + } + # IF line is done + if (!length(nextLine)) { + printf " Line %d: Allowed IP: %s\n", FNR, ip + } + # Search for yii\(debug|gii)\Module + } else if (match($0, /^(\s+).+yii\\(debug|gii)\\Module/, arr)) { + # Save next line and indent + nextLine["nubmer"] = FNR + 1 + nextLine["indent"] = arr[1] + } + # Rewrite the file + print $0 > FILENAME + } +} +ENDFILE { + delete isFile + close(FILENAME) +} +END { + print "AWK ENDs its work." +} diff --git a/yii.bat b/yii.bat new file mode 100644 index 0000000..3a68942 --- /dev/null +++ b/yii.bat @@ -0,0 +1,15 @@ +@echo off + +rem ------------------------------------------------------------- +rem Yii command line bootstrap script for Windows. +rem ------------------------------------------------------------- + +@setlocal + +set YII_PATH=%~dp0 + +if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe + +"%PHP_COMMAND%" "%YII_PATH%yii" %* + +@endlocal