From 43f5e15413f71c92cbaef018634975c2d8450d79 Mon Sep 17 00:00:00 2001 From: Devil Date: Sun, 18 Jul 2021 23:42:10 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BA=95=E5=B1=82=E6=A1=86=E6=9E=B6=E5=8D=87?= =?UTF-8?q?=E7=BA=A7=E5=88=B0tp6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 +- LICENSE => LICENSE.txt | 42 +- admin.php | 9 +- application/middleware.php => api.php | 10 +- app/.gitignore | 1 + application/tags.php => app/AppService.php | 44 +- app/BaseController.php | 104 + .../Http.php => app/ExceptionHandle.php | 65 +- application/command.php => app/Request.php | 8 +- .../template.php => app/admin/config/view.php | 23 +- .../admin/controller/Admin.php | 41 +- .../admin/controller/Agreement.php | 10 +- .../admin/controller/Answer.php | 22 +- .../admin/controller/Appcenternav.php | 24 +- .../admin/controller/Appconfig.php | 8 +- .../admin/controller/Apphomenav.php | 24 +- .../admin/controller/Appmini.php | 34 +- .../admin/controller/Article.php | 25 +- .../admin/controller/Articlecategory.php | 4 +- .../admin/controller/Brand.php | 27 +- .../admin/controller/Brandcategory.php | 4 +- .../admin/controller/Cache.php | 19 +- .../admin/controller/Common.php | 276 +- .../admin/controller/Config.php | 20 +- .../admin/controller/Customview.php | 18 +- .../admin/controller/Design.php | 54 +- .../admin/controller/Email.php | 10 +- .../admin/controller/Error.php | 13 +- .../admin/controller/Express.php | 6 +- .../admin/controller/Formtable.php | 0 .../admin/controller/Goods.php | 51 +- .../admin/controller/Goodsbrowse.php | 12 +- .../admin/controller/Goodscategory.php | 8 +- .../admin/controller/Goodscomments.php | 28 +- .../admin/controller/Goodsfavor.php | 12 +- .../admin/controller/Goodsparamstemplate.php | 29 +- .../admin/controller/Index.php | 26 +- .../admin/controller/Integrallog.php | 12 +- .../admin/controller/Layout.php | 0 .../admin/controller/Link.php | 8 +- .../admin/controller/Message.php | 12 +- .../admin/controller/Navigation.php | 16 +- .../admin/controller/Order.php | 22 +- .../admin/controller/Orderaftersale.php | 14 +- .../admin/controller/Packageinstall.php | 4 +- .../admin/controller/Packageupgrade.php | 0 .../admin/controller/Paylog.php | 12 +- .../admin/controller/Payment.php | 22 +- .../admin/controller/Payrequestlog.php | 12 +- .../admin/controller/Plugins.php | 24 +- .../admin/controller/Pluginsadmin.php | 32 +- .../admin/controller/Power.php | 6 +- .../admin/controller/Quicknav.php | 24 +- .../admin/controller/Refundlog.php | 12 +- .../admin/controller/Region.php | 4 +- .../admin/controller/Role.php | 23 +- .../admin/controller/Screeningprice.php | 4 +- {application => app}/admin/controller/Seo.php | 10 +- .../admin/controller/Site.php | 70 +- .../admin/controller/Slide.php | 26 +- {application => app}/admin/controller/Sms.php | 8 +- .../admin/controller/Sqlconsole.php | 2 +- .../admin/controller/Store.php | 4 +- .../admin/controller/Theme.php | 16 +- .../admin/controller/Ueditor.php | 0 .../admin/controller/User.php | 25 +- .../admin/controller/Useraddress.php | 26 +- .../admin/controller/Warehouse.php | 27 +- .../admin/controller/Warehousegoods.php | 29 +- .../admin/controller/index.html | 0 {application => app}/admin/form/Admin.php | 0 {application => app}/admin/form/Answer.php | 2 +- .../admin/form/Appcenternav.php | 0 .../admin/form/Apphomenav.php | 0 {application => app}/admin/form/Appmini.php | 0 {application => app}/admin/form/Article.php | 0 {application => app}/admin/form/Brand.php | 2 +- .../admin/form/Customview.php | 0 {application => app}/admin/form/Design.php | 0 {application => app}/admin/form/Goods.php | 2 +- .../admin/form/Goodsbrowse.php | 2 +- .../admin/form/Goodscomments.php | 4 +- .../admin/form/Goodsfavor.php | 2 +- .../admin/form/Goodsparamstemplate.php | 0 .../admin/form/Integrallog.php | 2 +- {application => app}/admin/form/Link.php | 0 {application => app}/admin/form/Message.php | 4 +- .../admin/form/Navigation.php | 0 {application => app}/admin/form/Order.php | 4 +- .../admin/form/Orderaftersale.php | 4 +- {application => app}/admin/form/Paylog.php | 4 +- {application => app}/admin/form/Payment.php | 0 .../admin/form/Payrequestlog.php | 4 +- {application => app}/admin/form/Quicknav.php | 0 {application => app}/admin/form/Refundlog.php | 4 +- {application => app}/admin/form/Role.php | 0 {application => app}/admin/form/Slide.php | 0 {application => app}/admin/form/User.php | 0 .../admin/form/Useraddress.php | 2 +- {application => app}/admin/form/Warehouse.php | 2 +- .../admin/form/Warehousegoods.php | 4 +- {application => app}/admin/index.html | 0 {application => app}/admin/lang/index.html | 0 {application => app}/admin/lang/zh-cn.php | 0 .../admin/view/default/admin/detail.html | 0 .../admin/view/default/admin/index.html | 2 +- .../admin/view/default/admin/login_info.html | 8 +- .../view/default/admin/module/operate.html | 0 .../admin/view/default/admin/save_info.html | 0 .../admin/view/default/agreement/nav.html | 0 .../admin/view/default/agreement/privacy.html | 0 .../view/default/agreement/register.html | 0 .../admin/view/default/answer/detail.html | 0 .../admin/view/default/answer/index.html | 0 .../view/default/answer/module/content.html | 0 .../view/default/answer/module/operate.html | 0 .../view/default/answer/module/reply.html | 0 .../admin/view/default/answer/save_info.html | 0 .../view/default/appcenternav/detail.html | 0 .../view/default/appcenternav/index.html | 0 .../default/appcenternav/module/images.html | 0 .../default/appcenternav/module/operate.html | 0 .../view/default/appcenternav/save_info.html | 0 .../admin/view/default/appconfig/app.html | 0 .../admin/view/default/appconfig/base.html | 0 .../admin/view/default/appconfig/nav.html | 0 .../admin/view/default/apphomenav/detail.html | 0 .../admin/view/default/apphomenav/index.html | 0 .../default/apphomenav/module/images.html | 0 .../default/apphomenav/module/operate.html | 0 .../view/default/apphomenav/save_info.html | 0 .../admin/view/default/appmini/base_nav.html | 0 .../admin/view/default/appmini/config.html | 0 .../admin/view/default/appmini/index.html | 0 .../view/default/appmini/module/operate.html | 0 .../admin/view/default/appmini/nav.html | 0 .../admin/view/default/appmini/package.html | 2 +- .../admin/view/default/appmini/upload.html | 0 .../admin/view/default/article/detail.html | 0 .../admin/view/default/article/index.html | 0 .../view/default/article/module/info.html | 0 .../view/default/article/module/operate.html | 0 .../admin/view/default/article/save_info.html | 0 .../view/default/articlecategory/index.html | 0 .../admin/view/default/brand/detail.html | 0 .../admin/view/default/brand/index.html | 0 .../admin/view/default/brand/module/logo.html | 0 .../view/default/brand/module/operate.html | 0 .../admin/view/default/brand/module/url.html | 0 .../admin/view/default/brand/save_info.html | 0 .../view/default/brandcategory/index.html | 0 .../admin/view/default/cache/index.html | 0 .../admin/view/default/config/index.html | 0 .../admin/view/default/config/store.html | 0 .../admin/view/default/customview/detail.html | 0 .../admin/view/default/customview/index.html | 0 .../view/default/customview/module/info.html | 0 .../default/customview/module/operate.html | 0 .../view/default/customview/save_info.html | 0 .../admin/view/default/design/index.html | 0 .../view/default/design/module/info.html | 0 .../view/default/design/module/operate.html | 0 .../view/default/design/popup_saveinfo.html | 0 .../admin/view/default/design/save_info.html | 0 .../admin/view/default/email/index.html | 0 .../admin/view/default/email/message.html | 0 .../admin/view/default/email/nav.html | 0 .../admin/view/default/express/index.html | 0 .../admin/view/default/goods/detail.html | 0 .../admin/view/default/goods/index.html | 0 .../admin/view/default/goods/module/info.html | 0 .../view/default/goods/module/operate.html | 0 .../admin/view/default/goods/save_info.html | 0 .../admin/view/default/goods/spec.html | 0 .../view/default/goods/spec_extends.html | 0 .../view/default/goodsbrowse/detail.html | 0 .../admin/view/default/goodsbrowse/index.html | 0 .../default/goodsbrowse/module/goods.html | 0 .../default/goodsbrowse/module/operate.html | 0 .../view/default/goodscategory/index.html | 0 .../view/default/goodscomments/detail.html | 0 .../view/default/goodscomments/index.html | 0 .../default/goodscomments/module/content.html | 0 .../default/goodscomments/module/goods.html | 0 .../default/goodscomments/module/images.html | 0 .../default/goodscomments/module/operate.html | 0 .../default/goodscomments/module/rating.html | 0 .../default/goodscomments/module/reply.html | 0 .../view/default/goodscomments/save_info.html | 0 .../admin/view/default/goodsfavor/detail.html | 0 .../admin/view/default/goodsfavor/index.html | 0 .../view/default/goodsfavor/module/goods.html | 0 .../default/goodsfavor/module/operate.html | 0 .../default/goodsparamstemplate/detail.html | 0 .../default/goodsparamstemplate/index.html | 0 .../goodsparamstemplate/module/operate.html | 0 .../goodsparamstemplate/save_info.html | 0 .../admin/view/default/index.html | 0 .../admin/view/default/index/index.html | 0 .../admin/view/default/index/init.html | 0 .../view/default/integrallog/detail.html | 0 .../admin/view/default/integrallog/index.html | 0 .../default/integrallog/module/operate.html | 0 .../admin/view/default/lib/enable.html | 0 .../view/default/lib/excel_win_html.html | 0 .../admin/view/default/lib/excel_win_js.html | 0 .../admin/view/default/lib/gender.html | 0 .../admin/view/default/lib/index.html | 0 .../admin/view/default/lib/is_footer.html | 0 .../view/default/lib/is_full_screen.html | 0 .../admin/view/default/lib/is_header.html | 0 .../view/default/lib/is_new_window_open.html | 0 .../admin/view/default/lib/is_show.html | 0 .../default/lib/module/category_brand.html | 0 .../default/lib/module/goods_category.html | 0 .../admin/view/default/lib/module/user.html | 0 .../view/default/lib/region_linkage.html | 0 .../admin/view/default/lib/seo.html | 0 .../admin/view/default/lib/user_status.html | 0 .../admin/view/default/link/detail.html | 0 .../admin/view/default/link/index.html | 0 .../admin/view/default/link/module/info.html | 0 .../view/default/link/module/operate.html | 0 .../admin/view/default/link/module/url.html | 0 .../admin/view/default/message/detail.html | 0 .../admin/view/default/message/index.html | 0 .../view/default/message/module/operate.html | 0 .../admin/view/default/navigation/index.html | 0 .../view/default/navigation/module/info.html | 0 .../default/navigation/module/operate.html | 0 .../admin/view/default/navigation/nav.html | 0 .../admin/view/default/order/detail.html | 0 .../admin/view/default/order/index.html | 0 .../view/default/order/module/address.html | 0 .../view/default/order/module/aftersale.html | 0 .../view/default/order/module/extension.html | 0 .../view/default/order/module/goods.html | 10 +- .../default/order/module/is_comments.html | 0 .../view/default/order/module/operate.html | 0 .../view/default/order/module/pay_status.html | 0 .../view/default/order/module/status.html | 0 .../admin/view/default/order/module/take.html | 0 .../view/default/orderaftersale/detail.html | 0 .../view/default/orderaftersale/index.html | 0 .../default/orderaftersale/module/goods.html | 6 +- .../orderaftersale/module/operate.html | 0 .../orderaftersale/module/voucher.html | 0 .../view/default/packageinstall/index.html | 0 .../admin/view/default/paylog/detail.html | 0 .../admin/view/default/paylog/index.html | 0 .../default/paylog/module/business_list.html | 0 .../view/default/paylog/module/operate.html | 0 .../view/default/paylog/module/payment.html | 0 .../admin/view/default/payment/index.html | 0 .../payment/module/apply_terminal.html | 0 .../view/default/payment/module/author.html | 0 .../view/default/payment/module/enable.html | 0 .../view/default/payment/module/logo.html | 0 .../default/payment/module/open_user.html | 0 .../view/default/payment/module/operate.html | 0 .../admin/view/default/payment/save_info.html | 0 .../view/default/payrequestlog/detail.html | 0 .../view/default/payrequestlog/index.html | 0 .../payrequestlog/module/business_handle.html | 0 .../default/payrequestlog/module/operate.html | 0 .../payrequestlog/module/request_params.html | 0 .../payrequestlog/module/response_data.html | 0 .../admin/view/default/plugins/index.html | 0 .../view/default/pluginsadmin/first_step.html | 0 .../view/default/pluginsadmin/index.html | 0 .../admin/view/default/pluginsadmin/nav.html | 0 .../view/default/pluginsadmin/save_info.html | 0 .../view/default/pluginsadmin/upload.html | 0 .../admin/view/default/power/index.html | 2 +- .../view/default/public/event_value_tips.html | 0 .../admin/view/default/public/footer.html | 0 .../public/goodsparamstemplate/detail.html | 0 .../public/goodsparamstemplate/table.html | 0 .../public/goodsparamstemplate/tips.html | 0 .../admin/view/default/public/header.html | 2 +- .../admin/view/default/public/index.html | 0 app/admin/view/default/public/jump_error.html | 33 + .../view/default/public/jump_success.html | 33 + .../admin/view/default/public/loading.html | 0 .../admin/view/default/public/menu.html | 0 .../view/default/public/module/detail.html | 8 +- .../view/default/public/module/form.html | 8 +- .../public/module/form_fields_select.html | 0 .../public/module/form_operate_bottom.html | 2 +- .../public/module/form_operate_top.html | 2 +- .../default/public/module/form_table.html | 2 +- .../admin/view/default/public/nav.html | 0 .../admin/view/default/public/nav_bar.html | 0 .../admin/view/default/public/not_data.html | 0 .../view/default/public/page_loading.html | 0 .../admin/view/default/public/tips_error.html | 0 .../admin/view/default/quicknav/detail.html | 0 .../admin/view/default/quicknav/index.html | 0 .../view/default/quicknav/module/images.html | 0 .../view/default/quicknav/module/operate.html | 0 .../view/default/quicknav/save_info.html | 0 .../admin/view/default/refundlog/detail.html | 0 .../admin/view/default/refundlog/index.html | 0 .../default/refundlog/module/operate.html | 0 .../default/refundlog/module/payment.html | 0 .../admin/view/default/region/index.html | 0 .../admin/view/default/role/detail.html | 0 .../admin/view/default/role/index.html | 0 .../view/default/role/module/operate.html | 0 .../admin/view/default/role/save_info.html | 0 .../view/default/screeningprice/index.html | 0 .../admin/view/default/seo/index.html | 0 .../view/default/site/attachment/index.html | 0 .../admin/view/default/site/base/index.html | 0 .../admin/view/default/site/cache/index.html | 40 +- .../view/default/site/extends/index.html | 0 .../view/default/site/forgetpwd/index.html | 0 .../admin/view/default/site/login/index.html | 0 .../default/site/orderaftersale/index.html | 0 .../default/site/public/goods_search.html | 0 .../admin/view/default/site/public/nav.html | 0 .../view/default/site/public/siteset_nav.html | 0 .../view/default/site/register/index.html | 0 .../view/default/site/siteset/discount.html | 0 .../view/default/site/siteset/extends.html | 0 .../view/default/site/siteset/goods.html | 0 .../view/default/site/siteset/index.html | 0 .../view/default/site/siteset/order.html | 0 .../view/default/site/siteset/search.html | 0 .../view/default/site/sitetype/index.html | 0 .../admin/view/default/site/verify/index.html | 0 .../admin/view/default/slide/detail.html | 0 .../admin/view/default/slide/index.html | 0 .../view/default/slide/module/images.html | 0 .../view/default/slide/module/operate.html | 0 .../admin/view/default/slide/save_info.html | 0 .../admin/view/default/sms/index.html | 0 .../admin/view/default/sms/message.html | 0 .../admin/view/default/sms/nav.html | 0 .../admin/view/default/sqlconsole/index.html | 0 .../admin/view/default/store/index.html | 0 .../admin/view/default/theme/index.html | 0 .../admin/view/default/theme/nav.html | 0 .../admin/view/default/theme/upload.html | 0 .../admin/view/default/user/detail.html | 0 .../admin/view/default/user/index.html | 0 .../view/default/user/module/avatar.html | 0 .../view/default/user/module/operate.html | 0 .../admin/view/default/user/save_info.html | 0 .../view/default/useraddress/detail.html | 0 .../admin/view/default/useraddress/index.html | 0 .../useraddress/module/idcard_info.html | 0 .../useraddress/module/is_default.html | 0 .../default/useraddress/module/operate.html | 0 .../default/useraddress/module/position.html | 0 .../view/default/useraddress/save_info.html | 0 .../admin/view/default/warehouse/detail.html | 0 .../admin/view/default/warehouse/index.html | 0 .../view/default/warehouse/module/info.html | 0 .../default/warehouse/module/operate.html | 0 .../default/warehouse/module/position.html | 0 .../view/default/warehouse/save_info.html | 0 .../view/default/warehousegoods/detail.html | 0 .../default/warehousegoods/goods_search.html | 0 .../default/warehousegoods/goods_spec.html | 0 .../view/default/warehousegoods/index.html | 0 .../warehousegoods/inventory_info.html | 0 .../default/warehousegoods/module/goods.html | 0 .../warehousegoods/module/operate.html | 0 {application => app}/admin/view/index.html | 0 {application => app}/api/config/app.php | 0 build.php => app/api/config/route.php | 19 +- .../api/controller/Agreement.php | 0 .../api/controller/Answer.php | 0 .../api/controller/Banner.php | 0 {application => app}/api/controller/Base.php | 0 {application => app}/api/controller/Buy.php | 0 {application => app}/api/controller/Cart.php | 0 .../api/controller/Common.php | 40 +- .../api/controller/Crontab.php | 0 .../api/controller/Design.php | 0 .../api/controller/Devtest.php | 16 +- app/api/controller/Error.php | 44 + {application => app}/api/controller/Goods.php | 0 {application => app}/api/controller/Index.php | 0 .../api/controller/Message.php | 0 .../api/controller/Navigation.php | 0 {application => app}/api/controller/Order.php | 0 .../api/controller/Orderaftersale.php | 0 .../api/controller/Ordernotify.php | 0 .../api/controller/Plugins.php | 0 .../api/controller/Region.php | 0 .../api/controller/Search.php | 0 .../api/controller/Ueditor.php | 0 {application => app}/api/controller/User.php | 0 .../api/controller/Useraddress.php | 0 .../api/controller/Usergoodsbrowse.php | 0 .../api/controller/Usergoodsfavor.php | 0 .../api/controller/Userintegral.php | 0 .../api/controller/index.html | 0 {application => app}/api/index.html | 0 {application => app}/common.php | 352 +- app/index/config/route.php | 18 + .../template.php => app/index/config/view.php | 32 +- .../index/controller/Agreement.php | 10 +- .../index/controller/Answer.php | 18 +- .../index/controller/Article.php | 22 +- {application => app}/index/controller/Buy.php | 43 +- .../index/controller/Cart.php | 8 +- .../index/controller/Category.php | 4 +- app/index/controller/Common.php | 588 +++ .../index/controller/Customview.php | 14 +- .../index/controller/Design.php | 20 +- .../index/controller/Error.php | 13 +- .../index/controller/Formtable.php | 0 .../index/controller/Goods.php | 35 +- .../index/controller/Index.php | 57 +- .../index/controller/Layout.php | 4 +- .../index/controller/Message.php | 18 +- .../index/controller/Order.php | 78 +- .../index/controller/Orderaftersale.php | 54 +- {application => app}/index/controller/Pay.php | 8 +- .../index/controller/Personal.php | 14 +- .../index/controller/Plugins.php | 24 +- .../index/controller/Qrcode.php | 8 +- .../index/controller/Region.php | 0 .../index/controller/Safety.php | 50 +- .../index/controller/Search.php | 31 +- .../index/controller/Ueditor.php | 0 .../index/controller/User.php | 95 +- .../index/controller/Useraddress.php | 18 +- .../index/controller/Usergoodsbrowse.php | 18 +- .../index/controller/Usergoodsfavor.php | 18 +- .../index/controller/Userintegral.php | 20 +- .../index/controller/index.html | 0 {application => app}/index/form/Answer.php | 2 +- {application => app}/index/form/Message.php | 4 +- {application => app}/index/form/Order.php | 2 +- .../index/form/Orderaftersale.php | 4 +- .../index/form/Usergoodsbrowse.php | 2 +- .../index/form/Usergoodsfavor.php | 2 +- .../index/form/Userintegral.php | 2 +- {application => app}/index/index.html | 0 {application => app}/index/lang/index.html | 0 {application => app}/index/lang/zh-cn.php | 0 app/index/route/.gitignore | 1 + {route => app/index/route}/route.config | 0 .../index/view/default/agreement/index.html | 0 .../index/view/default/answer/detail.html | 0 .../index/view/default/answer/index.html | 0 .../view/default/answer/module/content.html | 0 .../view/default/answer/module/operate.html | 0 .../view/default/answer/module/reply.html | 0 .../index/view/default/article/index.html | 0 .../index/view/default/buy/index.html | 14 +- .../index/view/default/cart/index.html | 22 +- .../index/view/default/category/index.html | 0 .../index/view/default/config.json | 2 +- .../index/view/default/customview/index.html | 0 .../index/view/default/design/index.html | 0 .../index/view/default/goods/comments.html | 0 .../index/view/default/goods/index.html | 0 .../index/view/default/index.html | 0 .../index/view/default/index/index.html | 16 +- .../index/view/default/lib/enable.html | 0 .../index/view/default/lib/gender.html | 0 .../index/view/default/lib/index.html | 0 .../view/default/lib/is_new_window_open.html | 0 .../index/view/default/lib/is_show.html | 0 .../default/lib/module/category_brand.html | 0 .../default/lib/module/goods_category.html | 0 .../view/default/lib/region_linkage.html | 0 .../index/view/default/lib/seo.html | 0 .../index/view/default/message/detail.html | 0 .../index/view/default/message/index.html | 0 .../view/default/message/module/operate.html | 0 .../index/view/default/order/comments.html | 0 .../index/view/default/order/detail.html | 16 +- .../index/view/default/order/index.html | 0 .../view/default/order/module/address.html | 0 .../view/default/order/module/extension.html | 0 .../view/default/order/module/goods.html | 10 +- .../default/order/module/is_comments.html | 0 .../view/default/order/module/operate.html | 0 .../view/default/order/module/pay_status.html | 0 .../index/view/default/order/module/take.html | 0 .../view/default/order/payment_popup.html | 0 .../view/default/orderaftersale/create.html | 0 .../view/default/orderaftersale/delivery.html | 0 .../view/default/orderaftersale/detail.html | 14 +- .../view/default/orderaftersale/index.html | 0 .../default/orderaftersale/module/goods.html | 6 +- .../orderaftersale/module/operate.html | 0 .../orderaftersale/module/voucher.html | 0 .../view/default/orderaftersale/step.html | 0 .../index/view/default/pay/qrcode.html | 0 .../index/view/default/personal/index.html | 0 .../view/default/personal/save_info.html | 0 .../index/view/default/public/footer.html | 0 .../index/view/default/public/footer_nav.html | 0 .../view/default/public/goods_category.html | 2 +- .../index/view/default/public/header.html | 6 +- .../index/view/default/public/header_nav.html | 0 .../view/default/public/header_top_nav.html | 0 .../view/default/public/home_banner.html | 0 .../index/view/default/public/home_nav.html | 0 .../index/view/default/public/index.html | 0 app/index/view/default/public/jump_error.html | 46 + .../view/default/public/jump_success.html | 46 + .../index/view/default/public/loading.html | 0 .../view/default/public/login_success.html | 0 .../view/default/public/module/base_form.html | 0 .../view/default/public/module/detail.html | 8 +- .../view/default/public/module/form.html | 8 +- .../public/module/form_fields_select.html | 0 .../public/module/form_operate_bottom.html | 2 +- .../public/module/form_operate_top.html | 2 +- .../default/public/module/form_table.html | 2 +- .../view/default/public/module/user_form.html | 8 +- .../index/view/default/public/nav.html | 0 .../index/view/default/public/nav_search.html | 0 .../index/view/default/public/not_data.html | 0 .../index/view/default/public/quick.html | 0 .../index/view/default/public/tips_error.html | 3 +- .../view/default/public/tips_success.html | 3 +- .../index/view/default/public/user_menu.html | 0 .../index/view/default/safety/email_info.html | 4 +- .../index/view/default/safety/index.html | 0 .../view/default/safety/login_pwd_info.html | 0 .../view/default/safety/mobile_info.html | 4 +- .../view/default/safety/new_email_info.html | 4 +- .../view/default/safety/new_mobile_info.html | 4 +- .../index/view/default/search/content.html | 6 +- .../index/view/default/search/index.html | 0 .../view/default/user/forget_pwd_info.html | 0 .../view/default/user/images_verify.html | 4 +- .../index/view/default/user/index.html | 0 .../view/default/user/login_content.html | 4 +- .../index/view/default/user/login_info.html | 0 .../index/view/default/user/logout.html | 0 .../view/default/user/modal_login_info.html | 0 .../index/view/default/user/reg_info.html | 4 +- .../index/view/default/useraddress/index.html | 0 .../view/default/useraddress/save_info.html | 0 .../view/default/usergoodsbrowse/detail.html | 0 .../view/default/usergoodsbrowse/index.html | 0 .../default/usergoodsbrowse/module/goods.html | 0 .../usergoodsbrowse/module/operate.html | 0 .../view/default/usergoodsfavor/detail.html | 0 .../view/default/usergoodsfavor/index.html | 0 .../default/usergoodsfavor/module/goods.html | 0 .../usergoodsfavor/module/operate.html | 0 .../view/default/userintegral/detail.html | 0 .../view/default/userintegral/index.html | 0 .../default/userintegral/module/operate.html | 0 {application => app}/index/view/index.html | 0 .../install/config/view.php | 23 +- .../install/controller/Common.php | 34 +- .../install/controller/Error.php | 16 +- .../install/controller/Index.php | 116 +- .../install/view/index/check.html | 134 +- .../install/view/index/create.html | 4 +- .../install/view/index/index.html | 2 +- .../install/view/index/successful.html | 0 app/install/view/public/error.html | 16 + .../install/view/public/footer.html | 0 .../install/view/public/footer_nav.html | 2 +- .../install/view/public/header.html | 0 .../install/view/public/header_nav.html | 0 .../install/view/public/index.html | 0 {application => app}/lang/zh-cn.php | 1 + .../layout/service/BaseLayout.php | 13 +- {application => app}/layout/view/base.html | 0 .../layout/view/form_back.html | 0 .../public/common/goods_category_choice.html | 0 .../view/public/common/goodssearch.html | 0 .../view/public/common/module_admin.html | 0 .../view/public/common/module_view.html | 0 .../view/public/content/goods_show_style.html | 0 .../content/many_images_show_style.html | 0 .../view/public/content/media_fixed.html | 0 .../view/public/content/view_list_number.html | 0 .../modal/modal_module_list_config.html | 0 .../modal/modal_module_pages_select.html | 0 .../modal/modal_module_rolling_config.html | 0 .../modal/modal_module_title_keywords.html | 0 .../offcanvas/offcanvas_layout_config.html | 0 .../offcanvas_module_config_border.html | 0 .../offcanvas_module_config_goods.html | 0 .../offcanvas_module_config_height.html | 0 .../offcanvas_module_config_images.html | 0 .../offcanvas_module_config_many_images.html | 0 .../offcanvas_module_config_title.html | 0 .../offcanvas_module_config_video.html | 0 .../popup/popup_module_goods_category.html | 0 .../popup/popup_module_goods_search.html | 0 .../popup/popup_module_goods_select.html | 0 .../view/public/style/background_color.html | 0 .../view/public/style/border_radius.html | 0 .../view/public/style/border_style.html | 0 .../view/public/style/border_style_4.html | 0 .../view/public/style/border_width_4.html | 0 .../view/public/style/border_width_color.html | 0 .../public/style/border_width_color_4.html | 0 .../layout/view/public/style/color.html | 0 .../layout/view/public/style/height.html | 0 .../layout/view/public/style/input_color.html | 0 .../layout/view/public/style/margin.html | 0 .../layout/view/public/style/margin_4.html | 0 .../layout/view/public/style/padding.html | 0 .../layout/view/public/style/padding_4.html | 0 .../layout/view/public/style/width.html | 0 {application => app}/layout/view/view.html | 0 app/middleware.php | 21 + .../module/FormHandleModule.php | 5 +- .../module/ViewIncludeModule.php | 24 +- {application => app}/plugins/.gitignore | 0 {application => app}/plugins/index.html | 0 {application => app}/plugins/view/.gitignore | 0 {application => app}/plugins/view/index.html | 0 {application => app}/provider.php | 10 +- app/service.php | 17 + .../service/AdminPowerService.php | 37 +- .../service/AdminRoleService.php | 10 +- {application => app}/service/AdminService.php | 16 +- .../service/AnswerService.php | 6 +- .../service/AppCenterNavService.php | 15 +- .../service/AppHomeNavService.php | 15 +- .../service/AppMiniService.php | 8 +- .../service/ArticleService.php | 17 +- .../service/BannerService.php | 10 +- .../service/BrandCategoryService.php | 6 +- {application => app}/service/BrandService.php | 11 +- {application => app}/service/BuyService.php | 47 +- {application => app}/service/CacheService.php | 0 .../service/ConfigService.php | 35 +- .../service/CrontabService.php | 6 +- .../service/CustomViewService.php | 6 +- .../service/DesignService.php | 6 +- .../service/ExpressService.php | 6 +- .../service/FormTableService.php | 4 +- .../service/GoodsBrowseService.php | 6 +- .../service/GoodsCommentsService.php | 4 +- .../service/GoodsFavorService.php | 6 +- .../service/GoodsParamsService.php | 9 +- {application => app}/service/GoodsService.php | 89 +- .../service/IntegralService.php | 10 +- .../service/LayoutService.php | 2 +- {application => app}/service/LinkService.php | 4 +- .../service/MessageService.php | 7 +- .../service/NavigationService.php | 53 +- .../service/OrderAftersaleService.php | 41 +- .../service/OrderCurrencyService.php | 4 +- {application => app}/service/OrderService.php | 51 +- .../service/OrderSplitService.php | 7 +- .../service/PackageInstallService.php | 10 +- .../service/PayLogService.php | 11 +- .../service/PayRequestLogService.php | 4 +- .../service/PaymentService.php | 82 +- .../service/PluginsAdminService.php | 67 +- .../service/PluginsService.php | 24 +- .../service/PluginsUpgradeService.php | 8 +- .../service/QuickNavService.php | 15 +- .../service/RefundLogService.php | 6 +- .../service/RegionService.php | 14 +- .../service/ResourcesService.php | 41 +- .../service/SafetyService.php | 11 +- .../service/ScreeningPriceService.php | 4 +- .../service/SearchService.php | 27 +- {application => app}/service/SeoService.php | 0 {application => app}/service/SiteService.php | 2 +- {application => app}/service/SlideService.php | 4 +- .../service/SqlconsoleService.php | 7 +- .../service/StatisticalService.php | 4 +- {application => app}/service/StoreService.php | 16 +- .../service/SystemBaseService.php | 23 +- .../service/SystemService.php | 23 +- .../service/SystemUpgradeService.php | 16 +- {application => app}/service/ThemeService.php | 4 +- .../service/UeditorService.php | 2 +- .../service/UserAddressService.php | 19 +- {application => app}/service/UserService.php | 51 +- .../service/WarehouseGoodsService.php | 21 +- .../service/WarehouseService.php | 13 +- {application => app}/service/index.html | 0 application/admin/config/app.php | 40 - .../admin/view/default/public/jump_error.html | 45 - .../view/default/public/jump_success.html | 45 - .../http/middleware/SystemEnvCheck.php | 69 - application/index/config/app.php | 32 - application/index/controller/Common.php | 545 --- .../index/view/default/public/jump_error.html | 45 - .../view/default/public/jump_success.html | 45 - application/install/view/public/error.html | 16 - changelog.txt | 14 + composer.json | 87 +- composer.lock | 1093 +++++ config/.gitignore | 0 config/app.php | 186 +- config/cache.php | 74 +- config/console.php | 7 +- config/cookie.php | 6 +- config/filesystem.php | 37 + config/lang.php | 37 + config/log.php | 52 +- config/middleware.php | 8 +- config/route.php | 55 + config/session.php | 43 +- config/shopxo.php | 10 +- config/trace.php | 10 +- extend/base/Baidu.php | 10 +- extend/base/Email.php | 10 +- extend/base/QQ.php | 10 +- extend/base/Sms.php | 10 +- extend/base/Toutiao.php | 4 +- extend/base/Verify.php | 16 +- extend/base/Wechat.php | 14 +- extend/payment/Alipay.php | 2 +- index.php | 2 +- install.php | 17 + public/admin.php | 11 +- public/api.php | 26 + public/core.php | 16 +- public/index.php | 13 +- public/install.php | 26 + public/router.php | 12 +- .../ueditor/dialogs/attachment/attachment.js | 4 +- .../common/lib/ueditor/dialogs/image/image.js | 4 +- .../common/lib/ueditor/dialogs/map/map.html | 2 +- .../common/lib/ueditor/dialogs/map/show.html | 2 +- .../common/lib/ueditor/dialogs/video/video.js | 4 +- public/static/index/default/js/goods.js | 1 + robots.txt | 10 - .../default/pages/common/copyright.axml | 2 +- .../baidu/default/pages/common/copyright.swan | 2 +- .../qq/default/pages/common/copyright.qml | 2 +- .../default/pages/common/copyright.ttml | 2 +- .../default/pages/common/copyright.wxml | 2 +- think | 18 +- thinkphp/.htaccess | 1 - thinkphp/README.md | 93 - thinkphp/base.php | 52 - thinkphp/convention.php | 327 -- thinkphp/helper.php | 720 ---- thinkphp/library/think/App.php | 981 ----- thinkphp/library/think/Build.php | 415 -- thinkphp/library/think/Cache.php | 133 - thinkphp/library/think/Config.php | 398 -- thinkphp/library/think/Container.php | 568 --- thinkphp/library/think/Controller.php | 316 -- thinkphp/library/think/Cookie.php | 268 -- thinkphp/library/think/Db.php | 197 - thinkphp/library/think/Debug.php | 278 -- thinkphp/library/think/Error.php | 147 - thinkphp/library/think/File.php | 496 --- thinkphp/library/think/Hook.php | 220 - thinkphp/library/think/Lang.php | 284 -- thinkphp/library/think/Loader.php | 417 -- thinkphp/library/think/Log.php | 387 -- thinkphp/library/think/Middleware.php | 205 - thinkphp/library/think/Model.php | 1072 ----- thinkphp/library/think/Process.php | 1268 ------ thinkphp/library/think/Route.php | 990 ----- thinkphp/library/think/Session.php | 579 --- thinkphp/library/think/Url.php | 404 -- thinkphp/library/think/View.php | 250 -- thinkphp/library/think/cache/Driver.php | 363 -- thinkphp/library/think/cache/driver/File.php | 305 -- thinkphp/library/think/cache/driver/Lite.php | 209 - .../library/think/cache/driver/Sqlite.php | 233 - .../library/think/cache/driver/Xcache.php | 179 - thinkphp/library/think/config/driver/Ini.php | 31 - thinkphp/library/think/config/driver/Xml.php | 40 - .../library/think/console/command/Build.php | 59 - .../command/make/stubs/controller.plain.stub | 10 - .../command/make/stubs/middleware.stub | 10 - .../console/command/optimize/Autoload.php | 279 -- .../think/console/command/optimize/Config.php | 107 - .../think/console/command/optimize/Schema.php | 118 - thinkphp/library/think/db/Builder.php | 1164 ----- thinkphp/library/think/db/Connection.php | 2150 ---------- thinkphp/library/think/db/Query.php | 3734 ----------------- thinkphp/library/think/db/builder/Mysql.php | 174 - .../library/think/db/connector/Sqlsrv.php | 235 -- .../think/exception/ThrowableError.php | 47 - thinkphp/library/think/facade/App.php | 63 - thinkphp/library/think/facade/Build.php | 33 - thinkphp/library/think/facade/Cache.php | 45 - thinkphp/library/think/facade/Debug.php | 40 - thinkphp/library/think/facade/Hook.php | 37 - thinkphp/library/think/facade/Lang.php | 41 - thinkphp/library/think/facade/Log.php | 49 - thinkphp/library/think/facade/Request.php | 97 - thinkphp/library/think/facade/Response.php | 47 - thinkphp/library/think/facade/Route.php | 57 - thinkphp/library/think/facade/Session.php | 46 - thinkphp/library/think/facade/Template.php | 36 - thinkphp/library/think/facade/Validate.php | 75 - thinkphp/library/think/facade/View.php | 40 - thinkphp/library/think/log/driver/File.php | 283 -- thinkphp/library/think/model/Collection.php | 100 - thinkphp/library/think/model/Relation.php | 166 - .../think/model/concern/Conversion.php | 288 -- .../think/model/concern/ModelEvent.php | 238 -- .../library/think/model/concern/TimeStamp.php | 92 - .../library/think/model/relation/HasMany.php | 351 -- .../think/model/relation/HasManyThrough.php | 156 - thinkphp/library/think/process/Builder.php | 233 - thinkphp/library/think/process/Utils.php | 75 - .../library/think/process/exception/Faild.php | 42 - .../think/process/exception/Failed.php | 42 - .../think/process/exception/Timeout.php | 61 - .../library/think/process/pipes/Pipes.php | 93 - thinkphp/library/think/process/pipes/Unix.php | 196 - .../library/think/process/pipes/Windows.php | 228 - thinkphp/library/think/response/View.php | 94 - thinkphp/library/think/route/AliasRule.php | 119 - thinkphp/library/think/route/Dispatch.php | 365 -- thinkphp/library/think/route/Resource.php | 126 - thinkphp/library/think/route/Rule.php | 1121 ----- thinkphp/library/think/route/RuleName.php | 147 - .../think/route/dispatch/Controller.php | 30 - .../library/think/route/dispatch/Module.php | 139 - thinkphp/library/think/route/dispatch/Url.php | 169 - .../library/think/session/driver/Memcache.php | 124 - .../think/session/driver/Memcached.php | 135 - .../library/think/session/driver/Redis.php | 185 - thinkphp/library/think/view/driver/Php.php | 183 - thinkphp/library/think/view/driver/Think.php | 192 - thinkphp/library/traits/controller/Jump.php | 168 - thinkphp/phpunit.xml.dist | 41 - thinkphp/tpl/default_index.tpl | 10 - thinkphp/tpl/dispatch_jump.tpl | 49 - {thinkphp/tpl => tpl}/think_exception.tpl | 342 +- vendor/.gitignore | 2 - vendor/autoload.php | 7 + vendor/bin/var-dump-server | 1 + vendor/composer/ClassLoader.php | 481 +++ vendor/composer/InstalledVersions.php | 337 ++ vendor/composer/LICENSE | 21 + vendor/composer/autoload_classmap.php | 14 + vendor/composer/autoload_files.php | 15 + vendor/composer/autoload_namespaces.php | 10 + vendor/composer/autoload_psr4.php | 25 + vendor/composer/autoload_real.php | 75 + vendor/composer/autoload_static.php | 144 + vendor/composer/installed.json | 1137 +++++ vendor/composer/installed.php | 185 + vendor/composer/platform_check.php | 26 + .../flysystem-cached-adapter/.editorconfig | 10 + .../flysystem-cached-adapter/.gitignore | 4 + .../league/flysystem-cached-adapter/.php_cs | 7 + .../flysystem-cached-adapter/.scrutinizer.yml | 34 + .../flysystem-cached-adapter/.travis.yml | 29 + .../league/flysystem-cached-adapter/LICENSE | 19 + .../clover}/.gitignore | 1 - .../flysystem-cached-adapter/composer.json | 30 + .../flysystem-cached-adapter/phpspec.yml | 6 + .../flysystem-cached-adapter/phpunit.php | 3 + .../flysystem-cached-adapter/phpunit.xml | 29 + .../league/flysystem-cached-adapter/readme.md | 20 + .../spec/CachedAdapterSpec.php | 435 ++ .../src/CacheInterface.php | 101 + .../src/CachedAdapter.php | 346 ++ .../src/Storage/AbstractCache.php | 418 ++ .../src/Storage/Adapter.php | 115 + .../src/Storage/Memcached.php | 59 + .../src/Storage/Memory.php | 22 + .../src/Storage/Noop.php | 171 + .../src/Storage/PhpRedis.php | 62 + .../src/Storage/Predis.php | 75 + .../src/Storage/Psr6Cache.php | 59 + .../src/Storage/Stash.php | 60 + .../tests/AdapterCacheTests.php | 104 + .../tests/InspectionTests.php | 16 + .../tests/MemcachedTests.php | 35 + .../tests/MemoryCacheTests.php | 255 ++ .../tests/NoopCacheTests.php | 35 + .../tests/PhpRedisTests.php | 45 + .../tests/PredisTests.php | 55 + .../tests/Psr6CacheTest.php | 45 + .../tests/StashTest.php | 43 + vendor/league/flysystem/CODE_OF_CONDUCT.md | 76 + vendor/league/flysystem/LICENSE | 19 + vendor/league/flysystem/SECURITY.md | 16 + vendor/league/flysystem/composer.json | 68 + vendor/league/flysystem/deprecations.md | 19 + .../flysystem/src/Adapter/AbstractAdapter.php | 72 + .../src/Adapter/AbstractFtpAdapter.php | 705 ++++ .../src/Adapter/CanOverwriteFiles.php | 12 + vendor/league/flysystem/src/Adapter/Ftp.php | 579 +++ vendor/league/flysystem/src/Adapter/Ftpd.php | 48 + vendor/league/flysystem/src/Adapter/Local.php | 533 +++ .../flysystem/src/Adapter/NullAdapter.php | 144 + .../Polyfill/NotSupportingVisibilityTrait.php | 33 + .../Adapter/Polyfill/StreamedCopyTrait.php | 51 + .../Adapter/Polyfill/StreamedReadingTrait.php | 44 + .../src/Adapter/Polyfill/StreamedTrait.php | 9 + .../Adapter/Polyfill/StreamedWritingTrait.php | 60 + .../flysystem/src/Adapter/SynologyFtp.php | 8 + .../league/flysystem/src/AdapterInterface.php | 118 + vendor/league/flysystem/src/Config.php | 107 + .../league/flysystem/src/ConfigAwareTrait.php | 49 + .../src/ConnectionErrorException.php | 9 + .../src/ConnectionRuntimeException.php | 9 + .../flysystem/src/CorruptedPathDetected.php | 17 + vendor/league/flysystem/src/Directory.php | 31 + vendor/league/flysystem/src/Exception.php | 8 + vendor/league/flysystem/src/File.php | 205 + .../flysystem/src/FileExistsException.php | 37 + .../flysystem/src/FileNotFoundException.php | 37 + vendor/league/flysystem/src/Filesystem.php | 409 ++ .../flysystem/src/FilesystemException.php | 7 + .../flysystem/src/FilesystemInterface.php | 284 ++ .../src/FilesystemNotFoundException.php | 12 + vendor/league/flysystem/src/Handler.php | 137 + .../flysystem/src/InvalidRootException.php | 9 + vendor/league/flysystem/src/MountManager.php | 648 +++ .../flysystem/src/NotSupportedException.php | 37 + .../flysystem/src/Plugin/AbstractPlugin.php | 24 + .../league/flysystem/src/Plugin/EmptyDir.php | 34 + .../flysystem/src/Plugin/ForcedCopy.php | 44 + .../flysystem/src/Plugin/ForcedRename.php | 44 + .../flysystem/src/Plugin/GetWithMetadata.php | 51 + .../league/flysystem/src/Plugin/ListFiles.php | 35 + .../league/flysystem/src/Plugin/ListPaths.php | 36 + .../league/flysystem/src/Plugin/ListWith.php | 60 + .../flysystem/src/Plugin/PluggableTrait.php | 97 + .../src/Plugin/PluginNotFoundException.php | 10 + .../league/flysystem/src/PluginInterface.php | 20 + vendor/league/flysystem/src/ReadInterface.php | 88 + .../flysystem/src/RootViolationException.php | 10 + vendor/league/flysystem/src/SafeStorage.php | 39 + .../flysystem/src/UnreadableFileException.php | 18 + vendor/league/flysystem/src/Util.php | 354 ++ .../src/Util/ContentListingFormatter.php | 122 + vendor/league/flysystem/src/Util/MimeType.php | 80 + .../flysystem/src/Util/StreamHasher.php | 36 + .../league/mime-type-detection/CHANGELOG.md | 13 + vendor/league/mime-type-detection/LICENSE | 19 + .../league/mime-type-detection/composer.json | 33 + .../src/EmptyExtensionToMimeTypeMap.php | 13 + .../src/ExtensionMimeTypeDetector.php | 42 + .../src/ExtensionToMimeTypeMap.php | 10 + .../src/FinfoMimeTypeDetector.php | 79 + .../src/GeneratedExtensionToMimeTypeMap.php | 1209 ++++++ .../src/MimeTypeDetector.php | 19 + vendor/psr/cache/CHANGELOG.md | 16 + vendor/psr/cache/LICENSE.txt | 19 + vendor/psr/cache/README.md | 9 + vendor/psr/cache/composer.json | 25 + vendor/psr/cache/src/CacheException.php | 10 + vendor/psr/cache/src/CacheItemInterface.php | 105 + .../psr/cache/src/CacheItemPoolInterface.php | 138 + .../cache/src/InvalidArgumentException.php | 13 + vendor/psr/container/.gitignore | 3 + vendor/psr/container/LICENSE | 21 + vendor/psr/container/README.md | 13 + vendor/psr/container/composer.json | 22 + .../src/ContainerExceptionInterface.php | 10 + .../psr/container/src/ContainerInterface.php | 36 + .../src/NotFoundExceptionInterface.php | 10 + vendor/psr/log/LICENSE | 19 + vendor/psr/log/Psr/Log/AbstractLogger.php | 128 + .../log/Psr/Log/InvalidArgumentException.php | 7 + vendor/psr/log/Psr/Log/LogLevel.php | 18 + .../psr/log/Psr/Log/LoggerAwareInterface.php | 18 + vendor/psr/log/Psr/Log/LoggerAwareTrait.php | 26 + vendor/psr/log/Psr/Log/LoggerInterface.php | 125 + vendor/psr/log/Psr/Log/LoggerTrait.php | 142 + vendor/psr/log/Psr/Log/NullLogger.php | 30 + vendor/psr/log/Psr/Log/Test/DummyTest.php | 18 + .../log/Psr/Log/Test/LoggerInterfaceTest.php | 138 + vendor/psr/log/Psr/Log/Test/TestLogger.php | 147 + vendor/psr/log/README.md | 58 + vendor/psr/log/composer.json | 26 + vendor/psr/simple-cache/.editorconfig | 12 + vendor/psr/simple-cache/LICENSE.md | 21 + vendor/psr/simple-cache/README.md | 8 + vendor/psr/simple-cache/composer.json | 25 + .../psr/simple-cache/src/CacheException.php | 10 + .../psr/simple-cache/src/CacheInterface.php | 114 + .../src/InvalidArgumentException.php | 13 + vendor/services.php | 7 + vendor/symfony/polyfill-mbstring/LICENSE | 19 + vendor/symfony/polyfill-mbstring/Mbstring.php | 869 ++++ vendor/symfony/polyfill-mbstring/README.md | 13 + .../Resources/unidata/lowerCase.php | 1397 ++++++ .../Resources/unidata/titleCaseRegexp.php | 5 + .../Resources/unidata/upperCase.php | 1489 +++++++ .../symfony/polyfill-mbstring/bootstrap.php | 147 + .../symfony/polyfill-mbstring/bootstrap80.php | 143 + .../symfony/polyfill-mbstring/composer.json | 38 + vendor/symfony/polyfill-php72/LICENSE | 19 + vendor/symfony/polyfill-php72/Php72.php | 217 + vendor/symfony/polyfill-php72/README.md | 28 + vendor/symfony/polyfill-php72/bootstrap.php | 57 + vendor/symfony/polyfill-php72/composer.json | 35 + vendor/symfony/polyfill-php80/LICENSE | 19 + vendor/symfony/polyfill-php80/Php80.php | 105 + vendor/symfony/polyfill-php80/README.md | 24 + .../Resources/stubs/Attribute.php | 22 + .../Resources/stubs/Stringable.php | 11 + .../Resources/stubs/UnhandledMatchError.php | 5 + .../Resources/stubs/ValueError.php | 5 + vendor/symfony/polyfill-php80/bootstrap.php | 42 + vendor/symfony/polyfill-php80/composer.json | 40 + vendor/symfony/var-dumper/CHANGELOG.md | 53 + .../symfony/var-dumper/Caster/AmqpCaster.php | 212 + vendor/symfony/var-dumper/Caster/ArgsStub.php | 80 + vendor/symfony/var-dumper/Caster/Caster.php | 175 + .../symfony/var-dumper/Caster/ClassStub.php | 106 + .../symfony/var-dumper/Caster/ConstStub.php | 36 + .../var-dumper/Caster/CutArrayStub.php | 30 + vendor/symfony/var-dumper/Caster/CutStub.php | 64 + .../symfony/var-dumper/Caster/DOMCaster.php | 304 ++ .../symfony/var-dumper/Caster/DateCaster.php | 128 + .../var-dumper/Caster/DoctrineCaster.php | 62 + vendor/symfony/var-dumper/Caster/DsCaster.php | 70 + .../symfony/var-dumper/Caster/DsPairStub.php | 28 + vendor/symfony/var-dumper/Caster/EnumStub.php | 30 + .../var-dumper/Caster/ExceptionCaster.php | 382 ++ .../symfony/var-dumper/Caster/FrameStub.php | 30 + .../symfony/var-dumper/Caster/GmpCaster.php | 32 + .../var-dumper/Caster/ImagineCaster.php | 37 + vendor/symfony/var-dumper/Caster/ImgStub.php | 26 + .../symfony/var-dumper/Caster/IntlCaster.php | 172 + vendor/symfony/var-dumper/Caster/LinkStub.php | 108 + .../var-dumper/Caster/MemcachedCaster.php | 81 + .../symfony/var-dumper/Caster/PdoCaster.php | 122 + .../symfony/var-dumper/Caster/PgSqlCaster.php | 156 + .../var-dumper/Caster/ProxyManagerCaster.php | 33 + .../symfony/var-dumper/Caster/RedisCaster.php | 152 + .../var-dumper/Caster/ReflectionCaster.php | 401 ++ .../var-dumper/Caster/ResourceCaster.php | 105 + .../symfony/var-dumper/Caster/SplCaster.php | 245 ++ .../symfony/var-dumper/Caster/StubCaster.php | 84 + .../var-dumper/Caster/SymfonyCaster.php | 69 + .../symfony/var-dumper/Caster/TraceStub.php | 36 + .../symfony/var-dumper/Caster/UuidCaster.php | 30 + .../var-dumper/Caster/XmlReaderCaster.php | 79 + .../var-dumper/Caster/XmlResourceCaster.php | 63 + .../var-dumper/Cloner/AbstractCloner.php | 375 ++ .../var-dumper/Cloner/ClonerInterface.php | 27 + vendor/symfony/var-dumper/Cloner/Cursor.php | 43 + vendor/symfony/var-dumper/Cloner/Data.php | 455 ++ .../var-dumper/Cloner/DumperInterface.php | 56 + vendor/symfony/var-dumper/Cloner/Stub.php | 67 + .../symfony/var-dumper/Cloner/VarCloner.php | 307 ++ .../Command/Descriptor/CliDescriptor.php | 88 + .../Descriptor/DumpDescriptorInterface.php | 23 + .../Command/Descriptor/HtmlDescriptor.php | 119 + .../var-dumper/Command/ServerDumpCommand.php | 101 + .../var-dumper/Dumper/AbstractDumper.php | 212 + .../symfony/var-dumper/Dumper/CliDumper.php | 655 +++ .../ContextProvider/CliContextProvider.php | 32 + .../ContextProviderInterface.php | 25 + .../RequestContextProvider.php | 51 + .../ContextProvider/SourceContextProvider.php | 126 + .../Dumper/ContextualizedDumper.php | 43 + .../var-dumper/Dumper/DataDumperInterface.php | 24 + .../symfony/var-dumper/Dumper/HtmlDumper.php | 1004 +++++ .../var-dumper/Dumper/ServerDumper.php | 53 + .../Exception/ThrowingCasterException.php | 26 + vendor/symfony/var-dumper/LICENSE | 19 + vendor/symfony/var-dumper/README.md | 15 + .../var-dumper/Resources/bin/var-dump-server | 63 + .../Resources/css/htmlDescriptor.css | 130 + .../var-dumper/Resources/functions/dump.php | 43 + .../var-dumper/Resources/js/htmlDescriptor.js | 10 + .../symfony/var-dumper/Server/Connection.php | 95 + .../symfony/var-dumper/Server/DumpServer.php | 107 + .../var-dumper/Test/VarDumperTestTrait.php | 87 + vendor/symfony/var-dumper/VarDumper.php | 66 + vendor/symfony/var-dumper/composer.json | 50 + .../topthink/framework}/.gitignore | 1 - vendor/topthink/framework/.travis.yml | 35 + .../topthink/framework}/CONTRIBUTING.md | 4 +- .../topthink/framework}/LICENSE.txt | 2 +- vendor/topthink/framework/README.md | 86 + vendor/topthink/framework/composer.json | 54 + .../topthink/framework}/logo.png | Bin vendor/topthink/framework/phpunit.xml.dist | 25 + vendor/topthink/framework/src/helper.php | 663 +++ .../topthink/framework/src}/lang/zh-cn.php | 14 +- vendor/topthink/framework/src/think/App.php | 639 +++ vendor/topthink/framework/src/think/Cache.php | 197 + .../topthink/framework/src/think/Config.php | 197 + .../topthink/framework/src}/think/Console.php | 559 ++- .../framework/src/think/Container.php | 554 +++ .../topthink/framework/src/think/Cookie.php | 230 + vendor/topthink/framework/src/think/Db.php | 117 + .../topthink/framework/src}/think/Env.php | 104 +- vendor/topthink/framework/src/think/Event.php | 263 ++ .../framework/src}/think/Exception.php | 10 +- .../topthink/framework/src}/think/Facade.php | 57 +- vendor/topthink/framework/src/think/File.php | 187 + .../framework/src/think/Filesystem.php | 89 + vendor/topthink/framework/src/think/Http.php | 288 ++ vendor/topthink/framework/src/think/Lang.php | 294 ++ vendor/topthink/framework/src/think/Log.php | 342 ++ .../topthink/framework/src/think/Manager.php | 177 + .../framework/src/think/Middleware.php | 257 ++ .../topthink/framework/src/think/Pipeline.php | 107 + .../topthink/framework/src}/think/Request.php | 1686 ++++---- .../framework/src}/think/Response.php | 197 +- vendor/topthink/framework/src/think/Route.php | 926 ++++ .../topthink/framework/src/think/Service.php | 66 + .../topthink/framework/src/think/Session.php | 65 + .../framework/src}/think/Validate.php | 944 +++-- vendor/topthink/framework/src/think/View.php | 191 + .../framework/src/think/cache/Driver.php | 357 ++ .../framework/src/think/cache/TagSet.php | 132 + .../framework/src/think/cache/driver/File.php | 304 ++ .../src}/think/cache/driver/Memcache.php | 99 +- .../src}/think/cache/driver/Memcached.php | 154 +- .../src}/think/cache/driver/Redis.php | 179 +- .../src}/think/cache/driver/Wincache.php | 88 +- .../framework/src}/think/console/Command.php | 184 +- .../framework/src}/think/console/Input.php | 47 +- .../framework/src}/think/console/LICENSE | 0 .../framework/src}/think/console/Output.php | 45 +- .../framework/src}/think/console/Table.php | 55 +- .../src}/think/console/bin/README.md | 0 .../src}/think/console/bin/hiddeninput.exe | Bin .../src/think/console/command/Clear.php | 85 + .../src}/think/console/command/Help.php | 6 +- .../src}/think/console/command/Lists.php | 7 +- .../src}/think/console/command/Make.php | 43 +- .../src}/think/console/command/RouteList.php | 67 +- .../src}/think/console/command/RunServer.php | 35 +- .../think/console/command/ServiceDiscover.php | 52 + .../think/console/command/VendorPublish.php | 69 + .../src}/think/console/command/Version.php | 6 +- .../think/console/command/make/Command.php | 15 +- .../think/console/command/make/Controller.php | 16 +- .../src/think/console/command/make/Event.php | 35 + .../think/console/command/make/Listener.php | 35 + .../think/console/command/make/Middleware.php | 12 +- .../src}/think/console/command/make/Model.php | 12 +- .../think/console/command/make/Service.php | 36 + .../think/console/command/make/Subscribe.php | 35 + .../think/console/command/make/Validate.php | 10 +- .../console/command/make/stubs/command.stub | 12 +- .../command/make/stubs/controller.api.stub | 4 +- .../command/make/stubs/controller.plain.stub | 9 + .../command/make/stubs/controller.stub | 4 +- .../console/command/make/stubs/event.stub | 8 + .../console/command/make/stubs/listener.stub | 17 + .../command/make/stubs/middleware.stub | 19 + .../console/command/make/stubs/model.stub | 4 + .../console/command/make/stubs/service.stub | 27 + .../console/command/make/stubs/subscribe.stub | 8 + .../console/command/make/stubs/validate.stub | 13 +- .../think/console/command/optimize/Route.php | 42 +- .../think/console/command/optimize/Schema.php | 104 + .../src}/think/console/input/Argument.php | 37 +- .../src}/think/console/input/Definition.php | 42 +- .../src}/think/console/input/Option.php | 33 +- .../src}/think/console/output/Ask.php | 4 - .../src}/think/console/output/Descriptor.php | 20 +- .../src}/think/console/output/Formatter.php | 2 +- .../src}/think/console/output/Question.php | 0 .../console/output/descriptor/Console.php | 12 +- .../think/console/output/driver/Buffer.php | 4 +- .../think/console/output/driver/Console.php | 18 +- .../think/console/output/driver/Nothing.php | 4 +- .../think/console/output/formatter/Stack.php | 10 +- .../think/console/output/formatter/Style.php | 15 +- .../think/console/output/question/Choice.php | 12 +- .../console/output/question/Confirmation.php | 2 +- .../think/contract/CacheHandlerInterface.php | 88 + .../think/contract/LogHandlerInterface.php | 28 + .../think/contract/ModelRelationInterface.php | 99 + .../contract/SessionHandlerInterface.php | 28 +- .../contract/TemplateHandlerInterface.php | 61 + .../framework/src/think/event/AppInit.php | 20 +- .../framework/src/think/event/HttpEnd.php | 20 +- .../framework/src/think/event/HttpRun.php | 19 + .../framework/src/think/event/LogRecord.php | 29 + .../framework/src/think/event/LogWrite.php | 27 +- .../framework/src/think/event/RouteLoaded.php | 21 + .../exception/ClassNotFoundException.php | 13 +- .../src}/think/exception/ErrorException.php | 5 +- .../src/think/exception/FileException.php | 17 + .../think/exception/FuncNotFoundException.php | 30 + .../framework/src}/think/exception/Handle.php | 198 +- .../src}/think/exception/HttpException.php | 10 +- .../think/exception/HttpResponseException.php | 6 +- .../exception/InvalidArgumentException.php | 22 + .../exception/RouteNotFoundException.php | 6 +- .../think/exception/ValidateException.php | 11 +- .../framework/src/think/facade/App.php | 59 + .../framework/src/think/facade/Cache.php | 48 + .../framework/src}/think/facade/Config.php | 13 +- .../framework/src/think/facade/Console.php | 56 + .../framework/src}/think/facade/Cookie.php | 19 +- .../framework/src/think/facade/Env.php | 44 + .../framework/src/think/facade/Event.php | 42 + .../framework/src/think/facade/Filesystem.php | 33 + .../framework/src/think/facade/Lang.php | 41 + .../framework/src/think/facade/Log.php | 58 + .../src}/think/facade/Middleware.php | 18 +- .../framework/src/think/facade/Request.php | 134 + .../framework/src/think/facade/Route.php | 83 + .../framework/src/think/facade/Session.php | 17 +- .../framework/src/think/facade/Validate.php | 95 + .../framework/src/think/facade/View.php | 42 + .../framework/src/think/file/UploadedFile.php | 143 + .../src/think/filesystem/CacheStore.php | 54 + .../framework/src/think/filesystem/Driver.php | 133 + .../src/think/filesystem/driver/Local.php | 44 + .../src/think/initializer/BootService.php | 26 + .../framework/src/think/initializer/Error.php | 117 + .../src/think/initializer/RegisterService.php | 48 + .../framework/src/think/log/Channel.php | 286 ++ .../framework/src/think/log/ChannelSet.php | 39 + .../framework/src/think/log/driver/File.php | 205 + .../src}/think/log/driver/Socket.php | 168 +- .../src/think/middleware/AllowCrossDomain.php | 63 + .../think/middleware/CheckRequestCache.php | 183 + .../src/think/middleware/FormTokenCheck.php | 45 + .../src/think/middleware/LoadLangPack.php | 61 + .../src/think/middleware/SessionInit.php | 80 + .../framework/src/think/response/File.php | 58 +- .../framework/src/think/response/Html.php | 26 +- .../framework/src}/think/response/Json.php | 17 +- .../framework/src}/think/response/Jsonp.php | 26 +- .../src}/think/response/Redirect.php | 72 +- .../framework/src/think/response/View.php | 151 + .../framework/src}/think/response/Xml.php | 21 +- .../framework/src/think/route/Dispatch.php | 257 ++ .../framework/src}/think/route/Domain.php | 111 +- .../framework/src/think/route/Resource.php | 251 ++ .../framework/src/think/route/Rule.php | 905 ++++ .../framework/src}/think/route/RuleGroup.php | 404 +- .../framework/src}/think/route/RuleItem.php | 196 +- .../framework/src/think/route/RuleName.php | 211 + .../framework/src/think/route/Url.php | 517 +++ .../src}/think/route/dispatch/Callback.php | 6 +- .../src/think/route/dispatch/Controller.php | 183 + .../src/think/route/dispatch/Url.php | 118 + .../src/think/service/ModelService.php | 47 + .../src/think/service/PaginatorService.php | 52 + .../src/think/service/ValidateService.php | 31 + .../framework/src/think/session/Store.php | 340 ++ .../src/think/session/driver/Cache.php | 50 + .../src/think/session/driver/File.php | 249 ++ .../src}/think/validate/ValidateRule.php | 15 +- .../framework/src/think/view/driver/Php.php | 191 + .../framework/src/tpl/think_exception.tpl | 502 +++ vendor/topthink/framework/tests/AppTest.php | 215 + vendor/topthink/framework/tests/CacheTest.php | 149 + .../topthink/framework/tests/ConfigTest.php | 46 + .../framework/tests/ContainerTest.php | 314 ++ vendor/topthink/framework/tests/DbTest.php | 49 + vendor/topthink/framework/tests/EnvTest.php | 82 + vendor/topthink/framework/tests/EventTest.php | 134 + .../framework/tests/FilesystemTest.php | 131 + vendor/topthink/framework/tests/HttpTest.php | 155 + .../framework/tests/InteractsWithApp.php | 30 + vendor/topthink/framework/tests/LogTest.php | 130 + .../framework/tests/MiddlewareTest.php | 108 + vendor/topthink/framework/tests/RouteTest.php | 286 ++ .../topthink/framework/tests/SessionTest.php | 225 + vendor/topthink/framework/tests/ViewTest.php | 127 + vendor/topthink/framework/tests/bootstrap.php | 3 + vendor/topthink/think-helper/.gitignore | 3 + vendor/topthink/think-helper/LICENSE | 201 + vendor/topthink/think-helper/README.md | 33 + vendor/topthink/think-helper/composer.json | 22 + .../topthink/think-helper/src}/Collection.php | 283 +- .../think-helper/src/contract/Arrayable.php | 8 + .../think-helper/src/contract/Jsonable.php | 8 + vendor/topthink/think-helper/src/helper.php | 279 ++ .../topthink/think-helper/src/helper/Arr.php | 634 +++ .../topthink/think-helper/src/helper/Str.php | 234 ++ vendor/topthink/think-multi-app/LICENSE | 201 + vendor/topthink/think-multi-app/README.md | 14 + vendor/topthink/think-multi-app/composer.json | 28 + .../topthink/think-multi-app/src/MultiApp.php | 245 ++ .../topthink/think-multi-app/src/Service.php | 32 + vendor/topthink/think-multi-app/src/Url.php | 232 + .../think-multi-app/src/command/Build.php | 180 + .../think-multi-app/src}/command/Clear.php | 36 +- .../src/command/stubs/controller.stub | 12 + vendor/topthink/think-orm/.gitattributes | 3 + vendor/topthink/think-orm/.gitignore | 3 + vendor/topthink/think-orm/LICENSE | 201 + vendor/topthink/think-orm/README.md | 27 + vendor/topthink/think-orm/composer.json | 42 + vendor/topthink/think-orm/src/DbManager.php | 376 ++ vendor/topthink/think-orm/src/Model.php | 1068 +++++ .../topthink/think-orm/src}/Paginator.php | 205 +- .../topthink/think-orm/src/db/BaseQuery.php | 1278 ++++++ vendor/topthink/think-orm/src/db/Builder.php | 1305 ++++++ .../topthink/think-orm/src/db/CacheItem.php | 209 + .../topthink/think-orm/src/db/Connection.php | 347 ++ .../think-orm/src/db/ConnectionInterface.php | 190 + vendor/topthink/think-orm/src/db/Fetch.php | 494 +++ vendor/topthink/think-orm/src/db/Mongo.php | 712 ++++ .../think-orm/src/db/PDOConnection.php | 1792 ++++++++ vendor/topthink/think-orm/src/db/Query.php | 451 ++ .../topthink/think-orm/src/db/Raw.php | 31 +- .../topthink/think-orm/src}/db/Where.php | 30 +- .../think-orm/src/db/builder/Mongo.php | 675 +++ .../think-orm/src/db/builder/Mysql.php | 426 ++ .../think-orm/src/db/builder/Oracle.php | 95 + .../think-orm/src}/db/builder/Pgsql.php | 38 +- .../think-orm/src}/db/builder/Sqlite.php | 21 +- .../think-orm/src}/db/builder/Sqlsrv.php | 83 +- .../src/db/concern/AggregateQuery.php | 107 + .../src/db/concern/JoinAndViewQuery.php | 229 + .../src/db/concern/ModelRelationQuery.php | 524 +++ .../think-orm/src/db/concern/ParamsBind.php | 106 + .../src/db/concern/ResultOperation.php | 247 ++ .../src/db/concern/TableFieldInfo.php | 99 + .../src/db/concern/TimeFieldQuery.php | 214 + .../think-orm/src/db/concern/Transaction.php | 117 + .../think-orm/src/db/concern/WhereQuery.php | 532 +++ .../think-orm/src/db/connector/Mongo.php | 1176 ++++++ .../think-orm/src}/db/connector/Mysql.php | 103 +- .../think-orm/src/db/connector/Oracle.php | 117 + .../think-orm/src}/db/connector/Pgsql.php | 44 +- .../think-orm/src}/db/connector/Sqlite.php | 40 +- .../think-orm/src/db/connector/Sqlsrv.php | 122 + .../think-orm/src}/db/connector/pgsql.sql | 0 .../src}/db/exception/BindParamException.php | 7 +- .../db/exception/DataNotFoundException.php | 7 +- .../src/db}/exception/DbException.php | 8 +- .../db/exception/InvalidArgumentException.php | 21 + .../src/db/exception/ModelEventException.php | 19 + .../db/exception/ModelNotFoundException.php | 7 +- .../src/db}/exception/PDOException.php | 24 +- .../topthink/think-orm/src/facade/Db.php | 12 +- .../think-orm/src/model/Collection.php | 265 ++ .../topthink/think-orm/src}/model/Pivot.php | 23 +- .../topthink/think-orm/src/model/Relation.php | 278 ++ .../src}/model/concern/Attribute.php | 508 +-- .../src/model/concern/Conversion.php | 358 ++ .../src/model/concern/ModelEvent.php | 88 + .../think-orm/src/model/concern/OptimLock.php | 85 + .../src}/model/concern/RelationShip.php | 488 ++- .../src}/model/concern/SoftDelete.php | 112 +- .../think-orm/src/model/concern/TimeStamp.php | 208 + .../src}/model/relation/BelongsTo.php | 167 +- .../src}/model/relation/BelongsToMany.php | 381 +- .../think-orm/src/model/relation/HasMany.php | 367 ++ .../src/model/relation/HasManyThrough.php | 382 ++ .../think-orm/src}/model/relation/HasOne.php | 157 +- .../src/model/relation/HasOneThrough.php | 163 + .../src}/model/relation/MorphMany.php | 194 +- .../src}/model/relation/MorphOne.php | 185 +- .../think-orm/src}/model/relation/MorphTo.php | 639 +-- .../src/model/relation/MorphToMany.php | 458 ++ .../src}/model/relation/OneToOne.php | 218 +- .../src}/paginator/driver/Bootstrap.php | 27 +- vendor/topthink/think-orm/stubs/Exception.php | 59 + vendor/topthink/think-orm/stubs/Facade.php | 65 + .../topthink/think-orm/stubs/load_stubs.php | 9 + vendor/topthink/think-template/.gitignore | 1 + vendor/topthink/think-template/LICENSE | 201 + vendor/topthink/think-template/README.md | 70 + vendor/topthink/think-template/composer.json | 20 + .../topthink/think-template/src}/Template.php | 408 +- .../think-template/src/facade/Template.php | 83 + .../think-template/src}/template/TagLib.php | 34 +- .../src}/template/driver/File.php | 14 +- .../exception/TemplateNotFoundException.php | 10 +- .../src}/template/taglib/Cx.php | 65 +- vendor/topthink/think-trace/.gitignore | 1 + vendor/topthink/think-trace/LICENSE | 201 + vendor/topthink/think-trace/README.md | 15 + vendor/topthink/think-trace/composer.json | 31 + .../topthink/think-trace/src}/Console.php | 329 +- .../topthink/think-trace/src}/Html.php | 232 +- vendor/topthink/think-trace/src/Service.php | 21 + .../topthink/think-trace/src/TraceDebug.php | 109 + vendor/topthink/think-trace/src/config.php | 10 + .../think-trace/src}/tpl/page_trace.tpl | 2 +- vendor/topthink/think-view/.gitignore | 1 + vendor/topthink/think-view/LICENSE | 201 + vendor/topthink/think-view/README.md | 36 + vendor/topthink/think-view/composer.json | 20 + vendor/topthink/think-view/src/Think.php | 259 ++ 1385 files changed, 74541 insertions(+), 36730 deletions(-) rename LICENSE => LICENSE.txt (98%) rename application/middleware.php => api.php (83%) mode change 100755 => 100644 create mode 100644 app/.gitignore rename application/tags.php => app/AppService.php (67%) mode change 100755 => 100644 create mode 100644 app/BaseController.php rename application/common/Http.php => app/ExceptionHandle.php (55%) mode change 100755 => 100644 rename application/command.php => app/Request.php (87%) mode change 100755 => 100644 rename application/install/config/template.php => app/admin/config/view.php (74%) rename {application => app}/admin/controller/Admin.php (88%) rename {application => app}/admin/controller/Agreement.php (88%) rename {application => app}/admin/controller/Answer.php (91%) rename {application => app}/admin/controller/Appcenternav.php (89%) rename {application => app}/admin/controller/Appconfig.php (88%) rename {application => app}/admin/controller/Apphomenav.php (89%) rename {application => app}/admin/controller/Appmini.php (85%) rename {application => app}/admin/controller/Article.php (86%) rename {application => app}/admin/controller/Articlecategory.php (91%) rename {application => app}/admin/controller/Brand.php (88%) rename {application => app}/admin/controller/Brandcategory.php (92%) rename {application => app}/admin/controller/Cache.php (77%) rename {application => app}/admin/controller/Common.php (59%) rename {application => app}/admin/controller/Config.php (82%) rename {application => app}/admin/controller/Customview.php (89%) rename {application => app}/admin/controller/Design.php (73%) rename {application => app}/admin/controller/Email.php (87%) rename {application => app}/admin/controller/Error.php (74%) rename {application => app}/admin/controller/Express.php (93%) rename {application => app}/admin/controller/Formtable.php (100%) rename {application => app}/admin/controller/Goods.php (80%) rename {application => app}/admin/controller/Goodsbrowse.php (93%) rename {application => app}/admin/controller/Goodscategory.php (90%) rename {application => app}/admin/controller/Goodscomments.php (86%) rename {application => app}/admin/controller/Goodsfavor.php (93%) rename {application => app}/admin/controller/Goodsparamstemplate.php (86%) rename {application => app}/admin/controller/Index.php (86%) rename {application => app}/admin/controller/Integrallog.php (91%) rename {application => app}/admin/controller/Layout.php (100%) rename {application => app}/admin/controller/Link.php (92%) rename {application => app}/admin/controller/Message.php (92%) rename {application => app}/admin/controller/Navigation.php (81%) rename {application => app}/admin/controller/Order.php (91%) rename {application => app}/admin/controller/Orderaftersale.php (93%) rename {application => app}/admin/controller/Packageinstall.php (96%) rename {application => app}/admin/controller/Packageupgrade.php (100%) rename {application => app}/admin/controller/Paylog.php (92%) rename {application => app}/admin/controller/Payment.php (88%) rename {application => app}/admin/controller/Payrequestlog.php (91%) rename {application => app}/admin/controller/Plugins.php (84%) rename {application => app}/admin/controller/Pluginsadmin.php (89%) rename {application => app}/admin/controller/Power.php (94%) rename {application => app}/admin/controller/Quicknav.php (89%) rename {application => app}/admin/controller/Refundlog.php (92%) rename {application => app}/admin/controller/Region.php (96%) rename {application => app}/admin/controller/Role.php (91%) rename {application => app}/admin/controller/Screeningprice.php (92%) rename {application => app}/admin/controller/Seo.php (84%) rename {application => app}/admin/controller/Site.php (79%) rename {application => app}/admin/controller/Slide.php (87%) rename {application => app}/admin/controller/Sms.php (91%) rename {application => app}/admin/controller/Sqlconsole.php (98%) rename {application => app}/admin/controller/Store.php (93%) rename {application => app}/admin/controller/Theme.php (84%) rename {application => app}/admin/controller/Ueditor.php (100%) rename {application => app}/admin/controller/User.php (89%) rename {application => app}/admin/controller/Useraddress.php (88%) rename {application => app}/admin/controller/Warehouse.php (88%) rename {application => app}/admin/controller/Warehousegoods.php (91%) rename {application => app}/admin/controller/index.html (100%) rename {application => app}/admin/form/Admin.php (100%) rename {application => app}/admin/form/Answer.php (99%) rename {application => app}/admin/form/Appcenternav.php (100%) rename {application => app}/admin/form/Apphomenav.php (100%) rename {application => app}/admin/form/Appmini.php (100%) rename {application => app}/admin/form/Article.php (100%) rename {application => app}/admin/form/Brand.php (99%) rename {application => app}/admin/form/Customview.php (100%) rename {application => app}/admin/form/Design.php (100%) rename {application => app}/admin/form/Goods.php (99%) rename {application => app}/admin/form/Goodsbrowse.php (99%) rename {application => app}/admin/form/Goodscomments.php (98%) rename {application => app}/admin/form/Goodsfavor.php (99%) rename {application => app}/admin/form/Goodsparamstemplate.php (100%) rename {application => app}/admin/form/Integrallog.php (99%) rename {application => app}/admin/form/Link.php (100%) rename {application => app}/admin/form/Message.php (99%) rename {application => app}/admin/form/Navigation.php (100%) rename {application => app}/admin/form/Order.php (99%) rename {application => app}/admin/form/Orderaftersale.php (98%) rename {application => app}/admin/form/Paylog.php (99%) rename {application => app}/admin/form/Payment.php (100%) rename {application => app}/admin/form/Payrequestlog.php (99%) rename {application => app}/admin/form/Quicknav.php (100%) rename {application => app}/admin/form/Refundlog.php (99%) rename {application => app}/admin/form/Role.php (100%) rename {application => app}/admin/form/Slide.php (100%) rename {application => app}/admin/form/User.php (100%) rename {application => app}/admin/form/Useraddress.php (99%) rename {application => app}/admin/form/Warehouse.php (99%) rename {application => app}/admin/form/Warehousegoods.php (98%) rename {application => app}/admin/index.html (100%) rename {application => app}/admin/lang/index.html (100%) rename {application => app}/admin/lang/zh-cn.php (100%) rename {application => app}/admin/view/default/admin/detail.html (100%) rename {application => app}/admin/view/default/admin/index.html (88%) rename {application => app}/admin/view/default/admin/login_info.html (98%) rename {application => app}/admin/view/default/admin/module/operate.html (100%) rename {application => app}/admin/view/default/admin/save_info.html (100%) rename {application => app}/admin/view/default/agreement/nav.html (100%) rename {application => app}/admin/view/default/agreement/privacy.html (100%) rename {application => app}/admin/view/default/agreement/register.html (100%) rename {application => app}/admin/view/default/answer/detail.html (100%) rename {application => app}/admin/view/default/answer/index.html (100%) rename {application => app}/admin/view/default/answer/module/content.html (100%) rename {application => app}/admin/view/default/answer/module/operate.html (100%) rename {application => app}/admin/view/default/answer/module/reply.html (100%) rename {application => app}/admin/view/default/answer/save_info.html (100%) rename {application => app}/admin/view/default/appcenternav/detail.html (100%) rename {application => app}/admin/view/default/appcenternav/index.html (100%) rename {application => app}/admin/view/default/appcenternav/module/images.html (100%) rename {application => app}/admin/view/default/appcenternav/module/operate.html (100%) rename {application => app}/admin/view/default/appcenternav/save_info.html (100%) rename {application => app}/admin/view/default/appconfig/app.html (100%) rename {application => app}/admin/view/default/appconfig/base.html (100%) rename {application => app}/admin/view/default/appconfig/nav.html (100%) rename {application => app}/admin/view/default/apphomenav/detail.html (100%) rename {application => app}/admin/view/default/apphomenav/index.html (100%) rename {application => app}/admin/view/default/apphomenav/module/images.html (100%) rename {application => app}/admin/view/default/apphomenav/module/operate.html (100%) rename {application => app}/admin/view/default/apphomenav/save_info.html (100%) rename {application => app}/admin/view/default/appmini/base_nav.html (100%) rename {application => app}/admin/view/default/appmini/config.html (100%) rename {application => app}/admin/view/default/appmini/index.html (100%) rename {application => app}/admin/view/default/appmini/module/operate.html (100%) rename {application => app}/admin/view/default/appmini/nav.html (100%) rename {application => app}/admin/view/default/appmini/package.html (97%) rename {application => app}/admin/view/default/appmini/upload.html (100%) rename {application => app}/admin/view/default/article/detail.html (100%) rename {application => app}/admin/view/default/article/index.html (100%) rename {application => app}/admin/view/default/article/module/info.html (100%) rename {application => app}/admin/view/default/article/module/operate.html (100%) rename {application => app}/admin/view/default/article/save_info.html (100%) rename {application => app}/admin/view/default/articlecategory/index.html (100%) rename {application => app}/admin/view/default/brand/detail.html (100%) rename {application => app}/admin/view/default/brand/index.html (100%) rename {application => app}/admin/view/default/brand/module/logo.html (100%) rename {application => app}/admin/view/default/brand/module/operate.html (100%) rename {application => app}/admin/view/default/brand/module/url.html (100%) rename {application => app}/admin/view/default/brand/save_info.html (100%) rename {application => app}/admin/view/default/brandcategory/index.html (100%) rename {application => app}/admin/view/default/cache/index.html (100%) rename {application => app}/admin/view/default/config/index.html (100%) rename {application => app}/admin/view/default/config/store.html (100%) rename {application => app}/admin/view/default/customview/detail.html (100%) rename {application => app}/admin/view/default/customview/index.html (100%) rename {application => app}/admin/view/default/customview/module/info.html (100%) rename {application => app}/admin/view/default/customview/module/operate.html (100%) rename {application => app}/admin/view/default/customview/save_info.html (100%) rename {application => app}/admin/view/default/design/index.html (100%) rename {application => app}/admin/view/default/design/module/info.html (100%) rename {application => app}/admin/view/default/design/module/operate.html (100%) rename {application => app}/admin/view/default/design/popup_saveinfo.html (100%) rename {application => app}/admin/view/default/design/save_info.html (100%) rename {application => app}/admin/view/default/email/index.html (100%) rename {application => app}/admin/view/default/email/message.html (100%) rename {application => app}/admin/view/default/email/nav.html (100%) rename {application => app}/admin/view/default/express/index.html (100%) rename {application => app}/admin/view/default/goods/detail.html (100%) rename {application => app}/admin/view/default/goods/index.html (100%) rename {application => app}/admin/view/default/goods/module/info.html (100%) rename {application => app}/admin/view/default/goods/module/operate.html (100%) rename {application => app}/admin/view/default/goods/save_info.html (100%) rename {application => app}/admin/view/default/goods/spec.html (100%) rename {application => app}/admin/view/default/goods/spec_extends.html (100%) rename {application => app}/admin/view/default/goodsbrowse/detail.html (100%) rename {application => app}/admin/view/default/goodsbrowse/index.html (100%) rename {application => app}/admin/view/default/goodsbrowse/module/goods.html (100%) rename {application => app}/admin/view/default/goodsbrowse/module/operate.html (100%) rename {application => app}/admin/view/default/goodscategory/index.html (100%) rename {application => app}/admin/view/default/goodscomments/detail.html (100%) rename {application => app}/admin/view/default/goodscomments/index.html (100%) rename {application => app}/admin/view/default/goodscomments/module/content.html (100%) rename {application => app}/admin/view/default/goodscomments/module/goods.html (100%) rename {application => app}/admin/view/default/goodscomments/module/images.html (100%) rename {application => app}/admin/view/default/goodscomments/module/operate.html (100%) rename {application => app}/admin/view/default/goodscomments/module/rating.html (100%) rename {application => app}/admin/view/default/goodscomments/module/reply.html (100%) rename {application => app}/admin/view/default/goodscomments/save_info.html (100%) rename {application => app}/admin/view/default/goodsfavor/detail.html (100%) rename {application => app}/admin/view/default/goodsfavor/index.html (100%) rename {application => app}/admin/view/default/goodsfavor/module/goods.html (100%) rename {application => app}/admin/view/default/goodsfavor/module/operate.html (100%) rename {application => app}/admin/view/default/goodsparamstemplate/detail.html (100%) rename {application => app}/admin/view/default/goodsparamstemplate/index.html (100%) rename {application => app}/admin/view/default/goodsparamstemplate/module/operate.html (100%) rename {application => app}/admin/view/default/goodsparamstemplate/save_info.html (100%) rename {application => app}/admin/view/default/index.html (100%) rename {application => app}/admin/view/default/index/index.html (100%) rename {application => app}/admin/view/default/index/init.html (100%) rename {application => app}/admin/view/default/integrallog/detail.html (100%) rename {application => app}/admin/view/default/integrallog/index.html (100%) rename {application => app}/admin/view/default/integrallog/module/operate.html (100%) rename {application => app}/admin/view/default/lib/enable.html (100%) rename {application => app}/admin/view/default/lib/excel_win_html.html (100%) rename {application => app}/admin/view/default/lib/excel_win_js.html (100%) rename {application => app}/admin/view/default/lib/gender.html (100%) rename {application => app}/admin/view/default/lib/index.html (100%) rename {application => app}/admin/view/default/lib/is_footer.html (100%) rename {application => app}/admin/view/default/lib/is_full_screen.html (100%) rename {application => app}/admin/view/default/lib/is_header.html (100%) rename {application => app}/admin/view/default/lib/is_new_window_open.html (100%) rename {application => app}/admin/view/default/lib/is_show.html (100%) rename {application => app}/admin/view/default/lib/module/category_brand.html (100%) rename {application => app}/admin/view/default/lib/module/goods_category.html (100%) rename {application => app}/admin/view/default/lib/module/user.html (100%) rename {application => app}/admin/view/default/lib/region_linkage.html (100%) rename {application => app}/admin/view/default/lib/seo.html (100%) rename {application => app}/admin/view/default/lib/user_status.html (100%) rename {application => app}/admin/view/default/link/detail.html (100%) rename {application => app}/admin/view/default/link/index.html (100%) rename {application => app}/admin/view/default/link/module/info.html (100%) rename {application => app}/admin/view/default/link/module/operate.html (100%) rename {application => app}/admin/view/default/link/module/url.html (100%) rename {application => app}/admin/view/default/message/detail.html (100%) rename {application => app}/admin/view/default/message/index.html (100%) rename {application => app}/admin/view/default/message/module/operate.html (100%) rename {application => app}/admin/view/default/navigation/index.html (100%) rename {application => app}/admin/view/default/navigation/module/info.html (100%) rename {application => app}/admin/view/default/navigation/module/operate.html (100%) rename {application => app}/admin/view/default/navigation/nav.html (100%) rename {application => app}/admin/view/default/order/detail.html (100%) rename {application => app}/admin/view/default/order/index.html (100%) rename {application => app}/admin/view/default/order/module/address.html (100%) rename {application => app}/admin/view/default/order/module/aftersale.html (100%) rename {application => app}/admin/view/default/order/module/extension.html (100%) rename {application => app}/admin/view/default/order/module/goods.html (92%) rename {application => app}/admin/view/default/order/module/is_comments.html (100%) rename {application => app}/admin/view/default/order/module/operate.html (100%) rename {application => app}/admin/view/default/order/module/pay_status.html (100%) rename {application => app}/admin/view/default/order/module/status.html (100%) rename {application => app}/admin/view/default/order/module/take.html (100%) rename {application => app}/admin/view/default/orderaftersale/detail.html (100%) rename {application => app}/admin/view/default/orderaftersale/index.html (100%) rename {application => app}/admin/view/default/orderaftersale/module/goods.html (91%) rename {application => app}/admin/view/default/orderaftersale/module/operate.html (100%) rename {application => app}/admin/view/default/orderaftersale/module/voucher.html (100%) rename {application => app}/admin/view/default/packageinstall/index.html (100%) rename {application => app}/admin/view/default/paylog/detail.html (100%) rename {application => app}/admin/view/default/paylog/index.html (100%) rename {application => app}/admin/view/default/paylog/module/business_list.html (100%) rename {application => app}/admin/view/default/paylog/module/operate.html (100%) rename {application => app}/admin/view/default/paylog/module/payment.html (100%) rename {application => app}/admin/view/default/payment/index.html (100%) rename {application => app}/admin/view/default/payment/module/apply_terminal.html (100%) rename {application => app}/admin/view/default/payment/module/author.html (100%) rename {application => app}/admin/view/default/payment/module/enable.html (100%) rename {application => app}/admin/view/default/payment/module/logo.html (100%) rename {application => app}/admin/view/default/payment/module/open_user.html (100%) rename {application => app}/admin/view/default/payment/module/operate.html (100%) rename {application => app}/admin/view/default/payment/save_info.html (100%) rename {application => app}/admin/view/default/payrequestlog/detail.html (100%) rename {application => app}/admin/view/default/payrequestlog/index.html (100%) rename {application => app}/admin/view/default/payrequestlog/module/business_handle.html (100%) rename {application => app}/admin/view/default/payrequestlog/module/operate.html (100%) rename {application => app}/admin/view/default/payrequestlog/module/request_params.html (100%) rename {application => app}/admin/view/default/payrequestlog/module/response_data.html (100%) rename {application => app}/admin/view/default/plugins/index.html (100%) rename {application => app}/admin/view/default/pluginsadmin/first_step.html (100%) rename {application => app}/admin/view/default/pluginsadmin/index.html (100%) rename {application => app}/admin/view/default/pluginsadmin/nav.html (100%) rename {application => app}/admin/view/default/pluginsadmin/save_info.html (100%) rename {application => app}/admin/view/default/pluginsadmin/upload.html (100%) rename {application => app}/admin/view/default/power/index.html (98%) rename {application => app}/admin/view/default/public/event_value_tips.html (100%) rename {application => app}/admin/view/default/public/footer.html (100%) rename {application => app}/admin/view/default/public/goodsparamstemplate/detail.html (100%) rename {application => app}/admin/view/default/public/goodsparamstemplate/table.html (100%) rename {application => app}/admin/view/default/public/goodsparamstemplate/tips.html (100%) rename {application => app}/admin/view/default/public/header.html (98%) rename {application => app}/admin/view/default/public/index.html (100%) create mode 100755 app/admin/view/default/public/jump_error.html create mode 100755 app/admin/view/default/public/jump_success.html rename {application => app}/admin/view/default/public/loading.html (100%) rename {application => app}/admin/view/default/public/menu.html (100%) rename {application/index => app/admin}/view/default/public/module/detail.html (94%) rename {application => app}/admin/view/default/public/module/form.html (90%) rename {application => app}/admin/view/default/public/module/form_fields_select.html (100%) rename {application => app}/admin/view/default/public/module/form_operate_bottom.html (77%) rename {application => app}/admin/view/default/public/module/form_operate_top.html (95%) rename {application/index => app/admin}/view/default/public/module/form_table.html (99%) rename {application => app}/admin/view/default/public/nav.html (100%) rename {application => app}/admin/view/default/public/nav_bar.html (100%) rename {application => app}/admin/view/default/public/not_data.html (100%) rename {application => app}/admin/view/default/public/page_loading.html (100%) rename {application => app}/admin/view/default/public/tips_error.html (100%) rename {application => app}/admin/view/default/quicknav/detail.html (100%) rename {application => app}/admin/view/default/quicknav/index.html (100%) rename {application => app}/admin/view/default/quicknav/module/images.html (100%) rename {application => app}/admin/view/default/quicknav/module/operate.html (100%) rename {application => app}/admin/view/default/quicknav/save_info.html (100%) rename {application => app}/admin/view/default/refundlog/detail.html (100%) rename {application => app}/admin/view/default/refundlog/index.html (100%) rename {application => app}/admin/view/default/refundlog/module/operate.html (100%) rename {application => app}/admin/view/default/refundlog/module/payment.html (100%) rename {application => app}/admin/view/default/region/index.html (100%) rename {application => app}/admin/view/default/role/detail.html (100%) rename {application => app}/admin/view/default/role/index.html (100%) rename {application => app}/admin/view/default/role/module/operate.html (100%) rename {application => app}/admin/view/default/role/save_info.html (100%) rename {application => app}/admin/view/default/screeningprice/index.html (100%) rename {application => app}/admin/view/default/seo/index.html (100%) rename {application => app}/admin/view/default/site/attachment/index.html (100%) rename {application => app}/admin/view/default/site/base/index.html (100%) rename {application => app}/admin/view/default/site/cache/index.html (73%) rename {application => app}/admin/view/default/site/extends/index.html (100%) rename {application => app}/admin/view/default/site/forgetpwd/index.html (100%) rename {application => app}/admin/view/default/site/login/index.html (100%) rename {application => app}/admin/view/default/site/orderaftersale/index.html (100%) rename {application => app}/admin/view/default/site/public/goods_search.html (100%) rename {application => app}/admin/view/default/site/public/nav.html (100%) rename {application => app}/admin/view/default/site/public/siteset_nav.html (100%) rename {application => app}/admin/view/default/site/register/index.html (100%) rename {application => app}/admin/view/default/site/siteset/discount.html (100%) rename {application => app}/admin/view/default/site/siteset/extends.html (100%) rename {application => app}/admin/view/default/site/siteset/goods.html (100%) rename {application => app}/admin/view/default/site/siteset/index.html (100%) rename {application => app}/admin/view/default/site/siteset/order.html (100%) rename {application => app}/admin/view/default/site/siteset/search.html (100%) rename {application => app}/admin/view/default/site/sitetype/index.html (100%) rename {application => app}/admin/view/default/site/verify/index.html (100%) rename {application => app}/admin/view/default/slide/detail.html (100%) rename {application => app}/admin/view/default/slide/index.html (100%) rename {application => app}/admin/view/default/slide/module/images.html (100%) rename {application => app}/admin/view/default/slide/module/operate.html (100%) rename {application => app}/admin/view/default/slide/save_info.html (100%) rename {application => app}/admin/view/default/sms/index.html (100%) rename {application => app}/admin/view/default/sms/message.html (100%) rename {application => app}/admin/view/default/sms/nav.html (100%) rename {application => app}/admin/view/default/sqlconsole/index.html (100%) rename {application => app}/admin/view/default/store/index.html (100%) rename {application => app}/admin/view/default/theme/index.html (100%) rename {application => app}/admin/view/default/theme/nav.html (100%) rename {application => app}/admin/view/default/theme/upload.html (100%) rename {application => app}/admin/view/default/user/detail.html (100%) rename {application => app}/admin/view/default/user/index.html (100%) rename {application => app}/admin/view/default/user/module/avatar.html (100%) rename {application => app}/admin/view/default/user/module/operate.html (100%) rename {application => app}/admin/view/default/user/save_info.html (100%) rename {application => app}/admin/view/default/useraddress/detail.html (100%) rename {application => app}/admin/view/default/useraddress/index.html (100%) rename {application => app}/admin/view/default/useraddress/module/idcard_info.html (100%) rename {application => app}/admin/view/default/useraddress/module/is_default.html (100%) rename {application => app}/admin/view/default/useraddress/module/operate.html (100%) rename {application => app}/admin/view/default/useraddress/module/position.html (100%) rename {application => app}/admin/view/default/useraddress/save_info.html (100%) rename {application => app}/admin/view/default/warehouse/detail.html (100%) rename {application => app}/admin/view/default/warehouse/index.html (100%) rename {application => app}/admin/view/default/warehouse/module/info.html (100%) rename {application => app}/admin/view/default/warehouse/module/operate.html (100%) rename {application => app}/admin/view/default/warehouse/module/position.html (100%) rename {application => app}/admin/view/default/warehouse/save_info.html (100%) rename {application => app}/admin/view/default/warehousegoods/detail.html (100%) rename {application => app}/admin/view/default/warehousegoods/goods_search.html (100%) rename {application => app}/admin/view/default/warehousegoods/goods_spec.html (100%) rename {application => app}/admin/view/default/warehousegoods/index.html (100%) rename {application => app}/admin/view/default/warehousegoods/inventory_info.html (100%) rename {application => app}/admin/view/default/warehousegoods/module/goods.html (100%) rename {application => app}/admin/view/default/warehousegoods/module/operate.html (100%) rename {application => app}/admin/view/index.html (100%) rename {application => app}/api/config/app.php (100%) rename build.php => app/api/config/route.php (56%) mode change 100755 => 100644 rename {application => app}/api/controller/Agreement.php (100%) rename {application => app}/api/controller/Answer.php (100%) rename {application => app}/api/controller/Banner.php (100%) rename {application => app}/api/controller/Base.php (100%) rename {application => app}/api/controller/Buy.php (100%) rename {application => app}/api/controller/Cart.php (100%) rename {application => app}/api/controller/Common.php (87%) rename {application => app}/api/controller/Crontab.php (100%) rename {application => app}/api/controller/Design.php (100%) rename {application => app}/api/controller/Devtest.php (97%) create mode 100644 app/api/controller/Error.php rename {application => app}/api/controller/Goods.php (100%) rename {application => app}/api/controller/Index.php (100%) rename {application => app}/api/controller/Message.php (100%) rename {application => app}/api/controller/Navigation.php (100%) rename {application => app}/api/controller/Order.php (100%) rename {application => app}/api/controller/Orderaftersale.php (100%) rename {application => app}/api/controller/Ordernotify.php (100%) rename {application => app}/api/controller/Plugins.php (100%) rename {application => app}/api/controller/Region.php (100%) rename {application => app}/api/controller/Search.php (100%) rename {application => app}/api/controller/Ueditor.php (100%) rename {application => app}/api/controller/User.php (100%) rename {application => app}/api/controller/Useraddress.php (100%) rename {application => app}/api/controller/Usergoodsbrowse.php (100%) rename {application => app}/api/controller/Usergoodsfavor.php (100%) rename {application => app}/api/controller/Userintegral.php (100%) rename {application => app}/api/controller/index.html (100%) rename {application => app}/api/index.html (100%) rename {application => app}/common.php (91%) create mode 100644 app/index/config/route.php rename application/index/config/template.php => app/index/config/view.php (61%) rename {application => app}/index/controller/Agreement.php (87%) rename {application => app}/index/controller/Answer.php (88%) rename {application => app}/index/controller/Article.php (75%) rename {application => app}/index/controller/Buy.php (78%) rename {application => app}/index/controller/Cart.php (93%) rename {application => app}/index/controller/Category.php (91%) create mode 100755 app/index/controller/Common.php rename {application => app}/index/controller/Customview.php (77%) rename {application => app}/index/controller/Design.php (79%) rename {application => app}/index/controller/Error.php (74%) rename {application => app}/index/controller/Formtable.php (100%) rename {application => app}/index/controller/Goods.php (90%) rename {application => app}/index/controller/Index.php (69%) rename {application => app}/index/controller/Layout.php (93%) rename {application => app}/index/controller/Message.php (87%) rename {application => app}/index/controller/Order.php (77%) rename {application => app}/index/controller/Orderaftersale.php (74%) rename {application => app}/index/controller/Pay.php (88%) rename {application => app}/index/controller/Personal.php (82%) rename {application => app}/index/controller/Plugins.php (84%) rename {application => app}/index/controller/Qrcode.php (88%) rename {application => app}/index/controller/Region.php (100%) rename {application => app}/index/controller/Safety.php (77%) rename {application => app}/index/controller/Search.php (85%) rename {application => app}/index/controller/Ueditor.php (100%) rename {application => app}/index/controller/User.php (78%) rename {application => app}/index/controller/Useraddress.php (85%) rename {application => app}/index/controller/Usergoodsbrowse.php (88%) rename {application => app}/index/controller/Usergoodsfavor.php (88%) rename {application => app}/index/controller/Userintegral.php (86%) rename {application => app}/index/controller/index.html (100%) rename {application => app}/index/form/Answer.php (99%) rename {application => app}/index/form/Message.php (98%) rename {application => app}/index/form/Order.php (99%) rename {application => app}/index/form/Orderaftersale.php (98%) rename {application => app}/index/form/Usergoodsbrowse.php (99%) rename {application => app}/index/form/Usergoodsfavor.php (99%) rename {application => app}/index/form/Userintegral.php (99%) rename {application => app}/index/index.html (100%) rename {application => app}/index/lang/index.html (100%) rename {application => app}/index/lang/zh-cn.php (100%) create mode 100644 app/index/route/.gitignore rename {route => app/index/route}/route.config (100%) mode change 100755 => 100644 rename {application => app}/index/view/default/agreement/index.html (100%) rename {application => app}/index/view/default/answer/detail.html (100%) rename {application => app}/index/view/default/answer/index.html (100%) rename {application => app}/index/view/default/answer/module/content.html (100%) rename {application => app}/index/view/default/answer/module/operate.html (100%) rename {application => app}/index/view/default/answer/module/reply.html (100%) rename {application => app}/index/view/default/article/index.html (100%) rename {application => app}/index/view/default/buy/index.html (98%) rename {application => app}/index/view/default/cart/index.html (93%) rename {application => app}/index/view/default/category/index.html (100%) rename {application => app}/index/view/default/config.json (81%) rename {application => app}/index/view/default/customview/index.html (100%) rename {application => app}/index/view/default/design/index.html (100%) rename {application => app}/index/view/default/goods/comments.html (100%) rename {application => app}/index/view/default/goods/index.html (100%) rename {application => app}/index/view/default/index.html (100%) rename {application => app}/index/view/default/index/index.html (94%) rename {application => app}/index/view/default/lib/enable.html (100%) rename {application => app}/index/view/default/lib/gender.html (100%) rename {application => app}/index/view/default/lib/index.html (100%) rename {application => app}/index/view/default/lib/is_new_window_open.html (100%) rename {application => app}/index/view/default/lib/is_show.html (100%) rename {application => app}/index/view/default/lib/module/category_brand.html (100%) rename {application => app}/index/view/default/lib/module/goods_category.html (100%) rename {application => app}/index/view/default/lib/region_linkage.html (100%) rename {application => app}/index/view/default/lib/seo.html (100%) rename {application => app}/index/view/default/message/detail.html (100%) rename {application => app}/index/view/default/message/index.html (100%) rename {application => app}/index/view/default/message/module/operate.html (100%) rename {application => app}/index/view/default/order/comments.html (100%) rename {application => app}/index/view/default/order/detail.html (97%) rename {application => app}/index/view/default/order/index.html (100%) rename {application => app}/index/view/default/order/module/address.html (100%) rename {application => app}/index/view/default/order/module/extension.html (100%) rename {application => app}/index/view/default/order/module/goods.html (92%) rename {application => app}/index/view/default/order/module/is_comments.html (100%) rename {application => app}/index/view/default/order/module/operate.html (100%) rename {application => app}/index/view/default/order/module/pay_status.html (100%) rename {application => app}/index/view/default/order/module/take.html (100%) rename {application => app}/index/view/default/order/payment_popup.html (100%) rename {application => app}/index/view/default/orderaftersale/create.html (100%) rename {application => app}/index/view/default/orderaftersale/delivery.html (100%) rename {application => app}/index/view/default/orderaftersale/detail.html (93%) rename {application => app}/index/view/default/orderaftersale/index.html (100%) rename {application => app}/index/view/default/orderaftersale/module/goods.html (91%) rename {application => app}/index/view/default/orderaftersale/module/operate.html (100%) rename {application => app}/index/view/default/orderaftersale/module/voucher.html (100%) rename {application => app}/index/view/default/orderaftersale/step.html (100%) rename {application => app}/index/view/default/pay/qrcode.html (100%) rename {application => app}/index/view/default/personal/index.html (100%) rename {application => app}/index/view/default/personal/save_info.html (100%) rename {application => app}/index/view/default/public/footer.html (100%) rename {application => app}/index/view/default/public/footer_nav.html (100%) rename {application => app}/index/view/default/public/goods_category.html (96%) rename {application => app}/index/view/default/public/header.html (95%) rename {application => app}/index/view/default/public/header_nav.html (100%) rename {application => app}/index/view/default/public/header_top_nav.html (100%) rename {application => app}/index/view/default/public/home_banner.html (100%) rename {application => app}/index/view/default/public/home_nav.html (100%) rename {application => app}/index/view/default/public/index.html (100%) create mode 100755 app/index/view/default/public/jump_error.html create mode 100755 app/index/view/default/public/jump_success.html rename {application => app}/index/view/default/public/loading.html (100%) rename {application => app}/index/view/default/public/login_success.html (100%) rename {application => app}/index/view/default/public/module/base_form.html (100%) rename {application/admin => app/index}/view/default/public/module/detail.html (94%) rename {application => app}/index/view/default/public/module/form.html (90%) rename {application => app}/index/view/default/public/module/form_fields_select.html (100%) rename {application => app}/index/view/default/public/module/form_operate_bottom.html (77%) rename {application => app}/index/view/default/public/module/form_operate_top.html (95%) rename {application/admin => app/index}/view/default/public/module/form_table.html (99%) rename {application => app}/index/view/default/public/module/user_form.html (91%) rename {application => app}/index/view/default/public/nav.html (100%) rename {application => app}/index/view/default/public/nav_search.html (100%) rename {application => app}/index/view/default/public/not_data.html (100%) rename {application => app}/index/view/default/public/quick.html (100%) rename {application => app}/index/view/default/public/tips_error.html (92%) rename {application => app}/index/view/default/public/tips_success.html (92%) rename {application => app}/index/view/default/public/user_menu.html (100%) rename {application => app}/index/view/default/safety/email_info.html (93%) rename {application => app}/index/view/default/safety/index.html (100%) rename {application => app}/index/view/default/safety/login_pwd_info.html (100%) rename {application => app}/index/view/default/safety/mobile_info.html (93%) rename {application => app}/index/view/default/safety/new_email_info.html (93%) rename {application => app}/index/view/default/safety/new_mobile_info.html (93%) rename {application => app}/index/view/default/search/content.html (89%) rename {application => app}/index/view/default/search/index.html (100%) rename {application => app}/index/view/default/user/forget_pwd_info.html (100%) rename {application => app}/index/view/default/user/images_verify.html (83%) rename {application => app}/index/view/default/user/index.html (100%) rename {application => app}/index/view/default/user/login_content.html (97%) rename {application => app}/index/view/default/user/login_info.html (100%) rename {application => app}/index/view/default/user/logout.html (100%) rename {application => app}/index/view/default/user/modal_login_info.html (100%) rename {application => app}/index/view/default/user/reg_info.html (99%) rename {application => app}/index/view/default/useraddress/index.html (100%) rename {application => app}/index/view/default/useraddress/save_info.html (100%) rename {application => app}/index/view/default/usergoodsbrowse/detail.html (100%) rename {application => app}/index/view/default/usergoodsbrowse/index.html (100%) rename {application => app}/index/view/default/usergoodsbrowse/module/goods.html (100%) rename {application => app}/index/view/default/usergoodsbrowse/module/operate.html (100%) rename {application => app}/index/view/default/usergoodsfavor/detail.html (100%) rename {application => app}/index/view/default/usergoodsfavor/index.html (100%) rename {application => app}/index/view/default/usergoodsfavor/module/goods.html (100%) rename {application => app}/index/view/default/usergoodsfavor/module/operate.html (100%) rename {application => app}/index/view/default/userintegral/detail.html (100%) rename {application => app}/index/view/default/userintegral/index.html (100%) rename {application => app}/index/view/default/userintegral/module/operate.html (100%) rename {application => app}/index/view/index.html (100%) rename application/admin/config/template.php => app/install/config/view.php (73%) rename {application => app}/install/controller/Common.php (63%) rename {application => app}/install/controller/Error.php (71%) rename {application => app}/install/controller/Index.php (87%) rename {application => app}/install/view/index/check.html (91%) rename {application => app}/install/view/index/create.html (95%) rename {application => app}/install/view/index/index.html (94%) rename {application => app}/install/view/index/successful.html (100%) create mode 100755 app/install/view/public/error.html rename {application => app}/install/view/public/footer.html (100%) rename {application => app}/install/view/public/footer_nav.html (96%) rename {application => app}/install/view/public/header.html (100%) rename {application => app}/install/view/public/header_nav.html (100%) rename {application => app}/install/view/public/index.html (100%) rename {application => app}/lang/zh-cn.php (99%) rename {application => app}/layout/service/BaseLayout.php (99%) rename {application => app}/layout/view/base.html (100%) rename {application => app}/layout/view/form_back.html (100%) rename {application => app}/layout/view/public/common/goods_category_choice.html (100%) rename {application => app}/layout/view/public/common/goodssearch.html (100%) rename {application => app}/layout/view/public/common/module_admin.html (100%) rename {application => app}/layout/view/public/common/module_view.html (100%) rename {application => app}/layout/view/public/content/goods_show_style.html (100%) rename {application => app}/layout/view/public/content/many_images_show_style.html (100%) rename {application => app}/layout/view/public/content/media_fixed.html (100%) rename {application => app}/layout/view/public/content/view_list_number.html (100%) rename {application => app}/layout/view/public/modal/modal_module_list_config.html (100%) rename {application => app}/layout/view/public/modal/modal_module_pages_select.html (100%) rename {application => app}/layout/view/public/modal/modal_module_rolling_config.html (100%) rename {application => app}/layout/view/public/modal/modal_module_title_keywords.html (100%) rename {application => app}/layout/view/public/offcanvas/offcanvas_layout_config.html (100%) rename {application => app}/layout/view/public/offcanvas/offcanvas_module_config_border.html (100%) rename {application => app}/layout/view/public/offcanvas/offcanvas_module_config_goods.html (100%) rename {application => app}/layout/view/public/offcanvas/offcanvas_module_config_height.html (100%) rename {application => app}/layout/view/public/offcanvas/offcanvas_module_config_images.html (100%) rename {application => app}/layout/view/public/offcanvas/offcanvas_module_config_many_images.html (100%) rename {application => app}/layout/view/public/offcanvas/offcanvas_module_config_title.html (100%) rename {application => app}/layout/view/public/offcanvas/offcanvas_module_config_video.html (100%) rename {application => app}/layout/view/public/popup/popup_module_goods_category.html (100%) rename {application => app}/layout/view/public/popup/popup_module_goods_search.html (100%) rename {application => app}/layout/view/public/popup/popup_module_goods_select.html (100%) rename {application => app}/layout/view/public/style/background_color.html (100%) rename {application => app}/layout/view/public/style/border_radius.html (100%) rename {application => app}/layout/view/public/style/border_style.html (100%) rename {application => app}/layout/view/public/style/border_style_4.html (100%) rename {application => app}/layout/view/public/style/border_width_4.html (100%) rename {application => app}/layout/view/public/style/border_width_color.html (100%) rename {application => app}/layout/view/public/style/border_width_color_4.html (100%) rename {application => app}/layout/view/public/style/color.html (100%) rename {application => app}/layout/view/public/style/height.html (100%) rename {application => app}/layout/view/public/style/input_color.html (100%) rename {application => app}/layout/view/public/style/margin.html (100%) rename {application => app}/layout/view/public/style/margin_4.html (100%) rename {application => app}/layout/view/public/style/padding.html (100%) rename {application => app}/layout/view/public/style/padding_4.html (100%) rename {application => app}/layout/view/public/style/width.html (100%) rename {application => app}/layout/view/view.html (100%) create mode 100644 app/middleware.php rename {application => app}/module/FormHandleModule.php (99%) rename {application => app}/module/ViewIncludeModule.php (71%) rename {application => app}/plugins/.gitignore (100%) rename {application => app}/plugins/index.html (100%) rename {application => app}/plugins/view/.gitignore (100%) rename {application => app}/plugins/view/index.html (100%) rename {application => app}/provider.php (76%) mode change 100755 => 100644 create mode 100644 app/service.php rename {application => app}/service/AdminPowerService.php (89%) rename {application => app}/service/AdminRoleService.php (96%) rename {application => app}/service/AdminService.php (98%) rename {application => app}/service/AnswerService.php (99%) rename {application => app}/service/AppCenterNavService.php (97%) rename {application => app}/service/AppHomeNavService.php (97%) rename {application => app}/service/AppMiniService.php (98%) rename {application => app}/service/ArticleService.php (97%) rename {application => app}/service/BannerService.php (93%) rename {application => app}/service/BrandCategoryService.php (97%) rename {application => app}/service/BrandService.php (98%) rename {application => app}/service/BuyService.php (98%) rename {application => app}/service/CacheService.php (100%) rename {application => app}/service/ConfigService.php (94%) rename {application => app}/service/CrontabService.php (98%) rename {application => app}/service/CustomViewService.php (98%) rename {application => app}/service/DesignService.php (98%) rename {application => app}/service/ExpressService.php (98%) rename {application => app}/service/FormTableService.php (98%) rename {application => app}/service/GoodsBrowseService.php (95%) rename {application => app}/service/GoodsCommentsService.php (99%) rename {application => app}/service/GoodsFavorService.php (96%) rename {application => app}/service/GoodsParamsService.php (97%) rename {application => app}/service/GoodsService.php (97%) rename {application => app}/service/IntegralService.php (98%) rename {application => app}/service/LayoutService.php (99%) rename {application => app}/service/LinkService.php (99%) rename {application => app}/service/MessageService.php (98%) rename {application => app}/service/NavigationService.php (96%) rename {application => app}/service/OrderAftersaleService.php (97%) rename {application => app}/service/OrderCurrencyService.php (97%) rename {application => app}/service/OrderService.php (98%) rename {application => app}/service/OrderSplitService.php (97%) rename {application => app}/service/PackageInstallService.php (98%) rename {application => app}/service/PayLogService.php (97%) rename {application => app}/service/PayRequestLogService.php (98%) rename {application => app}/service/PaymentService.php (92%) rename {application => app}/service/PluginsAdminService.php (97%) rename {application => app}/service/PluginsService.php (95%) rename {application => app}/service/PluginsUpgradeService.php (98%) rename {application => app}/service/QuickNavService.php (97%) rename {application => app}/service/RefundLogService.php (97%) rename {application => app}/service/RegionService.php (97%) rename {application => app}/service/ResourcesService.php (95%) rename {application => app}/service/SafetyService.php (98%) rename {application => app}/service/ScreeningPriceService.php (98%) rename {application => app}/service/SearchService.php (94%) rename {application => app}/service/SeoService.php (100%) rename {application => app}/service/SiteService.php (99%) rename {application => app}/service/SlideService.php (99%) rename {application => app}/service/SqlconsoleService.php (90%) rename {application => app}/service/StatisticalService.php (99%) rename {application => app}/service/StoreService.php (96%) rename {application => app}/service/SystemBaseService.php (97%) rename {application => app}/service/SystemService.php (76%) rename {application => app}/service/SystemUpgradeService.php (95%) rename {application => app}/service/ThemeService.php (99%) rename {application => app}/service/UeditorService.php (99%) rename {application => app}/service/UserAddressService.php (98%) rename {application => app}/service/UserService.php (98%) rename {application => app}/service/WarehouseGoodsService.php (98%) rename {application => app}/service/WarehouseService.php (98%) rename {application => app}/service/index.html (100%) delete mode 100755 application/admin/config/app.php delete mode 100755 application/admin/view/default/public/jump_error.html delete mode 100755 application/admin/view/default/public/jump_success.html delete mode 100755 application/http/middleware/SystemEnvCheck.php delete mode 100755 application/index/config/app.php delete mode 100755 application/index/controller/Common.php delete mode 100755 application/index/view/default/public/jump_error.html delete mode 100755 application/index/view/default/public/jump_success.html delete mode 100755 application/install/view/public/error.html mode change 100755 => 100644 composer.json create mode 100644 composer.lock mode change 100755 => 100644 config/.gitignore mode change 100755 => 100644 config/app.php mode change 100755 => 100644 config/cache.php mode change 100755 => 100644 config/console.php mode change 100755 => 100644 config/cookie.php create mode 100644 config/filesystem.php create mode 100644 config/lang.php mode change 100755 => 100644 config/log.php mode change 100755 => 100644 config/middleware.php create mode 100644 config/route.php mode change 100755 => 100644 config/session.php mode change 100755 => 100644 config/trace.php create mode 100644 install.php create mode 100644 public/api.php mode change 100755 => 100644 public/index.php create mode 100644 public/install.php mode change 100755 => 100644 public/router.php delete mode 100755 robots.txt mode change 100755 => 100644 think delete mode 100755 thinkphp/.htaccess delete mode 100755 thinkphp/README.md delete mode 100755 thinkphp/base.php delete mode 100755 thinkphp/convention.php delete mode 100755 thinkphp/helper.php delete mode 100755 thinkphp/library/think/App.php delete mode 100755 thinkphp/library/think/Build.php delete mode 100755 thinkphp/library/think/Cache.php delete mode 100755 thinkphp/library/think/Config.php delete mode 100755 thinkphp/library/think/Container.php delete mode 100755 thinkphp/library/think/Controller.php delete mode 100755 thinkphp/library/think/Cookie.php delete mode 100755 thinkphp/library/think/Db.php delete mode 100755 thinkphp/library/think/Debug.php delete mode 100755 thinkphp/library/think/Error.php delete mode 100755 thinkphp/library/think/File.php delete mode 100755 thinkphp/library/think/Hook.php delete mode 100755 thinkphp/library/think/Lang.php delete mode 100755 thinkphp/library/think/Loader.php delete mode 100755 thinkphp/library/think/Log.php delete mode 100755 thinkphp/library/think/Middleware.php delete mode 100755 thinkphp/library/think/Model.php delete mode 100755 thinkphp/library/think/Process.php delete mode 100755 thinkphp/library/think/Route.php delete mode 100755 thinkphp/library/think/Session.php delete mode 100755 thinkphp/library/think/Url.php delete mode 100755 thinkphp/library/think/View.php delete mode 100755 thinkphp/library/think/cache/Driver.php delete mode 100755 thinkphp/library/think/cache/driver/File.php delete mode 100755 thinkphp/library/think/cache/driver/Lite.php delete mode 100755 thinkphp/library/think/cache/driver/Sqlite.php delete mode 100755 thinkphp/library/think/cache/driver/Xcache.php delete mode 100755 thinkphp/library/think/config/driver/Ini.php delete mode 100755 thinkphp/library/think/config/driver/Xml.php delete mode 100755 thinkphp/library/think/console/command/Build.php delete mode 100755 thinkphp/library/think/console/command/make/stubs/controller.plain.stub delete mode 100755 thinkphp/library/think/console/command/make/stubs/middleware.stub delete mode 100755 thinkphp/library/think/console/command/optimize/Autoload.php delete mode 100755 thinkphp/library/think/console/command/optimize/Config.php delete mode 100755 thinkphp/library/think/console/command/optimize/Schema.php delete mode 100755 thinkphp/library/think/db/Builder.php delete mode 100755 thinkphp/library/think/db/Connection.php delete mode 100755 thinkphp/library/think/db/Query.php delete mode 100755 thinkphp/library/think/db/builder/Mysql.php delete mode 100755 thinkphp/library/think/db/connector/Sqlsrv.php delete mode 100755 thinkphp/library/think/exception/ThrowableError.php delete mode 100755 thinkphp/library/think/facade/App.php delete mode 100755 thinkphp/library/think/facade/Build.php delete mode 100755 thinkphp/library/think/facade/Cache.php delete mode 100755 thinkphp/library/think/facade/Debug.php delete mode 100755 thinkphp/library/think/facade/Hook.php delete mode 100755 thinkphp/library/think/facade/Lang.php delete mode 100755 thinkphp/library/think/facade/Log.php delete mode 100755 thinkphp/library/think/facade/Request.php delete mode 100755 thinkphp/library/think/facade/Response.php delete mode 100755 thinkphp/library/think/facade/Route.php delete mode 100755 thinkphp/library/think/facade/Session.php delete mode 100755 thinkphp/library/think/facade/Template.php delete mode 100755 thinkphp/library/think/facade/Validate.php delete mode 100755 thinkphp/library/think/facade/View.php delete mode 100755 thinkphp/library/think/log/driver/File.php delete mode 100755 thinkphp/library/think/model/Collection.php delete mode 100755 thinkphp/library/think/model/Relation.php delete mode 100755 thinkphp/library/think/model/concern/Conversion.php delete mode 100755 thinkphp/library/think/model/concern/ModelEvent.php delete mode 100755 thinkphp/library/think/model/concern/TimeStamp.php delete mode 100755 thinkphp/library/think/model/relation/HasMany.php delete mode 100755 thinkphp/library/think/model/relation/HasManyThrough.php delete mode 100755 thinkphp/library/think/process/Builder.php delete mode 100755 thinkphp/library/think/process/Utils.php delete mode 100755 thinkphp/library/think/process/exception/Faild.php delete mode 100755 thinkphp/library/think/process/exception/Failed.php delete mode 100755 thinkphp/library/think/process/exception/Timeout.php delete mode 100755 thinkphp/library/think/process/pipes/Pipes.php delete mode 100755 thinkphp/library/think/process/pipes/Unix.php delete mode 100755 thinkphp/library/think/process/pipes/Windows.php delete mode 100755 thinkphp/library/think/response/View.php delete mode 100755 thinkphp/library/think/route/AliasRule.php delete mode 100755 thinkphp/library/think/route/Dispatch.php delete mode 100755 thinkphp/library/think/route/Resource.php delete mode 100755 thinkphp/library/think/route/Rule.php delete mode 100755 thinkphp/library/think/route/RuleName.php delete mode 100755 thinkphp/library/think/route/dispatch/Controller.php delete mode 100755 thinkphp/library/think/route/dispatch/Module.php delete mode 100755 thinkphp/library/think/route/dispatch/Url.php delete mode 100755 thinkphp/library/think/session/driver/Memcache.php delete mode 100755 thinkphp/library/think/session/driver/Memcached.php delete mode 100755 thinkphp/library/think/session/driver/Redis.php delete mode 100755 thinkphp/library/think/view/driver/Php.php delete mode 100755 thinkphp/library/think/view/driver/Think.php delete mode 100755 thinkphp/library/traits/controller/Jump.php delete mode 100755 thinkphp/phpunit.xml.dist delete mode 100755 thinkphp/tpl/default_index.tpl delete mode 100755 thinkphp/tpl/dispatch_jump.tpl rename {thinkphp/tpl => tpl}/think_exception.tpl (62%) mode change 100755 => 100644 delete mode 100755 vendor/.gitignore create mode 100644 vendor/autoload.php create mode 120000 vendor/bin/var-dump-server create mode 100644 vendor/composer/ClassLoader.php create mode 100644 vendor/composer/InstalledVersions.php create mode 100644 vendor/composer/LICENSE create mode 100644 vendor/composer/autoload_classmap.php create mode 100644 vendor/composer/autoload_files.php create mode 100644 vendor/composer/autoload_namespaces.php create mode 100644 vendor/composer/autoload_psr4.php create mode 100644 vendor/composer/autoload_real.php create mode 100644 vendor/composer/autoload_static.php create mode 100644 vendor/composer/installed.json create mode 100644 vendor/composer/installed.php create mode 100644 vendor/composer/platform_check.php create mode 100644 vendor/league/flysystem-cached-adapter/.editorconfig create mode 100644 vendor/league/flysystem-cached-adapter/.gitignore create mode 100644 vendor/league/flysystem-cached-adapter/.php_cs create mode 100644 vendor/league/flysystem-cached-adapter/.scrutinizer.yml create mode 100644 vendor/league/flysystem-cached-adapter/.travis.yml create mode 100644 vendor/league/flysystem-cached-adapter/LICENSE rename {route => vendor/league/flysystem-cached-adapter/clover}/.gitignore (51%) create mode 100644 vendor/league/flysystem-cached-adapter/composer.json create mode 100644 vendor/league/flysystem-cached-adapter/phpspec.yml create mode 100644 vendor/league/flysystem-cached-adapter/phpunit.php create mode 100644 vendor/league/flysystem-cached-adapter/phpunit.xml create mode 100644 vendor/league/flysystem-cached-adapter/readme.md create mode 100644 vendor/league/flysystem-cached-adapter/spec/CachedAdapterSpec.php create mode 100644 vendor/league/flysystem-cached-adapter/src/CacheInterface.php create mode 100644 vendor/league/flysystem-cached-adapter/src/CachedAdapter.php create mode 100644 vendor/league/flysystem-cached-adapter/src/Storage/AbstractCache.php create mode 100644 vendor/league/flysystem-cached-adapter/src/Storage/Adapter.php create mode 100644 vendor/league/flysystem-cached-adapter/src/Storage/Memcached.php create mode 100644 vendor/league/flysystem-cached-adapter/src/Storage/Memory.php create mode 100644 vendor/league/flysystem-cached-adapter/src/Storage/Noop.php create mode 100644 vendor/league/flysystem-cached-adapter/src/Storage/PhpRedis.php create mode 100644 vendor/league/flysystem-cached-adapter/src/Storage/Predis.php create mode 100644 vendor/league/flysystem-cached-adapter/src/Storage/Psr6Cache.php create mode 100644 vendor/league/flysystem-cached-adapter/src/Storage/Stash.php create mode 100644 vendor/league/flysystem-cached-adapter/tests/AdapterCacheTests.php create mode 100644 vendor/league/flysystem-cached-adapter/tests/InspectionTests.php create mode 100644 vendor/league/flysystem-cached-adapter/tests/MemcachedTests.php create mode 100644 vendor/league/flysystem-cached-adapter/tests/MemoryCacheTests.php create mode 100644 vendor/league/flysystem-cached-adapter/tests/NoopCacheTests.php create mode 100644 vendor/league/flysystem-cached-adapter/tests/PhpRedisTests.php create mode 100644 vendor/league/flysystem-cached-adapter/tests/PredisTests.php create mode 100644 vendor/league/flysystem-cached-adapter/tests/Psr6CacheTest.php create mode 100644 vendor/league/flysystem-cached-adapter/tests/StashTest.php create mode 100644 vendor/league/flysystem/CODE_OF_CONDUCT.md create mode 100644 vendor/league/flysystem/LICENSE create mode 100644 vendor/league/flysystem/SECURITY.md create mode 100644 vendor/league/flysystem/composer.json create mode 100644 vendor/league/flysystem/deprecations.md create mode 100644 vendor/league/flysystem/src/Adapter/AbstractAdapter.php create mode 100644 vendor/league/flysystem/src/Adapter/AbstractFtpAdapter.php create mode 100644 vendor/league/flysystem/src/Adapter/CanOverwriteFiles.php create mode 100644 vendor/league/flysystem/src/Adapter/Ftp.php create mode 100644 vendor/league/flysystem/src/Adapter/Ftpd.php create mode 100644 vendor/league/flysystem/src/Adapter/Local.php create mode 100644 vendor/league/flysystem/src/Adapter/NullAdapter.php create mode 100644 vendor/league/flysystem/src/Adapter/Polyfill/NotSupportingVisibilityTrait.php create mode 100644 vendor/league/flysystem/src/Adapter/Polyfill/StreamedCopyTrait.php create mode 100644 vendor/league/flysystem/src/Adapter/Polyfill/StreamedReadingTrait.php create mode 100644 vendor/league/flysystem/src/Adapter/Polyfill/StreamedTrait.php create mode 100644 vendor/league/flysystem/src/Adapter/Polyfill/StreamedWritingTrait.php create mode 100644 vendor/league/flysystem/src/Adapter/SynologyFtp.php create mode 100644 vendor/league/flysystem/src/AdapterInterface.php create mode 100644 vendor/league/flysystem/src/Config.php create mode 100644 vendor/league/flysystem/src/ConfigAwareTrait.php create mode 100644 vendor/league/flysystem/src/ConnectionErrorException.php create mode 100644 vendor/league/flysystem/src/ConnectionRuntimeException.php create mode 100644 vendor/league/flysystem/src/CorruptedPathDetected.php create mode 100644 vendor/league/flysystem/src/Directory.php create mode 100644 vendor/league/flysystem/src/Exception.php create mode 100644 vendor/league/flysystem/src/File.php create mode 100644 vendor/league/flysystem/src/FileExistsException.php create mode 100644 vendor/league/flysystem/src/FileNotFoundException.php create mode 100644 vendor/league/flysystem/src/Filesystem.php create mode 100644 vendor/league/flysystem/src/FilesystemException.php create mode 100644 vendor/league/flysystem/src/FilesystemInterface.php create mode 100644 vendor/league/flysystem/src/FilesystemNotFoundException.php create mode 100644 vendor/league/flysystem/src/Handler.php create mode 100644 vendor/league/flysystem/src/InvalidRootException.php create mode 100644 vendor/league/flysystem/src/MountManager.php create mode 100644 vendor/league/flysystem/src/NotSupportedException.php create mode 100644 vendor/league/flysystem/src/Plugin/AbstractPlugin.php create mode 100644 vendor/league/flysystem/src/Plugin/EmptyDir.php create mode 100644 vendor/league/flysystem/src/Plugin/ForcedCopy.php create mode 100644 vendor/league/flysystem/src/Plugin/ForcedRename.php create mode 100644 vendor/league/flysystem/src/Plugin/GetWithMetadata.php create mode 100644 vendor/league/flysystem/src/Plugin/ListFiles.php create mode 100644 vendor/league/flysystem/src/Plugin/ListPaths.php create mode 100644 vendor/league/flysystem/src/Plugin/ListWith.php create mode 100644 vendor/league/flysystem/src/Plugin/PluggableTrait.php create mode 100644 vendor/league/flysystem/src/Plugin/PluginNotFoundException.php create mode 100644 vendor/league/flysystem/src/PluginInterface.php create mode 100644 vendor/league/flysystem/src/ReadInterface.php create mode 100644 vendor/league/flysystem/src/RootViolationException.php create mode 100644 vendor/league/flysystem/src/SafeStorage.php create mode 100644 vendor/league/flysystem/src/UnreadableFileException.php create mode 100644 vendor/league/flysystem/src/Util.php create mode 100644 vendor/league/flysystem/src/Util/ContentListingFormatter.php create mode 100644 vendor/league/flysystem/src/Util/MimeType.php create mode 100644 vendor/league/flysystem/src/Util/StreamHasher.php create mode 100644 vendor/league/mime-type-detection/CHANGELOG.md create mode 100644 vendor/league/mime-type-detection/LICENSE create mode 100644 vendor/league/mime-type-detection/composer.json create mode 100644 vendor/league/mime-type-detection/src/EmptyExtensionToMimeTypeMap.php create mode 100644 vendor/league/mime-type-detection/src/ExtensionMimeTypeDetector.php create mode 100644 vendor/league/mime-type-detection/src/ExtensionToMimeTypeMap.php create mode 100644 vendor/league/mime-type-detection/src/FinfoMimeTypeDetector.php create mode 100644 vendor/league/mime-type-detection/src/GeneratedExtensionToMimeTypeMap.php create mode 100644 vendor/league/mime-type-detection/src/MimeTypeDetector.php create mode 100644 vendor/psr/cache/CHANGELOG.md create mode 100644 vendor/psr/cache/LICENSE.txt create mode 100644 vendor/psr/cache/README.md create mode 100644 vendor/psr/cache/composer.json create mode 100644 vendor/psr/cache/src/CacheException.php create mode 100644 vendor/psr/cache/src/CacheItemInterface.php create mode 100644 vendor/psr/cache/src/CacheItemPoolInterface.php create mode 100644 vendor/psr/cache/src/InvalidArgumentException.php create mode 100644 vendor/psr/container/.gitignore create mode 100644 vendor/psr/container/LICENSE create mode 100644 vendor/psr/container/README.md create mode 100644 vendor/psr/container/composer.json create mode 100644 vendor/psr/container/src/ContainerExceptionInterface.php create mode 100644 vendor/psr/container/src/ContainerInterface.php create mode 100644 vendor/psr/container/src/NotFoundExceptionInterface.php create mode 100644 vendor/psr/log/LICENSE create mode 100644 vendor/psr/log/Psr/Log/AbstractLogger.php create mode 100644 vendor/psr/log/Psr/Log/InvalidArgumentException.php create mode 100644 vendor/psr/log/Psr/Log/LogLevel.php create mode 100644 vendor/psr/log/Psr/Log/LoggerAwareInterface.php create mode 100644 vendor/psr/log/Psr/Log/LoggerAwareTrait.php create mode 100644 vendor/psr/log/Psr/Log/LoggerInterface.php create mode 100644 vendor/psr/log/Psr/Log/LoggerTrait.php create mode 100644 vendor/psr/log/Psr/Log/NullLogger.php create mode 100644 vendor/psr/log/Psr/Log/Test/DummyTest.php create mode 100644 vendor/psr/log/Psr/Log/Test/LoggerInterfaceTest.php create mode 100644 vendor/psr/log/Psr/Log/Test/TestLogger.php create mode 100644 vendor/psr/log/README.md create mode 100644 vendor/psr/log/composer.json create mode 100644 vendor/psr/simple-cache/.editorconfig create mode 100644 vendor/psr/simple-cache/LICENSE.md create mode 100644 vendor/psr/simple-cache/README.md create mode 100644 vendor/psr/simple-cache/composer.json create mode 100644 vendor/psr/simple-cache/src/CacheException.php create mode 100644 vendor/psr/simple-cache/src/CacheInterface.php create mode 100644 vendor/psr/simple-cache/src/InvalidArgumentException.php create mode 100644 vendor/services.php create mode 100644 vendor/symfony/polyfill-mbstring/LICENSE create mode 100644 vendor/symfony/polyfill-mbstring/Mbstring.php create mode 100644 vendor/symfony/polyfill-mbstring/README.md create mode 100644 vendor/symfony/polyfill-mbstring/Resources/unidata/lowerCase.php create mode 100644 vendor/symfony/polyfill-mbstring/Resources/unidata/titleCaseRegexp.php create mode 100644 vendor/symfony/polyfill-mbstring/Resources/unidata/upperCase.php create mode 100644 vendor/symfony/polyfill-mbstring/bootstrap.php create mode 100644 vendor/symfony/polyfill-mbstring/bootstrap80.php create mode 100644 vendor/symfony/polyfill-mbstring/composer.json create mode 100644 vendor/symfony/polyfill-php72/LICENSE create mode 100644 vendor/symfony/polyfill-php72/Php72.php create mode 100644 vendor/symfony/polyfill-php72/README.md create mode 100644 vendor/symfony/polyfill-php72/bootstrap.php create mode 100644 vendor/symfony/polyfill-php72/composer.json create mode 100644 vendor/symfony/polyfill-php80/LICENSE create mode 100644 vendor/symfony/polyfill-php80/Php80.php create mode 100644 vendor/symfony/polyfill-php80/README.md create mode 100644 vendor/symfony/polyfill-php80/Resources/stubs/Attribute.php create mode 100644 vendor/symfony/polyfill-php80/Resources/stubs/Stringable.php create mode 100644 vendor/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php create mode 100644 vendor/symfony/polyfill-php80/Resources/stubs/ValueError.php create mode 100644 vendor/symfony/polyfill-php80/bootstrap.php create mode 100644 vendor/symfony/polyfill-php80/composer.json create mode 100644 vendor/symfony/var-dumper/CHANGELOG.md create mode 100644 vendor/symfony/var-dumper/Caster/AmqpCaster.php create mode 100644 vendor/symfony/var-dumper/Caster/ArgsStub.php create mode 100644 vendor/symfony/var-dumper/Caster/Caster.php create mode 100644 vendor/symfony/var-dumper/Caster/ClassStub.php create mode 100644 vendor/symfony/var-dumper/Caster/ConstStub.php create mode 100644 vendor/symfony/var-dumper/Caster/CutArrayStub.php create mode 100644 vendor/symfony/var-dumper/Caster/CutStub.php create mode 100644 vendor/symfony/var-dumper/Caster/DOMCaster.php create mode 100644 vendor/symfony/var-dumper/Caster/DateCaster.php create mode 100644 vendor/symfony/var-dumper/Caster/DoctrineCaster.php create mode 100644 vendor/symfony/var-dumper/Caster/DsCaster.php create mode 100644 vendor/symfony/var-dumper/Caster/DsPairStub.php create mode 100644 vendor/symfony/var-dumper/Caster/EnumStub.php create mode 100644 vendor/symfony/var-dumper/Caster/ExceptionCaster.php create mode 100644 vendor/symfony/var-dumper/Caster/FrameStub.php create mode 100644 vendor/symfony/var-dumper/Caster/GmpCaster.php create mode 100644 vendor/symfony/var-dumper/Caster/ImagineCaster.php create mode 100644 vendor/symfony/var-dumper/Caster/ImgStub.php create mode 100644 vendor/symfony/var-dumper/Caster/IntlCaster.php create mode 100644 vendor/symfony/var-dumper/Caster/LinkStub.php create mode 100644 vendor/symfony/var-dumper/Caster/MemcachedCaster.php create mode 100644 vendor/symfony/var-dumper/Caster/PdoCaster.php create mode 100644 vendor/symfony/var-dumper/Caster/PgSqlCaster.php create mode 100644 vendor/symfony/var-dumper/Caster/ProxyManagerCaster.php create mode 100644 vendor/symfony/var-dumper/Caster/RedisCaster.php create mode 100644 vendor/symfony/var-dumper/Caster/ReflectionCaster.php create mode 100644 vendor/symfony/var-dumper/Caster/ResourceCaster.php create mode 100644 vendor/symfony/var-dumper/Caster/SplCaster.php create mode 100644 vendor/symfony/var-dumper/Caster/StubCaster.php create mode 100644 vendor/symfony/var-dumper/Caster/SymfonyCaster.php create mode 100644 vendor/symfony/var-dumper/Caster/TraceStub.php create mode 100644 vendor/symfony/var-dumper/Caster/UuidCaster.php create mode 100644 vendor/symfony/var-dumper/Caster/XmlReaderCaster.php create mode 100644 vendor/symfony/var-dumper/Caster/XmlResourceCaster.php create mode 100644 vendor/symfony/var-dumper/Cloner/AbstractCloner.php create mode 100644 vendor/symfony/var-dumper/Cloner/ClonerInterface.php create mode 100644 vendor/symfony/var-dumper/Cloner/Cursor.php create mode 100644 vendor/symfony/var-dumper/Cloner/Data.php create mode 100644 vendor/symfony/var-dumper/Cloner/DumperInterface.php create mode 100644 vendor/symfony/var-dumper/Cloner/Stub.php create mode 100644 vendor/symfony/var-dumper/Cloner/VarCloner.php create mode 100644 vendor/symfony/var-dumper/Command/Descriptor/CliDescriptor.php create mode 100644 vendor/symfony/var-dumper/Command/Descriptor/DumpDescriptorInterface.php create mode 100644 vendor/symfony/var-dumper/Command/Descriptor/HtmlDescriptor.php create mode 100644 vendor/symfony/var-dumper/Command/ServerDumpCommand.php create mode 100644 vendor/symfony/var-dumper/Dumper/AbstractDumper.php create mode 100644 vendor/symfony/var-dumper/Dumper/CliDumper.php create mode 100644 vendor/symfony/var-dumper/Dumper/ContextProvider/CliContextProvider.php create mode 100644 vendor/symfony/var-dumper/Dumper/ContextProvider/ContextProviderInterface.php create mode 100644 vendor/symfony/var-dumper/Dumper/ContextProvider/RequestContextProvider.php create mode 100644 vendor/symfony/var-dumper/Dumper/ContextProvider/SourceContextProvider.php create mode 100644 vendor/symfony/var-dumper/Dumper/ContextualizedDumper.php create mode 100644 vendor/symfony/var-dumper/Dumper/DataDumperInterface.php create mode 100644 vendor/symfony/var-dumper/Dumper/HtmlDumper.php create mode 100644 vendor/symfony/var-dumper/Dumper/ServerDumper.php create mode 100644 vendor/symfony/var-dumper/Exception/ThrowingCasterException.php create mode 100644 vendor/symfony/var-dumper/LICENSE create mode 100644 vendor/symfony/var-dumper/README.md create mode 100755 vendor/symfony/var-dumper/Resources/bin/var-dump-server create mode 100644 vendor/symfony/var-dumper/Resources/css/htmlDescriptor.css create mode 100644 vendor/symfony/var-dumper/Resources/functions/dump.php create mode 100644 vendor/symfony/var-dumper/Resources/js/htmlDescriptor.js create mode 100644 vendor/symfony/var-dumper/Server/Connection.php create mode 100644 vendor/symfony/var-dumper/Server/DumpServer.php create mode 100644 vendor/symfony/var-dumper/Test/VarDumperTestTrait.php create mode 100644 vendor/symfony/var-dumper/VarDumper.php create mode 100644 vendor/symfony/var-dumper/composer.json rename {thinkphp => vendor/topthink/framework}/.gitignore (75%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/.travis.yml rename {thinkphp => vendor/topthink/framework}/CONTRIBUTING.md (95%) mode change 100755 => 100644 rename {thinkphp => vendor/topthink/framework}/LICENSE.txt (96%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/README.md create mode 100644 vendor/topthink/framework/composer.json rename {thinkphp => vendor/topthink/framework}/logo.png (100%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/phpunit.xml.dist create mode 100644 vendor/topthink/framework/src/helper.php rename {thinkphp => vendor/topthink/framework/src}/lang/zh-cn.php (94%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/src/think/App.php create mode 100644 vendor/topthink/framework/src/think/Cache.php create mode 100644 vendor/topthink/framework/src/think/Config.php rename {thinkphp/library => vendor/topthink/framework/src}/think/Console.php (55%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/src/think/Container.php create mode 100644 vendor/topthink/framework/src/think/Cookie.php create mode 100644 vendor/topthink/framework/src/think/Db.php rename {thinkphp/library => vendor/topthink/framework/src}/think/Env.php (51%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/src/think/Event.php rename {thinkphp/library => vendor/topthink/framework/src}/think/Exception.php (88%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/Facade.php (59%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/src/think/File.php create mode 100644 vendor/topthink/framework/src/think/Filesystem.php create mode 100644 vendor/topthink/framework/src/think/Http.php create mode 100644 vendor/topthink/framework/src/think/Lang.php create mode 100644 vendor/topthink/framework/src/think/Log.php create mode 100644 vendor/topthink/framework/src/think/Manager.php create mode 100644 vendor/topthink/framework/src/think/Middleware.php create mode 100644 vendor/topthink/framework/src/think/Pipeline.php rename {thinkphp/library => vendor/topthink/framework/src}/think/Request.php (55%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/Response.php (64%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/src/think/Route.php create mode 100644 vendor/topthink/framework/src/think/Service.php create mode 100644 vendor/topthink/framework/src/think/Session.php rename {thinkphp/library => vendor/topthink/framework/src}/think/Validate.php (60%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/src/think/View.php create mode 100644 vendor/topthink/framework/src/think/cache/Driver.php create mode 100644 vendor/topthink/framework/src/think/cache/TagSet.php create mode 100644 vendor/topthink/framework/src/think/cache/driver/File.php rename {thinkphp/library => vendor/topthink/framework/src}/think/cache/driver/Memcache.php (64%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/cache/driver/Memcached.php (53%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/cache/driver/Redis.php (55%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/cache/driver/Wincache.php (64%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/console/Command.php (68%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/console/Input.php (89%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/console/LICENSE (100%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/console/Output.php (82%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/console/Table.php (79%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/console/bin/README.md (100%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/console/bin/hiddeninput.exe (100%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/src/think/console/command/Clear.php rename {thinkphp/library => vendor/topthink/framework/src}/think/console/command/Help.php (96%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/console/command/Lists.php (91%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/console/command/Make.php (63%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/console/command/RouteList.php (60%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/console/command/RunServer.php (65%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/src/think/console/command/ServiceDiscover.php create mode 100644 vendor/topthink/framework/src/think/console/command/VendorPublish.php rename {thinkphp/library => vendor/topthink/framework/src}/think/console/command/Version.php (92%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/console/command/make/Command.php (81%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/console/command/make/Controller.php (75%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/src/think/console/command/make/Event.php create mode 100644 vendor/topthink/framework/src/think/console/command/make/Listener.php rename {thinkphp/library => vendor/topthink/framework/src}/think/console/command/make/Middleware.php (73%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/console/command/make/Model.php (73%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/src/think/console/command/make/Service.php create mode 100644 vendor/topthink/framework/src/think/console/command/make/Subscribe.php rename {thinkphp/library => vendor/topthink/framework/src}/think/console/command/make/Validate.php (77%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/console/command/make/stubs/command.stub (52%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/console/command/make/stubs/controller.api.stub (94%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/src/think/console/command/make/stubs/controller.plain.stub rename {thinkphp/library => vendor/topthink/framework/src}/think/console/command/make/stubs/controller.stub (95%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/src/think/console/command/make/stubs/event.stub create mode 100644 vendor/topthink/framework/src/think/console/command/make/stubs/listener.stub create mode 100644 vendor/topthink/framework/src/think/console/command/make/stubs/middleware.stub rename {thinkphp/library => vendor/topthink/framework/src}/think/console/command/make/stubs/model.stub (61%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/src/think/console/command/make/stubs/service.stub create mode 100644 vendor/topthink/framework/src/think/console/command/make/stubs/subscribe.stub rename {thinkphp/library => vendor/topthink/framework/src}/think/console/command/make/stubs/validate.stub (56%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/console/command/optimize/Route.php (53%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/src/think/console/command/optimize/Schema.php rename {thinkphp/library => vendor/topthink/framework/src}/think/console/input/Argument.php (82%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/console/input/Definition.php (88%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/console/input/Option.php (93%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/console/output/Ask.php (99%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/console/output/Descriptor.php (94%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/console/output/Formatter.php (98%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/console/output/Question.php (100%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/console/output/descriptor/Console.php (92%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/console/output/driver/Buffer.php (89%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/console/output/driver/Console.php (95%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/console/output/driver/Nothing.php (85%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/console/output/formatter/Stack.php (92%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/console/output/formatter/Style.php (95%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/console/output/question/Choice.php (94%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/console/output/question/Confirmation.php (94%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php create mode 100644 vendor/topthink/framework/src/think/contract/LogHandlerInterface.php create mode 100644 vendor/topthink/framework/src/think/contract/ModelRelationInterface.php rename thinkphp/library/think/config/driver/Json.php => vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php (57%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php rename thinkphp/library/think/route/dispatch/Response.php => vendor/topthink/framework/src/think/event/AppInit.php (69%) mode change 100755 => 100644 rename thinkphp/library/think/route/dispatch/Redirect.php => vendor/topthink/framework/src/think/event/HttpEnd.php (64%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/src/think/event/HttpRun.php create mode 100644 vendor/topthink/framework/src/think/event/LogRecord.php rename thinkphp/library/think/route/dispatch/View.php => vendor/topthink/framework/src/think/event/LogWrite.php (59%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/src/think/event/RouteLoaded.php rename {thinkphp/library => vendor/topthink/framework/src}/think/exception/ClassNotFoundException.php (67%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/exception/ErrorException.php (89%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/src/think/exception/FileException.php create mode 100644 vendor/topthink/framework/src/think/exception/FuncNotFoundException.php rename {thinkphp/library => vendor/topthink/framework/src}/think/exception/Handle.php (54%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/exception/HttpException.php (78%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/exception/HttpResponseException.php (88%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/src/think/exception/InvalidArgumentException.php rename {thinkphp/library => vendor/topthink/framework/src}/think/exception/RouteNotFoundException.php (85%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/exception/ValidateException.php (78%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/src/think/facade/App.php create mode 100644 vendor/topthink/framework/src/think/facade/Cache.php rename {thinkphp/library => vendor/topthink/framework/src}/think/facade/Config.php (63%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/src/think/facade/Console.php rename {thinkphp/library => vendor/topthink/framework/src}/think/facade/Cookie.php (55%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/src/think/facade/Env.php create mode 100644 vendor/topthink/framework/src/think/facade/Event.php create mode 100644 vendor/topthink/framework/src/think/facade/Filesystem.php create mode 100644 vendor/topthink/framework/src/think/facade/Lang.php create mode 100644 vendor/topthink/framework/src/think/facade/Log.php rename {thinkphp/library => vendor/topthink/framework/src}/think/facade/Middleware.php (50%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/src/think/facade/Request.php create mode 100644 vendor/topthink/framework/src/think/facade/Route.php rename thinkphp/library/think/facade/Env.php => vendor/topthink/framework/src/think/facade/Session.php (66%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/src/think/facade/Validate.php create mode 100644 vendor/topthink/framework/src/think/facade/View.php create mode 100644 vendor/topthink/framework/src/think/file/UploadedFile.php create mode 100644 vendor/topthink/framework/src/think/filesystem/CacheStore.php create mode 100644 vendor/topthink/framework/src/think/filesystem/Driver.php create mode 100644 vendor/topthink/framework/src/think/filesystem/driver/Local.php create mode 100644 vendor/topthink/framework/src/think/initializer/BootService.php create mode 100644 vendor/topthink/framework/src/think/initializer/Error.php create mode 100644 vendor/topthink/framework/src/think/initializer/RegisterService.php create mode 100644 vendor/topthink/framework/src/think/log/Channel.php create mode 100644 vendor/topthink/framework/src/think/log/ChannelSet.php create mode 100644 vendor/topthink/framework/src/think/log/driver/File.php rename {thinkphp/library => vendor/topthink/framework/src}/think/log/driver/Socket.php (53%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/src/think/middleware/AllowCrossDomain.php create mode 100644 vendor/topthink/framework/src/think/middleware/CheckRequestCache.php create mode 100644 vendor/topthink/framework/src/think/middleware/FormTokenCheck.php create mode 100644 vendor/topthink/framework/src/think/middleware/LoadLangPack.php create mode 100644 vendor/topthink/framework/src/think/middleware/SessionInit.php rename thinkphp/library/think/response/Download.php => vendor/topthink/framework/src/think/response/File.php (77%) mode change 100755 => 100644 rename thinkphp/library/think/response/Jump.php => vendor/topthink/framework/src/think/response/Html.php (63%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/response/Json.php (79%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/response/Jsonp.php (71%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/response/Redirect.php (51%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/src/think/response/View.php rename {thinkphp/library => vendor/topthink/framework/src}/think/response/Xml.php (85%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/src/think/route/Dispatch.php rename {thinkphp/library => vendor/topthink/framework/src}/think/route/Domain.php (57%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/src/think/route/Resource.php create mode 100644 vendor/topthink/framework/src/think/route/Rule.php rename {thinkphp/library => vendor/topthink/framework/src}/think/route/RuleGroup.php (53%) mode change 100755 => 100644 rename {thinkphp/library => vendor/topthink/framework/src}/think/route/RuleItem.php (63%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/src/think/route/RuleName.php create mode 100644 vendor/topthink/framework/src/think/route/Url.php rename {thinkphp/library => vendor/topthink/framework/src}/think/route/dispatch/Callback.php (87%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/src/think/route/dispatch/Controller.php create mode 100644 vendor/topthink/framework/src/think/route/dispatch/Url.php create mode 100644 vendor/topthink/framework/src/think/service/ModelService.php create mode 100644 vendor/topthink/framework/src/think/service/PaginatorService.php create mode 100644 vendor/topthink/framework/src/think/service/ValidateService.php create mode 100644 vendor/topthink/framework/src/think/session/Store.php create mode 100644 vendor/topthink/framework/src/think/session/driver/Cache.php create mode 100644 vendor/topthink/framework/src/think/session/driver/File.php rename {thinkphp/library => vendor/topthink/framework/src}/think/validate/ValidateRule.php (95%) mode change 100755 => 100644 create mode 100644 vendor/topthink/framework/src/think/view/driver/Php.php create mode 100644 vendor/topthink/framework/src/tpl/think_exception.tpl create mode 100644 vendor/topthink/framework/tests/AppTest.php create mode 100644 vendor/topthink/framework/tests/CacheTest.php create mode 100644 vendor/topthink/framework/tests/ConfigTest.php create mode 100644 vendor/topthink/framework/tests/ContainerTest.php create mode 100644 vendor/topthink/framework/tests/DbTest.php create mode 100644 vendor/topthink/framework/tests/EnvTest.php create mode 100644 vendor/topthink/framework/tests/EventTest.php create mode 100644 vendor/topthink/framework/tests/FilesystemTest.php create mode 100644 vendor/topthink/framework/tests/HttpTest.php create mode 100644 vendor/topthink/framework/tests/InteractsWithApp.php create mode 100644 vendor/topthink/framework/tests/LogTest.php create mode 100644 vendor/topthink/framework/tests/MiddlewareTest.php create mode 100644 vendor/topthink/framework/tests/RouteTest.php create mode 100644 vendor/topthink/framework/tests/SessionTest.php create mode 100644 vendor/topthink/framework/tests/ViewTest.php create mode 100644 vendor/topthink/framework/tests/bootstrap.php create mode 100644 vendor/topthink/think-helper/.gitignore create mode 100644 vendor/topthink/think-helper/LICENSE create mode 100644 vendor/topthink/think-helper/README.md create mode 100644 vendor/topthink/think-helper/composer.json rename {thinkphp/library/think => vendor/topthink/think-helper/src}/Collection.php (64%) mode change 100755 => 100644 create mode 100644 vendor/topthink/think-helper/src/contract/Arrayable.php create mode 100644 vendor/topthink/think-helper/src/contract/Jsonable.php create mode 100644 vendor/topthink/think-helper/src/helper.php create mode 100644 vendor/topthink/think-helper/src/helper/Arr.php create mode 100644 vendor/topthink/think-helper/src/helper/Str.php create mode 100644 vendor/topthink/think-multi-app/LICENSE create mode 100644 vendor/topthink/think-multi-app/README.md create mode 100644 vendor/topthink/think-multi-app/composer.json create mode 100644 vendor/topthink/think-multi-app/src/MultiApp.php create mode 100644 vendor/topthink/think-multi-app/src/Service.php create mode 100644 vendor/topthink/think-multi-app/src/Url.php create mode 100644 vendor/topthink/think-multi-app/src/command/Build.php rename {thinkphp/library/think/console => vendor/topthink/think-multi-app/src}/command/Clear.php (66%) mode change 100755 => 100644 create mode 100644 vendor/topthink/think-multi-app/src/command/stubs/controller.stub create mode 100644 vendor/topthink/think-orm/.gitattributes create mode 100644 vendor/topthink/think-orm/.gitignore create mode 100644 vendor/topthink/think-orm/LICENSE create mode 100644 vendor/topthink/think-orm/README.md create mode 100644 vendor/topthink/think-orm/composer.json create mode 100644 vendor/topthink/think-orm/src/DbManager.php create mode 100644 vendor/topthink/think-orm/src/Model.php rename {thinkphp/library/think => vendor/topthink/think-orm/src}/Paginator.php (65%) mode change 100755 => 100644 create mode 100644 vendor/topthink/think-orm/src/db/BaseQuery.php create mode 100644 vendor/topthink/think-orm/src/db/Builder.php create mode 100644 vendor/topthink/think-orm/src/db/CacheItem.php create mode 100644 vendor/topthink/think-orm/src/db/Connection.php create mode 100644 vendor/topthink/think-orm/src/db/ConnectionInterface.php create mode 100644 vendor/topthink/think-orm/src/db/Fetch.php create mode 100644 vendor/topthink/think-orm/src/db/Mongo.php create mode 100644 vendor/topthink/think-orm/src/db/PDOConnection.php create mode 100644 vendor/topthink/think-orm/src/db/Query.php rename thinkphp/library/think/db/Expression.php => vendor/topthink/think-orm/src/db/Raw.php (65%) mode change 100755 => 100644 rename {thinkphp/library/think => vendor/topthink/think-orm/src}/db/Where.php (83%) mode change 100755 => 100644 create mode 100644 vendor/topthink/think-orm/src/db/builder/Mongo.php create mode 100644 vendor/topthink/think-orm/src/db/builder/Mysql.php create mode 100644 vendor/topthink/think-orm/src/db/builder/Oracle.php rename {thinkphp/library/think => vendor/topthink/think-orm/src}/db/builder/Pgsql.php (70%) mode change 100755 => 100644 rename {thinkphp/library/think => vendor/topthink/think-orm/src}/db/builder/Sqlite.php (80%) mode change 100755 => 100644 rename {thinkphp/library/think => vendor/topthink/think-orm/src}/db/builder/Sqlsrv.php (60%) mode change 100755 => 100644 create mode 100644 vendor/topthink/think-orm/src/db/concern/AggregateQuery.php create mode 100644 vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php create mode 100644 vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php create mode 100644 vendor/topthink/think-orm/src/db/concern/ParamsBind.php create mode 100644 vendor/topthink/think-orm/src/db/concern/ResultOperation.php create mode 100644 vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php create mode 100644 vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php create mode 100644 vendor/topthink/think-orm/src/db/concern/Transaction.php create mode 100644 vendor/topthink/think-orm/src/db/concern/WhereQuery.php create mode 100644 vendor/topthink/think-orm/src/db/connector/Mongo.php rename {thinkphp/library/think => vendor/topthink/think-orm/src}/db/connector/Mysql.php (55%) mode change 100755 => 100644 create mode 100644 vendor/topthink/think-orm/src/db/connector/Oracle.php rename {thinkphp/library/think => vendor/topthink/think-orm/src}/db/connector/Pgsql.php (70%) mode change 100755 => 100644 rename {thinkphp/library/think => vendor/topthink/think-orm/src}/db/connector/Sqlite.php (70%) mode change 100755 => 100644 create mode 100644 vendor/topthink/think-orm/src/db/connector/Sqlsrv.php rename {thinkphp/library/think => vendor/topthink/think-orm/src}/db/connector/pgsql.sql (100%) mode change 100755 => 100644 rename {thinkphp/library/think => vendor/topthink/think-orm/src}/db/exception/BindParamException.php (83%) mode change 100755 => 100644 rename {thinkphp/library/think => vendor/topthink/think-orm/src}/db/exception/DataNotFoundException.php (86%) mode change 100755 => 100644 rename {thinkphp/library/think => vendor/topthink/think-orm/src/db}/exception/DbException.php (84%) mode change 100755 => 100644 create mode 100644 vendor/topthink/think-orm/src/db/exception/InvalidArgumentException.php create mode 100644 vendor/topthink/think-orm/src/db/exception/ModelEventException.php rename {thinkphp/library/think => vendor/topthink/think-orm/src}/db/exception/ModelNotFoundException.php (85%) mode change 100755 => 100644 rename {thinkphp/library/think => vendor/topthink/think-orm/src/db}/exception/PDOException.php (60%) mode change 100755 => 100644 rename thinkphp/library/think/facade/Url.php => vendor/topthink/think-orm/src/facade/Db.php (68%) mode change 100755 => 100644 create mode 100644 vendor/topthink/think-orm/src/model/Collection.php rename {thinkphp/library/think => vendor/topthink/think-orm/src}/model/Pivot.php (65%) mode change 100755 => 100644 create mode 100644 vendor/topthink/think-orm/src/model/Relation.php rename {thinkphp/library/think => vendor/topthink/think-orm/src}/model/concern/Attribute.php (53%) mode change 100755 => 100644 create mode 100644 vendor/topthink/think-orm/src/model/concern/Conversion.php create mode 100644 vendor/topthink/think-orm/src/model/concern/ModelEvent.php create mode 100644 vendor/topthink/think-orm/src/model/concern/OptimLock.php rename {thinkphp/library/think => vendor/topthink/think-orm/src}/model/concern/RelationShip.php (50%) mode change 100755 => 100644 rename {thinkphp/library/think => vendor/topthink/think-orm/src}/model/concern/SoftDelete.php (58%) mode change 100755 => 100644 create mode 100644 vendor/topthink/think-orm/src/model/concern/TimeStamp.php rename {thinkphp/library/think => vendor/topthink/think-orm/src}/model/relation/BelongsTo.php (54%) mode change 100755 => 100644 rename {thinkphp/library/think => vendor/topthink/think-orm/src}/model/relation/BelongsToMany.php (59%) mode change 100755 => 100644 create mode 100644 vendor/topthink/think-orm/src/model/relation/HasMany.php create mode 100644 vendor/topthink/think-orm/src/model/relation/HasManyThrough.php rename {thinkphp/library/think => vendor/topthink/think-orm/src}/model/relation/HasOne.php (52%) mode change 100755 => 100644 create mode 100644 vendor/topthink/think-orm/src/model/relation/HasOneThrough.php rename {thinkphp/library/think => vendor/topthink/think-orm/src}/model/relation/MorphMany.php (53%) mode change 100755 => 100644 rename {thinkphp/library/think => vendor/topthink/think-orm/src}/model/relation/MorphOne.php (50%) mode change 100755 => 100644 rename {thinkphp/library/think => vendor/topthink/think-orm/src}/model/relation/MorphTo.php (62%) mode change 100755 => 100644 create mode 100644 vendor/topthink/think-orm/src/model/relation/MorphToMany.php rename {thinkphp/library/think => vendor/topthink/think-orm/src}/model/relation/OneToOne.php (53%) mode change 100755 => 100644 rename {thinkphp/library/think => vendor/topthink/think-orm/src}/paginator/driver/Bootstrap.php (86%) mode change 100755 => 100644 create mode 100644 vendor/topthink/think-orm/stubs/Exception.php create mode 100644 vendor/topthink/think-orm/stubs/Facade.php create mode 100644 vendor/topthink/think-orm/stubs/load_stubs.php create mode 100644 vendor/topthink/think-template/.gitignore create mode 100644 vendor/topthink/think-template/LICENSE create mode 100644 vendor/topthink/think-template/README.md create mode 100644 vendor/topthink/think-template/composer.json rename {thinkphp/library/think => vendor/topthink/think-template/src}/Template.php (84%) mode change 100755 => 100644 create mode 100644 vendor/topthink/think-template/src/facade/Template.php rename {thinkphp/library/think => vendor/topthink/think-template/src}/template/TagLib.php (91%) mode change 100755 => 100644 rename {thinkphp/library/think => vendor/topthink/think-template/src}/template/driver/File.php (86%) mode change 100755 => 100644 rename {thinkphp/library/think => vendor/topthink/think-template/src/template}/exception/TemplateNotFoundException.php (75%) mode change 100755 => 100644 rename {thinkphp/library/think => vendor/topthink/think-template/src}/template/taglib/Cx.php (93%) mode change 100755 => 100644 create mode 100644 vendor/topthink/think-trace/.gitignore create mode 100644 vendor/topthink/think-trace/LICENSE create mode 100644 vendor/topthink/think-trace/README.md create mode 100644 vendor/topthink/think-trace/composer.json rename {thinkphp/library/think/debug => vendor/topthink/think-trace/src}/Console.php (66%) mode change 100755 => 100644 rename {thinkphp/library/think/debug => vendor/topthink/think-trace/src}/Html.php (55%) mode change 100755 => 100644 create mode 100644 vendor/topthink/think-trace/src/Service.php create mode 100644 vendor/topthink/think-trace/src/TraceDebug.php create mode 100644 vendor/topthink/think-trace/src/config.php rename {thinkphp => vendor/topthink/think-trace/src}/tpl/page_trace.tpl (98%) mode change 100755 => 100644 create mode 100644 vendor/topthink/think-view/.gitignore create mode 100644 vendor/topthink/think-view/LICENSE create mode 100644 vendor/topthink/think-view/README.md create mode 100644 vendor/topthink/think-view/composer.json create mode 100644 vendor/topthink/think-view/src/Think.php diff --git a/.gitignore b/.gitignore index b8c5122c2..bdad8fc43 100755 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ .DS_Store .ide *.log -*.lock +.env .tea .idea .htaccess diff --git a/LICENSE b/LICENSE.txt similarity index 98% rename from LICENSE rename to LICENSE.txt index 77af19b14..b419273bc 100644 --- a/LICENSE +++ b/LICENSE.txt @@ -1,21 +1,21 @@ -MIT License - -Copyright (c) 2020 ShopXO - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +MIT License + +Copyright (c) 2020 ShopXO + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/admin.php b/admin.php index f2f1b0ab5..bae246b74 100644 --- a/admin.php +++ b/admin.php @@ -13,7 +13,7 @@ namespace think; // 加载基础文件 -require __DIR__ . '/thinkphp/base.php'; +require __DIR__ . '/vendor/autoload.php'; // 根目录入口 define('IS_ROOT_ACCESS', true); @@ -21,6 +21,9 @@ define('IS_ROOT_ACCESS', true); // 引入公共入口文件 require __DIR__.'/public/core.php'; -// 执行应用并响应 -Container::get('app')->bind('admin')->run()->send(); +// 执行HTTP应用并响应 +$http = (new App())->http; +$response = $http->name('admin')->run(); +$response->send(); +$http->end($response); ?> \ No newline at end of file diff --git a/application/middleware.php b/api.php old mode 100755 new mode 100644 similarity index 83% rename from application/middleware.php rename to api.php index 083646ddc..ff7e5538c --- a/application/middleware.php +++ b/api.php @@ -9,9 +9,9 @@ // | Author: Devil // +---------------------------------------------------------------------- -// 中间件配置 -return [ - // 系统环境检查 - app\http\middleware\SystemEnvCheck::class, -]; +// [ API入口文件 ] +define('IS_ROOT_ACCESS', true); + +// 引入公共入口文件 +require './public/api.php'; ?> \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 000000000..49f588f59 --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +event.php \ No newline at end of file diff --git a/application/tags.php b/app/AppService.php old mode 100755 new mode 100644 similarity index 67% rename from application/tags.php rename to app/AppService.php index 975bac18d..348d0fe82 --- a/application/tags.php +++ b/app/AppService.php @@ -8,29 +8,25 @@ // +---------------------------------------------------------------------- // | Author: Devil // +---------------------------------------------------------------------- +declare (strict_types = 1); -// 应用行为扩展定义文件 -return array ( - 'app_init' => - array ( - ), - 'app_begin' => - array ( - ), - 'module_init' => - array ( - ), - 'action_begin' => - array ( - ), - 'view_filter' => - array ( - ), - 'app_end' => - array ( - ), - 'log_write' => - array ( - ), -); +namespace app; + +use think\Service; + +/** + * 应用服务类 + */ +class AppService extends Service +{ + public function register() + { + // 服务注册 + } + + public function boot() + { + // 服务启动 + } +} ?> \ No newline at end of file diff --git a/app/BaseController.php b/app/BaseController.php new file mode 100644 index 000000000..e61309d4a --- /dev/null +++ b/app/BaseController.php @@ -0,0 +1,104 @@ +app = $app; + $this->request = $this->app->request; + + // 控制器初始化 + $this->initialize(); + } + + // 初始化 + protected function initialize() + {} + + /** + * 验证数据 + * @access protected + * @param array $data 数据 + * @param string|array $validate 验证器名或者验证规则数组 + * @param array $message 提示信息 + * @param bool $batch 是否批量验证 + * @return array|string|true + * @throws ValidateException + */ + protected function validate(array $data, $validate, array $message = [], bool $batch = false) + { + if (is_array($validate)) { + $v = new Validate(); + $v->rule($validate); + } else { + if (strpos($validate, '.')) { + // 支持场景 + [$validate, $scene] = explode('.', $validate); + } + $class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate); + $v = new $class(); + if (!empty($scene)) { + $v->scene($scene); + } + } + + $v->message($message); + + // 是否批量验证 + if ($batch || $this->batchValidate) { + $v->batch(true); + } + + return $v->failException(true)->check($data); + } + +} +?> \ No newline at end of file diff --git a/application/common/Http.php b/app/ExceptionHandle.php old mode 100755 new mode 100644 similarity index 55% rename from application/common/Http.php rename to app/ExceptionHandle.php index cbbbdd1ab..ffa1adf1e --- a/application/common/Http.php +++ b/app/ExceptionHandle.php @@ -8,34 +8,58 @@ // +---------------------------------------------------------------------- // | Author: Devil // +---------------------------------------------------------------------- -namespace app\common; +namespace app; -use Exception; +use think\db\exception\DataNotFoundException; +use think\db\exception\ModelNotFoundException; use think\exception\Handle; use think\exception\HttpException; +use think\exception\HttpResponseException; use think\exception\ValidateException; +use think\Response; +use Throwable; /** - * 异常处理 - * @author Devil - * @blog http://gong.gg/ - * @version 0.0.1 - * @datetime 2016-12-01T21:51:08+0800 + * 应用异常处理类 */ -class Http extends Handle +class ExceptionHandle extends Handle { /** - * 异常处理 - * @author Devil - * @blog http://gong.gg/ - * @version 1.0.0 - * @date 2019-01-14 - * @desc description - * @param Exception $e [错误对象] + * 不需要记录信息(日志)的异常类列表 + * @var array */ - public function render(Exception $e) + protected $ignoreReport = [ + HttpException::class, + HttpResponseException::class, + ModelNotFoundException::class, + DataNotFoundException::class, + ValidateException::class, + ]; + + /** + * 记录异常信息(包括日志或者其它方式记录) + * + * @access public + * @param Throwable $exception + * @return void + */ + public function report(Throwable $exception): void { - // ajax请求处理 + // 使用内置的方式记录异常日志 + parent::report($exception); + } + + /** + * Render an exception into an HTTP response. + * + * @access public + * @param \think\Request $request + * @param Throwable $e + * @return Response + */ + public function render($request, Throwable $e): Response + { + // 添加自定义异常处理机制 if(IS_AJAX) { // 参数验证错误 @@ -66,11 +90,10 @@ class Http extends Handle } } exit(json_encode(DataReturn($msg, $code))); - - // web错误交给系统处理 - } else { - return parent::render($e); } + + // 其他错误交给系统处理 + return parent::render($request, $e); } } ?> \ No newline at end of file diff --git a/application/command.php b/app/Request.php old mode 100755 new mode 100644 similarity index 87% rename from application/command.php rename to app/Request.php index 288dd38df..8a9dd237e --- a/application/command.php +++ b/app/Request.php @@ -8,6 +8,10 @@ // +---------------------------------------------------------------------- // | Author: Devil // +---------------------------------------------------------------------- +namespace app; -return []; -?> \ No newline at end of file +// 应用请求对象类 +class Request extends \think\Request +{ + +} diff --git a/application/install/config/template.php b/app/admin/config/view.php similarity index 74% rename from application/install/config/template.php rename to app/admin/config/view.php index 36c4a534d..6300c4a88 100755 --- a/application/install/config/template.php +++ b/app/admin/config/view.php @@ -12,25 +12,24 @@ // +---------------------------------------------------------------------- // | 模板设置 // +---------------------------------------------------------------------- - return [ - // 模板引擎类型 支持 php think 支持扩展 - 'type' => 'Think', + // 模板引擎类型使用Think + 'type' => 'Think', // 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写 3 保持操作方法 - 'auto_rule' => 1, - // 模板路径 - 'view_path' => APP_PATH.'install'.DS.'view'.DS, + 'auto_rule' => 1, + // 模板目录名 + 'view_dir_name' => 'view'.DS.'default', // 模板后缀 - 'view_suffix' => 'html', + 'view_suffix' => 'html', // 模板文件名分隔符 - 'view_depr' => DIRECTORY_SEPARATOR, + 'view_depr' => DIRECTORY_SEPARATOR, // 模板引擎普通标签开始标记 - 'tpl_begin' => '{{', + 'tpl_begin' => '{{', // 模板引擎普通标签结束标记 - 'tpl_end' => '}}', + 'tpl_end' => '}}', // 标签库标签开始标记 - 'taglib_begin' => '{{', + 'taglib_begin' => '{{', // 标签库标签结束标记 - 'taglib_end' => '}}', + 'taglib_end' => '}}', ]; ?> \ No newline at end of file diff --git a/application/admin/controller/Admin.php b/app/admin/controller/Admin.php similarity index 88% rename from application/admin/controller/Admin.php rename to app/admin/controller/Admin.php index ac9b46225..ca1aaccc7 100755 --- a/application/admin/controller/Admin.php +++ b/app/admin/controller/Admin.php @@ -10,7 +10,6 @@ // +---------------------------------------------------------------------- namespace app\admin\controller; -use think\facade\Hook; use app\service\AdminService; use app\service\SystemBaseService; @@ -76,10 +75,10 @@ class Admin extends Common $ret = AdminService::AdminList($data_params); // 基础参数赋值 - $this->assign('params', $this->data_request); - $this->assign('page_html', $page->GetPageHtml()); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + MyViewAssign('page_html', $page->GetPageHtml()); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -107,9 +106,9 @@ class Admin extends Common ]; $ret = AdminService::AdminList($data_params); $data = (empty($ret['data']) || empty($ret['data'][0])) ? [] : $ret['data'][0]; - $this->assign('data', $data); + MyViewAssign('data', $data); } - return $this->fetch(); + return MyView(); } /** @@ -158,15 +157,15 @@ class Admin extends Common 'field' => 'id,name', ]; $role = AdminService::RoleList($role_params); - $this->assign('role_list', $role['data']); + MyViewAssign('role_list', $role['data']); - $this->assign('id', isset($params['id']) ? $params['id'] : 0); - $this->assign('common_gender_list', lang('common_gender_list')); - $this->assign('common_admin_status_list', lang('common_admin_status_list')); + MyViewAssign('id', isset($params['id']) ? $params['id'] : 0); + MyViewAssign('common_gender_list', lang('common_gender_list')); + MyViewAssign('common_admin_status_list', lang('common_admin_status_list')); // 管理员编辑页面钩子 $hook_name = 'plugins_view_admin_admin_save'; - $this->assign($hook_name.'_data', Hook::listen($hook_name, + MyViewAssign($hook_name.'_data', MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, @@ -177,9 +176,9 @@ class Admin extends Common // 数据 unset($params['id']); - $this->assign('data', $data); - $this->assign('params', $params); - return $this->fetch(); + MyViewAssign('data', $data); + MyViewAssign('params', $params); + return MyView(); } /** @@ -257,11 +256,11 @@ class Admin extends Common // 是否已登录 if(AdminService::LoginInfo() !== null) { - return redirect(MyUrl('admin/index/index')); + return MyRedirect(MyUrl('admin/index/index')); } // 登录方式 - $this->assign('admin_login_type', MyC('admin_login_type', [], true)); + MyViewAssign('admin_login_type', MyC('admin_login_type', [], true)); // 背景图片 $host = SystemBaseService::AttachmentHost(); @@ -282,17 +281,17 @@ class Admin extends Common $host.'/static/admin/default/images/login/14.jpg', $host.'/static/admin/default/images/login/15.jpg', ]; - $this->assign('bg_images_list', $bg_images_list); + MyViewAssign('bg_images_list', $bg_images_list); // 管理员登录页面钩子 $hook_name = 'plugins_view_admin_login_info'; - $this->assign($hook_name.'_data', Hook::listen($hook_name, + MyViewAssign($hook_name.'_data', MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, ])); - return $this->fetch(); + return MyView(); } /** @@ -366,7 +365,7 @@ class Admin extends Common public function Logout() { AdminService::LoginLogout(); - return redirect(MyUrl('admin/admin/logininfo')); + return MyRedirect(MyUrl('admin/admin/logininfo')); } } ?> \ No newline at end of file diff --git a/application/admin/controller/Agreement.php b/app/admin/controller/Agreement.php similarity index 88% rename from application/admin/controller/Agreement.php rename to app/admin/controller/Agreement.php index 1bea9e1ab..ee30a6669 100644 --- a/application/admin/controller/Agreement.php +++ b/app/admin/controller/Agreement.php @@ -52,10 +52,10 @@ class Agreement extends Common public function Index() { // 配置信息 - $this->assign('data', ConfigService::ConfigList()); + MyViewAssign('data', ConfigService::ConfigList()); // 编辑器文件存放地址 - $this->assign('editor_path_type', ResourcesService::EditorPathTypeValue('agreement')); + MyViewAssign('editor_path_type', ResourcesService::EditorPathTypeValue('agreement')); // 导航数据 $nav_data = [ @@ -68,12 +68,12 @@ class Agreement extends Common 'type' => 'privacy', ] ]; - $this->assign('nav_data', $nav_data); + MyViewAssign('nav_data', $nav_data); // 导航/视图 $nav_type = input('nav_type', 'register'); - $this->assign('nav_type', $nav_type); - return $this->fetch($nav_type); + MyViewAssign('nav_type', $nav_type); + return MyView($nav_type); } /** diff --git a/application/admin/controller/Answer.php b/app/admin/controller/Answer.php similarity index 91% rename from application/admin/controller/Answer.php rename to app/admin/controller/Answer.php index 60fd90007..76781c636 100755 --- a/application/admin/controller/Answer.php +++ b/app/admin/controller/Answer.php @@ -73,10 +73,10 @@ class Answer extends Common $ret = AnswerService::AnswerList($data_params); // 基础参数赋值 - $this->assign('params', $this->data_request); - $this->assign('page_html', $page->GetPageHtml()); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + MyViewAssign('page_html', $page->GetPageHtml()); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -105,9 +105,9 @@ class Answer extends Common ]; $ret = AnswerService::AnswerList($data_params); $data = (empty($ret['data']) || empty($ret['data'][0])) ? [] : $ret['data'][0]; - $this->assign('data', $data); + MyViewAssign('data', $data); } - return $this->fetch(); + return MyView(); } /** @@ -150,16 +150,16 @@ class Answer extends Common $data = empty($ret['data'][0]) ? [] : $ret['data'][0]; } - $this->assign('data', $data); + MyViewAssign('data', $data); // 静态数据 - $this->assign('common_is_show_list', lang('common_is_show_list')); - $this->assign('common_is_text_list', lang('common_is_text_list')); + MyViewAssign('common_is_show_list', lang('common_is_show_list')); + MyViewAssign('common_is_text_list', lang('common_is_text_list')); // 参数 unset($params['id']); - $this->assign('params', $params); - return $this->fetch(); + MyViewAssign('params', $params); + return MyView(); } /** diff --git a/application/admin/controller/Appcenternav.php b/app/admin/controller/Appcenternav.php similarity index 89% rename from application/admin/controller/Appcenternav.php rename to app/admin/controller/Appcenternav.php index 563bfd9c8..bef6218b9 100755 --- a/application/admin/controller/Appcenternav.php +++ b/app/admin/controller/Appcenternav.php @@ -73,10 +73,10 @@ class AppCenterNav extends Common $ret = AppCenterNavService::AppCenterNavList($data_params); // 基础参数赋值 - $this->assign('params', $this->data_request); - $this->assign('page_html', $page->GetPageHtml()); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + MyViewAssign('page_html', $page->GetPageHtml()); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -103,9 +103,9 @@ class AppCenterNav extends Common ]; $ret = AppCenterNavService::AppCenterNavList($data_params); $data = (empty($ret['data']) || empty($ret['data'][0])) ? [] : $ret['data'][0]; - $this->assign('data', $data); + MyViewAssign('data', $data); } - return $this->fetch(); + return MyView(); } /** @@ -136,17 +136,17 @@ class AppCenterNav extends Common } // 静态数据 - $this->assign('common_platform_type', lang('common_platform_type')); - $this->assign('common_app_event_type', lang('common_app_event_type')); + MyViewAssign('common_platform_type', lang('common_platform_type')); + MyViewAssign('common_app_event_type', lang('common_app_event_type')); // 编辑器文件存放地址 - $this->assign('editor_path_type', ResourcesService::EditorPathTypeValue('app_center_nav')); + MyViewAssign('editor_path_type', ResourcesService::EditorPathTypeValue('app_center_nav')); // 数据 unset($params['id']); - $this->assign('params', $params); - $this->assign('data', $data); - return $this->fetch(); + MyViewAssign('params', $params); + MyViewAssign('data', $data); + return MyView(); } /** diff --git a/application/admin/controller/Appconfig.php b/app/admin/controller/Appconfig.php similarity index 88% rename from application/admin/controller/Appconfig.php rename to app/admin/controller/Appconfig.php index 2a4b6f1d5..ee15ff935 100755 --- a/application/admin/controller/Appconfig.php +++ b/app/admin/controller/Appconfig.php @@ -50,15 +50,15 @@ class AppConfig extends Common public function Index() { // 配置信息 - $this->assign('data', ConfigService::ConfigList()); + MyViewAssign('data', ConfigService::ConfigList()); // 是否 - $this->assign('common_is_text_list', lang('common_is_text_list')); + MyViewAssign('common_is_text_list', lang('common_is_text_list')); // 导航/视图 $nav_type = input('nav_type', 'base'); - $this->assign('nav_type', $nav_type); - return $this->fetch($nav_type); + MyViewAssign('nav_type', $nav_type); + return MyView($nav_type); } /** diff --git a/application/admin/controller/Apphomenav.php b/app/admin/controller/Apphomenav.php similarity index 89% rename from application/admin/controller/Apphomenav.php rename to app/admin/controller/Apphomenav.php index d95c5afd5..f4cbc7e89 100755 --- a/application/admin/controller/Apphomenav.php +++ b/app/admin/controller/Apphomenav.php @@ -73,10 +73,10 @@ class AppHomeNav extends Common $ret = AppHomeNavService::AppHomeNavList($data_params); // 基础参数赋值 - $this->assign('params', $this->data_request); - $this->assign('page_html', $page->GetPageHtml()); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + MyViewAssign('page_html', $page->GetPageHtml()); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -103,9 +103,9 @@ class AppHomeNav extends Common ]; $ret = AppHomeNavService::AppHomeNavList($data_params); $data = (empty($ret['data']) || empty($ret['data'][0])) ? [] : $ret['data'][0]; - $this->assign('data', $data); + MyViewAssign('data', $data); } - return $this->fetch(); + return MyView(); } /** @@ -136,17 +136,17 @@ class AppHomeNav extends Common } // 静态数据 - $this->assign('common_platform_type', lang('common_platform_type')); - $this->assign('common_app_event_type', lang('common_app_event_type')); + MyViewAssign('common_platform_type', lang('common_platform_type')); + MyViewAssign('common_app_event_type', lang('common_app_event_type')); // 编辑器文件存放地址 - $this->assign('editor_path_type', ResourcesService::EditorPathTypeValue('app_nav')); + MyViewAssign('editor_path_type', ResourcesService::EditorPathTypeValue('app_nav')); // 数据 unset($params['id']); - $this->assign('params', $params); - $this->assign('data', $data); - return $this->fetch(); + MyViewAssign('params', $params); + MyViewAssign('data', $data); + return MyView(); } /** diff --git a/application/admin/controller/Appmini.php b/app/admin/controller/Appmini.php similarity index 85% rename from application/admin/controller/Appmini.php rename to app/admin/controller/Appmini.php index ecab5bf7e..1e2c00153 100755 --- a/application/admin/controller/Appmini.php +++ b/app/admin/controller/Appmini.php @@ -75,15 +75,15 @@ class Appmini extends Common // 首页 case 'index' : // 默认主题 - $this->assign('theme', AppMiniService::DefaultTheme()); + MyViewAssign('theme', AppMiniService::DefaultTheme()); // 获取主题列表 $data = AppMiniService::ThemeList($this->params); - $this->assign('data_list', $data); + MyViewAssign('data_list', $data); // 插件更新信息 $upgrade = AppMiniService::AppMiniUpgradeInfo(['terminal'=>$this->params['application_name'], 'data'=>$data]); - $this->assign('upgrade_info', $upgrade['data']); + MyViewAssign('upgrade_info', $upgrade['data']); break; // 源码包列表 @@ -91,7 +91,7 @@ class Appmini extends Common $this->Package(); break; } - return $this->fetch($this->view_type); + return MyView($this->view_type); } /** @@ -104,7 +104,7 @@ class Appmini extends Common */ public function Package() { - $host = config('shopxo.website_url'); + $host = MyConfig('shopxo.website_url'); $nav_dev_tips = [ // 微信 'weixin' => [ @@ -132,11 +132,11 @@ class Appmini extends Common 'url' => $host.'qq.html', ], ]; - $this->assign('nav_dev_tips', $nav_dev_tips); + MyViewAssign('nav_dev_tips', $nav_dev_tips); // 源码包列表 $ret = AppMiniService::DownloadDataList($this->params); - $this->assign('data_list', $ret['data']); + MyViewAssign('data_list', $ret['data']); } /** @@ -150,19 +150,19 @@ class Appmini extends Common public function CurrentViewInit() { // 操作导航类型 - $this->assign('nav_type', $this->params['application_name']); + MyViewAssign('nav_type', $this->params['application_name']); // 操作页面类型 - $this->assign('view_type', $this->view_type); + MyViewAssign('view_type', $this->view_type); // 应用商店 - $this->assign('store_theme_url', StoreService::StoreThemeUrl()); + MyViewAssign('store_theme_url', StoreService::StoreThemeUrl()); // 小程序平台 - $this->assign('common_appmini_type', lang('common_appmini_type')); + MyViewAssign('common_appmini_type', lang('common_appmini_type')); // 是否 - $this->assign('common_is_text_list', lang('common_is_text_list')); + MyViewAssign('common_is_text_list', lang('common_is_text_list')); // 基础导航 $base_nav = [ @@ -179,7 +179,7 @@ class Appmini extends Common 'name' => '源码包下载', ], ]; - $this->assign('base_nav', $base_nav); + MyViewAssign('base_nav', $base_nav); } /** @@ -234,8 +234,8 @@ class Appmini extends Common $ret = AppMiniService::ThemeDownload($params); if(isset($ret['code']) && $ret['code'] != 0) { - $this->assign('msg', $ret['msg']); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', $ret['msg']); + return MyView('public/tips_error'); } else { return $ret; } @@ -276,8 +276,8 @@ class Appmini extends Common $this->CurrentViewInit(); // 配置信息 - $this->assign('data', ConfigService::ConfigList()); - return $this->fetch(); + MyViewAssign('data', ConfigService::ConfigList()); + return MyView(); } /** diff --git a/application/admin/controller/Article.php b/app/admin/controller/Article.php similarity index 86% rename from application/admin/controller/Article.php rename to app/admin/controller/Article.php index dbe9abab8..c07c92568 100755 --- a/application/admin/controller/Article.php +++ b/app/admin/controller/Article.php @@ -10,7 +10,6 @@ // +---------------------------------------------------------------------- namespace app\admin\controller; -use think\facade\Hook; use app\service\ArticleService; use app\service\ResourcesService; @@ -74,10 +73,10 @@ class Article extends Common $ret = ArticleService::ArticleList($data_params); // 基础参数赋值 - $this->assign('params', $this->data_request); - $this->assign('page_html', $page->GetPageHtml()); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + MyViewAssign('page_html', $page->GetPageHtml()); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -104,9 +103,9 @@ class Article extends Common ]; $ret = ArticleService::ArticleList($data_params); $data = (empty($ret['data']) || empty($ret['data'][0])) ? [] : $ret['data'][0]; - $this->assign('data', $data); + MyViewAssign('data', $data); } - return $this->fetch(); + return MyView(); } /** @@ -137,11 +136,11 @@ class Article extends Common // 文章分类 $article_category = ArticleService::ArticleCategoryList(['field'=>'id,name']); - $this->assign('article_category_list', $article_category['data']); + MyViewAssign('article_category_list', $article_category['data']); // 文章编辑页面钩子 $hook_name = 'plugins_view_admin_article_save'; - $this->assign($hook_name.'_data', Hook::listen($hook_name, + MyViewAssign($hook_name.'_data', MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, @@ -151,13 +150,13 @@ class Article extends Common ])); // 编辑器文件存放地址 - $this->assign('editor_path_type', ResourcesService::EditorPathTypeValue('article')); + MyViewAssign('editor_path_type', ResourcesService::EditorPathTypeValue('article')); // 数据 unset($params['id']); - $this->assign('data', $data); - $this->assign('params', $params); - return $this->fetch(); + MyViewAssign('data', $data); + MyViewAssign('params', $params); + return MyView(); } /** diff --git a/application/admin/controller/Articlecategory.php b/app/admin/controller/Articlecategory.php similarity index 91% rename from application/admin/controller/Articlecategory.php rename to app/admin/controller/Articlecategory.php index 10ae27326..27f39b9d9 100755 --- a/application/admin/controller/Articlecategory.php +++ b/app/admin/controller/Articlecategory.php @@ -50,9 +50,9 @@ class ArticleCategory extends Common public function Index() { // 是否启用 - $this->assign('common_is_enable_list', lang('common_is_enable_list')); + MyViewAssign('common_is_enable_list', lang('common_is_enable_list')); - return $this->fetch(); + return MyView(); } /** diff --git a/application/admin/controller/Brand.php b/app/admin/controller/Brand.php similarity index 88% rename from application/admin/controller/Brand.php rename to app/admin/controller/Brand.php index 4bf182e9e..2a91b4a1d 100755 --- a/application/admin/controller/Brand.php +++ b/app/admin/controller/Brand.php @@ -10,7 +10,6 @@ // +---------------------------------------------------------------------- namespace app\admin\controller; -use think\facade\Hook; use app\service\BrandService; use app\service\BrandCategoryService; use app\service\ResourcesService; @@ -75,10 +74,10 @@ class Brand extends Common $ret = BrandService::BrandList($data_params); // 基础参数赋值 - $this->assign('params', $this->data_request); - $this->assign('page_html', $page->GetPageHtml()); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + MyViewAssign('page_html', $page->GetPageHtml()); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -105,9 +104,9 @@ class Brand extends Common ]; $ret = BrandService::BrandList($data_params); $data = (empty($ret['data']) || empty($ret['data'][0])) ? [] : $ret['data'][0]; - $this->assign('data', $data); + MyViewAssign('data', $data); } - return $this->fetch(); + return MyView(); } /** @@ -138,15 +137,15 @@ class Brand extends Common } // 是否启用 - $this->assign('common_is_enable_list', lang('common_is_enable_list')); + MyViewAssign('common_is_enable_list', lang('common_is_enable_list')); // 品牌分类 $brand_category = BrandCategoryService::BrandCategoryList(['field'=>'id,name']); - $this->assign('brand_category', $brand_category['data']); + MyViewAssign('brand_category', $brand_category['data']); // 编辑页面钩子 $hook_name = 'plugins_view_admin_brand_save'; - $this->assign($hook_name.'_data', Hook::listen($hook_name, + MyViewAssign($hook_name.'_data', MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, @@ -156,13 +155,13 @@ class Brand extends Common ])); // 编辑器文件存放地址 - $this->assign('editor_path_type', ResourcesService::EditorPathTypeValue('brand')); + MyViewAssign('editor_path_type', ResourcesService::EditorPathTypeValue('brand')); // 数据 unset($params['id']); - $this->assign('data', $data); - $this->assign('params', $params); - return $this->fetch(); + MyViewAssign('data', $data); + MyViewAssign('params', $params); + return MyView(); } /** diff --git a/application/admin/controller/Brandcategory.php b/app/admin/controller/Brandcategory.php similarity index 92% rename from application/admin/controller/Brandcategory.php rename to app/admin/controller/Brandcategory.php index e83b985b6..854ac28a3 100755 --- a/application/admin/controller/Brandcategory.php +++ b/app/admin/controller/Brandcategory.php @@ -50,9 +50,9 @@ class BrandCategory extends Common public function Index() { // 是否启用 - $this->assign('common_is_enable_list', lang('common_is_enable_list')); + MyViewAssign('common_is_enable_list', lang('common_is_enable_list')); - return $this->fetch(); + return MyView(); } /** diff --git a/application/admin/controller/Cache.php b/app/admin/controller/Cache.php similarity index 77% rename from application/admin/controller/Cache.php rename to app/admin/controller/Cache.php index 6f4d1b603..73b72d3d6 100755 --- a/application/admin/controller/Cache.php +++ b/app/admin/controller/Cache.php @@ -50,9 +50,9 @@ class Cache extends Common public function Index() { // 缓存类型 - $this->assign('cache_type_list', CacheService::AdminCacheTypeList()); + MyViewAssign('cache_type_list', CacheService::AdminCacheTypeList()); - return $this->fetch(); + return MyView(); } /** @@ -65,10 +65,13 @@ class Cache extends Common public function StatusUpdate() { // 模板 cache - // 数据 temp + // 系统配置缓存 data + // 模板数据 temp \base\FileUtil::UnlinkDir(ROOT.'runtime'.DS.'cache'); - \base\FileUtil::UnlinkDir(ROOT.'runtime'.DS.'temp'); \base\FileUtil::UnlinkDir(ROOT.'runtime'.DS.'data'); + \base\FileUtil::UnlinkDir(ROOT.'runtime'.DS.'admin'.DS.'temp'); + \base\FileUtil::UnlinkDir(ROOT.'runtime'.DS.'index'.DS.'temp'); + \base\FileUtil::UnlinkDir(ROOT.'runtime'.DS.'api'.DS.'temp'); // 缓存操作清除 \think\facade\Cache::clear(); @@ -86,7 +89,9 @@ class Cache extends Common public function TemplateUpdate() { // 模板 cache - \base\FileUtil::UnlinkDir(ROOT.'runtime'.DS.'cache'); + \base\FileUtil::UnlinkDir(ROOT.'runtime'.DS.'admin'.DS.'temp'); + \base\FileUtil::UnlinkDir(ROOT.'runtime'.DS.'index'.DS.'temp'); + \base\FileUtil::UnlinkDir(ROOT.'runtime'.DS.'api'.DS.'temp'); return $this->success('更新成功'); } @@ -112,7 +117,9 @@ class Cache extends Common */ public function LogDelete() { - \base\FileUtil::UnlinkDir(ROOT.'runtime'.DS.'log'); + \base\FileUtil::UnlinkDir(ROOT.'runtime'.DS.'admin'.DS.'log'); + \base\FileUtil::UnlinkDir(ROOT.'runtime'.DS.'index'.DS.'log'); + \base\FileUtil::UnlinkDir(ROOT.'runtime'.DS.'api'.DS.'log'); return $this->success('更新成功'); } diff --git a/application/admin/controller/Common.php b/app/admin/controller/Common.php similarity index 59% rename from application/admin/controller/Common.php rename to app/admin/controller/Common.php index 3b8ca67b5..067d05b91 100755 --- a/application/admin/controller/Common.php +++ b/app/admin/controller/Common.php @@ -10,15 +10,15 @@ // +---------------------------------------------------------------------- namespace app\admin\controller; -use think\facade\Hook; -use think\Controller; +use app\BaseController; use app\module\FormHandleModule; +use app\service\SystemService; +use app\service\SystemBaseService; use app\service\AdminService; use app\service\AdminPowerService; use app\service\ConfigService; use app\service\ResourcesService; use app\service\StoreService; -use app\service\SystemBaseService; /** * 管理员公共控制器 @@ -27,7 +27,7 @@ use app\service\SystemBaseService; * @version 0.0.1 * @datetime 2016-12-01T21:51:08+0800 */ -class Common extends Controller +class Common extends BaseController { // 管理员 protected $admin; @@ -68,7 +68,8 @@ class Common extends Controller */ public function __construct() { - parent::__construct(); + // 检测是否是新安装 + SystemService::SystemInstallCheck(); // 输入参数 $this->data_post = input('post.'); @@ -95,72 +96,6 @@ class Common extends Controller $this->CommonPluginsInit(); } - /** - * 公共钩子初始化 - * @author Devil - * @blog http://gong.gg/ - * @version 1.0.0 - * @date 2018-12-07 - * @desc description - */ - private function CommonPluginsInit() - { - // css钩子 - $this->assign('plugins_admin_css_data', Hook::listen('plugins_admin_css', ['hook_name'=>'plugins_admin_css', 'is_backend'=>true])); - - // js钩子 - $this->assign('plugins_admin_js_data', Hook::listen('plugins_admin_js', ['hook_name'=>'plugins_admin_js', 'is_backend'=>true])); - - // 公共header内钩子 - $this->assign('plugins_admin_common_header_data', Hook::listen('plugins_admin_common_header', ['hook_name'=>'plugins_admin_common_header', 'is_backend'=>true, 'admin'=>$this->admin])); - - // 公共页面底部钩子 - $this->assign('plugins_admin_common_page_bottom_data', Hook::listen('plugins_admin_common_page_bottom', ['hook_name'=>'plugins_admin_common_page_bottom', 'is_backend'=>true, 'admin'=>$this->admin])); - - // 公共顶部钩子 - $this->assign('plugins_admin_view_common_top_data', Hook::listen('plugins_admin_view_common_top', ['hook_name'=>'plugins_admin_view_common_top', 'is_backend'=>true, 'admin'=>$this->admin])); - - // 公共底部钩子 - $this->assign('plugins_admin_view_common_bottom_data', Hook::listen('plugins_admin_view_common_bottom', ['hook_name'=>'plugins_admin_view_common_bottom', 'is_backend'=>true, 'admin'=>$this->admin])); - - // 公共表格钩子名称动态处理 - $current = 'plugins_view_admin_'.$this->controller_name; - - // 是否插件默认下 - if($this->controller_name == 'plugins') - { - if(!empty($this->data_request['pluginsname'])) - { - $current .= '_'.trim($this->data_request['pluginsname']); - } - } - - // 内容外部顶部 - $this->assign('hook_name_content_top', $current.'_content_top'); - // 内容外部底部 - $this->assign('hook_name_content_bottom', $current.'_content_bottom'); - // 内容内部顶部 - $this->assign('hook_name_content_inside_top', $current.'_content_inside_top'); - // 内容内部底部 - $this->assign('hook_name_content_inside_bottom', $current.'_content_inside_bottom'); - // 表格列表顶部操作 - $this->assign('hook_name_form_top_operate', $current.'_top_operate'); - // 表格列表底部操作 - $this->assign('hook_name_form_bottom_operate', $current.'_bottom_operate'); - // 表格列表后面操作栏 - $this->assign('hook_name_form_list_operate', $current.'_list_operate'); - - // 公共详情页面钩子名称动态处理 - // 内容外部顶部 - $this->assign('hook_name_detail_top', $current.'_detail_top'); - // 内容外部底部 - $this->assign('hook_name_detail_bottom', $current.'_detail_bottom'); - // 内容内部顶部 - $this->assign('hook_name_detail_inside_top', $current.'_detail_inside_top'); - // 内容内部底部 - $this->assign('hook_name_detail_inside_bottom', $current.'_detail_inside_bottom'); - } - /** * 系统初始化 * @author Devil @@ -173,9 +108,6 @@ class Common extends Controller { // 配置信息初始化 ConfigService::ConfigInit(); - - // url模式,后端采用兼容模式 - \think\facade\Url::root(__MY_ROOT_PUBLIC__.CurrentScriptName().'?s='); } /** @@ -209,75 +141,75 @@ class Common extends Controller { // 主题 $default_theme = 'default'; - $this->assign('default_theme', $default_theme); + MyViewAssign('default_theme', $default_theme); // 当前操作名称 - $this->module_name = strtolower(request()->module()); - $this->controller_name = strtolower(request()->controller()); - $this->action_name = strtolower(request()->action()); + $this->module_name = RequestModule(); + $this->controller_name = RequestController(); + $this->action_name = RequestAction(); // 当前操作名称 - $this->assign('module_name', $this->module_name); - $this->assign('controller_name', $this->controller_name); - $this->assign('action_name', $this->action_name); + MyViewAssign('module_name', $this->module_name); + MyViewAssign('controller_name', $this->controller_name); + MyViewAssign('action_name', $this->action_name); // 管理员 - $this->assign('admin', $this->admin); + MyViewAssign('admin', $this->admin); // 权限菜单 - $this->assign('left_menu', $this->left_menu); + MyViewAssign('left_menu', $this->left_menu); // 分页信息 $this->page = max(1, isset($this->data_request['page']) ? intval($this->data_request['page']) : 1); $this->page_size = MyC('common_page_size', 10, true); - $this->assign('page', $this->page); - $this->assign('page_size', $this->page_size); + MyViewAssign('page', $this->page); + MyViewAssign('page_size', $this->page_size); // 货币符号 - $this->assign('currency_symbol', ResourcesService::CurrencyDataSymbol()); + MyViewAssign('currency_symbol', ResourcesService::CurrencyDataSymbol()); // 控制器静态文件状态css,js $module_css = $this->module_name.DS.$default_theme.DS.'css'.DS.$this->controller_name; $module_css .= file_exists(ROOT_PATH.'static'.DS.$module_css.'.'.$this->action_name.'.css') ? '.'.$this->action_name.'.css' : '.css'; - $this->assign('module_css', file_exists(ROOT_PATH.'static'.DS.$module_css) ? $module_css : ''); + MyViewAssign('module_css', file_exists(ROOT_PATH.'static'.DS.$module_css) ? $module_css : ''); $module_js = $this->module_name.DS.$default_theme.DS.'js'.DS.$this->controller_name; $module_js .= file_exists(ROOT_PATH.'static'.DS.$module_js.'.'.$this->action_name.'.js') ? '.'.$this->action_name.'.js' : '.js'; - $this->assign('module_js', file_exists(ROOT_PATH.'static'.DS.$module_js) ? $module_js : ''); + MyViewAssign('module_js', file_exists(ROOT_PATH.'static'.DS.$module_js) ? $module_js : ''); // 价格正则 - $this->assign('default_price_regex', lang('common_regex_price')); + MyViewAssign('default_price_regex', lang('common_regex_price')); // 附件host地址 - $this->assign('attachment_host', SystemBaseService::AttachmentHost()); + MyViewAssign('attachment_host', SystemBaseService::AttachmentHost()); // css/js引入host地址 - $this->assign('public_host', config('shopxo.public_host')); + MyViewAssign('public_host', MyConfig('shopxo.public_host')); // 当前url地址 - $this->assign('my_url', __MY_URL__); + MyViewAssign('my_url', __MY_URL__); // 项目public目录URL地址 - $this->assign('my_public_url', __MY_PUBLIC_URL__); + MyViewAssign('my_public_url', __MY_PUBLIC_URL__); // 当前http类型 - $this->assign('my_http', __MY_HTTP__); + MyViewAssign('my_http', __MY_HTTP__); // 开发模式 - $this->assign('shopxo_is_develop', config('shopxo.is_develop')); + MyViewAssign('shopxo_is_develop', MyConfig('shopxo.is_develop')); // 默认不加载百度地图api - $this->assign('is_load_baidu_map_api', 0); + MyViewAssign('is_load_baidu_map_api', 0); // 布局样式+管理 - $this->assign('is_load_layout', 0); - $this->assign('is_load_layout_admin', 0); + MyViewAssign('is_load_layout', 0); + MyViewAssign('is_load_layout_admin', 0); // 是否加载附件组件 - $this->assign('is_load_upload_editor', !empty($this->admin) ? 1 : 0); + MyViewAssign('is_load_upload_editor', !empty($this->admin) ? 1 : 0); // 站点名称 - $this->assign('admin_theme_site_name', MyC('admin_theme_site_name', 'ShopXO', true)); + MyViewAssign('admin_theme_site_name', MyC('admin_theme_site_name', 'ShopXO', true)); // 站点商店信息 $site_store_info = StoreService::SiteStoreInfo(); @@ -289,11 +221,11 @@ class Common extends Controller $site_store_info = StoreService::SiteStoreInfo(); } } - $this->assign('site_store_info', $site_store_info); + MyViewAssign('site_store_info', $site_store_info); // 系统基础信息 $is_system_show_base = (empty($site_store_info) || empty($site_store_info['vip']) || !isset($site_store_info['vip']['status']) || $site_store_info['vip']['status'] == 0 || ($site_store_info['vip']['status'] == 1 && (AdminIsPower('index', 'storeaccountsbind') || AdminIsPower('index', 'inspectupgrade')))) ? 1 : 0; - $this->assign('is_system_show_base', $is_system_show_base); + MyViewAssign('is_system_show_base', $is_system_show_base); } /** @@ -323,14 +255,14 @@ class Common extends Controller $this->form_user_fields = $ret['data']['user_fields']; $this->form_order_by = $ret['data']['order_by']; - $this->assign('form_table', $this->form_table); - $this->assign('form_params', $this->form_params); - $this->assign('form_md5_key', $this->form_md5_key); - $this->assign('form_user_fields', $this->form_user_fields); - $this->assign('form_order_by', $this->form_order_by); + MyViewAssign('form_table', $this->form_table); + MyViewAssign('form_params', $this->form_params); + MyViewAssign('form_md5_key', $this->form_md5_key); + MyViewAssign('form_user_fields', $this->form_user_fields); + MyViewAssign('form_order_by', $this->form_order_by); } else { $this->form_error = $ret['msg']; - $this->assign('form_error', $this->form_error); + MyViewAssign('form_error', $this->form_error); } } } @@ -358,22 +290,130 @@ class Common extends Controller } /** - * [_empty 空方法操作] - * @author Devil - * @blog http://gong.gg/ - * @version 0.0.1 - * @datetime 2017-02-25T15:47:50+0800 - * @param [string] $name [方法名称] + * 成功提示 + * @author Devil + * @blog http://gong.gg/ + * @version 1.0.0 + * @date 2021-07-15 + * @desc description + * @param [string] $msg [提示信息、默认(操作成功)] */ - public function _empty($name) + public function success($msg) { if(IS_AJAX) { - exit(json_encode(DataReturn($name.' 非法访问', -1000))); + return DataReturn($msg, 0); } else { - $this->assign('msg', $name.' 非法访问'); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', $msg); + return MyView('public/jump_success'); } } + + /** + * 错误提示 + * @author Devil + * @blog http://gong.gg/ + * @version 1.0.0 + * @date 2021-07-15 + * @desc description + * @param [string] $msg [提示信息、默认(操作失败)] + */ + public function error($msg) + { + if(IS_AJAX) + { + return DataReturn($msg, -1); + } else { + MyViewAssign('msg', $msg); + return MyView('public/jump_error'); + } + } + + /** + * 空方法响应 + * @author Devil + * @blog http://gong.gg/ + * @version 1.0.0 + * @date 2018-11-30 + * @desc description + * @param [string] $method [方法名称] + * @param [array] $args [参数] + */ + public function __call($method, $args) + { + if(IS_AJAX) + { + return DataReturn($method.' 非法访问', -1000); + } else { + MyViewAssign('msg', $method.' 非法访问'); + return MyView('public/tips_error'); + } + } + + /** + * 公共钩子初始化 + * @author Devil + * @blog http://gong.gg/ + * @version 1.0.0 + * @date 2018-12-07 + * @desc description + */ + private function CommonPluginsInit() + { + // css钩子 + MyViewAssign('plugins_admin_css_data', MyEventTrigger('plugins_admin_css', ['hook_name'=>'plugins_admin_css', 'is_backend'=>true])); + + // js钩子 + MyViewAssign('plugins_admin_js_data', MyEventTrigger('plugins_admin_js', ['hook_name'=>'plugins_admin_js', 'is_backend'=>true])); + + // 公共header内钩子 + MyViewAssign('plugins_admin_common_header_data', MyEventTrigger('plugins_admin_common_header', ['hook_name'=>'plugins_admin_common_header', 'is_backend'=>true, 'admin'=>$this->admin])); + + // 公共页面底部钩子 + MyViewAssign('plugins_admin_common_page_bottom_data', MyEventTrigger('plugins_admin_common_page_bottom', ['hook_name'=>'plugins_admin_common_page_bottom', 'is_backend'=>true, 'admin'=>$this->admin])); + + // 公共顶部钩子 + MyViewAssign('plugins_admin_view_common_top_data', MyEventTrigger('plugins_admin_view_common_top', ['hook_name'=>'plugins_admin_view_common_top', 'is_backend'=>true, 'admin'=>$this->admin])); + + // 公共底部钩子 + MyViewAssign('plugins_admin_view_common_bottom_data', MyEventTrigger('plugins_admin_view_common_bottom', ['hook_name'=>'plugins_admin_view_common_bottom', 'is_backend'=>true, 'admin'=>$this->admin])); + + // 公共表格钩子名称动态处理 + $current = 'plugins_view_admin_'.$this->controller_name; + + // 是否插件默认下 + if($this->controller_name == 'plugins') + { + if(!empty($this->data_request['pluginsname'])) + { + $current .= '_'.trim($this->data_request['pluginsname']); + } + } + + // 内容外部顶部 + MyViewAssign('hook_name_content_top', $current.'_content_top'); + // 内容外部底部 + MyViewAssign('hook_name_content_bottom', $current.'_content_bottom'); + // 内容内部顶部 + MyViewAssign('hook_name_content_inside_top', $current.'_content_inside_top'); + // 内容内部底部 + MyViewAssign('hook_name_content_inside_bottom', $current.'_content_inside_bottom'); + // 表格列表顶部操作 + MyViewAssign('hook_name_form_top_operate', $current.'_top_operate'); + // 表格列表底部操作 + MyViewAssign('hook_name_form_bottom_operate', $current.'_bottom_operate'); + // 表格列表后面操作栏 + MyViewAssign('hook_name_form_list_operate', $current.'_list_operate'); + + // 公共详情页面钩子名称动态处理 + // 内容外部顶部 + MyViewAssign('hook_name_detail_top', $current.'_detail_top'); + // 内容外部底部 + MyViewAssign('hook_name_detail_bottom', $current.'_detail_bottom'); + // 内容内部顶部 + MyViewAssign('hook_name_detail_inside_top', $current.'_detail_inside_top'); + // 内容内部底部 + MyViewAssign('hook_name_detail_inside_bottom', $current.'_detail_inside_bottom'); + } } ?> \ No newline at end of file diff --git a/application/admin/controller/Config.php b/app/admin/controller/Config.php similarity index 82% rename from application/admin/controller/Config.php rename to app/admin/controller/Config.php index 2ccbc5650..9260e4d52 100755 --- a/application/admin/controller/Config.php +++ b/app/admin/controller/Config.php @@ -50,16 +50,16 @@ class Config extends Common public function Index() { // 静态数据 - $this->assign('common_excel_charset_list', lang('common_excel_charset_list')); - $this->assign('common_is_enable_list', lang('common_is_enable_list')); - $this->assign('common_login_type_list', lang('common_login_type_list')); - $this->assign('common_close_open_list', lang('common_close_open_list')); + MyViewAssign('common_excel_charset_list', lang('common_excel_charset_list')); + MyViewAssign('common_is_enable_list', lang('common_is_enable_list')); + MyViewAssign('common_login_type_list', lang('common_login_type_list')); + MyViewAssign('common_close_open_list', lang('common_close_open_list')); // 配置信息 - $this->assign('data', ConfigService::ConfigList()); + MyViewAssign('data', ConfigService::ConfigList()); - $this->assign('view_type', 'index'); - return $this->fetch(); + MyViewAssign('view_type', 'index'); + return MyView(); } /** @@ -72,10 +72,10 @@ class Config extends Common public function Store() { // 配置信息 - $this->assign('data', ConfigService::ConfigList()); + MyViewAssign('data', ConfigService::ConfigList()); - $this->assign('view_type', 'store'); - return $this->fetch(); + MyViewAssign('view_type', 'store'); + return MyView(); } /** diff --git a/application/admin/controller/Customview.php b/app/admin/controller/Customview.php similarity index 89% rename from application/admin/controller/Customview.php rename to app/admin/controller/Customview.php index d74d40bd9..e3606c90b 100755 --- a/application/admin/controller/Customview.php +++ b/app/admin/controller/Customview.php @@ -72,10 +72,10 @@ class CustomView extends Common $ret = CustomViewService::CustomViewList($data_params); // 基础参数赋值 - $this->assign('params', $this->data_request); - $this->assign('page_html', $page->GetPageHtml()); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + MyViewAssign('page_html', $page->GetPageHtml()); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -102,9 +102,9 @@ class CustomView extends Common ]; $ret = CustomViewService::CustomViewList($data_params); $data = (empty($ret['data']) || empty($ret['data'][0])) ? [] : $ret['data'][0]; - $this->assign('data', $data); + MyViewAssign('data', $data); } - return $this->fetch(); + return MyView(); } /** @@ -134,9 +134,9 @@ class CustomView extends Common $data = empty($ret['data'][0]) ? [] : $ret['data'][0]; } unset($params['id']); - $this->assign('data', $data); - $this->assign('params', $params); - return $this->fetch(); + MyViewAssign('data', $data); + MyViewAssign('params', $params); + return MyView(); } /** diff --git a/application/admin/controller/Design.php b/app/admin/controller/Design.php similarity index 73% rename from application/admin/controller/Design.php rename to app/admin/controller/Design.php index 2ff0f1d40..f46bc1127 100644 --- a/application/admin/controller/Design.php +++ b/app/admin/controller/Design.php @@ -77,10 +77,10 @@ class Design extends Common $ret = DesignService::DesignList($data_params); // 基础参数赋值 - $this->assign('params', $this->data_request); - $this->assign('page_html', $page->GetPageHtml()); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + MyViewAssign('page_html', $page->GetPageHtml()); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -99,10 +99,10 @@ class Design extends Common $ret = DesignService::DesignSave(); if($ret['code'] == 0) { - return redirect(MyUrl('admin/design/saveinfo', ['id'=>$ret['data']])); + return MyRedirect(MyUrl('admin/design/saveinfo', ['id'=>$ret['data']])); } else { - $this->assign('msg', $ret['msg']); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', $ret['msg']); + return MyView('public/tips_error'); } } @@ -117,50 +117,50 @@ class Design extends Common $ret = DesignService::DesignList($data_params); if(empty($ret['data']) || empty($ret['data'][0])) { - $this->assign('to_title', '去添加 >>'); - $this->assign('to_url', MyUrl('admin/design/saveinfo')); - $this->assign('msg', '编辑数据为空、请重新添加'); - return $this->fetch('public/tips_error'); + MyViewAssign('to_title', '去添加 >>'); + MyViewAssign('to_url', MyUrl('admin/design/saveinfo')); + MyViewAssign('msg', '编辑数据为空、请重新添加'); + return MyView('public/tips_error'); } $data = $ret['data'][0]; // 配置处理 $layout_data = BaseLayout::ConfigAdminHandle($data['config']); - $this->assign('layout_data', $layout_data); - $this->assign('data', $data); + MyViewAssign('layout_data', $layout_data); + MyViewAssign('data', $data); unset($data['config']); // 页面列表 $pages_list = BaseLayout::PagesList(); - $this->assign('pages_list', $pages_list); + MyViewAssign('pages_list', $pages_list); // 商品分类 $goods_category = GoodsService::GoodsCategoryAll(); - $this->assign('goods_category_list', $goods_category); + MyViewAssign('goods_category_list', $goods_category); // 商品搜索分类(分类) - $this->assign('layout_goods_category', $goods_category); - $this->assign('layout_goods_category_field', 'gci.category_id'); + MyViewAssign('layout_goods_category', $goods_category); + MyViewAssign('layout_goods_category_field', 'gci.category_id'); // 品牌 - $this->assign('brand_list', BrandService::CategoryBrand()); + MyViewAssign('brand_list', BrandService::CategoryBrand()); // 静态数据 - $this->assign('border_style_type_list', BaseLayout::$border_style_type_list); - $this->assign('goods_view_list_show_style', BaseLayout::$goods_view_list_show_style); - $this->assign('many_images_view_list_show_style', BaseLayout::$many_images_view_list_show_style); + MyViewAssign('border_style_type_list', BaseLayout::$border_style_type_list); + MyViewAssign('goods_view_list_show_style', BaseLayout::$goods_view_list_show_style); + MyViewAssign('many_images_view_list_show_style', BaseLayout::$many_images_view_list_show_style); // 首页商品排序规则 - $this->assign('goods_order_by_type_list', lang('goods_order_by_type_list')); - $this->assign('goods_order_by_rule_list', lang('goods_order_by_rule_list')); + MyViewAssign('goods_order_by_type_list', lang('goods_order_by_type_list')); + MyViewAssign('goods_order_by_rule_list', lang('goods_order_by_rule_list')); // 加载布局样式+管理 - $this->assign('is_load_layout', 1); - $this->assign('is_load_layout_admin', 1); + MyViewAssign('is_load_layout', 1); + MyViewAssign('is_load_layout_admin', 1); // 编辑器文件存放地址定义 - $this->assign('editor_path_type', DesignService::AttachmentPathTypeValue($data['id'])); - return $this->fetch(); + MyViewAssign('editor_path_type', DesignService::AttachmentPathTypeValue($data['id'])); + return MyView(); } /** diff --git a/application/admin/controller/Email.php b/app/admin/controller/Email.php similarity index 87% rename from application/admin/controller/Email.php rename to app/admin/controller/Email.php index c764b9b03..bdf950ce5 100755 --- a/application/admin/controller/Email.php +++ b/app/admin/controller/Email.php @@ -50,19 +50,19 @@ class Email extends Common public function Index() { // 配置信息 - $this->assign('data', ConfigService::ConfigList()); + MyViewAssign('data', ConfigService::ConfigList()); $type = input('type', 'email'); // 静态数据 - $this->assign('common_is_text_list', lang('common_is_text_list')); + MyViewAssign('common_is_text_list', lang('common_is_text_list')); // 导航 - $this->assign('nav_type', $type); + MyViewAssign('nav_type', $type); if($type == 'email') { - return $this->fetch('index'); + return MyView('index'); } else { - return $this->fetch('message'); + return MyView('message'); } } diff --git a/application/admin/controller/Error.php b/app/admin/controller/Error.php similarity index 74% rename from application/admin/controller/Error.php rename to app/admin/controller/Error.php index 06fee7dd7..c1bedd3d3 100755 --- a/application/admin/controller/Error.php +++ b/app/admin/controller/Error.php @@ -10,8 +10,6 @@ // +---------------------------------------------------------------------- namespace app\admin\controller; -use think\Request; - /** * 空控制器响应 * @author Devil @@ -29,16 +27,17 @@ class Error extends Common * @version 1.0.0 * @date 2018-11-30 * @desc description - * @param Request $request [参数] + * @param [string] $method [方法名称] + * @param [array] $args [参数] */ - public function Index(Request $request) + public function __call($method, $args) { if(IS_AJAX) { - exit(json_encode(DataReturn($request->controller().' 控制器不存在', -1000))); + return DataReturn(RequestController().' 控制器不存在', -1000); } else { - $this->assign('msg', $request->controller().' 控制器不存在'); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', RequestController().' 控制器不存在'); + return MyView('public/tips_error'); } } } diff --git a/application/admin/controller/Express.php b/app/admin/controller/Express.php similarity index 93% rename from application/admin/controller/Express.php rename to app/admin/controller/Express.php index 48fcffac4..197ba20ac 100755 --- a/application/admin/controller/Express.php +++ b/app/admin/controller/Express.php @@ -51,12 +51,12 @@ class Express extends Common public function Index() { // 是否启用 - $this->assign('common_is_enable_list', lang('common_is_enable_list')); + MyViewAssign('common_is_enable_list', lang('common_is_enable_list')); // 编辑器文件存放地址 - $this->assign('editor_path_type', ResourcesService::EditorPathTypeValue('express')); + MyViewAssign('editor_path_type', ResourcesService::EditorPathTypeValue('express')); - return $this->fetch(); + return MyView(); } /** diff --git a/application/admin/controller/Formtable.php b/app/admin/controller/Formtable.php similarity index 100% rename from application/admin/controller/Formtable.php rename to app/admin/controller/Formtable.php diff --git a/application/admin/controller/Goods.php b/app/admin/controller/Goods.php similarity index 80% rename from application/admin/controller/Goods.php rename to app/admin/controller/Goods.php index 797318607..561e404cf 100755 --- a/application/admin/controller/Goods.php +++ b/app/admin/controller/Goods.php @@ -10,7 +10,6 @@ // +---------------------------------------------------------------------- namespace app\admin\controller; -use think\facade\Hook; use app\service\SystemBaseService; use app\service\GoodsService; use app\service\RegionService; @@ -79,10 +78,10 @@ class Goods extends Common $ret = GoodsService::GoodsList($data_params); // 基础参数赋值 - $this->assign('params', $this->data_request); - $this->assign('page_html', $page->GetPageHtml()); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + MyViewAssign('page_html', $page->GetPageHtml()); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -119,20 +118,20 @@ class Goods extends Common // 获取商品编辑规格 $specifications = GoodsService::GoodsEditSpecifications($data['id']); - $this->assign('specifications', $specifications); + MyViewAssign('specifications', $specifications); // 获取商品编辑参数 $parameters = GoodsService::GoodsEditParameters($data['id']); // 商品参数类型 - $this->assign('common_goods_parameters_type_list', lang('common_goods_parameters_type_list')); + MyViewAssign('common_goods_parameters_type_list', lang('common_goods_parameters_type_list')); - $this->assign('parameters', $parameters); + MyViewAssign('parameters', $parameters); } - $this->assign('data', $data); + MyViewAssign('data', $data); } - return $this->fetch(); + return MyView(); } /** @@ -175,33 +174,33 @@ class Goods extends Common // 获取商品编辑规格 $specifications = GoodsService::GoodsEditSpecifications($data['id']); - $this->assign('specifications', $specifications); + MyViewAssign('specifications', $specifications); // 获取商品编辑参数 $parameters = GoodsService::GoodsEditParameters($data['id']); - $this->assign('parameters', $parameters); + MyViewAssign('parameters', $parameters); } // 地区信息 - $this->assign('region_province_list', RegionService::RegionItems(['pid'=>0])); + MyViewAssign('region_province_list', RegionService::RegionItems(['pid'=>0])); // 商品分类 - $this->assign('goods_category_list', GoodsService::GoodsCategoryAll()); + MyViewAssign('goods_category_list', GoodsService::GoodsCategoryAll()); // 品牌 - $this->assign('brand_list', BrandService::CategoryBrand()); + MyViewAssign('brand_list', BrandService::CategoryBrand()); // 规格扩展数据 $goods_spec_extends = GoodsService::GoodsSpecificationsExtends($params); - $this->assign('goods_specifications_extends', $goods_spec_extends['data']); + MyViewAssign('goods_specifications_extends', $goods_spec_extends['data']); // 站点类型 - $this->assign('common_site_type_list', lang('common_site_type_list')); + MyViewAssign('common_site_type_list', lang('common_site_type_list')); // 当前系统设置的站点类型 - $this->assign('common_site_type', SystemBaseService::SiteTypeValue()); + MyViewAssign('common_site_type', SystemBaseService::SiteTypeValue()); // 商品参数类型 - $this->assign('common_goods_parameters_type_list', lang('common_goods_parameters_type_list')); + MyViewAssign('common_goods_parameters_type_list', lang('common_goods_parameters_type_list')); // 商品参数模板 $data_params = array( @@ -214,14 +213,14 @@ class Goods extends Common 'field' => 'id,name', ); $template = GoodsParamsService::GoodsParamsTemplateList($data_params); - $this->assign('goods_template_list', $template['data']); + MyViewAssign('goods_template_list', $template['data']); // 是否拷贝 - $this->assign('is_copy', (isset($params['is_copy']) && $params['is_copy'] == 1) ? 1 : 0); + MyViewAssign('is_copy', (isset($params['is_copy']) && $params['is_copy'] == 1) ? 1 : 0); // 商品编辑页面钩子 $hook_name = 'plugins_view_admin_goods_save'; - $this->assign($hook_name.'_data', Hook::listen($hook_name, + MyViewAssign($hook_name.'_data', MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, @@ -231,13 +230,13 @@ class Goods extends Common ])); // 编辑器文件存放地址 - $this->assign('editor_path_type', ResourcesService::EditorPathTypeValue('goods')); + MyViewAssign('editor_path_type', ResourcesService::EditorPathTypeValue('goods')); // 数据 unset($params['id'], $params['is_copy']); - $this->assign('data', $data); - $this->assign('params', $params); - return $this->fetch(); + MyViewAssign('data', $data); + MyViewAssign('params', $params); + return MyView(); } /** diff --git a/application/admin/controller/Goodsbrowse.php b/app/admin/controller/Goodsbrowse.php similarity index 93% rename from application/admin/controller/Goodsbrowse.php rename to app/admin/controller/Goodsbrowse.php index 3185f09ea..7b20f4df1 100644 --- a/application/admin/controller/Goodsbrowse.php +++ b/app/admin/controller/Goodsbrowse.php @@ -76,10 +76,10 @@ class GoodsBrowse extends Common $ret = GoodsBrowseService::GoodsBrowseList($data_params); // 基础参数赋值 - $this->assign('params', $this->data_request); - $this->assign('page_html', $page->GetPageHtml()); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + MyViewAssign('page_html', $page->GetPageHtml()); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -109,9 +109,9 @@ class GoodsBrowse extends Common ]; $ret = GoodsBrowseService::GoodsBrowseList($data_params); $data = (empty($ret['data']) || empty($ret['data'][0])) ? [] : $ret['data'][0]; - $this->assign('data', $data); + MyViewAssign('data', $data); } - return $this->fetch(); + return MyView(); } /** diff --git a/application/admin/controller/Goodscategory.php b/app/admin/controller/Goodscategory.php similarity index 90% rename from application/admin/controller/Goodscategory.php rename to app/admin/controller/Goodscategory.php index 2549c3cb7..2955bc340 100755 --- a/application/admin/controller/Goodscategory.php +++ b/app/admin/controller/Goodscategory.php @@ -51,15 +51,15 @@ class GoodsCategory extends Common public function Index() { // 静态数据 - $this->assign('common_is_text_list', lang('common_is_text_list')); + MyViewAssign('common_is_text_list', lang('common_is_text_list')); // 商品分类 - $this->assign('goods_category_list', GoodsService::GoodsCategoryAll()); + MyViewAssign('goods_category_list', GoodsService::GoodsCategoryAll()); // 编辑器文件存放地址 - $this->assign('editor_path_type', ResourcesService::EditorPathTypeValue('goods_category')); + MyViewAssign('editor_path_type', ResourcesService::EditorPathTypeValue('goods_category')); - return $this->fetch(); + return MyView(); } /** diff --git a/application/admin/controller/Goodscomments.php b/app/admin/controller/Goodscomments.php similarity index 86% rename from application/admin/controller/Goodscomments.php rename to app/admin/controller/Goodscomments.php index f13a3723f..2611c4dac 100644 --- a/application/admin/controller/Goodscomments.php +++ b/app/admin/controller/Goodscomments.php @@ -73,10 +73,10 @@ class Goodscomments extends Common $ret = GoodsCommentsService::GoodsCommentsList($data_params); // 基础参数赋值 - $this->assign('params', $this->data_request); - $this->assign('page_html', $page->GetPageHtml()); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + MyViewAssign('page_html', $page->GetPageHtml()); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -103,11 +103,11 @@ class Goodscomments extends Common ]; $ret = GoodsCommentsService::GoodsCommentsList($data_params); $data = (empty($ret['data']) || empty($ret['data'][0])) ? [] : $ret['data'][0]; - $this->assign('data', $data); + MyViewAssign('data', $data); - $this->assign('common_goods_comments_rating_list', lang('common_goods_comments_rating_list')); + MyViewAssign('common_goods_comments_rating_list', lang('common_goods_comments_rating_list')); } - return $this->fetch(); + return MyView(); } /** @@ -136,18 +136,18 @@ class Goodscomments extends Common $ret = GoodsCommentsService::GoodsCommentsList($data_params); $data = empty($ret['data'][0]) ? [] : $ret['data'][0]; } - $this->assign('data', $data); + MyViewAssign('data', $data); // 静态数据 - $this->assign('common_is_show_list', lang('common_is_show_list')); - $this->assign('common_is_text_list', lang('common_is_text_list')); - $this->assign('common_goods_comments_rating_list', lang('common_goods_comments_rating_list')); - $this->assign('common_goods_comments_business_type_list', lang('common_goods_comments_business_type_list')); + MyViewAssign('common_is_show_list', lang('common_is_show_list')); + MyViewAssign('common_is_text_list', lang('common_is_text_list')); + MyViewAssign('common_goods_comments_rating_list', lang('common_goods_comments_rating_list')); + MyViewAssign('common_goods_comments_business_type_list', lang('common_goods_comments_business_type_list')); // 参数 unset($params['id']); - $this->assign('params', $params); - return $this->fetch(); + MyViewAssign('params', $params); + return MyView(); } /** diff --git a/application/admin/controller/Goodsfavor.php b/app/admin/controller/Goodsfavor.php similarity index 93% rename from application/admin/controller/Goodsfavor.php rename to app/admin/controller/Goodsfavor.php index 36db350c0..575ae933d 100644 --- a/application/admin/controller/Goodsfavor.php +++ b/app/admin/controller/Goodsfavor.php @@ -76,10 +76,10 @@ class Goodsfavor extends Common $ret = GoodsFavorService::GoodsFavorList($data_params); // 基础参数赋值 - $this->assign('params', $this->data_request); - $this->assign('page_html', $page->GetPageHtml()); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + MyViewAssign('page_html', $page->GetPageHtml()); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -109,9 +109,9 @@ class Goodsfavor extends Common ]; $ret = GoodsFavorService::GoodsFavorList($data_params); $data = (empty($ret['data']) || empty($ret['data'][0])) ? [] : $ret['data'][0]; - $this->assign('data', $data); + MyViewAssign('data', $data); } - return $this->fetch(); + return MyView(); } /** diff --git a/application/admin/controller/Goodsparamstemplate.php b/app/admin/controller/Goodsparamstemplate.php similarity index 86% rename from application/admin/controller/Goodsparamstemplate.php rename to app/admin/controller/Goodsparamstemplate.php index a2170253e..cb31850f8 100755 --- a/application/admin/controller/Goodsparamstemplate.php +++ b/app/admin/controller/Goodsparamstemplate.php @@ -10,7 +10,6 @@ // +---------------------------------------------------------------------- namespace app\admin\controller; -use think\facade\Hook; use app\service\GoodsParamsService; /** @@ -76,10 +75,10 @@ class GoodsParamsTemplate extends Common $ret = GoodsParamsService::GoodsParamsTemplateList($data_params); // 基础参数赋值 - $this->assign('params', $this->data_request); - $this->assign('page_html', $page->GetPageHtml()); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + MyViewAssign('page_html', $page->GetPageHtml()); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -107,15 +106,15 @@ class GoodsParamsTemplate extends Common ]; $ret = GoodsParamsService::GoodsParamsTemplateList($data_params); $data = (empty($ret['data']) || empty($ret['data'][0])) ? [] : $ret['data'][0]; - $this->assign('data', $data); + MyViewAssign('data', $data); // 商品参数类型 - $this->assign('common_goods_parameters_type_list', lang('common_goods_parameters_type_list')); + MyViewAssign('common_goods_parameters_type_list', lang('common_goods_parameters_type_list')); // 参数配置 - $this->assign('parameters', empty($data['config_data']) ? [] : $data['config_data']); + MyViewAssign('parameters', empty($data['config_data']) ? [] : $data['config_data']); } - return $this->fetch(); + return MyView(); } /** @@ -147,14 +146,14 @@ class GoodsParamsTemplate extends Common } // 商品参数类型 - $this->assign('common_goods_parameters_type_list', lang('common_goods_parameters_type_list')); + MyViewAssign('common_goods_parameters_type_list', lang('common_goods_parameters_type_list')); // 参数配置 - $this->assign('parameters', empty($data['config_data']) ? [] : $data['config_data']); + MyViewAssign('parameters', empty($data['config_data']) ? [] : $data['config_data']); // 编辑页面钩子 $hook_name = 'plugins_view_admin_goods_params_template_save'; - $this->assign($hook_name.'_data', Hook::listen($hook_name, + MyViewAssign($hook_name.'_data', MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, @@ -165,9 +164,9 @@ class GoodsParamsTemplate extends Common // 数据 unset($params['id']); - $this->assign('data', $data); - $this->assign('params', $params); - return $this->fetch(); + MyViewAssign('data', $data); + MyViewAssign('params', $params); + return MyView(); } /** diff --git a/application/admin/controller/Index.php b/app/admin/controller/Index.php similarity index 86% rename from application/admin/controller/Index.php rename to app/admin/controller/Index.php index 6146e65d3..52c281acd 100755 --- a/application/admin/controller/Index.php +++ b/app/admin/controller/Index.php @@ -57,8 +57,8 @@ class Index extends Common $to_url = base64_decode(urldecode($this->data_request['to_url'])); } - $this->assign('to_url', $to_url); - return $this->fetch(); + MyViewAssign('to_url', $to_url); + return MyView(); } /** @@ -71,7 +71,7 @@ class Index extends Common public function Init() { // 系统信息 - $mysql_ver = db()->query('SELECT VERSION() AS `ver`'); + $mysql_ver = \think\facade\Db::query('SELECT VERSION() AS `ver`'); $data = array( 'server_ver' => php_sapi_name(), 'php_ver' => PHP_VERSION, @@ -80,41 +80,41 @@ class Index extends Common 'host' => isset($_SERVER["HTTP_HOST"]) ? $_SERVER["HTTP_HOST"] : '', 'ver' => 'ShopXO'.' '.APPLICATION_VERSION, ); - $this->assign('data', $data); + MyViewAssign('data', $data); // 用户 $user = StatisticalService::UserYesterdayTodayTotal(); - $this->assign('user', $user['data']); + MyViewAssign('user', $user['data']); // 订单总数 $order_number = StatisticalService::OrderNumberYesterdayTodayTotal(); - $this->assign('order_number', $order_number['data']); + MyViewAssign('order_number', $order_number['data']); // 订单成交总量 $order_complete_number = StatisticalService::OrderCompleteYesterdayTodayTotal(); - $this->assign('order_complete_number', $order_complete_number['data']); + MyViewAssign('order_complete_number', $order_complete_number['data']); // 订单收入总计 $order_complete_money = StatisticalService::OrderCompleteMoneyYesterdayTodayTotal(); - $this->assign('order_complete_money', $order_complete_money['data']); + MyViewAssign('order_complete_money', $order_complete_money['data']); // 近30日订单成交金额走势 $order_profit_chart = StatisticalService::OrderProfitSevenTodayTotal(); - $this->assign('order_profit_chart', $order_profit_chart['data']); + MyViewAssign('order_profit_chart', $order_profit_chart['data']); // 近30日订单交易走势 $order_trading_trend = StatisticalService::OrderTradingTrendSevenTodayTotal(); - $this->assign('order_trading_trend', $order_trading_trend['data']); + MyViewAssign('order_trading_trend', $order_trading_trend['data']); // 近30日支付方式 $pay_type_number = StatisticalService::PayTypeSevenTodayTotal(); - $this->assign('pay_type_number', $pay_type_number['data']); + MyViewAssign('pay_type_number', $pay_type_number['data']); // 近30日热销商品 $goods_hot_sale = StatisticalService::GoodsHotSaleSevenTodayTotal(); - $this->assign('goods_hot_sale', $goods_hot_sale['data']); + MyViewAssign('goods_hot_sale', $goods_hot_sale['data']); - return $this->fetch(); + return MyView(); } /** diff --git a/application/admin/controller/Integrallog.php b/app/admin/controller/Integrallog.php similarity index 91% rename from application/admin/controller/Integrallog.php rename to app/admin/controller/Integrallog.php index 5de3ae2fd..a280b86e2 100755 --- a/application/admin/controller/Integrallog.php +++ b/app/admin/controller/Integrallog.php @@ -74,10 +74,10 @@ class IntegralLog extends Common $ret = IntegralService::IntegralLogList($data_params); // 基础参数赋值 - $this->assign('params', $this->data_request); - $this->assign('page_html', $page->GetPageHtml()); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + MyViewAssign('page_html', $page->GetPageHtml()); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -107,9 +107,9 @@ class IntegralLog extends Common ]; $ret = IntegralService::IntegralLogList($data_params); $data = (empty($ret['data']) || empty($ret['data'][0])) ? [] : $ret['data'][0]; - $this->assign('data', $data); + MyViewAssign('data', $data); } - return $this->fetch(); + return MyView(); } } ?> \ No newline at end of file diff --git a/application/admin/controller/Layout.php b/app/admin/controller/Layout.php similarity index 100% rename from application/admin/controller/Layout.php rename to app/admin/controller/Layout.php diff --git a/application/admin/controller/Link.php b/app/admin/controller/Link.php similarity index 92% rename from application/admin/controller/Link.php rename to app/admin/controller/Link.php index 7e5117730..7685a4e22 100755 --- a/application/admin/controller/Link.php +++ b/app/admin/controller/Link.php @@ -55,8 +55,8 @@ class Link extends Common 'order_by' => $this->form_order_by['data'], ]; $ret = LinkService::LinkList($data_params); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -83,9 +83,9 @@ class Link extends Common ]; $ret = LinkService::LinkList($data_params); $data = (empty($ret['data']) || empty($ret['data'][0])) ? [] : $ret['data'][0]; - $this->assign('data', $data); + MyViewAssign('data', $data); } - return $this->fetch(); + return MyView(); } /** diff --git a/application/admin/controller/Message.php b/app/admin/controller/Message.php similarity index 92% rename from application/admin/controller/Message.php rename to app/admin/controller/Message.php index 60487003c..21b1cfca6 100755 --- a/application/admin/controller/Message.php +++ b/app/admin/controller/Message.php @@ -74,10 +74,10 @@ class Message extends Common $ret = MessageService::MessageList($data_params); // 基础参数赋值 - $this->assign('params', $this->data_request); - $this->assign('page_html', $page->GetPageHtml()); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + MyViewAssign('page_html', $page->GetPageHtml()); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -106,9 +106,9 @@ class Message extends Common ]; $ret = MessageService::MessageList($data_params); $data = (empty($ret['data']) || empty($ret['data'][0])) ? [] : $ret['data'][0]; - $this->assign('data', $data); + MyViewAssign('data', $data); } - return $this->fetch(); + return MyView(); } /** diff --git a/application/admin/controller/Navigation.php b/app/admin/controller/Navigation.php similarity index 81% rename from application/admin/controller/Navigation.php rename to app/admin/controller/Navigation.php index b6e311fdd..846b597f9 100755 --- a/application/admin/controller/Navigation.php +++ b/app/admin/controller/Navigation.php @@ -13,6 +13,7 @@ namespace app\admin\controller; use app\service\ArticleService; use app\service\NavigationService; use app\service\GoodsService; +use app\service\CustomViewService; /** * 导航管理 @@ -63,23 +64,24 @@ class Navigation extends Common ]; $data_params['where'][] = ['nav_type', '=', $this->nav_type]; $ret = NavigationService::NavList($data_params); - $this->assign('data_list', $ret['data']); + MyViewAssign('data_list', $ret['data']); // 一级分类 - $this->assign('nav_header_pid_list', NavigationService::LevelOneNav(['nav_type'=>$this->nav_type])); + MyViewAssign('nav_header_pid_list', NavigationService::LevelOneNav(['nav_type'=>$this->nav_type])); // 获取分类和文章 $article_category_content = ArticleService::ArticleCategoryListContent(); - $this->assign('article_list', $article_category_content['data']); + MyViewAssign('article_list', $article_category_content['data']); // 商品分类 - $this->assign('goods_category_list', GoodsService::GoodsCategoryAll()); + MyViewAssign('goods_category_list', GoodsService::GoodsCategoryAll()); // 自定义页面 - $this->assign('customview_list', db('CustomView')->field(array('id', 'title'))->where(array('is_enable'=>1))->select()); + $custom_view = CustomViewService::CustomViewList(['where'=>['is_enable'=>1], 'field'=>'id,title', 'n'=>0]); + MyViewAssign('customview_list', $custom_view['data']); - $this->assign('nav_type', $this->nav_type); - return $this->fetch(); + MyViewAssign('nav_type', $this->nav_type); + return MyView(); } /** diff --git a/application/admin/controller/Order.php b/app/admin/controller/Order.php similarity index 91% rename from application/admin/controller/Order.php rename to app/admin/controller/Order.php index a1a9262fd..946d817df 100755 --- a/application/admin/controller/Order.php +++ b/app/admin/controller/Order.php @@ -79,21 +79,21 @@ class Order extends Common // 发起支付 - 支付方式 $pay_where = [ - 'where' => ['is_enable'=>1, 'payment'=>config('shopxo.under_line_list')], + 'where' => ['is_enable'=>1, 'payment'=>MyConfig('shopxo.under_line_list')], ]; - $this->assign('buy_payment_list', PaymentService::BuyPaymentList($pay_where)); + MyViewAssign('buy_payment_list', PaymentService::BuyPaymentList($pay_where)); // 快递公司 - $this->assign('express_list', ExpressService::ExpressList()); + MyViewAssign('express_list', ExpressService::ExpressList()); // 加载百度地图api - $this->assign('is_load_baidu_map_api', 1); + MyViewAssign('is_load_baidu_map_api', 1); // 基础参数赋值 - $this->assign('params', $this->data_request); - $this->assign('page_html', $page->GetPageHtml()); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + MyViewAssign('page_html', $page->GetPageHtml()); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -124,12 +124,12 @@ class Order extends Common ]; $ret = OrderService::OrderList($data_params); $data = (empty($ret['data']) || empty($ret['data'][0])) ? [] : $ret['data'][0]; - $this->assign('data', $data); + MyViewAssign('data', $data); // 加载百度地图api - $this->assign('is_load_baidu_map_api', 1); + MyViewAssign('is_load_baidu_map_api', 1); } - return $this->fetch(); + return MyView(); } /** diff --git a/application/admin/controller/Orderaftersale.php b/app/admin/controller/Orderaftersale.php similarity index 93% rename from application/admin/controller/Orderaftersale.php rename to app/admin/controller/Orderaftersale.php index 1602da6f1..6dd6902fe 100644 --- a/application/admin/controller/Orderaftersale.php +++ b/app/admin/controller/Orderaftersale.php @@ -76,13 +76,13 @@ class Orderaftersale extends Common $ret = OrderAftersaleService::OrderAftersaleList($data_params); // 静态数据 - $this->assign('common_order_aftersale_refundment_list', lang('common_order_aftersale_refundment_list')); + MyViewAssign('common_order_aftersale_refundment_list', lang('common_order_aftersale_refundment_list')); // 基础参数赋值 - $this->assign('params', $this->data_request); - $this->assign('page_html', $page->GetPageHtml()); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + MyViewAssign('page_html', $page->GetPageHtml()); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -110,9 +110,9 @@ class Orderaftersale extends Common ); $ret = OrderAftersaleService::OrderAftersaleList($data_params); $data = (empty($ret['data']) || empty($ret['data'][0])) ? [] : $ret['data'][0]; - $this->assign('data', $data); + MyViewAssign('data', $data); } - return $this->fetch(); + return MyView(); } /** diff --git a/application/admin/controller/Packageinstall.php b/app/admin/controller/Packageinstall.php similarity index 96% rename from application/admin/controller/Packageinstall.php rename to app/admin/controller/Packageinstall.php index 429dc4fff..b15652f85 100644 --- a/application/admin/controller/Packageinstall.php +++ b/app/admin/controller/Packageinstall.php @@ -52,8 +52,8 @@ class PackageInstall extends Common public function Index() { $data = PackageInstallService::RequestInstallParams($this->data_request); - $this->assign('data', $data); - return $this->fetch(); + MyViewAssign('data', $data); + return MyView(); } /** diff --git a/application/admin/controller/Packageupgrade.php b/app/admin/controller/Packageupgrade.php similarity index 100% rename from application/admin/controller/Packageupgrade.php rename to app/admin/controller/Packageupgrade.php diff --git a/application/admin/controller/Paylog.php b/app/admin/controller/Paylog.php similarity index 92% rename from application/admin/controller/Paylog.php rename to app/admin/controller/Paylog.php index 334035def..5887b807d 100755 --- a/application/admin/controller/Paylog.php +++ b/app/admin/controller/Paylog.php @@ -74,10 +74,10 @@ class PayLog extends Common $ret = PayLogService::PayLogList($data_params); // 基础参数赋值 - $this->assign('params', $this->data_request); - $this->assign('page_html', $page->GetPageHtml()); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + MyViewAssign('page_html', $page->GetPageHtml()); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -106,9 +106,9 @@ class PayLog extends Common ]; $ret = PayLogService::PayLogList($data_params); $data = (empty($ret['data']) || empty($ret['data'][0])) ? [] : $ret['data'][0]; - $this->assign('data', $data); + MyViewAssign('data', $data); } - return $this->fetch(); + return MyView(); } /** diff --git a/application/admin/controller/Payment.php b/app/admin/controller/Payment.php similarity index 88% rename from application/admin/controller/Payment.php rename to app/admin/controller/Payment.php index 24bfc0360..7507ea7b3 100755 --- a/application/admin/controller/Payment.php +++ b/app/admin/controller/Payment.php @@ -53,24 +53,24 @@ class Payment extends Common { // 插件列表 $ret = PaymentService::PlugPaymentList(); - $this->assign('data_list', $ret['data']); + MyViewAssign('data_list', $ret['data']); // 不能删除的支付方式 - $this->assign('cannot_deleted_list', PaymentService::$cannot_deleted_list); + MyViewAssign('cannot_deleted_list', PaymentService::$cannot_deleted_list); // 适用平台 - $this->assign('common_platform_type', lang('common_platform_type')); + MyViewAssign('common_platform_type', lang('common_platform_type')); // 应用商店 - $this->assign('store_payment_url', StoreService::StorePaymentUrl()); + MyViewAssign('store_payment_url', StoreService::StorePaymentUrl()); // 插件更新信息 $upgrade = PaymentService::PaymentUpgradeInfo($ret['data']); - $this->assign('upgrade_info', $upgrade['data']); + MyViewAssign('upgrade_info', $upgrade['data']); // print_r($upgrade); // print_r($ret['data']); - return $this->fetch(); + return MyView(); } /** @@ -98,19 +98,19 @@ class Payment extends Common { return $this->error('没有相关支付方式', MyUrl('admin/payment/index')); } - $this->assign('data', $data[0]); + MyViewAssign('data', $data[0]); } // 适用平台 - $this->assign('common_platform_type', lang('common_platform_type')); + MyViewAssign('common_platform_type', lang('common_platform_type')); // 参数 - $this->assign('params', $params); + MyViewAssign('params', $params); // 编辑器文件存放地址 - $this->assign('editor_path_type', ResourcesService::EditorPathTypeValue('payment')); + MyViewAssign('editor_path_type', ResourcesService::EditorPathTypeValue('payment')); - return $this->fetch(); + return MyView(); } /** diff --git a/application/admin/controller/Payrequestlog.php b/app/admin/controller/Payrequestlog.php similarity index 91% rename from application/admin/controller/Payrequestlog.php rename to app/admin/controller/Payrequestlog.php index 9706571db..203658fae 100644 --- a/application/admin/controller/Payrequestlog.php +++ b/app/admin/controller/Payrequestlog.php @@ -74,10 +74,10 @@ class PayRequestLog extends Common $ret = PayRequestLogService::PayRequestLogList($data_params); // 基础参数赋值 - $this->assign('params', $this->data_request); - $this->assign('page_html', $page->GetPageHtml()); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + MyViewAssign('page_html', $page->GetPageHtml()); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -106,9 +106,9 @@ class PayRequestLog extends Common ]; $ret = PayRequestLogService::PayRequestLogList($data_params); $data = (empty($ret['data']) || empty($ret['data'][0])) ? [] : $ret['data'][0]; - $this->assign('data', $data); + MyViewAssign('data', $data); } - return $this->fetch(); + return MyView(); } } ?> \ No newline at end of file diff --git a/application/admin/controller/Plugins.php b/app/admin/controller/Plugins.php similarity index 84% rename from application/admin/controller/Plugins.php rename to app/admin/controller/Plugins.php index 4132a5dfa..36802fa27 100755 --- a/application/admin/controller/Plugins.php +++ b/app/admin/controller/Plugins.php @@ -78,8 +78,8 @@ class Plugins extends Common { return DataReturn($ret, -5000); } else { - $this->assign('msg', $ret); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', $ret); + return MyView('public/tips_error'); } } @@ -92,7 +92,7 @@ class Plugins extends Common $this->PluginsViewInit($pluginsname, $pluginscontrol, $pluginsaction); // 编辑器文件存放地址定义 - $this->assign('editor_path_type', ResourcesService::EditorPathTypeValue('plugins_'.$pluginsname)); + MyViewAssign('editor_path_type', ResourcesService::EditorPathTypeValue('plugins_'.$pluginsname)); // 调用 $ret = PluginsService::PluginsControlCall($pluginsname, $pluginscontrol, $pluginsaction, 'admin', $params); @@ -106,8 +106,8 @@ class Plugins extends Common { return $ret; } else { - $this->assign('msg', $ret['msg']); - return $this->fetch(); + MyViewAssign('msg', $ret['msg']); + return MyView(); } } @@ -146,9 +146,9 @@ class Plugins extends Common public function PluginsViewInit($plugins_name, $plugins_control, $plugins_action) { // 应用名称/控制器/方法 - $this->assign('plugins_name', $plugins_name); - $this->assign('plugins_control', $plugins_control); - $this->assign('plugins_action', $plugins_action); + MyViewAssign('plugins_name', $plugins_name); + MyViewAssign('plugins_control', $plugins_control); + MyViewAssign('plugins_action', $plugins_action); // 当前操作名称 $module_name = 'plugins'; @@ -159,17 +159,17 @@ class Plugins extends Common // 控制器静态文件状态css,js $module_css = $module_name.DS.'css'.DS.$plugins_name.DS.$group.DS.$plugins_control; $module_css .= file_exists(ROOT_PATH.'static'.DS.$module_css.'.'.$plugins_action.'.css') ? '.'.$plugins_action.'.css' : '.css'; - $this->assign('module_css', file_exists(ROOT_PATH.'static'.DS.$module_css) ? $module_css : ''); + MyViewAssign('module_css', file_exists(ROOT_PATH.'static'.DS.$module_css) ? $module_css : ''); $module_js = $module_name.DS.'js'.DS.$plugins_name.DS.$group.DS.$plugins_control; $module_js .= file_exists(ROOT_PATH.'static'.DS.$module_js.'.'.$plugins_action.'.js') ? '.'.$plugins_action.'.js' : '.js'; - $this->assign('module_js', file_exists(ROOT_PATH.'static'.DS.$module_js) ? $module_js : ''); + MyViewAssign('module_js', file_exists(ROOT_PATH.'static'.DS.$module_js) ? $module_js : ''); // 应用公共css,js $plugins_css = $module_name.DS.'css'.DS.$plugins_name.DS.$group.DS.'common.css'; - $this->assign('plugins_css', file_exists(ROOT_PATH.'static'.DS.$plugins_css) ? $plugins_css : ''); + MyViewAssign('plugins_css', file_exists(ROOT_PATH.'static'.DS.$plugins_css) ? $plugins_css : ''); $plugins_js = $module_name.DS.'js'.DS.$plugins_name.DS.$group.DS.'common.js'; - $this->assign('plugins_js', file_exists(ROOT_PATH.'static'.DS.$plugins_js) ? $plugins_js : ''); + MyViewAssign('plugins_js', file_exists(ROOT_PATH.'static'.DS.$plugins_js) ? $plugins_js : ''); } } ?> \ No newline at end of file diff --git a/application/admin/controller/Pluginsadmin.php b/app/admin/controller/Pluginsadmin.php similarity index 89% rename from application/admin/controller/Pluginsadmin.php rename to app/admin/controller/Pluginsadmin.php index 903dcafcd..5789f295d 100755 --- a/application/admin/controller/Pluginsadmin.php +++ b/app/admin/controller/Pluginsadmin.php @@ -57,28 +57,28 @@ class Pluginsadmin extends Common public function Index() { // 导航参数 - $this->assign('view_type', $this->view_type); + MyViewAssign('view_type', $this->view_type); // 参数 $params = $this->data_request; // 应用商店地址 - $this->assign('store_url', StoreService::StoreUrl()); + MyViewAssign('store_url', StoreService::StoreUrl()); // 页面类型 if($this->view_type == 'home') { // 插件列表 $ret = PluginsAdminService::PluginsList(); - $this->assign('data_list', $ret['data']); + MyViewAssign('data_list', $ret['data']); // 插件更新信息 $upgrade = PluginsService::PluginsUpgradeInfo($ret['data']); - $this->assign('upgrade_info', $upgrade['data']); + MyViewAssign('upgrade_info', $upgrade['data']); - return $this->fetch(); + return MyView(); } else { - return $this->fetch('upload'); + return MyView('upload'); } } @@ -95,7 +95,7 @@ class Pluginsadmin extends Common $params = $this->data_request; // 参数 - $this->assign('params', $params); + MyViewAssign('params', $params); // 获取数据 $data = []; @@ -113,7 +113,7 @@ class Pluginsadmin extends Common } } } - $this->assign('data', $data); + MyViewAssign('data', $data); // 名称校验 if(!empty($params['plugins'])) @@ -121,22 +121,22 @@ class Pluginsadmin extends Common $ret = PluginsAdminService::PluginsVerification($params, $params['plugins']); if($ret['code'] != 0) { - $this->assign('verification_msg', $ret['msg']); - return $this->fetch('first_step'); + MyViewAssign('verification_msg', $ret['msg']); + return MyView('first_step'); } } // 标记为空或等于view 并且 编辑数据为空则走第一步 if(empty($params['plugins']) && empty($data['data'][0])) { - return $this->fetch('first_step'); + return MyView('first_step'); } else { // 编辑器文件存放地址 - $this->assign('editor_path_type', ResourcesService::EditorPathTypeValue('plugins_'.$params['plugins'])); + MyViewAssign('editor_path_type', ResourcesService::EditorPathTypeValue('plugins_'.$params['plugins'])); // 唯一标记 - $this->assign('plugins', $params['plugins']); - return $this->fetch('save_info'); + MyViewAssign('plugins', $params['plugins']); + return MyView('save_info'); } } @@ -230,8 +230,8 @@ class Pluginsadmin extends Common $ret = PluginsAdminService::PluginsDownload($this->data_request); if(isset($ret['code']) && $ret['code'] != 0) { - $this->assign('msg', $ret['msg']); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', $ret['msg']); + return MyView('public/tips_error'); } else { return $ret; } diff --git a/application/admin/controller/Power.php b/app/admin/controller/Power.php similarity index 94% rename from application/admin/controller/Power.php rename to app/admin/controller/Power.php index 27a2d5fc7..1813a3db8 100755 --- a/application/admin/controller/Power.php +++ b/app/admin/controller/Power.php @@ -56,9 +56,9 @@ class Power extends Common ]; $data = AdminPowerService::PowerList($data_params); - $this->assign('data', $data); - $this->assign('common_is_show_list', lang('common_is_show_list')); - return $this->fetch(); + MyViewAssign('data', $data); + MyViewAssign('common_is_show_list', lang('common_is_show_list')); + return MyView(); } /** diff --git a/application/admin/controller/Quicknav.php b/app/admin/controller/Quicknav.php similarity index 89% rename from application/admin/controller/Quicknav.php rename to app/admin/controller/Quicknav.php index ec643a096..14c14f5c2 100755 --- a/application/admin/controller/Quicknav.php +++ b/app/admin/controller/Quicknav.php @@ -73,10 +73,10 @@ class QuickNav extends Common $ret = QuickNavService::QuickNavList($data_params); // 基础参数赋值 - $this->assign('params', $this->data_request); - $this->assign('page_html', $page->GetPageHtml()); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + MyViewAssign('page_html', $page->GetPageHtml()); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -103,9 +103,9 @@ class QuickNav extends Common ]; $ret = QuickNavService::QuickNavList($data_params); $data = (empty($ret['data']) || empty($ret['data'][0])) ? [] : $ret['data'][0]; - $this->assign('data', $data); + MyViewAssign('data', $data); } - return $this->fetch(); + return MyView(); } /** @@ -134,19 +134,19 @@ class QuickNav extends Common $ret = QuickNavService::QuickNavList($data_params); $data = empty($ret['data'][0]) ? [] : $ret['data'][0]; } - $this->assign('data', $data); + MyViewAssign('data', $data); // 静态数据 - $this->assign('common_platform_type', lang('common_platform_type')); - $this->assign('common_app_event_type', lang('common_app_event_type')); + MyViewAssign('common_platform_type', lang('common_platform_type')); + MyViewAssign('common_app_event_type', lang('common_app_event_type')); // 参数 - $this->assign('params', $params); + MyViewAssign('params', $params); // 编辑器文件存放地址 - $this->assign('editor_path_type', ResourcesService::EditorPathTypeValue('quick_nav')); + MyViewAssign('editor_path_type', ResourcesService::EditorPathTypeValue('quick_nav')); - return $this->fetch(); + return MyView(); } /** diff --git a/application/admin/controller/Refundlog.php b/app/admin/controller/Refundlog.php similarity index 92% rename from application/admin/controller/Refundlog.php rename to app/admin/controller/Refundlog.php index 6a0309ba9..2e8b5dfd8 100644 --- a/application/admin/controller/Refundlog.php +++ b/app/admin/controller/Refundlog.php @@ -74,10 +74,10 @@ class RefundLog extends Common $ret = RefundLogService::RefundLogList($data_params); // 基础参数赋值 - $this->assign('params', $this->data_request); - $this->assign('page_html', $page->GetPageHtml()); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + MyViewAssign('page_html', $page->GetPageHtml()); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -106,9 +106,9 @@ class RefundLog extends Common ]; $ret = RefundLogService::RefundLogList($data_params); $data = (empty($ret['data']) || empty($ret['data'][0])) ? [] : $ret['data'][0]; - $this->assign('data', $data); + MyViewAssign('data', $data); } - return $this->fetch(); + return MyView(); } } ?> \ No newline at end of file diff --git a/application/admin/controller/Region.php b/app/admin/controller/Region.php similarity index 96% rename from application/admin/controller/Region.php rename to app/admin/controller/Region.php index e31b7787a..4b2f4c9a5 100755 --- a/application/admin/controller/Region.php +++ b/app/admin/controller/Region.php @@ -50,9 +50,9 @@ class Region extends Common $this->IsPower(); // 是否启用 - $this->assign('common_is_enable_list', lang('common_is_enable_list')); + MyViewAssign('common_is_enable_list', lang('common_is_enable_list')); - return $this->fetch(); + return MyView(); } /** diff --git a/application/admin/controller/Role.php b/app/admin/controller/Role.php similarity index 91% rename from application/admin/controller/Role.php rename to app/admin/controller/Role.php index 2860382ad..0113b9489 100644 --- a/application/admin/controller/Role.php +++ b/app/admin/controller/Role.php @@ -10,7 +10,6 @@ // +---------------------------------------------------------------------- namespace app\admin\controller; -use think\facade\Hook; use app\service\AdminRoleService; /** @@ -73,10 +72,10 @@ class Role extends Common $ret = AdminRoleService::RoleList($data_params); // 基础参数赋值 - $this->assign('params', $this->data_request); - $this->assign('page_html', $page->GetPageHtml()); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + MyViewAssign('page_html', $page->GetPageHtml()); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -103,9 +102,9 @@ class Role extends Common ]; $ret = AdminRoleService::RoleList($data_params); $data = (empty($ret['data']) || empty($ret['data'][0])) ? [] : $ret['data'][0]; - $this->assign('data', $data); + MyViewAssign('data', $data); } - return $this->fetch(); + return MyView(); } /** @@ -139,11 +138,11 @@ class Role extends Common // 菜单列表 $power = AdminRoleService::RolePowerEditData($params); - $this->assign('power', $power); + MyViewAssign('power', $power); // 角色编辑页面钩子 $hook_name = 'plugins_view_admin_role_save'; - $this->assign($hook_name.'_data', Hook::listen($hook_name, + MyViewAssign($hook_name.'_data', MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, @@ -154,9 +153,9 @@ class Role extends Common // 数据 unset($params['id']); - $this->assign('data', $data); - $this->assign('params', $params); - return $this->fetch(); + MyViewAssign('data', $data); + MyViewAssign('params', $params); + return MyView(); } /** diff --git a/application/admin/controller/Screeningprice.php b/app/admin/controller/Screeningprice.php similarity index 92% rename from application/admin/controller/Screeningprice.php rename to app/admin/controller/Screeningprice.php index 44cbed9b1..ad8f17570 100755 --- a/application/admin/controller/Screeningprice.php +++ b/app/admin/controller/Screeningprice.php @@ -50,9 +50,9 @@ class ScreeningPrice extends Common public function Index() { // 是否启用 - $this->assign('common_is_enable_list', lang('common_is_enable_list')); + MyViewAssign('common_is_enable_list', lang('common_is_enable_list')); - return $this->fetch(); + return MyView(); } /** diff --git a/application/admin/controller/Seo.php b/app/admin/controller/Seo.php similarity index 84% rename from application/admin/controller/Seo.php rename to app/admin/controller/Seo.php index d64dd50c0..7b51073ef 100755 --- a/application/admin/controller/Seo.php +++ b/app/admin/controller/Seo.php @@ -50,18 +50,18 @@ class Seo extends Common public function Index() { // url模式 - $this->assign('seo_url_model_list', lang('seo_url_model_list')); + MyViewAssign('seo_url_model_list', lang('seo_url_model_list')); // 文章标题seo方案 - $this->assign('seo_article_browser_list', lang('seo_article_browser_list')); + MyViewAssign('seo_article_browser_list', lang('seo_article_browser_list')); // 频道标题seo方案 - $this->assign('seo_channel_browser_list', lang('seo_channel_browser_list')); + MyViewAssign('seo_channel_browser_list', lang('seo_channel_browser_list')); // 配置信息 - $this->assign('data', ConfigService::ConfigList()); + MyViewAssign('data', ConfigService::ConfigList()); - return $this->fetch(); + return MyView(); } /** diff --git a/application/admin/controller/Site.php b/app/admin/controller/Site.php similarity index 79% rename from application/admin/controller/Site.php rename to app/admin/controller/Site.php index 89214d398..3a05842d6 100755 --- a/application/admin/controller/Site.php +++ b/app/admin/controller/Site.php @@ -71,7 +71,7 @@ class Site extends Common // 配置信息 $data = ConfigService::ConfigList(); - $this->assign('data', $data); + MyViewAssign('data', $data); // 数据处理 switch($this->nav_type) @@ -82,11 +82,11 @@ class Site extends Common if(!empty($data['common_self_extraction_address']) && !empty($data['common_self_extraction_address']['value'])) { $address = ConfigService::SiteTypeExtractionAddressList($data['common_self_extraction_address']['value']); - $this->assign('sitetype_address_list', $address['data']); + MyViewAssign('sitetype_address_list', $address['data']); } // 加载百度地图api - $this->assign('is_load_baidu_map_api', 1); + MyViewAssign('is_load_baidu_map_api', 1); break; // 网站设置 @@ -120,23 +120,23 @@ class Site extends Common $c['config_category_ids'] = array_key_exists($c['id'], $floor_category) ? explode(',', $floor_category[$c['id']]) : []; } } - $this->assign('goods_category_list', $category); + MyViewAssign('goods_category_list', $category); // 楼层自定义商品 if(!empty($data['home_index_floor_manual_mode_goods']) && !empty($data['home_index_floor_manual_mode_goods']['value'])) { $ret = SiteService::FloorManualModeGoodsViewHandle(json_decode($data['home_index_floor_manual_mode_goods']['value'], true)); - $this->assign('floor_manual_mode_goods_list', $ret['data']); + MyViewAssign('floor_manual_mode_goods_list', $ret['data']); } break; } // 编辑器文件存放地址 - $this->assign('editor_path_type', ResourcesService::EditorPathTypeValue('common')); + MyViewAssign('editor_path_type', ResourcesService::EditorPathTypeValue('common')); // 视图 $view = 'site/'.$this->nav_type.'/'.$this->view_type; - return $this->fetch($view); + return MyView($view); } /** @@ -150,51 +150,51 @@ class Site extends Common public function CurrentViewInit() { // 主/子导航 - $this->assign('nav_type', $this->nav_type); - $this->assign('view_type', $this->view_type); + MyViewAssign('nav_type', $this->nav_type); + MyViewAssign('view_type', $this->view_type); // 时区 - $this->assign('site_timezone_list', lang('site_timezone_list')); + MyViewAssign('site_timezone_list', lang('site_timezone_list')); // 关闭开启 - $this->assign('common_close_open_list', lang('common_close_open_list')); + MyViewAssign('common_close_open_list', lang('common_close_open_list')); // 登录方式 - $this->assign('common_login_type_list', lang('common_login_type_list')); + MyViewAssign('common_login_type_list', lang('common_login_type_list')); // 用户注册类型列表 - $this->assign('common_user_reg_type_list', lang('common_user_reg_type_list')); + MyViewAssign('common_user_reg_type_list', lang('common_user_reg_type_list')); // 图片验证码规则 - $this->assign('site_images_verify_rules_list', lang('site_images_verify_rules_list')); + MyViewAssign('site_images_verify_rules_list', lang('site_images_verify_rules_list')); // 热门搜索关键字 - $this->assign('common_search_keywords_type_list', lang('common_search_keywords_type_list')); + MyViewAssign('common_search_keywords_type_list', lang('common_search_keywords_type_list')); // 是否 - $this->assign('common_is_text_list', lang('common_is_text_list')); + MyViewAssign('common_is_text_list', lang('common_is_text_list')); // 站点类型 - $this->assign('common_site_type_list', lang('common_site_type_list')); + MyViewAssign('common_site_type_list', lang('common_site_type_list')); // 扣除库存规则 - $this->assign('common_deduction_inventory_rules_list', lang('common_deduction_inventory_rules_list')); + MyViewAssign('common_deduction_inventory_rules_list', lang('common_deduction_inventory_rules_list')); // 增加销量规则 - $this->assign('common_sales_count_inc_rules_list', lang('common_sales_count_inc_rules_list')); + MyViewAssign('common_sales_count_inc_rules_list', lang('common_sales_count_inc_rules_list')); // 首页商品排序规则 - $this->assign('goods_order_by_type_list', lang('goods_order_by_type_list')); - $this->assign('goods_order_by_rule_list', lang('goods_order_by_rule_list')); + MyViewAssign('goods_order_by_type_list', lang('goods_order_by_type_list')); + MyViewAssign('goods_order_by_rule_list', lang('goods_order_by_rule_list')); // 首页楼层数据类型 - $this->assign('common_site_floor_data_type_list', lang('common_site_floor_data_type_list')); + MyViewAssign('common_site_floor_data_type_list', lang('common_site_floor_data_type_list')); // 搜索参数类型 - $this->assign('common_goods_parameters_type_list', lang('common_goods_parameters_type_list')); + MyViewAssign('common_goods_parameters_type_list', lang('common_goods_parameters_type_list')); // 主导航 - $this->assign('second_nav_list', [ + MyViewAssign('second_nav_list', [ [ 'name' => '基础配置', 'type' => 'base', @@ -242,7 +242,7 @@ class Site extends Common ]); // 网站设置导航 - $this->assign('siteset_nav_list', [ + MyViewAssign('siteset_nav_list', [ [ 'name' => '首页', 'type' => 'index', @@ -359,18 +359,8 @@ class Site extends Common // 缓存 case 'cache' : // session是否使用缓存 - if(isset($params['common_session_is_use_cache']) && $params['common_session_is_use_cache'] == 1) - { - // 连接测试 - $ret = SiteService::RedisCheckConnectPing($params['common_cache_session_redis_host'], $params['common_cache_session_redis_port'], $params['common_cache_session_redis_password']); - if($ret['code'] != 0) - { - return $ret; - } - } - // 数据是否使用缓存 - if(isset($params['common_data_is_use_cache']) && $params['common_data_is_use_cache'] == 1) + if((isset($params['common_session_is_use_cache']) && $params['common_session_is_use_cache'] == 1) || (isset($params['common_data_is_use_cache']) && $params['common_data_is_use_cache'] == 1)) { // 连接测试 $ret = SiteService::RedisCheckConnectPing($params['common_cache_data_redis_host'], $params['common_cache_data_redis_port'], $params['common_cache_data_redis_password']); @@ -404,11 +394,11 @@ class Site extends Common { // 登录 case 'login' : - cache(config('shopxo.cache_user_login_left_key'), null); + MyCache(MyConfig('shopxo.cache_user_login_left_key'), null); // 密码找回 case 'forgetpwd' : - cache(config('shopxo.cache_user_forgetpwd_left_key'), null); + MyCache(MyConfig('shopxo.cache_user_forgetpwd_left_key'), null); break; } } @@ -436,8 +426,8 @@ class Site extends Common $ret = SiteService::GoodsSearchList($this->data_post); if($ret['code'] == 0) { - $this->assign('data', $ret['data']['data']); - $ret['data']['data'] = $this->fetch('site/public/goods_search'); + MyViewAssign('data', $ret['data']['data']); + $ret['data']['data'] = MyView('site/public/goods_search'); } return $ret; } diff --git a/application/admin/controller/Slide.php b/app/admin/controller/Slide.php similarity index 87% rename from application/admin/controller/Slide.php rename to app/admin/controller/Slide.php index 0e54da7db..3a5cd2304 100755 --- a/application/admin/controller/Slide.php +++ b/app/admin/controller/Slide.php @@ -73,10 +73,10 @@ class Slide extends Common $ret = SlideService::SlideList($data_params); // 基础参数赋值 - $this->assign('params', $this->data_request); - $this->assign('page_html', $page->GetPageHtml()); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + MyViewAssign('page_html', $page->GetPageHtml()); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -103,9 +103,9 @@ class Slide extends Common ]; $ret = SlideService::SlideList($data_params); $data = (empty($ret['data']) || empty($ret['data'][0])) ? [] : $ret['data'][0]; - $this->assign('data', $data); + MyViewAssign('data', $data); } - return $this->fetch(); + return MyView(); } /** @@ -136,18 +136,18 @@ class Slide extends Common } // 静态资源 - $this->assign('common_is_enable_list', lang('common_is_enable_list')); - $this->assign('common_platform_type', lang('common_platform_type')); - $this->assign('common_app_event_type', lang('common_app_event_type')); + MyViewAssign('common_is_enable_list', lang('common_is_enable_list')); + MyViewAssign('common_platform_type', lang('common_platform_type')); + MyViewAssign('common_app_event_type', lang('common_app_event_type')); // 编辑器文件存放地址 - $this->assign('editor_path_type', ResourcesService::EditorPathTypeValue('slide')); + MyViewAssign('editor_path_type', ResourcesService::EditorPathTypeValue('slide')); // 数据 unset($params['id']); - $this->assign('params', $params); - $this->assign('data', $data); - return $this->fetch(); + MyViewAssign('params', $params); + MyViewAssign('data', $data); + return MyView(); } /** diff --git a/application/admin/controller/Sms.php b/app/admin/controller/Sms.php similarity index 91% rename from application/admin/controller/Sms.php rename to app/admin/controller/Sms.php index 285a1e5e6..e42239569 100755 --- a/application/admin/controller/Sms.php +++ b/app/admin/controller/Sms.php @@ -50,16 +50,16 @@ class Sms extends Common public function Index() { // 配置信息 - $this->assign('data', ConfigService::ConfigList()); + MyViewAssign('data', ConfigService::ConfigList()); // 导航 $type = input('type', 'sms'); - $this->assign('nav_type', $type); + MyViewAssign('nav_type', $type); if($type == 'sms') { - return $this->fetch('index'); + return MyView('index'); } else { - return $this->fetch('message'); + return MyView('message'); } } diff --git a/application/admin/controller/Sqlconsole.php b/app/admin/controller/Sqlconsole.php similarity index 98% rename from application/admin/controller/Sqlconsole.php rename to app/admin/controller/Sqlconsole.php index ea44c2362..1623490bf 100755 --- a/application/admin/controller/Sqlconsole.php +++ b/app/admin/controller/Sqlconsole.php @@ -49,7 +49,7 @@ class Sqlconsole extends Common */ public function Index() { - return $this->fetch(); + return MyView(); } /** diff --git a/application/admin/controller/Store.php b/app/admin/controller/Store.php similarity index 93% rename from application/admin/controller/Store.php rename to app/admin/controller/Store.php index 66a09b46f..35d127f42 100644 --- a/application/admin/controller/Store.php +++ b/app/admin/controller/Store.php @@ -48,8 +48,8 @@ class Store extends Common */ public function Index() { - $this->assign('store_url', StoreService::StoreUrl()); - return $this->fetch(); + MyViewAssign('store_url', StoreService::StoreUrl()); + return MyView(); } } ?> \ No newline at end of file diff --git a/application/admin/controller/Theme.php b/app/admin/controller/Theme.php similarity index 84% rename from application/admin/controller/Theme.php rename to app/admin/controller/Theme.php index 2dd4f9cc2..4a1f333fe 100755 --- a/application/admin/controller/Theme.php +++ b/app/admin/controller/Theme.php @@ -57,26 +57,26 @@ class Theme extends Common public function Index() { // 导航参数 - $this->assign('view_type', $this->view_type); + MyViewAssign('view_type', $this->view_type); // 应用商店 - $this->assign('store_theme_url', StoreService::StoreThemeUrl()); + MyViewAssign('store_theme_url', StoreService::StoreThemeUrl()); // 是否默认首页 if($this->view_type == 'index') { // 默认主题 - $this->assign('theme', ThemeService::DefaultTheme()); + MyViewAssign('theme', ThemeService::DefaultTheme()); // 获取主题列表 $data = ThemeService::ThemeList(); - $this->assign('data_list', $data); + MyViewAssign('data_list', $data); // 插件更新信息 $upgrade = ThemeService::ThemeUpgradeInfo($data); - $this->assign('upgrade_info', $upgrade['data']); + MyViewAssign('upgrade_info', $upgrade['data']); } - return $this->fetch($this->view_type); + return MyView($this->view_type); } /** @@ -149,8 +149,8 @@ class Theme extends Common $ret = ThemeService::ThemeDownload($this->data_request); if(isset($ret['code']) && $ret['code'] != 0) { - $this->assign('msg', $ret['msg']); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', $ret['msg']); + return MyView('public/tips_error'); } else { return $ret; } diff --git a/application/admin/controller/Ueditor.php b/app/admin/controller/Ueditor.php similarity index 100% rename from application/admin/controller/Ueditor.php rename to app/admin/controller/Ueditor.php diff --git a/application/admin/controller/User.php b/app/admin/controller/User.php similarity index 89% rename from application/admin/controller/User.php rename to app/admin/controller/User.php index 0f5161d4c..e39942110 100755 --- a/application/admin/controller/User.php +++ b/app/admin/controller/User.php @@ -10,7 +10,6 @@ // +---------------------------------------------------------------------- namespace app\admin\controller; -use think\facade\Hook; use app\service\IntegralService; use app\service\UserService; @@ -74,13 +73,13 @@ class User extends Common $ret = UserService::UserList($data_params); // Excel地址 - $this->assign('excel_url', MyUrl('admin/user/excelexport', $this->data_request)); + MyViewAssign('excel_url', MyUrl('admin/user/excelexport', $this->data_request)); // 基础参数赋值 - $this->assign('params', $this->data_request); - $this->assign('page_html', $page->GetPageHtml()); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + MyViewAssign('page_html', $page->GetPageHtml()); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -107,9 +106,9 @@ class User extends Common ]; $ret = UserService::UserList($data_params); $data = (empty($ret['data']) || empty($ret['data'][0])) ? [] : $ret['data'][0]; - $this->assign('data', $data); + MyViewAssign('data', $data); } - return $this->fetch(); + return MyView(); } /** @@ -169,7 +168,7 @@ class User extends Common // 用户编辑页面钩子 $hook_name = 'plugins_view_admin_user_save'; - $this->assign($hook_name.'_data', Hook::listen($hook_name, + MyViewAssign($hook_name.'_data', MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, @@ -179,13 +178,13 @@ class User extends Common ])); // 性别 - $this->assign('common_gender_list', lang('common_gender_list')); + MyViewAssign('common_gender_list', lang('common_gender_list')); // 数据 unset($params['id']); - $this->assign('data', $data); - $this->assign('params', $params); - return $this->fetch(); + MyViewAssign('data', $data); + MyViewAssign('params', $params); + return MyView(); } diff --git a/application/admin/controller/Useraddress.php b/app/admin/controller/Useraddress.php similarity index 88% rename from application/admin/controller/Useraddress.php rename to app/admin/controller/Useraddress.php index bf80fbf32..1aeb0cca1 100644 --- a/application/admin/controller/Useraddress.php +++ b/app/admin/controller/Useraddress.php @@ -73,13 +73,13 @@ class UserAddress extends Common $ret = UserAddressService::UserAddressAdminList($data_params); // 加载百度地图api - $this->assign('is_load_baidu_map_api', 1); + MyViewAssign('is_load_baidu_map_api', 1); // 基础参数赋值 - $this->assign('params', $this->data_request); - $this->assign('page_html', $page->GetPageHtml()); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + MyViewAssign('page_html', $page->GetPageHtml()); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -106,12 +106,12 @@ class UserAddress extends Common ]; $ret = UserAddressService::UserAddressAdminList($data_params); $data = (empty($ret['data']) || empty($ret['data'][0])) ? [] : $ret['data'][0]; - $this->assign('data', $data); + MyViewAssign('data', $data); // 加载百度地图api - $this->assign('is_load_baidu_map_api', 1); + MyViewAssign('is_load_baidu_map_api', 1); } - return $this->fetch(); + return MyView(); } /** @@ -142,19 +142,19 @@ class UserAddress extends Common } // 加载百度地图api - $this->assign('is_load_baidu_map_api', 1); + MyViewAssign('is_load_baidu_map_api', 1); // 编辑器文件存放地址 if(!empty($data['user_id'])) { - $this->assign('editor_path_type', ResourcesService::EditorPathTypeValue(UserAddressService::EditorAttachmentPathType($data['user_id']))); + MyViewAssign('editor_path_type', ResourcesService::EditorPathTypeValue(UserAddressService::EditorAttachmentPathType($data['user_id']))); } // 数据 unset($params['id']); - $this->assign('data', $data); - $this->assign('params', $params); - return $this->fetch(); + MyViewAssign('data', $data); + MyViewAssign('params', $params); + return MyView(); } /** diff --git a/application/admin/controller/Warehouse.php b/app/admin/controller/Warehouse.php similarity index 88% rename from application/admin/controller/Warehouse.php rename to app/admin/controller/Warehouse.php index 699cf6f14..90061d2eb 100644 --- a/application/admin/controller/Warehouse.php +++ b/app/admin/controller/Warehouse.php @@ -10,7 +10,6 @@ // +---------------------------------------------------------------------- namespace app\admin\controller; -use think\facade\Hook; use app\service\WarehouseService; use app\service\ResourcesService; @@ -60,14 +59,14 @@ class Warehouse extends Common 'order_by' => $this->form_order_by['data'], ]; $ret = WarehouseService::WarehouseList($data_params); - $this->assign('data_list', $ret['data']); + MyViewAssign('data_list', $ret['data']); // 加载百度地图api - $this->assign('is_load_baidu_map_api', 1); + MyViewAssign('is_load_baidu_map_api', 1); // 基础参数赋值 - $this->assign('params', $this->data_request); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + return MyView(); } /** @@ -94,12 +93,12 @@ class Warehouse extends Common ]; $ret = WarehouseService::WarehouseList($data_params); $data = (empty($ret['data']) || empty($ret['data'][0])) ? [] : $ret['data'][0]; - $this->assign('data', $data); + MyViewAssign('data', $data); // 加载百度地图api - $this->assign('is_load_baidu_map_api', 1); + MyViewAssign('is_load_baidu_map_api', 1); } - return $this->fetch(); + return MyView(); } /** @@ -129,7 +128,7 @@ class Warehouse extends Common // 编辑页面钩子 $hook_name = 'plugins_view_admin_warehouse_save'; - $this->assign($hook_name.'_data', Hook::listen($hook_name, + MyViewAssign($hook_name.'_data', MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, @@ -139,16 +138,16 @@ class Warehouse extends Common ])); // 加载百度地图api - $this->assign('is_load_baidu_map_api', 1); + MyViewAssign('is_load_baidu_map_api', 1); // 编辑器文件存放地址 - $this->assign('editor_path_type', ResourcesService::EditorPathTypeValue('warehouse')); + MyViewAssign('editor_path_type', ResourcesService::EditorPathTypeValue('warehouse')); // 数据 unset($params['id']); - $this->assign('data', $data); - $this->assign('params', $params); - return $this->fetch(); + MyViewAssign('data', $data); + MyViewAssign('params', $params); + return MyView(); } /** diff --git a/application/admin/controller/Warehousegoods.php b/app/admin/controller/Warehousegoods.php similarity index 91% rename from application/admin/controller/Warehousegoods.php rename to app/admin/controller/Warehousegoods.php index c933fd0ac..f62cd23a7 100644 --- a/application/admin/controller/Warehousegoods.php +++ b/app/admin/controller/Warehousegoods.php @@ -10,7 +10,6 @@ // +---------------------------------------------------------------------- namespace app\admin\controller; -use think\facade\Hook; use app\service\WarehouseGoodsService; use app\service\WarehouseService; use app\service\GoodsService; @@ -86,16 +85,16 @@ class WarehouseGoods extends Common ], ]; $warehouse = WarehouseService::WarehouseList($data_params); - $this->assign('warehouse_list', $warehouse['data']); + MyViewAssign('warehouse_list', $warehouse['data']); // 商品分类 - $this->assign('goods_category_list', GoodsService::GoodsCategoryAll()); + MyViewAssign('goods_category_list', GoodsService::GoodsCategoryAll()); // 基础参数赋值 - $this->assign('params', $this->data_request); - $this->assign('page_html', $page->GetPageHtml()); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + MyViewAssign('page_html', $page->GetPageHtml()); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -129,9 +128,9 @@ class WarehouseGoods extends Common } } } - $this->assign('spec', $spec); - $this->assign('data', $data); - return $this->fetch(); + MyViewAssign('spec', $spec); + MyViewAssign('data', $data); + return MyView(); } /** @@ -156,9 +155,9 @@ class WarehouseGoods extends Common } // 数据 - $this->assign('data', $data); - $this->assign('params', $params); - return $this->fetch(); + MyViewAssign('data', $data); + MyViewAssign('params', $params); + return MyView(); } /** @@ -246,8 +245,8 @@ class WarehouseGoods extends Common $ret = WarehouseGoodsService::GoodsSearchList($this->data_request); if($ret['code'] == 0) { - $this->assign('data', $ret['data']['data']); - $ret['data']['data'] = $this->fetch(); + MyViewAssign('data', $ret['data']['data']); + $ret['data']['data'] = MyView(); } return $ret; } diff --git a/application/admin/controller/index.html b/app/admin/controller/index.html similarity index 100% rename from application/admin/controller/index.html rename to app/admin/controller/index.html diff --git a/application/admin/form/Admin.php b/app/admin/form/Admin.php similarity index 100% rename from application/admin/form/Admin.php rename to app/admin/form/Admin.php diff --git a/application/admin/form/Answer.php b/app/admin/form/Answer.php similarity index 99% rename from application/admin/form/Answer.php rename to app/admin/form/Answer.php index 1ef1a3196..471897a07 100644 --- a/application/admin/form/Answer.php +++ b/app/admin/form/Answer.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\admin\form; -use think\Db; +use think\facade\Db; /** * 问答动态表格 diff --git a/application/admin/form/Appcenternav.php b/app/admin/form/Appcenternav.php similarity index 100% rename from application/admin/form/Appcenternav.php rename to app/admin/form/Appcenternav.php diff --git a/application/admin/form/Apphomenav.php b/app/admin/form/Apphomenav.php similarity index 100% rename from application/admin/form/Apphomenav.php rename to app/admin/form/Apphomenav.php diff --git a/application/admin/form/Appmini.php b/app/admin/form/Appmini.php similarity index 100% rename from application/admin/form/Appmini.php rename to app/admin/form/Appmini.php diff --git a/application/admin/form/Article.php b/app/admin/form/Article.php similarity index 100% rename from application/admin/form/Article.php rename to app/admin/form/Article.php diff --git a/application/admin/form/Brand.php b/app/admin/form/Brand.php similarity index 99% rename from application/admin/form/Brand.php rename to app/admin/form/Brand.php index bbf8e2377..1ee989493 100644 --- a/application/admin/form/Brand.php +++ b/app/admin/form/Brand.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\admin\form; -use think\Db; +use think\facade\Db; use app\service\BrandService; use app\service\BrandCategoryService; diff --git a/application/admin/form/Customview.php b/app/admin/form/Customview.php similarity index 100% rename from application/admin/form/Customview.php rename to app/admin/form/Customview.php diff --git a/application/admin/form/Design.php b/app/admin/form/Design.php similarity index 100% rename from application/admin/form/Design.php rename to app/admin/form/Design.php diff --git a/application/admin/form/Goods.php b/app/admin/form/Goods.php similarity index 99% rename from application/admin/form/Goods.php rename to app/admin/form/Goods.php index 9692d70ac..bd1017e60 100644 --- a/application/admin/form/Goods.php +++ b/app/admin/form/Goods.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\admin\form; -use think\Db; +use think\facade\Db; use app\service\GoodsService; use app\service\RegionService; use app\service\BrandService; diff --git a/application/admin/form/Goodsbrowse.php b/app/admin/form/Goodsbrowse.php similarity index 99% rename from application/admin/form/Goodsbrowse.php rename to app/admin/form/Goodsbrowse.php index 71024350e..fd5dc4768 100644 --- a/application/admin/form/Goodsbrowse.php +++ b/app/admin/form/Goodsbrowse.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\admin\form; -use think\Db; +use think\facade\Db; /** * 商品浏览管理动态表格 diff --git a/application/admin/form/Goodscomments.php b/app/admin/form/Goodscomments.php similarity index 98% rename from application/admin/form/Goodscomments.php rename to app/admin/form/Goodscomments.php index 9ddd5e86a..50a102cf5 100644 --- a/application/admin/form/Goodscomments.php +++ b/app/admin/form/Goodscomments.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\admin\form; -use think\Db; +use think\facade\Db; /** * 商品评论动态表格 @@ -275,7 +275,7 @@ class GoodsComments if(!empty($value)) { // 获取关联的商品 id - $ids = Db::name('GoodsComments')->alias('gc')->join(['__GOODS__'=>'g'], 'gc.goods_id=g.id')->where('g.title|g.model', 'like', '%'.$value.'%')->column('gc.id'); + $ids = Db::name('GoodsComments')->alias('gc')->join('goods g', 'gc.goods_id=g.id')->where('g.title|g.model', 'like', '%'.$value.'%')->column('gc.id'); // 避免空条件造成无效的错觉 return empty($ids) ? [0] : $ids; diff --git a/application/admin/form/Goodsfavor.php b/app/admin/form/Goodsfavor.php similarity index 99% rename from application/admin/form/Goodsfavor.php rename to app/admin/form/Goodsfavor.php index cacca698c..c589ebb2f 100644 --- a/application/admin/form/Goodsfavor.php +++ b/app/admin/form/Goodsfavor.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\admin\form; -use think\Db; +use think\facade\Db; /** * 商品收藏管理动态表格 diff --git a/application/admin/form/Goodsparamstemplate.php b/app/admin/form/Goodsparamstemplate.php similarity index 100% rename from application/admin/form/Goodsparamstemplate.php rename to app/admin/form/Goodsparamstemplate.php diff --git a/application/admin/form/Integrallog.php b/app/admin/form/Integrallog.php similarity index 99% rename from application/admin/form/Integrallog.php rename to app/admin/form/Integrallog.php index 2fa7c1fc7..21467d912 100644 --- a/application/admin/form/Integrallog.php +++ b/app/admin/form/Integrallog.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\admin\form; -use think\Db; +use think\facade\Db; /** * 积分日志动态表格 diff --git a/application/admin/form/Link.php b/app/admin/form/Link.php similarity index 100% rename from application/admin/form/Link.php rename to app/admin/form/Link.php diff --git a/application/admin/form/Message.php b/app/admin/form/Message.php similarity index 99% rename from application/admin/form/Message.php rename to app/admin/form/Message.php index 048413fd8..e08e61b24 100644 --- a/application/admin/form/Message.php +++ b/app/admin/form/Message.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\admin\form; -use think\Db; +use think\facade\Db; /** * 消息管理动态表格 @@ -250,7 +250,7 @@ class Message */ public function MessageBusinessTypeList() { - return Db::name('Message')->field('business_type as name')->group('business_type')->select(); + return Db::name('Message')->field('business_type as name')->group('business_type')->select()->toArray(); } } ?> \ No newline at end of file diff --git a/application/admin/form/Navigation.php b/app/admin/form/Navigation.php similarity index 100% rename from application/admin/form/Navigation.php rename to app/admin/form/Navigation.php diff --git a/application/admin/form/Order.php b/app/admin/form/Order.php similarity index 99% rename from application/admin/form/Order.php rename to app/admin/form/Order.php index 476872618..c09cd425c 100644 --- a/application/admin/form/Order.php +++ b/app/admin/form/Order.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\admin\form; -use think\Db; +use think\facade\Db; use app\service\PaymentService; use app\service\ExpressService; @@ -483,7 +483,7 @@ class Order { $where = ['id'=>$wids]; $order_by = 'level desc, id desc'; - $data = Db::name('Warehouse')->field('id,name')->where($where)->order($order_by)->select(); + $data = Db::name('Warehouse')->field('id,name')->where($where)->order($order_by)->select()->toArray(); } return $data; } diff --git a/application/admin/form/Orderaftersale.php b/app/admin/form/Orderaftersale.php similarity index 98% rename from application/admin/form/Orderaftersale.php rename to app/admin/form/Orderaftersale.php index 12974c79e..4a6ccf89e 100644 --- a/application/admin/form/Orderaftersale.php +++ b/app/admin/form/Orderaftersale.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\admin\form; -use think\Db; +use think\facade\Db; /** * 订单售后动态表格 @@ -312,7 +312,7 @@ class OrderAftersale if(!empty($value)) { // 获取订单详情搜索的订单售后 id - $ids = Db::name('OrderAftersale')->alias('oa')->join(['__ORDER_DETAIL__'=>'od'], 'oa.order_detail_id=od.id')->whereOr('od.title|od.model', 'like', '%'.$value.'%')->whereOr('oa.order_no', '=', $value)->column('oa.id'); + $ids = Db::name('OrderAftersale')->alias('oa')->join('order_detail od', 'oa.order_detail_id=od.id')->whereOr('od.title|od.model', 'like', '%'.$value.'%')->whereOr('oa.order_no', '=', $value)->column('oa.id'); // 避免空条件造成无效的错觉 return empty($ids) ? [0] : $ids; diff --git a/application/admin/form/Paylog.php b/app/admin/form/Paylog.php similarity index 99% rename from application/admin/form/Paylog.php rename to app/admin/form/Paylog.php index d971e06df..9992255e9 100644 --- a/application/admin/form/Paylog.php +++ b/app/admin/form/Paylog.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\admin\form; -use think\Db; +use think\facade\Db; use app\service\PayLogService; /** @@ -278,7 +278,7 @@ class PayLog */ public function PayLogBusinessTypeList() { - return Db::name('PayLog')->field('business_type as name')->group('business_type')->select(); + return Db::name('PayLog')->field('business_type as name')->group('business_type')->select()->toArray(); } /** diff --git a/application/admin/form/Payment.php b/app/admin/form/Payment.php similarity index 100% rename from application/admin/form/Payment.php rename to app/admin/form/Payment.php diff --git a/application/admin/form/Payrequestlog.php b/app/admin/form/Payrequestlog.php similarity index 99% rename from application/admin/form/Payrequestlog.php rename to app/admin/form/Payrequestlog.php index 5bb1959a4..dea0c0a4f 100644 --- a/application/admin/form/Payrequestlog.php +++ b/app/admin/form/Payrequestlog.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\admin\form; -use think\Db; +use think\facade\Db; /** * 支付请求日志动态表格 @@ -262,7 +262,7 @@ class PayRequestLog */ public function PayRequestLogFieldWhereList($field) { - return Db::name('PayRequestLog')->field($field.' as name')->group($field)->select(); + return Db::name('PayRequestLog')->field($field.' as name')->group($field)->select()->toArray(); } } ?> \ No newline at end of file diff --git a/application/admin/form/Quicknav.php b/app/admin/form/Quicknav.php similarity index 100% rename from application/admin/form/Quicknav.php rename to app/admin/form/Quicknav.php diff --git a/application/admin/form/Refundlog.php b/app/admin/form/Refundlog.php similarity index 99% rename from application/admin/form/Refundlog.php rename to app/admin/form/Refundlog.php index ebc40f008..772c11597 100644 --- a/application/admin/form/Refundlog.php +++ b/app/admin/form/Refundlog.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\admin\form; -use think\Db; +use think\facade\Db; use app\service\RefundLogService; /** @@ -247,7 +247,7 @@ class RefundLog */ public function RefundLogBusinessTypeList() { - return Db::name('RefundLog')->field('business_type as name')->group('business_type')->select(); + return Db::name('RefundLog')->field('business_type as name')->group('business_type')->select()->toArray(); } } ?> \ No newline at end of file diff --git a/application/admin/form/Role.php b/app/admin/form/Role.php similarity index 100% rename from application/admin/form/Role.php rename to app/admin/form/Role.php diff --git a/application/admin/form/Slide.php b/app/admin/form/Slide.php similarity index 100% rename from application/admin/form/Slide.php rename to app/admin/form/Slide.php diff --git a/application/admin/form/User.php b/app/admin/form/User.php similarity index 100% rename from application/admin/form/User.php rename to app/admin/form/User.php diff --git a/application/admin/form/Useraddress.php b/app/admin/form/Useraddress.php similarity index 99% rename from application/admin/form/Useraddress.php rename to app/admin/form/Useraddress.php index 1f54b3706..2dc008463 100644 --- a/application/admin/form/Useraddress.php +++ b/app/admin/form/Useraddress.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\admin\form; -use think\Db; +use think\facade\Db; use app\service\RegionService; /** diff --git a/application/admin/form/Warehouse.php b/app/admin/form/Warehouse.php similarity index 99% rename from application/admin/form/Warehouse.php rename to app/admin/form/Warehouse.php index 066b3d6ca..8bb29a3e2 100644 --- a/application/admin/form/Warehouse.php +++ b/app/admin/form/Warehouse.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\admin\form; -use think\Db; +use think\facade\Db; use app\service\WarehouseService; use app\service\RegionService; diff --git a/application/admin/form/Warehousegoods.php b/app/admin/form/Warehousegoods.php similarity index 98% rename from application/admin/form/Warehousegoods.php rename to app/admin/form/Warehousegoods.php index cec92c20f..0649a8dec 100644 --- a/application/admin/form/Warehousegoods.php +++ b/app/admin/form/Warehousegoods.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\admin\form; -use think\Db; +use think\facade\Db; use app\service\WarehouseService; use app\service\RegionService; @@ -183,7 +183,7 @@ class WarehouseGoods if(!empty($value)) { // 获取关联的商品 id - $ids = Db::name('WarehouseGoods')->alias('wg')->join(['__GOODS__'=>'g'], 'wg.goods_id=g.id')->where('g.title|g.model', 'like', '%'.$value.'%')->column('wg.id'); + $ids = Db::name('WarehouseGoods')->alias('wg')->join('goods g', 'wg.goods_id=g.id')->where('g.title|g.model', 'like', '%'.$value.'%')->column('wg.id'); // 避免空条件造成无效的错觉 return empty($ids) ? [0] : $ids; diff --git a/application/admin/index.html b/app/admin/index.html similarity index 100% rename from application/admin/index.html rename to app/admin/index.html diff --git a/application/admin/lang/index.html b/app/admin/lang/index.html similarity index 100% rename from application/admin/lang/index.html rename to app/admin/lang/index.html diff --git a/application/admin/lang/zh-cn.php b/app/admin/lang/zh-cn.php similarity index 100% rename from application/admin/lang/zh-cn.php rename to app/admin/lang/zh-cn.php diff --git a/application/admin/view/default/admin/detail.html b/app/admin/view/default/admin/detail.html similarity index 100% rename from application/admin/view/default/admin/detail.html rename to app/admin/view/default/admin/detail.html diff --git a/application/admin/view/default/admin/index.html b/app/admin/view/default/admin/index.html similarity index 88% rename from application/admin/view/default/admin/index.html rename to app/admin/view/default/admin/index.html index 26a100884..6d1574298 100755 --- a/application/admin/view/default/admin/index.html +++ b/app/admin/view/default/admin/index.html @@ -8,7 +8,7 @@

1. admin 账户默认拥有所有权限,不可更改。

-

2. admin 账户不可更改,但是可以在数据表中修改[ {{:config('database.prefix')}}admin ] 字段 username

+

2. admin 账户不可更改,但是可以在数据表中修改[ {{:MyConfig('database.connections.mysql.prefix')}}admin ] 字段 username

{{/if}} {{/block}} diff --git a/application/admin/view/default/admin/login_info.html b/app/admin/view/default/admin/login_info.html similarity index 98% rename from application/admin/view/default/admin/login_info.html rename to app/admin/view/default/admin/login_info.html index bff8582d5..94e0b3c48 100755 --- a/application/admin/view/default/admin/login_info.html +++ b/app/admin/view/default/admin/login_info.html @@ -49,8 +49,8 @@ - - 更换一张 + + 更换一张 @@ -141,8 +141,8 @@
diff --git a/application/admin/view/default/admin/module/operate.html b/app/admin/view/default/admin/module/operate.html similarity index 100% rename from application/admin/view/default/admin/module/operate.html rename to app/admin/view/default/admin/module/operate.html diff --git a/application/admin/view/default/admin/save_info.html b/app/admin/view/default/admin/save_info.html similarity index 100% rename from application/admin/view/default/admin/save_info.html rename to app/admin/view/default/admin/save_info.html diff --git a/application/admin/view/default/agreement/nav.html b/app/admin/view/default/agreement/nav.html similarity index 100% rename from application/admin/view/default/agreement/nav.html rename to app/admin/view/default/agreement/nav.html diff --git a/application/admin/view/default/agreement/privacy.html b/app/admin/view/default/agreement/privacy.html similarity index 100% rename from application/admin/view/default/agreement/privacy.html rename to app/admin/view/default/agreement/privacy.html diff --git a/application/admin/view/default/agreement/register.html b/app/admin/view/default/agreement/register.html similarity index 100% rename from application/admin/view/default/agreement/register.html rename to app/admin/view/default/agreement/register.html diff --git a/application/admin/view/default/answer/detail.html b/app/admin/view/default/answer/detail.html similarity index 100% rename from application/admin/view/default/answer/detail.html rename to app/admin/view/default/answer/detail.html diff --git a/application/admin/view/default/answer/index.html b/app/admin/view/default/answer/index.html similarity index 100% rename from application/admin/view/default/answer/index.html rename to app/admin/view/default/answer/index.html diff --git a/application/admin/view/default/answer/module/content.html b/app/admin/view/default/answer/module/content.html similarity index 100% rename from application/admin/view/default/answer/module/content.html rename to app/admin/view/default/answer/module/content.html diff --git a/application/admin/view/default/answer/module/operate.html b/app/admin/view/default/answer/module/operate.html similarity index 100% rename from application/admin/view/default/answer/module/operate.html rename to app/admin/view/default/answer/module/operate.html diff --git a/application/admin/view/default/answer/module/reply.html b/app/admin/view/default/answer/module/reply.html similarity index 100% rename from application/admin/view/default/answer/module/reply.html rename to app/admin/view/default/answer/module/reply.html diff --git a/application/admin/view/default/answer/save_info.html b/app/admin/view/default/answer/save_info.html similarity index 100% rename from application/admin/view/default/answer/save_info.html rename to app/admin/view/default/answer/save_info.html diff --git a/application/admin/view/default/appcenternav/detail.html b/app/admin/view/default/appcenternav/detail.html similarity index 100% rename from application/admin/view/default/appcenternav/detail.html rename to app/admin/view/default/appcenternav/detail.html diff --git a/application/admin/view/default/appcenternav/index.html b/app/admin/view/default/appcenternav/index.html similarity index 100% rename from application/admin/view/default/appcenternav/index.html rename to app/admin/view/default/appcenternav/index.html diff --git a/application/admin/view/default/appcenternav/module/images.html b/app/admin/view/default/appcenternav/module/images.html similarity index 100% rename from application/admin/view/default/appcenternav/module/images.html rename to app/admin/view/default/appcenternav/module/images.html diff --git a/application/admin/view/default/appcenternav/module/operate.html b/app/admin/view/default/appcenternav/module/operate.html similarity index 100% rename from application/admin/view/default/appcenternav/module/operate.html rename to app/admin/view/default/appcenternav/module/operate.html diff --git a/application/admin/view/default/appcenternav/save_info.html b/app/admin/view/default/appcenternav/save_info.html similarity index 100% rename from application/admin/view/default/appcenternav/save_info.html rename to app/admin/view/default/appcenternav/save_info.html diff --git a/application/admin/view/default/appconfig/app.html b/app/admin/view/default/appconfig/app.html similarity index 100% rename from application/admin/view/default/appconfig/app.html rename to app/admin/view/default/appconfig/app.html diff --git a/application/admin/view/default/appconfig/base.html b/app/admin/view/default/appconfig/base.html similarity index 100% rename from application/admin/view/default/appconfig/base.html rename to app/admin/view/default/appconfig/base.html diff --git a/application/admin/view/default/appconfig/nav.html b/app/admin/view/default/appconfig/nav.html similarity index 100% rename from application/admin/view/default/appconfig/nav.html rename to app/admin/view/default/appconfig/nav.html diff --git a/application/admin/view/default/apphomenav/detail.html b/app/admin/view/default/apphomenav/detail.html similarity index 100% rename from application/admin/view/default/apphomenav/detail.html rename to app/admin/view/default/apphomenav/detail.html diff --git a/application/admin/view/default/apphomenav/index.html b/app/admin/view/default/apphomenav/index.html similarity index 100% rename from application/admin/view/default/apphomenav/index.html rename to app/admin/view/default/apphomenav/index.html diff --git a/application/admin/view/default/apphomenav/module/images.html b/app/admin/view/default/apphomenav/module/images.html similarity index 100% rename from application/admin/view/default/apphomenav/module/images.html rename to app/admin/view/default/apphomenav/module/images.html diff --git a/application/admin/view/default/apphomenav/module/operate.html b/app/admin/view/default/apphomenav/module/operate.html similarity index 100% rename from application/admin/view/default/apphomenav/module/operate.html rename to app/admin/view/default/apphomenav/module/operate.html diff --git a/application/admin/view/default/apphomenav/save_info.html b/app/admin/view/default/apphomenav/save_info.html similarity index 100% rename from application/admin/view/default/apphomenav/save_info.html rename to app/admin/view/default/apphomenav/save_info.html diff --git a/application/admin/view/default/appmini/base_nav.html b/app/admin/view/default/appmini/base_nav.html similarity index 100% rename from application/admin/view/default/appmini/base_nav.html rename to app/admin/view/default/appmini/base_nav.html diff --git a/application/admin/view/default/appmini/config.html b/app/admin/view/default/appmini/config.html similarity index 100% rename from application/admin/view/default/appmini/config.html rename to app/admin/view/default/appmini/config.html diff --git a/application/admin/view/default/appmini/index.html b/app/admin/view/default/appmini/index.html similarity index 100% rename from application/admin/view/default/appmini/index.html rename to app/admin/view/default/appmini/index.html diff --git a/application/admin/view/default/appmini/module/operate.html b/app/admin/view/default/appmini/module/operate.html similarity index 100% rename from application/admin/view/default/appmini/module/operate.html rename to app/admin/view/default/appmini/module/operate.html diff --git a/application/admin/view/default/appmini/nav.html b/app/admin/view/default/appmini/nav.html similarity index 100% rename from application/admin/view/default/appmini/nav.html rename to app/admin/view/default/appmini/nav.html diff --git a/application/admin/view/default/appmini/package.html b/app/admin/view/default/appmini/package.html similarity index 97% rename from application/admin/view/default/appmini/package.html rename to app/admin/view/default/appmini/package.html index 2b3f79cfd..fab893a64 100755 --- a/application/admin/view/default/appmini/package.html +++ b/app/admin/view/default/appmini/package.html @@ -12,7 +12,7 @@

生成源码包采用当前设置的默认主题进行生成zip压缩包

- {{if config('shopxo.is_develop') eq true}} + {{if MyConfig('shopxo.is_develop') eq true}}

当前为开发模式

1. 发布小程序必须采用 https 协议,上线需确认 app.js 中 request_url 参数值是否正确。

2. 发布小程序,建议关闭开发者模式、从正式环境重新生成小程序下载使用开发者工具上传审核。

diff --git a/application/admin/view/default/appmini/upload.html b/app/admin/view/default/appmini/upload.html similarity index 100% rename from application/admin/view/default/appmini/upload.html rename to app/admin/view/default/appmini/upload.html diff --git a/application/admin/view/default/article/detail.html b/app/admin/view/default/article/detail.html similarity index 100% rename from application/admin/view/default/article/detail.html rename to app/admin/view/default/article/detail.html diff --git a/application/admin/view/default/article/index.html b/app/admin/view/default/article/index.html similarity index 100% rename from application/admin/view/default/article/index.html rename to app/admin/view/default/article/index.html diff --git a/application/admin/view/default/article/module/info.html b/app/admin/view/default/article/module/info.html similarity index 100% rename from application/admin/view/default/article/module/info.html rename to app/admin/view/default/article/module/info.html diff --git a/application/admin/view/default/article/module/operate.html b/app/admin/view/default/article/module/operate.html similarity index 100% rename from application/admin/view/default/article/module/operate.html rename to app/admin/view/default/article/module/operate.html diff --git a/application/admin/view/default/article/save_info.html b/app/admin/view/default/article/save_info.html similarity index 100% rename from application/admin/view/default/article/save_info.html rename to app/admin/view/default/article/save_info.html diff --git a/application/admin/view/default/articlecategory/index.html b/app/admin/view/default/articlecategory/index.html similarity index 100% rename from application/admin/view/default/articlecategory/index.html rename to app/admin/view/default/articlecategory/index.html diff --git a/application/admin/view/default/brand/detail.html b/app/admin/view/default/brand/detail.html similarity index 100% rename from application/admin/view/default/brand/detail.html rename to app/admin/view/default/brand/detail.html diff --git a/application/admin/view/default/brand/index.html b/app/admin/view/default/brand/index.html similarity index 100% rename from application/admin/view/default/brand/index.html rename to app/admin/view/default/brand/index.html diff --git a/application/admin/view/default/brand/module/logo.html b/app/admin/view/default/brand/module/logo.html similarity index 100% rename from application/admin/view/default/brand/module/logo.html rename to app/admin/view/default/brand/module/logo.html diff --git a/application/admin/view/default/brand/module/operate.html b/app/admin/view/default/brand/module/operate.html similarity index 100% rename from application/admin/view/default/brand/module/operate.html rename to app/admin/view/default/brand/module/operate.html diff --git a/application/admin/view/default/brand/module/url.html b/app/admin/view/default/brand/module/url.html similarity index 100% rename from application/admin/view/default/brand/module/url.html rename to app/admin/view/default/brand/module/url.html diff --git a/application/admin/view/default/brand/save_info.html b/app/admin/view/default/brand/save_info.html similarity index 100% rename from application/admin/view/default/brand/save_info.html rename to app/admin/view/default/brand/save_info.html diff --git a/application/admin/view/default/brandcategory/index.html b/app/admin/view/default/brandcategory/index.html similarity index 100% rename from application/admin/view/default/brandcategory/index.html rename to app/admin/view/default/brandcategory/index.html diff --git a/application/admin/view/default/cache/index.html b/app/admin/view/default/cache/index.html similarity index 100% rename from application/admin/view/default/cache/index.html rename to app/admin/view/default/cache/index.html diff --git a/application/admin/view/default/config/index.html b/app/admin/view/default/config/index.html similarity index 100% rename from application/admin/view/default/config/index.html rename to app/admin/view/default/config/index.html diff --git a/application/admin/view/default/config/store.html b/app/admin/view/default/config/store.html similarity index 100% rename from application/admin/view/default/config/store.html rename to app/admin/view/default/config/store.html diff --git a/application/admin/view/default/customview/detail.html b/app/admin/view/default/customview/detail.html similarity index 100% rename from application/admin/view/default/customview/detail.html rename to app/admin/view/default/customview/detail.html diff --git a/application/admin/view/default/customview/index.html b/app/admin/view/default/customview/index.html similarity index 100% rename from application/admin/view/default/customview/index.html rename to app/admin/view/default/customview/index.html diff --git a/application/admin/view/default/customview/module/info.html b/app/admin/view/default/customview/module/info.html similarity index 100% rename from application/admin/view/default/customview/module/info.html rename to app/admin/view/default/customview/module/info.html diff --git a/application/admin/view/default/customview/module/operate.html b/app/admin/view/default/customview/module/operate.html similarity index 100% rename from application/admin/view/default/customview/module/operate.html rename to app/admin/view/default/customview/module/operate.html diff --git a/application/admin/view/default/customview/save_info.html b/app/admin/view/default/customview/save_info.html similarity index 100% rename from application/admin/view/default/customview/save_info.html rename to app/admin/view/default/customview/save_info.html diff --git a/application/admin/view/default/design/index.html b/app/admin/view/default/design/index.html similarity index 100% rename from application/admin/view/default/design/index.html rename to app/admin/view/default/design/index.html diff --git a/application/admin/view/default/design/module/info.html b/app/admin/view/default/design/module/info.html similarity index 100% rename from application/admin/view/default/design/module/info.html rename to app/admin/view/default/design/module/info.html diff --git a/application/admin/view/default/design/module/operate.html b/app/admin/view/default/design/module/operate.html similarity index 100% rename from application/admin/view/default/design/module/operate.html rename to app/admin/view/default/design/module/operate.html diff --git a/application/admin/view/default/design/popup_saveinfo.html b/app/admin/view/default/design/popup_saveinfo.html similarity index 100% rename from application/admin/view/default/design/popup_saveinfo.html rename to app/admin/view/default/design/popup_saveinfo.html diff --git a/application/admin/view/default/design/save_info.html b/app/admin/view/default/design/save_info.html similarity index 100% rename from application/admin/view/default/design/save_info.html rename to app/admin/view/default/design/save_info.html diff --git a/application/admin/view/default/email/index.html b/app/admin/view/default/email/index.html similarity index 100% rename from application/admin/view/default/email/index.html rename to app/admin/view/default/email/index.html diff --git a/application/admin/view/default/email/message.html b/app/admin/view/default/email/message.html similarity index 100% rename from application/admin/view/default/email/message.html rename to app/admin/view/default/email/message.html diff --git a/application/admin/view/default/email/nav.html b/app/admin/view/default/email/nav.html similarity index 100% rename from application/admin/view/default/email/nav.html rename to app/admin/view/default/email/nav.html diff --git a/application/admin/view/default/express/index.html b/app/admin/view/default/express/index.html similarity index 100% rename from application/admin/view/default/express/index.html rename to app/admin/view/default/express/index.html diff --git a/application/admin/view/default/goods/detail.html b/app/admin/view/default/goods/detail.html similarity index 100% rename from application/admin/view/default/goods/detail.html rename to app/admin/view/default/goods/detail.html diff --git a/application/admin/view/default/goods/index.html b/app/admin/view/default/goods/index.html similarity index 100% rename from application/admin/view/default/goods/index.html rename to app/admin/view/default/goods/index.html diff --git a/application/admin/view/default/goods/module/info.html b/app/admin/view/default/goods/module/info.html similarity index 100% rename from application/admin/view/default/goods/module/info.html rename to app/admin/view/default/goods/module/info.html diff --git a/application/admin/view/default/goods/module/operate.html b/app/admin/view/default/goods/module/operate.html similarity index 100% rename from application/admin/view/default/goods/module/operate.html rename to app/admin/view/default/goods/module/operate.html diff --git a/application/admin/view/default/goods/save_info.html b/app/admin/view/default/goods/save_info.html similarity index 100% rename from application/admin/view/default/goods/save_info.html rename to app/admin/view/default/goods/save_info.html diff --git a/application/admin/view/default/goods/spec.html b/app/admin/view/default/goods/spec.html similarity index 100% rename from application/admin/view/default/goods/spec.html rename to app/admin/view/default/goods/spec.html diff --git a/application/admin/view/default/goods/spec_extends.html b/app/admin/view/default/goods/spec_extends.html similarity index 100% rename from application/admin/view/default/goods/spec_extends.html rename to app/admin/view/default/goods/spec_extends.html diff --git a/application/admin/view/default/goodsbrowse/detail.html b/app/admin/view/default/goodsbrowse/detail.html similarity index 100% rename from application/admin/view/default/goodsbrowse/detail.html rename to app/admin/view/default/goodsbrowse/detail.html diff --git a/application/admin/view/default/goodsbrowse/index.html b/app/admin/view/default/goodsbrowse/index.html similarity index 100% rename from application/admin/view/default/goodsbrowse/index.html rename to app/admin/view/default/goodsbrowse/index.html diff --git a/application/admin/view/default/goodsbrowse/module/goods.html b/app/admin/view/default/goodsbrowse/module/goods.html similarity index 100% rename from application/admin/view/default/goodsbrowse/module/goods.html rename to app/admin/view/default/goodsbrowse/module/goods.html diff --git a/application/admin/view/default/goodsbrowse/module/operate.html b/app/admin/view/default/goodsbrowse/module/operate.html similarity index 100% rename from application/admin/view/default/goodsbrowse/module/operate.html rename to app/admin/view/default/goodsbrowse/module/operate.html diff --git a/application/admin/view/default/goodscategory/index.html b/app/admin/view/default/goodscategory/index.html similarity index 100% rename from application/admin/view/default/goodscategory/index.html rename to app/admin/view/default/goodscategory/index.html diff --git a/application/admin/view/default/goodscomments/detail.html b/app/admin/view/default/goodscomments/detail.html similarity index 100% rename from application/admin/view/default/goodscomments/detail.html rename to app/admin/view/default/goodscomments/detail.html diff --git a/application/admin/view/default/goodscomments/index.html b/app/admin/view/default/goodscomments/index.html similarity index 100% rename from application/admin/view/default/goodscomments/index.html rename to app/admin/view/default/goodscomments/index.html diff --git a/application/admin/view/default/goodscomments/module/content.html b/app/admin/view/default/goodscomments/module/content.html similarity index 100% rename from application/admin/view/default/goodscomments/module/content.html rename to app/admin/view/default/goodscomments/module/content.html diff --git a/application/admin/view/default/goodscomments/module/goods.html b/app/admin/view/default/goodscomments/module/goods.html similarity index 100% rename from application/admin/view/default/goodscomments/module/goods.html rename to app/admin/view/default/goodscomments/module/goods.html diff --git a/application/admin/view/default/goodscomments/module/images.html b/app/admin/view/default/goodscomments/module/images.html similarity index 100% rename from application/admin/view/default/goodscomments/module/images.html rename to app/admin/view/default/goodscomments/module/images.html diff --git a/application/admin/view/default/goodscomments/module/operate.html b/app/admin/view/default/goodscomments/module/operate.html similarity index 100% rename from application/admin/view/default/goodscomments/module/operate.html rename to app/admin/view/default/goodscomments/module/operate.html diff --git a/application/admin/view/default/goodscomments/module/rating.html b/app/admin/view/default/goodscomments/module/rating.html similarity index 100% rename from application/admin/view/default/goodscomments/module/rating.html rename to app/admin/view/default/goodscomments/module/rating.html diff --git a/application/admin/view/default/goodscomments/module/reply.html b/app/admin/view/default/goodscomments/module/reply.html similarity index 100% rename from application/admin/view/default/goodscomments/module/reply.html rename to app/admin/view/default/goodscomments/module/reply.html diff --git a/application/admin/view/default/goodscomments/save_info.html b/app/admin/view/default/goodscomments/save_info.html similarity index 100% rename from application/admin/view/default/goodscomments/save_info.html rename to app/admin/view/default/goodscomments/save_info.html diff --git a/application/admin/view/default/goodsfavor/detail.html b/app/admin/view/default/goodsfavor/detail.html similarity index 100% rename from application/admin/view/default/goodsfavor/detail.html rename to app/admin/view/default/goodsfavor/detail.html diff --git a/application/admin/view/default/goodsfavor/index.html b/app/admin/view/default/goodsfavor/index.html similarity index 100% rename from application/admin/view/default/goodsfavor/index.html rename to app/admin/view/default/goodsfavor/index.html diff --git a/application/admin/view/default/goodsfavor/module/goods.html b/app/admin/view/default/goodsfavor/module/goods.html similarity index 100% rename from application/admin/view/default/goodsfavor/module/goods.html rename to app/admin/view/default/goodsfavor/module/goods.html diff --git a/application/admin/view/default/goodsfavor/module/operate.html b/app/admin/view/default/goodsfavor/module/operate.html similarity index 100% rename from application/admin/view/default/goodsfavor/module/operate.html rename to app/admin/view/default/goodsfavor/module/operate.html diff --git a/application/admin/view/default/goodsparamstemplate/detail.html b/app/admin/view/default/goodsparamstemplate/detail.html similarity index 100% rename from application/admin/view/default/goodsparamstemplate/detail.html rename to app/admin/view/default/goodsparamstemplate/detail.html diff --git a/application/admin/view/default/goodsparamstemplate/index.html b/app/admin/view/default/goodsparamstemplate/index.html similarity index 100% rename from application/admin/view/default/goodsparamstemplate/index.html rename to app/admin/view/default/goodsparamstemplate/index.html diff --git a/application/admin/view/default/goodsparamstemplate/module/operate.html b/app/admin/view/default/goodsparamstemplate/module/operate.html similarity index 100% rename from application/admin/view/default/goodsparamstemplate/module/operate.html rename to app/admin/view/default/goodsparamstemplate/module/operate.html diff --git a/application/admin/view/default/goodsparamstemplate/save_info.html b/app/admin/view/default/goodsparamstemplate/save_info.html similarity index 100% rename from application/admin/view/default/goodsparamstemplate/save_info.html rename to app/admin/view/default/goodsparamstemplate/save_info.html diff --git a/application/admin/view/default/index.html b/app/admin/view/default/index.html similarity index 100% rename from application/admin/view/default/index.html rename to app/admin/view/default/index.html diff --git a/application/admin/view/default/index/index.html b/app/admin/view/default/index/index.html similarity index 100% rename from application/admin/view/default/index/index.html rename to app/admin/view/default/index/index.html diff --git a/application/admin/view/default/index/init.html b/app/admin/view/default/index/init.html similarity index 100% rename from application/admin/view/default/index/init.html rename to app/admin/view/default/index/init.html diff --git a/application/admin/view/default/integrallog/detail.html b/app/admin/view/default/integrallog/detail.html similarity index 100% rename from application/admin/view/default/integrallog/detail.html rename to app/admin/view/default/integrallog/detail.html diff --git a/application/admin/view/default/integrallog/index.html b/app/admin/view/default/integrallog/index.html similarity index 100% rename from application/admin/view/default/integrallog/index.html rename to app/admin/view/default/integrallog/index.html diff --git a/application/admin/view/default/integrallog/module/operate.html b/app/admin/view/default/integrallog/module/operate.html similarity index 100% rename from application/admin/view/default/integrallog/module/operate.html rename to app/admin/view/default/integrallog/module/operate.html diff --git a/application/admin/view/default/lib/enable.html b/app/admin/view/default/lib/enable.html similarity index 100% rename from application/admin/view/default/lib/enable.html rename to app/admin/view/default/lib/enable.html diff --git a/application/admin/view/default/lib/excel_win_html.html b/app/admin/view/default/lib/excel_win_html.html similarity index 100% rename from application/admin/view/default/lib/excel_win_html.html rename to app/admin/view/default/lib/excel_win_html.html diff --git a/application/admin/view/default/lib/excel_win_js.html b/app/admin/view/default/lib/excel_win_js.html similarity index 100% rename from application/admin/view/default/lib/excel_win_js.html rename to app/admin/view/default/lib/excel_win_js.html diff --git a/application/admin/view/default/lib/gender.html b/app/admin/view/default/lib/gender.html similarity index 100% rename from application/admin/view/default/lib/gender.html rename to app/admin/view/default/lib/gender.html diff --git a/application/admin/view/default/lib/index.html b/app/admin/view/default/lib/index.html similarity index 100% rename from application/admin/view/default/lib/index.html rename to app/admin/view/default/lib/index.html diff --git a/application/admin/view/default/lib/is_footer.html b/app/admin/view/default/lib/is_footer.html similarity index 100% rename from application/admin/view/default/lib/is_footer.html rename to app/admin/view/default/lib/is_footer.html diff --git a/application/admin/view/default/lib/is_full_screen.html b/app/admin/view/default/lib/is_full_screen.html similarity index 100% rename from application/admin/view/default/lib/is_full_screen.html rename to app/admin/view/default/lib/is_full_screen.html diff --git a/application/admin/view/default/lib/is_header.html b/app/admin/view/default/lib/is_header.html similarity index 100% rename from application/admin/view/default/lib/is_header.html rename to app/admin/view/default/lib/is_header.html diff --git a/application/admin/view/default/lib/is_new_window_open.html b/app/admin/view/default/lib/is_new_window_open.html similarity index 100% rename from application/admin/view/default/lib/is_new_window_open.html rename to app/admin/view/default/lib/is_new_window_open.html diff --git a/application/admin/view/default/lib/is_show.html b/app/admin/view/default/lib/is_show.html similarity index 100% rename from application/admin/view/default/lib/is_show.html rename to app/admin/view/default/lib/is_show.html diff --git a/application/admin/view/default/lib/module/category_brand.html b/app/admin/view/default/lib/module/category_brand.html similarity index 100% rename from application/admin/view/default/lib/module/category_brand.html rename to app/admin/view/default/lib/module/category_brand.html diff --git a/application/admin/view/default/lib/module/goods_category.html b/app/admin/view/default/lib/module/goods_category.html similarity index 100% rename from application/admin/view/default/lib/module/goods_category.html rename to app/admin/view/default/lib/module/goods_category.html diff --git a/application/admin/view/default/lib/module/user.html b/app/admin/view/default/lib/module/user.html similarity index 100% rename from application/admin/view/default/lib/module/user.html rename to app/admin/view/default/lib/module/user.html diff --git a/application/admin/view/default/lib/region_linkage.html b/app/admin/view/default/lib/region_linkage.html similarity index 100% rename from application/admin/view/default/lib/region_linkage.html rename to app/admin/view/default/lib/region_linkage.html diff --git a/application/admin/view/default/lib/seo.html b/app/admin/view/default/lib/seo.html similarity index 100% rename from application/admin/view/default/lib/seo.html rename to app/admin/view/default/lib/seo.html diff --git a/application/admin/view/default/lib/user_status.html b/app/admin/view/default/lib/user_status.html similarity index 100% rename from application/admin/view/default/lib/user_status.html rename to app/admin/view/default/lib/user_status.html diff --git a/application/admin/view/default/link/detail.html b/app/admin/view/default/link/detail.html similarity index 100% rename from application/admin/view/default/link/detail.html rename to app/admin/view/default/link/detail.html diff --git a/application/admin/view/default/link/index.html b/app/admin/view/default/link/index.html similarity index 100% rename from application/admin/view/default/link/index.html rename to app/admin/view/default/link/index.html diff --git a/application/admin/view/default/link/module/info.html b/app/admin/view/default/link/module/info.html similarity index 100% rename from application/admin/view/default/link/module/info.html rename to app/admin/view/default/link/module/info.html diff --git a/application/admin/view/default/link/module/operate.html b/app/admin/view/default/link/module/operate.html similarity index 100% rename from application/admin/view/default/link/module/operate.html rename to app/admin/view/default/link/module/operate.html diff --git a/application/admin/view/default/link/module/url.html b/app/admin/view/default/link/module/url.html similarity index 100% rename from application/admin/view/default/link/module/url.html rename to app/admin/view/default/link/module/url.html diff --git a/application/admin/view/default/message/detail.html b/app/admin/view/default/message/detail.html similarity index 100% rename from application/admin/view/default/message/detail.html rename to app/admin/view/default/message/detail.html diff --git a/application/admin/view/default/message/index.html b/app/admin/view/default/message/index.html similarity index 100% rename from application/admin/view/default/message/index.html rename to app/admin/view/default/message/index.html diff --git a/application/admin/view/default/message/module/operate.html b/app/admin/view/default/message/module/operate.html similarity index 100% rename from application/admin/view/default/message/module/operate.html rename to app/admin/view/default/message/module/operate.html diff --git a/application/admin/view/default/navigation/index.html b/app/admin/view/default/navigation/index.html similarity index 100% rename from application/admin/view/default/navigation/index.html rename to app/admin/view/default/navigation/index.html diff --git a/application/admin/view/default/navigation/module/info.html b/app/admin/view/default/navigation/module/info.html similarity index 100% rename from application/admin/view/default/navigation/module/info.html rename to app/admin/view/default/navigation/module/info.html diff --git a/application/admin/view/default/navigation/module/operate.html b/app/admin/view/default/navigation/module/operate.html similarity index 100% rename from application/admin/view/default/navigation/module/operate.html rename to app/admin/view/default/navigation/module/operate.html diff --git a/application/admin/view/default/navigation/nav.html b/app/admin/view/default/navigation/nav.html similarity index 100% rename from application/admin/view/default/navigation/nav.html rename to app/admin/view/default/navigation/nav.html diff --git a/application/admin/view/default/order/detail.html b/app/admin/view/default/order/detail.html similarity index 100% rename from application/admin/view/default/order/detail.html rename to app/admin/view/default/order/detail.html diff --git a/application/admin/view/default/order/index.html b/app/admin/view/default/order/index.html similarity index 100% rename from application/admin/view/default/order/index.html rename to app/admin/view/default/order/index.html diff --git a/application/admin/view/default/order/module/address.html b/app/admin/view/default/order/module/address.html similarity index 100% rename from application/admin/view/default/order/module/address.html rename to app/admin/view/default/order/module/address.html diff --git a/application/admin/view/default/order/module/aftersale.html b/app/admin/view/default/order/module/aftersale.html similarity index 100% rename from application/admin/view/default/order/module/aftersale.html rename to app/admin/view/default/order/module/aftersale.html diff --git a/application/admin/view/default/order/module/extension.html b/app/admin/view/default/order/module/extension.html similarity index 100% rename from application/admin/view/default/order/module/extension.html rename to app/admin/view/default/order/module/extension.html diff --git a/application/admin/view/default/order/module/goods.html b/app/admin/view/default/order/module/goods.html similarity index 92% rename from application/admin/view/default/order/module/goods.html rename to app/admin/view/default/order/module/goods.html index f845efe69..313dba4f9 100644 --- a/application/admin/view/default/order/module/goods.html +++ b/app/admin/view/default/order/module/goods.html @@ -8,7 +8,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_admin_order_list_base_top'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$module_data]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$module_data]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -63,7 +63,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_admin_order_list_base_nav_bottom'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$module_data]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$module_data]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -86,7 +86,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_admin_order_list_base_goods_top'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$module_data]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$module_data]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -135,7 +135,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_admin_order_list_base_goods_bottom'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$module_data]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$module_data]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -160,7 +160,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_admin_order_list_base_bottom'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$module_data]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$module_data]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) diff --git a/application/admin/view/default/order/module/is_comments.html b/app/admin/view/default/order/module/is_comments.html similarity index 100% rename from application/admin/view/default/order/module/is_comments.html rename to app/admin/view/default/order/module/is_comments.html diff --git a/application/admin/view/default/order/module/operate.html b/app/admin/view/default/order/module/operate.html similarity index 100% rename from application/admin/view/default/order/module/operate.html rename to app/admin/view/default/order/module/operate.html diff --git a/application/admin/view/default/order/module/pay_status.html b/app/admin/view/default/order/module/pay_status.html similarity index 100% rename from application/admin/view/default/order/module/pay_status.html rename to app/admin/view/default/order/module/pay_status.html diff --git a/application/admin/view/default/order/module/status.html b/app/admin/view/default/order/module/status.html similarity index 100% rename from application/admin/view/default/order/module/status.html rename to app/admin/view/default/order/module/status.html diff --git a/application/admin/view/default/order/module/take.html b/app/admin/view/default/order/module/take.html similarity index 100% rename from application/admin/view/default/order/module/take.html rename to app/admin/view/default/order/module/take.html diff --git a/application/admin/view/default/orderaftersale/detail.html b/app/admin/view/default/orderaftersale/detail.html similarity index 100% rename from application/admin/view/default/orderaftersale/detail.html rename to app/admin/view/default/orderaftersale/detail.html diff --git a/application/admin/view/default/orderaftersale/index.html b/app/admin/view/default/orderaftersale/index.html similarity index 100% rename from application/admin/view/default/orderaftersale/index.html rename to app/admin/view/default/orderaftersale/index.html diff --git a/application/admin/view/default/orderaftersale/module/goods.html b/app/admin/view/default/orderaftersale/module/goods.html similarity index 91% rename from application/admin/view/default/orderaftersale/module/goods.html rename to app/admin/view/default/orderaftersale/module/goods.html index a51050c5a..dfca33ab2 100644 --- a/application/admin/view/default/orderaftersale/module/goods.html +++ b/app/admin/view/default/orderaftersale/module/goods.html @@ -8,7 +8,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_admin_orderaftersale_list_base_top'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$module_data]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$module_data]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -35,7 +35,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_admin_orderaftersale_list_base_goods_top'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$module_data]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$module_data]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -81,7 +81,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_admin_orderaftersale_list_base_bottom'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$module_data]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$module_data]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) diff --git a/application/admin/view/default/orderaftersale/module/operate.html b/app/admin/view/default/orderaftersale/module/operate.html similarity index 100% rename from application/admin/view/default/orderaftersale/module/operate.html rename to app/admin/view/default/orderaftersale/module/operate.html diff --git a/application/admin/view/default/orderaftersale/module/voucher.html b/app/admin/view/default/orderaftersale/module/voucher.html similarity index 100% rename from application/admin/view/default/orderaftersale/module/voucher.html rename to app/admin/view/default/orderaftersale/module/voucher.html diff --git a/application/admin/view/default/packageinstall/index.html b/app/admin/view/default/packageinstall/index.html similarity index 100% rename from application/admin/view/default/packageinstall/index.html rename to app/admin/view/default/packageinstall/index.html diff --git a/application/admin/view/default/paylog/detail.html b/app/admin/view/default/paylog/detail.html similarity index 100% rename from application/admin/view/default/paylog/detail.html rename to app/admin/view/default/paylog/detail.html diff --git a/application/admin/view/default/paylog/index.html b/app/admin/view/default/paylog/index.html similarity index 100% rename from application/admin/view/default/paylog/index.html rename to app/admin/view/default/paylog/index.html diff --git a/application/admin/view/default/paylog/module/business_list.html b/app/admin/view/default/paylog/module/business_list.html similarity index 100% rename from application/admin/view/default/paylog/module/business_list.html rename to app/admin/view/default/paylog/module/business_list.html diff --git a/application/admin/view/default/paylog/module/operate.html b/app/admin/view/default/paylog/module/operate.html similarity index 100% rename from application/admin/view/default/paylog/module/operate.html rename to app/admin/view/default/paylog/module/operate.html diff --git a/application/admin/view/default/paylog/module/payment.html b/app/admin/view/default/paylog/module/payment.html similarity index 100% rename from application/admin/view/default/paylog/module/payment.html rename to app/admin/view/default/paylog/module/payment.html diff --git a/application/admin/view/default/payment/index.html b/app/admin/view/default/payment/index.html similarity index 100% rename from application/admin/view/default/payment/index.html rename to app/admin/view/default/payment/index.html diff --git a/application/admin/view/default/payment/module/apply_terminal.html b/app/admin/view/default/payment/module/apply_terminal.html similarity index 100% rename from application/admin/view/default/payment/module/apply_terminal.html rename to app/admin/view/default/payment/module/apply_terminal.html diff --git a/application/admin/view/default/payment/module/author.html b/app/admin/view/default/payment/module/author.html similarity index 100% rename from application/admin/view/default/payment/module/author.html rename to app/admin/view/default/payment/module/author.html diff --git a/application/admin/view/default/payment/module/enable.html b/app/admin/view/default/payment/module/enable.html similarity index 100% rename from application/admin/view/default/payment/module/enable.html rename to app/admin/view/default/payment/module/enable.html diff --git a/application/admin/view/default/payment/module/logo.html b/app/admin/view/default/payment/module/logo.html similarity index 100% rename from application/admin/view/default/payment/module/logo.html rename to app/admin/view/default/payment/module/logo.html diff --git a/application/admin/view/default/payment/module/open_user.html b/app/admin/view/default/payment/module/open_user.html similarity index 100% rename from application/admin/view/default/payment/module/open_user.html rename to app/admin/view/default/payment/module/open_user.html diff --git a/application/admin/view/default/payment/module/operate.html b/app/admin/view/default/payment/module/operate.html similarity index 100% rename from application/admin/view/default/payment/module/operate.html rename to app/admin/view/default/payment/module/operate.html diff --git a/application/admin/view/default/payment/save_info.html b/app/admin/view/default/payment/save_info.html similarity index 100% rename from application/admin/view/default/payment/save_info.html rename to app/admin/view/default/payment/save_info.html diff --git a/application/admin/view/default/payrequestlog/detail.html b/app/admin/view/default/payrequestlog/detail.html similarity index 100% rename from application/admin/view/default/payrequestlog/detail.html rename to app/admin/view/default/payrequestlog/detail.html diff --git a/application/admin/view/default/payrequestlog/index.html b/app/admin/view/default/payrequestlog/index.html similarity index 100% rename from application/admin/view/default/payrequestlog/index.html rename to app/admin/view/default/payrequestlog/index.html diff --git a/application/admin/view/default/payrequestlog/module/business_handle.html b/app/admin/view/default/payrequestlog/module/business_handle.html similarity index 100% rename from application/admin/view/default/payrequestlog/module/business_handle.html rename to app/admin/view/default/payrequestlog/module/business_handle.html diff --git a/application/admin/view/default/payrequestlog/module/operate.html b/app/admin/view/default/payrequestlog/module/operate.html similarity index 100% rename from application/admin/view/default/payrequestlog/module/operate.html rename to app/admin/view/default/payrequestlog/module/operate.html diff --git a/application/admin/view/default/payrequestlog/module/request_params.html b/app/admin/view/default/payrequestlog/module/request_params.html similarity index 100% rename from application/admin/view/default/payrequestlog/module/request_params.html rename to app/admin/view/default/payrequestlog/module/request_params.html diff --git a/application/admin/view/default/payrequestlog/module/response_data.html b/app/admin/view/default/payrequestlog/module/response_data.html similarity index 100% rename from application/admin/view/default/payrequestlog/module/response_data.html rename to app/admin/view/default/payrequestlog/module/response_data.html diff --git a/application/admin/view/default/plugins/index.html b/app/admin/view/default/plugins/index.html similarity index 100% rename from application/admin/view/default/plugins/index.html rename to app/admin/view/default/plugins/index.html diff --git a/application/admin/view/default/pluginsadmin/first_step.html b/app/admin/view/default/pluginsadmin/first_step.html similarity index 100% rename from application/admin/view/default/pluginsadmin/first_step.html rename to app/admin/view/default/pluginsadmin/first_step.html diff --git a/application/admin/view/default/pluginsadmin/index.html b/app/admin/view/default/pluginsadmin/index.html similarity index 100% rename from application/admin/view/default/pluginsadmin/index.html rename to app/admin/view/default/pluginsadmin/index.html diff --git a/application/admin/view/default/pluginsadmin/nav.html b/app/admin/view/default/pluginsadmin/nav.html similarity index 100% rename from application/admin/view/default/pluginsadmin/nav.html rename to app/admin/view/default/pluginsadmin/nav.html diff --git a/application/admin/view/default/pluginsadmin/save_info.html b/app/admin/view/default/pluginsadmin/save_info.html similarity index 100% rename from application/admin/view/default/pluginsadmin/save_info.html rename to app/admin/view/default/pluginsadmin/save_info.html diff --git a/application/admin/view/default/pluginsadmin/upload.html b/app/admin/view/default/pluginsadmin/upload.html similarity index 100% rename from application/admin/view/default/pluginsadmin/upload.html rename to app/admin/view/default/pluginsadmin/upload.html diff --git a/application/admin/view/default/power/index.html b/app/admin/view/default/power/index.html similarity index 98% rename from application/admin/view/default/power/index.html rename to app/admin/view/default/power/index.html index d4f8fee92..a81f749ab 100755 --- a/application/admin/view/default/power/index.html +++ b/app/admin/view/default/power/index.html @@ -8,7 +8,7 @@

1. 非专业技术人员请勿操作该页面数据、操作失误可能会导致权限菜单错乱。

2. 权限菜单分为[ 使用、操作 ]两种类型,使用菜单一般开启显示,操作菜单必须隐藏。

-

3. 如果出现权限菜单错乱,可以重新覆盖[ {{:config('database.prefix')}}power ]数据表的数据恢复。

+

3. 如果出现权限菜单错乱,可以重新覆盖[ {{:MyConfig('database.connections.mysql.prefix')}}power ]数据表的数据恢复。

4. [ 超级管理员、admin账户 ]默认拥有所有权限,不可更改。

diff --git a/application/admin/view/default/public/event_value_tips.html b/app/admin/view/default/public/event_value_tips.html similarity index 100% rename from application/admin/view/default/public/event_value_tips.html rename to app/admin/view/default/public/event_value_tips.html diff --git a/application/admin/view/default/public/footer.html b/app/admin/view/default/public/footer.html similarity index 100% rename from application/admin/view/default/public/footer.html rename to app/admin/view/default/public/footer.html diff --git a/application/admin/view/default/public/goodsparamstemplate/detail.html b/app/admin/view/default/public/goodsparamstemplate/detail.html similarity index 100% rename from application/admin/view/default/public/goodsparamstemplate/detail.html rename to app/admin/view/default/public/goodsparamstemplate/detail.html diff --git a/application/admin/view/default/public/goodsparamstemplate/table.html b/app/admin/view/default/public/goodsparamstemplate/table.html similarity index 100% rename from application/admin/view/default/public/goodsparamstemplate/table.html rename to app/admin/view/default/public/goodsparamstemplate/table.html diff --git a/application/admin/view/default/public/goodsparamstemplate/tips.html b/app/admin/view/default/public/goodsparamstemplate/tips.html similarity index 100% rename from application/admin/view/default/public/goodsparamstemplate/tips.html rename to app/admin/view/default/public/goodsparamstemplate/tips.html diff --git a/application/admin/view/default/public/header.html b/app/admin/view/default/public/header.html similarity index 98% rename from application/admin/view/default/public/header.html rename to app/admin/view/default/public/header.html index c7ec1092a..c44eb02c2 100755 --- a/application/admin/view/default/public/header.html +++ b/app/admin/view/default/public/header.html @@ -1,7 +1,7 @@ - + {{$admin_theme_site_name}}后台管理系统 diff --git a/application/admin/view/default/public/index.html b/app/admin/view/default/public/index.html similarity index 100% rename from application/admin/view/default/public/index.html rename to app/admin/view/default/public/index.html diff --git a/app/admin/view/default/public/jump_error.html b/app/admin/view/default/public/jump_error.html new file mode 100755 index 000000000..655e489c1 --- /dev/null +++ b/app/admin/view/default/public/jump_error.html @@ -0,0 +1,33 @@ +{{include file="public/header" /}} + + +
+
+
+

+

{{if isset($msg)}}{{$msg}}{{else /}}操作失败{{/if}}

+

+ 返回上一页 + {{if empty($wait_time)}}5{{else /}}{{$wait_time}}{{/if}}秒自动返回 +

+
+
+
+ + + +{{include file="public/footer" /}} + + \ No newline at end of file diff --git a/app/admin/view/default/public/jump_success.html b/app/admin/view/default/public/jump_success.html new file mode 100755 index 000000000..c14c6fc49 --- /dev/null +++ b/app/admin/view/default/public/jump_success.html @@ -0,0 +1,33 @@ +{{include file="public/header" /}} + + +
+
+
+

+

{{if isset($msg)}}{{$msg}}{{else /}}操作成功{{/if}}

+

+ 返回上一页 + {{if empty($wait_time)}}5{{else /}}{{$wait_time}}{{/if}}秒自动返回 +

+
+
+
+ + + +{{include file="public/footer" /}} + + \ No newline at end of file diff --git a/application/admin/view/default/public/loading.html b/app/admin/view/default/public/loading.html similarity index 100% rename from application/admin/view/default/public/loading.html rename to app/admin/view/default/public/loading.html diff --git a/application/admin/view/default/public/menu.html b/app/admin/view/default/public/menu.html similarity index 100% rename from application/admin/view/default/public/menu.html rename to app/admin/view/default/public/menu.html diff --git a/application/index/view/default/public/module/detail.html b/app/admin/view/default/public/module/detail.html similarity index 94% rename from application/index/view/default/public/module/detail.html rename to app/admin/view/default/public/module/detail.html index b0db5d1a8..4b702ff12 100644 --- a/application/index/view/default/public/module/detail.html +++ b/app/admin/view/default/public/module/detail.html @@ -7,7 +7,7 @@ {{/if}} {{php}} - $hook_data = Hook::listen($hook_name_detail_top, ['hook_name'=>$hook_name_detail_top, 'is_backend'=>true]); + $hook_data = MyEventTrigger($hook_name_detail_top, ['hook_name'=>$hook_name_detail_top, 'is_backend'=>true]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -29,7 +29,7 @@ {{/if}} {{php}} - $hook_data = Hook::listen($hook_name_detail_inside_top, ['hook_name'=>$hook_name_detail_inside_top, 'is_backend'=>true]); + $hook_data = MyEventTrigger($hook_name_detail_inside_top, ['hook_name'=>$hook_name_detail_inside_top, 'is_backend'=>true]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -143,7 +143,7 @@ {{/if}} {{php}} - $hook_data = Hook::listen($hook_name_detail_inside_bottom, ['hook_name'=>$hook_name_detail_inside_bottom, 'is_backend'=>true]); + $hook_data = MyEventTrigger($hook_name_detail_inside_bottom, ['hook_name'=>$hook_name_detail_inside_bottom, 'is_backend'=>true]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -165,7 +165,7 @@ {{/if}} {{php}} - $hook_data = Hook::listen($hook_name_detail_bottom, ['hook_name'=>$hook_name_detail_bottom, 'is_backend'=>true]); + $hook_data = MyEventTrigger($hook_name_detail_bottom, ['hook_name'=>$hook_name_detail_bottom, 'is_backend'=>true]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) diff --git a/application/admin/view/default/public/module/form.html b/app/admin/view/default/public/module/form.html similarity index 90% rename from application/admin/view/default/public/module/form.html rename to app/admin/view/default/public/module/form.html index c8f092995..b43e23a94 100644 --- a/application/admin/view/default/public/module/form.html +++ b/app/admin/view/default/public/module/form.html @@ -7,7 +7,7 @@ {{/if}} {{php}} - $hook_data = Hook::listen($hook_name_content_top, ['hook_name'=>$hook_name_content_top, 'is_backend'=>true]); + $hook_data = MyEventTrigger($hook_name_content_top, ['hook_name'=>$hook_name_content_top, 'is_backend'=>true]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -35,7 +35,7 @@ {{/if}} {{php}} - $hook_data = Hook::listen($hook_name_content_inside_top, ['hook_name'=>$hook_name_content_inside_top, 'is_backend'=>true]); + $hook_data = MyEventTrigger($hook_name_content_inside_top, ['hook_name'=>$hook_name_content_inside_top, 'is_backend'=>true]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -104,7 +104,7 @@ {{/if}} {{php}} - $hook_data = Hook::listen($hook_name_content_inside_bottom, ['hook_name'=>$hook_name_content_inside_bottom, 'is_backend'=>true]); + $hook_data = MyEventTrigger($hook_name_content_inside_bottom, ['hook_name'=>$hook_name_content_inside_bottom, 'is_backend'=>true]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -127,7 +127,7 @@ {{/if}} {{php}} - $hook_data = Hook::listen($hook_name_content_bottom, ['hook_name'=>$hook_name_content_bottom, 'is_backend'=>true]); + $hook_data = MyEventTrigger($hook_name_content_bottom, ['hook_name'=>$hook_name_content_bottom, 'is_backend'=>true]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) diff --git a/application/admin/view/default/public/module/form_fields_select.html b/app/admin/view/default/public/module/form_fields_select.html similarity index 100% rename from application/admin/view/default/public/module/form_fields_select.html rename to app/admin/view/default/public/module/form_fields_select.html diff --git a/application/admin/view/default/public/module/form_operate_bottom.html b/app/admin/view/default/public/module/form_operate_bottom.html similarity index 77% rename from application/admin/view/default/public/module/form_operate_bottom.html rename to app/admin/view/default/public/module/form_operate_bottom.html index a2e50a169..fe8f38c8e 100644 --- a/application/admin/view/default/public/module/form_operate_bottom.html +++ b/app/admin/view/default/public/module/form_operate_bottom.html @@ -4,7 +4,7 @@ {{/if}} {{php}} - $hook_data = Hook::listen($hook_name_form_bottom_operate, ['hook_name'=>$hook_name_form_bottom_operate, 'is_backend'=>true]); + $hook_data = MyEventTrigger($hook_name_form_bottom_operate, ['hook_name'=>$hook_name_form_bottom_operate, 'is_backend'=>true]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) diff --git a/application/admin/view/default/public/module/form_operate_top.html b/app/admin/view/default/public/module/form_operate_top.html similarity index 95% rename from application/admin/view/default/public/module/form_operate_top.html rename to app/admin/view/default/public/module/form_operate_top.html index 8ddb2cd9b..be8b2df0d 100644 --- a/application/admin/view/default/public/module/form_operate_top.html +++ b/app/admin/view/default/public/module/form_operate_top.html @@ -20,7 +20,7 @@ {{/if}} {{php}} - $hook_data = Hook::listen($hook_name_form_top_operate, ['hook_name'=>$hook_name_form_top_operate, 'is_backend'=>true]); + $hook_data = MyEventTrigger($hook_name_form_top_operate, ['hook_name'=>$hook_name_form_top_operate, 'is_backend'=>true]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) diff --git a/application/index/view/default/public/module/form_table.html b/app/admin/view/default/public/module/form_table.html similarity index 99% rename from application/index/view/default/public/module/form_table.html rename to app/admin/view/default/public/module/form_table.html index e25e83b94..b6ffedfd4 100644 --- a/application/index/view/default/public/module/form_table.html +++ b/app/admin/view/default/public/module/form_table.html @@ -255,7 +255,7 @@ {{/if}} {{php}} - $hook_data = Hook::listen($hook_name_form_list_operate, [ + $hook_data = MyEventTrigger($hook_name_form_list_operate, [ 'hook_name' => $hook_name_form_list_operate, 'is_backend' => true, 'id' => isset($data_list[$i][$form_table['base']['key_field']]) ? $data_list[$i][$form_table['base']['key_field']] : 0, diff --git a/application/admin/view/default/public/nav.html b/app/admin/view/default/public/nav.html similarity index 100% rename from application/admin/view/default/public/nav.html rename to app/admin/view/default/public/nav.html diff --git a/application/admin/view/default/public/nav_bar.html b/app/admin/view/default/public/nav_bar.html similarity index 100% rename from application/admin/view/default/public/nav_bar.html rename to app/admin/view/default/public/nav_bar.html diff --git a/application/admin/view/default/public/not_data.html b/app/admin/view/default/public/not_data.html similarity index 100% rename from application/admin/view/default/public/not_data.html rename to app/admin/view/default/public/not_data.html diff --git a/application/admin/view/default/public/page_loading.html b/app/admin/view/default/public/page_loading.html similarity index 100% rename from application/admin/view/default/public/page_loading.html rename to app/admin/view/default/public/page_loading.html diff --git a/application/admin/view/default/public/tips_error.html b/app/admin/view/default/public/tips_error.html similarity index 100% rename from application/admin/view/default/public/tips_error.html rename to app/admin/view/default/public/tips_error.html diff --git a/application/admin/view/default/quicknav/detail.html b/app/admin/view/default/quicknav/detail.html similarity index 100% rename from application/admin/view/default/quicknav/detail.html rename to app/admin/view/default/quicknav/detail.html diff --git a/application/admin/view/default/quicknav/index.html b/app/admin/view/default/quicknav/index.html similarity index 100% rename from application/admin/view/default/quicknav/index.html rename to app/admin/view/default/quicknav/index.html diff --git a/application/admin/view/default/quicknav/module/images.html b/app/admin/view/default/quicknav/module/images.html similarity index 100% rename from application/admin/view/default/quicknav/module/images.html rename to app/admin/view/default/quicknav/module/images.html diff --git a/application/admin/view/default/quicknav/module/operate.html b/app/admin/view/default/quicknav/module/operate.html similarity index 100% rename from application/admin/view/default/quicknav/module/operate.html rename to app/admin/view/default/quicknav/module/operate.html diff --git a/application/admin/view/default/quicknav/save_info.html b/app/admin/view/default/quicknav/save_info.html similarity index 100% rename from application/admin/view/default/quicknav/save_info.html rename to app/admin/view/default/quicknav/save_info.html diff --git a/application/admin/view/default/refundlog/detail.html b/app/admin/view/default/refundlog/detail.html similarity index 100% rename from application/admin/view/default/refundlog/detail.html rename to app/admin/view/default/refundlog/detail.html diff --git a/application/admin/view/default/refundlog/index.html b/app/admin/view/default/refundlog/index.html similarity index 100% rename from application/admin/view/default/refundlog/index.html rename to app/admin/view/default/refundlog/index.html diff --git a/application/admin/view/default/refundlog/module/operate.html b/app/admin/view/default/refundlog/module/operate.html similarity index 100% rename from application/admin/view/default/refundlog/module/operate.html rename to app/admin/view/default/refundlog/module/operate.html diff --git a/application/admin/view/default/refundlog/module/payment.html b/app/admin/view/default/refundlog/module/payment.html similarity index 100% rename from application/admin/view/default/refundlog/module/payment.html rename to app/admin/view/default/refundlog/module/payment.html diff --git a/application/admin/view/default/region/index.html b/app/admin/view/default/region/index.html similarity index 100% rename from application/admin/view/default/region/index.html rename to app/admin/view/default/region/index.html diff --git a/application/admin/view/default/role/detail.html b/app/admin/view/default/role/detail.html similarity index 100% rename from application/admin/view/default/role/detail.html rename to app/admin/view/default/role/detail.html diff --git a/application/admin/view/default/role/index.html b/app/admin/view/default/role/index.html similarity index 100% rename from application/admin/view/default/role/index.html rename to app/admin/view/default/role/index.html diff --git a/application/admin/view/default/role/module/operate.html b/app/admin/view/default/role/module/operate.html similarity index 100% rename from application/admin/view/default/role/module/operate.html rename to app/admin/view/default/role/module/operate.html diff --git a/application/admin/view/default/role/save_info.html b/app/admin/view/default/role/save_info.html similarity index 100% rename from application/admin/view/default/role/save_info.html rename to app/admin/view/default/role/save_info.html diff --git a/application/admin/view/default/screeningprice/index.html b/app/admin/view/default/screeningprice/index.html similarity index 100% rename from application/admin/view/default/screeningprice/index.html rename to app/admin/view/default/screeningprice/index.html diff --git a/application/admin/view/default/seo/index.html b/app/admin/view/default/seo/index.html similarity index 100% rename from application/admin/view/default/seo/index.html rename to app/admin/view/default/seo/index.html diff --git a/application/admin/view/default/site/attachment/index.html b/app/admin/view/default/site/attachment/index.html similarity index 100% rename from application/admin/view/default/site/attachment/index.html rename to app/admin/view/default/site/attachment/index.html diff --git a/application/admin/view/default/site/base/index.html b/app/admin/view/default/site/base/index.html similarity index 100% rename from application/admin/view/default/site/base/index.html rename to app/admin/view/default/site/base/index.html diff --git a/application/admin/view/default/site/cache/index.html b/app/admin/view/default/site/cache/index.html similarity index 73% rename from application/admin/view/default/site/cache/index.html rename to app/admin/view/default/site/cache/index.html index 01fe1c72f..73115fc11 100644 --- a/application/admin/view/default/site/cache/index.html +++ b/app/admin/view/default/site/cache/index.html @@ -30,28 +30,6 @@ {{/foreach}} -
- - -
- -
- - -
-
- - -
-
- -
- - - - -
-
@@ -73,11 +51,23 @@ {{/foreach}}
+
+ + +
+ + + + +
+
+

redis缓存配置

+
+
-
@@ -95,10 +85,6 @@
-
- - -
diff --git a/application/admin/view/default/site/extends/index.html b/app/admin/view/default/site/extends/index.html similarity index 100% rename from application/admin/view/default/site/extends/index.html rename to app/admin/view/default/site/extends/index.html diff --git a/application/admin/view/default/site/forgetpwd/index.html b/app/admin/view/default/site/forgetpwd/index.html similarity index 100% rename from application/admin/view/default/site/forgetpwd/index.html rename to app/admin/view/default/site/forgetpwd/index.html diff --git a/application/admin/view/default/site/login/index.html b/app/admin/view/default/site/login/index.html similarity index 100% rename from application/admin/view/default/site/login/index.html rename to app/admin/view/default/site/login/index.html diff --git a/application/admin/view/default/site/orderaftersale/index.html b/app/admin/view/default/site/orderaftersale/index.html similarity index 100% rename from application/admin/view/default/site/orderaftersale/index.html rename to app/admin/view/default/site/orderaftersale/index.html diff --git a/application/admin/view/default/site/public/goods_search.html b/app/admin/view/default/site/public/goods_search.html similarity index 100% rename from application/admin/view/default/site/public/goods_search.html rename to app/admin/view/default/site/public/goods_search.html diff --git a/application/admin/view/default/site/public/nav.html b/app/admin/view/default/site/public/nav.html similarity index 100% rename from application/admin/view/default/site/public/nav.html rename to app/admin/view/default/site/public/nav.html diff --git a/application/admin/view/default/site/public/siteset_nav.html b/app/admin/view/default/site/public/siteset_nav.html similarity index 100% rename from application/admin/view/default/site/public/siteset_nav.html rename to app/admin/view/default/site/public/siteset_nav.html diff --git a/application/admin/view/default/site/register/index.html b/app/admin/view/default/site/register/index.html similarity index 100% rename from application/admin/view/default/site/register/index.html rename to app/admin/view/default/site/register/index.html diff --git a/application/admin/view/default/site/siteset/discount.html b/app/admin/view/default/site/siteset/discount.html similarity index 100% rename from application/admin/view/default/site/siteset/discount.html rename to app/admin/view/default/site/siteset/discount.html diff --git a/application/admin/view/default/site/siteset/extends.html b/app/admin/view/default/site/siteset/extends.html similarity index 100% rename from application/admin/view/default/site/siteset/extends.html rename to app/admin/view/default/site/siteset/extends.html diff --git a/application/admin/view/default/site/siteset/goods.html b/app/admin/view/default/site/siteset/goods.html similarity index 100% rename from application/admin/view/default/site/siteset/goods.html rename to app/admin/view/default/site/siteset/goods.html diff --git a/application/admin/view/default/site/siteset/index.html b/app/admin/view/default/site/siteset/index.html similarity index 100% rename from application/admin/view/default/site/siteset/index.html rename to app/admin/view/default/site/siteset/index.html diff --git a/application/admin/view/default/site/siteset/order.html b/app/admin/view/default/site/siteset/order.html similarity index 100% rename from application/admin/view/default/site/siteset/order.html rename to app/admin/view/default/site/siteset/order.html diff --git a/application/admin/view/default/site/siteset/search.html b/app/admin/view/default/site/siteset/search.html similarity index 100% rename from application/admin/view/default/site/siteset/search.html rename to app/admin/view/default/site/siteset/search.html diff --git a/application/admin/view/default/site/sitetype/index.html b/app/admin/view/default/site/sitetype/index.html similarity index 100% rename from application/admin/view/default/site/sitetype/index.html rename to app/admin/view/default/site/sitetype/index.html diff --git a/application/admin/view/default/site/verify/index.html b/app/admin/view/default/site/verify/index.html similarity index 100% rename from application/admin/view/default/site/verify/index.html rename to app/admin/view/default/site/verify/index.html diff --git a/application/admin/view/default/slide/detail.html b/app/admin/view/default/slide/detail.html similarity index 100% rename from application/admin/view/default/slide/detail.html rename to app/admin/view/default/slide/detail.html diff --git a/application/admin/view/default/slide/index.html b/app/admin/view/default/slide/index.html similarity index 100% rename from application/admin/view/default/slide/index.html rename to app/admin/view/default/slide/index.html diff --git a/application/admin/view/default/slide/module/images.html b/app/admin/view/default/slide/module/images.html similarity index 100% rename from application/admin/view/default/slide/module/images.html rename to app/admin/view/default/slide/module/images.html diff --git a/application/admin/view/default/slide/module/operate.html b/app/admin/view/default/slide/module/operate.html similarity index 100% rename from application/admin/view/default/slide/module/operate.html rename to app/admin/view/default/slide/module/operate.html diff --git a/application/admin/view/default/slide/save_info.html b/app/admin/view/default/slide/save_info.html similarity index 100% rename from application/admin/view/default/slide/save_info.html rename to app/admin/view/default/slide/save_info.html diff --git a/application/admin/view/default/sms/index.html b/app/admin/view/default/sms/index.html similarity index 100% rename from application/admin/view/default/sms/index.html rename to app/admin/view/default/sms/index.html diff --git a/application/admin/view/default/sms/message.html b/app/admin/view/default/sms/message.html similarity index 100% rename from application/admin/view/default/sms/message.html rename to app/admin/view/default/sms/message.html diff --git a/application/admin/view/default/sms/nav.html b/app/admin/view/default/sms/nav.html similarity index 100% rename from application/admin/view/default/sms/nav.html rename to app/admin/view/default/sms/nav.html diff --git a/application/admin/view/default/sqlconsole/index.html b/app/admin/view/default/sqlconsole/index.html similarity index 100% rename from application/admin/view/default/sqlconsole/index.html rename to app/admin/view/default/sqlconsole/index.html diff --git a/application/admin/view/default/store/index.html b/app/admin/view/default/store/index.html similarity index 100% rename from application/admin/view/default/store/index.html rename to app/admin/view/default/store/index.html diff --git a/application/admin/view/default/theme/index.html b/app/admin/view/default/theme/index.html similarity index 100% rename from application/admin/view/default/theme/index.html rename to app/admin/view/default/theme/index.html diff --git a/application/admin/view/default/theme/nav.html b/app/admin/view/default/theme/nav.html similarity index 100% rename from application/admin/view/default/theme/nav.html rename to app/admin/view/default/theme/nav.html diff --git a/application/admin/view/default/theme/upload.html b/app/admin/view/default/theme/upload.html similarity index 100% rename from application/admin/view/default/theme/upload.html rename to app/admin/view/default/theme/upload.html diff --git a/application/admin/view/default/user/detail.html b/app/admin/view/default/user/detail.html similarity index 100% rename from application/admin/view/default/user/detail.html rename to app/admin/view/default/user/detail.html diff --git a/application/admin/view/default/user/index.html b/app/admin/view/default/user/index.html similarity index 100% rename from application/admin/view/default/user/index.html rename to app/admin/view/default/user/index.html diff --git a/application/admin/view/default/user/module/avatar.html b/app/admin/view/default/user/module/avatar.html similarity index 100% rename from application/admin/view/default/user/module/avatar.html rename to app/admin/view/default/user/module/avatar.html diff --git a/application/admin/view/default/user/module/operate.html b/app/admin/view/default/user/module/operate.html similarity index 100% rename from application/admin/view/default/user/module/operate.html rename to app/admin/view/default/user/module/operate.html diff --git a/application/admin/view/default/user/save_info.html b/app/admin/view/default/user/save_info.html similarity index 100% rename from application/admin/view/default/user/save_info.html rename to app/admin/view/default/user/save_info.html diff --git a/application/admin/view/default/useraddress/detail.html b/app/admin/view/default/useraddress/detail.html similarity index 100% rename from application/admin/view/default/useraddress/detail.html rename to app/admin/view/default/useraddress/detail.html diff --git a/application/admin/view/default/useraddress/index.html b/app/admin/view/default/useraddress/index.html similarity index 100% rename from application/admin/view/default/useraddress/index.html rename to app/admin/view/default/useraddress/index.html diff --git a/application/admin/view/default/useraddress/module/idcard_info.html b/app/admin/view/default/useraddress/module/idcard_info.html similarity index 100% rename from application/admin/view/default/useraddress/module/idcard_info.html rename to app/admin/view/default/useraddress/module/idcard_info.html diff --git a/application/admin/view/default/useraddress/module/is_default.html b/app/admin/view/default/useraddress/module/is_default.html similarity index 100% rename from application/admin/view/default/useraddress/module/is_default.html rename to app/admin/view/default/useraddress/module/is_default.html diff --git a/application/admin/view/default/useraddress/module/operate.html b/app/admin/view/default/useraddress/module/operate.html similarity index 100% rename from application/admin/view/default/useraddress/module/operate.html rename to app/admin/view/default/useraddress/module/operate.html diff --git a/application/admin/view/default/useraddress/module/position.html b/app/admin/view/default/useraddress/module/position.html similarity index 100% rename from application/admin/view/default/useraddress/module/position.html rename to app/admin/view/default/useraddress/module/position.html diff --git a/application/admin/view/default/useraddress/save_info.html b/app/admin/view/default/useraddress/save_info.html similarity index 100% rename from application/admin/view/default/useraddress/save_info.html rename to app/admin/view/default/useraddress/save_info.html diff --git a/application/admin/view/default/warehouse/detail.html b/app/admin/view/default/warehouse/detail.html similarity index 100% rename from application/admin/view/default/warehouse/detail.html rename to app/admin/view/default/warehouse/detail.html diff --git a/application/admin/view/default/warehouse/index.html b/app/admin/view/default/warehouse/index.html similarity index 100% rename from application/admin/view/default/warehouse/index.html rename to app/admin/view/default/warehouse/index.html diff --git a/application/admin/view/default/warehouse/module/info.html b/app/admin/view/default/warehouse/module/info.html similarity index 100% rename from application/admin/view/default/warehouse/module/info.html rename to app/admin/view/default/warehouse/module/info.html diff --git a/application/admin/view/default/warehouse/module/operate.html b/app/admin/view/default/warehouse/module/operate.html similarity index 100% rename from application/admin/view/default/warehouse/module/operate.html rename to app/admin/view/default/warehouse/module/operate.html diff --git a/application/admin/view/default/warehouse/module/position.html b/app/admin/view/default/warehouse/module/position.html similarity index 100% rename from application/admin/view/default/warehouse/module/position.html rename to app/admin/view/default/warehouse/module/position.html diff --git a/application/admin/view/default/warehouse/save_info.html b/app/admin/view/default/warehouse/save_info.html similarity index 100% rename from application/admin/view/default/warehouse/save_info.html rename to app/admin/view/default/warehouse/save_info.html diff --git a/application/admin/view/default/warehousegoods/detail.html b/app/admin/view/default/warehousegoods/detail.html similarity index 100% rename from application/admin/view/default/warehousegoods/detail.html rename to app/admin/view/default/warehousegoods/detail.html diff --git a/application/admin/view/default/warehousegoods/goods_search.html b/app/admin/view/default/warehousegoods/goods_search.html similarity index 100% rename from application/admin/view/default/warehousegoods/goods_search.html rename to app/admin/view/default/warehousegoods/goods_search.html diff --git a/application/admin/view/default/warehousegoods/goods_spec.html b/app/admin/view/default/warehousegoods/goods_spec.html similarity index 100% rename from application/admin/view/default/warehousegoods/goods_spec.html rename to app/admin/view/default/warehousegoods/goods_spec.html diff --git a/application/admin/view/default/warehousegoods/index.html b/app/admin/view/default/warehousegoods/index.html similarity index 100% rename from application/admin/view/default/warehousegoods/index.html rename to app/admin/view/default/warehousegoods/index.html diff --git a/application/admin/view/default/warehousegoods/inventory_info.html b/app/admin/view/default/warehousegoods/inventory_info.html similarity index 100% rename from application/admin/view/default/warehousegoods/inventory_info.html rename to app/admin/view/default/warehousegoods/inventory_info.html diff --git a/application/admin/view/default/warehousegoods/module/goods.html b/app/admin/view/default/warehousegoods/module/goods.html similarity index 100% rename from application/admin/view/default/warehousegoods/module/goods.html rename to app/admin/view/default/warehousegoods/module/goods.html diff --git a/application/admin/view/default/warehousegoods/module/operate.html b/app/admin/view/default/warehousegoods/module/operate.html similarity index 100% rename from application/admin/view/default/warehousegoods/module/operate.html rename to app/admin/view/default/warehousegoods/module/operate.html diff --git a/application/admin/view/index.html b/app/admin/view/index.html similarity index 100% rename from application/admin/view/index.html rename to app/admin/view/index.html diff --git a/application/api/config/app.php b/app/api/config/app.php similarity index 100% rename from application/api/config/app.php rename to app/api/config/app.php diff --git a/build.php b/app/api/config/route.php old mode 100755 new mode 100644 similarity index 56% rename from build.php rename to app/api/config/route.php index 87230c0fa..141326d59 --- a/build.php +++ b/app/api/config/route.php @@ -9,19 +9,10 @@ // | Author: Devil // +---------------------------------------------------------------------- +// +---------------------------------------------------------------------- +// | 路由设置 +// +---------------------------------------------------------------------- return [ - // 生成应用公共文件 - '__file__' => ['common.php'], - - // 定义demo模块的自动生成 (按照实际定义的文件名生成) - 'demo' => [ - '__file__' => ['common.php'], - '__dir__' => ['behavior', 'controller', 'model', 'view'], - 'controller' => ['Index', 'Test', 'UserType'], - 'model' => ['User', 'UserType'], - 'view' => ['index/index'], - ], - - // 其他更多的模块定义 + // URL伪静态后缀 + 'url_html_suffix' => MyFileConfig('home_seo_url_html_suffix', '', 'html', true), ]; -?> \ No newline at end of file diff --git a/application/api/controller/Agreement.php b/app/api/controller/Agreement.php similarity index 100% rename from application/api/controller/Agreement.php rename to app/api/controller/Agreement.php diff --git a/application/api/controller/Answer.php b/app/api/controller/Answer.php similarity index 100% rename from application/api/controller/Answer.php rename to app/api/controller/Answer.php diff --git a/application/api/controller/Banner.php b/app/api/controller/Banner.php similarity index 100% rename from application/api/controller/Banner.php rename to app/api/controller/Banner.php diff --git a/application/api/controller/Base.php b/app/api/controller/Base.php similarity index 100% rename from application/api/controller/Base.php rename to app/api/controller/Base.php diff --git a/application/api/controller/Buy.php b/app/api/controller/Buy.php similarity index 100% rename from application/api/controller/Buy.php rename to app/api/controller/Buy.php diff --git a/application/api/controller/Cart.php b/app/api/controller/Cart.php similarity index 100% rename from application/api/controller/Cart.php rename to app/api/controller/Cart.php diff --git a/application/api/controller/Common.php b/app/api/controller/Common.php similarity index 87% rename from application/api/controller/Common.php rename to app/api/controller/Common.php index 736a56935..3ae57cc4a 100755 --- a/application/api/controller/Common.php +++ b/app/api/controller/Common.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\api\controller; -use think\Controller; +use app\BaseController; use app\service\SystemService; use app\service\ConfigService; use app\service\UserService; @@ -23,7 +23,7 @@ use app\module\FormHandleModule; * @version 0.0.1 * @datetime 2016-12-01T21:51:08+0800 */ -class Common extends Controller +class Common extends BaseController { // 用户信息 protected $user; @@ -61,7 +61,8 @@ class Common extends Controller */ public function __construct() { - parent::__construct(); + // 检测是否是新安装 + SystemService::SystemInstallCheck(); // 输入参数 $this->data_post = input('post.'); @@ -110,9 +111,6 @@ class Common extends Controller { // 配置信息初始化 ConfigService::ConfigInit(); - - // url模式,后端采用兼容模式 - \think\facade\Url::root(__MY_ROOT_PUBLIC__.'index.php?s='); } /** @@ -189,9 +187,9 @@ class Common extends Controller $this->user = UserService::LoginUserInfo(); // 当前操作名称 - $this->module_name = strtolower(request()->module()); - $this->controller_name = strtolower(request()->controller()); - $this->action_name = strtolower(request()->action()); + $this->module_name = RequestModule(); + $this->controller_name = RequestController(); + $this->action_name = RequestAction(); // 分页信息 $this->page = max(1, isset($this->data_request['page']) ? intval($this->data_request['page']) : 1); @@ -199,16 +197,18 @@ class Common extends Controller } /** - * 空方法操作 - * @author Devil - * @blog http://gong.gg/ - * @version 0.0.1 - * @datetime 2017-02-25T15:47:50+0800 - * @param [string] $name [方法名称] - */ - protected function _empty($name) - { - exit(json_encode(DataReturn($name.' 非法访问', -1000))); - } + * 空方法响应 + * @author Devil + * @blog http://gong.gg/ + * @version 1.0.0 + * @date 2018-11-30 + * @desc description + * @param [string] $method [方法名称] + * @param [array] $args [参数] + */ + public function __call($method, $args) + { + return DataReturn($method.' 非法访问', -1000); + } } ?> \ No newline at end of file diff --git a/application/api/controller/Crontab.php b/app/api/controller/Crontab.php similarity index 100% rename from application/api/controller/Crontab.php rename to app/api/controller/Crontab.php diff --git a/application/api/controller/Design.php b/app/api/controller/Design.php similarity index 100% rename from application/api/controller/Design.php rename to app/api/controller/Design.php diff --git a/application/api/controller/Devtest.php b/app/api/controller/Devtest.php similarity index 97% rename from application/api/controller/Devtest.php rename to app/api/controller/Devtest.php index 4a3613988..7a222a3ab 100644 --- a/application/api/controller/Devtest.php +++ b/app/api/controller/Devtest.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\api\controller; -use think\Db; +use think\facade\Db; use app\service\ResourcesService; use app\service\RegionService; use app\service\GoodsService; @@ -96,7 +96,7 @@ class Devtest extends Common // 获取数据 // 一次处理100条 - $prefix = config('database.prefix'); + $prefix = MyConfig('database.connections.mysql.prefix'); $field = 'id, user_id, receive_address_id, receive_name, receive_tel, receive_province, receive_city, receive_county, receive_address'; $sql = 'SELECT '.$field.' FROM '.$prefix.'order WHERE `id` NOT IN (SELECT `order_id` FROM '.$prefix.'order_address) LIMIT 500'; $result = Db::query($sql); @@ -167,7 +167,7 @@ class Devtest extends Common // 获取数据 // 一次处理100条 - $prefix = config('database.prefix'); + $prefix = MyConfig('database.connections.mysql.prefix'); $field = 'id as goods_id'; $sql = 'SELECT '.$field.' FROM `'.$prefix.'goods` WHERE `id` NOT IN (SELECT `goods_id` FROM `'.$prefix.'warehouse_goods` WHERE `warehouse_id`='.$warehouse_id.') ORDER BY `id` ASC LIMIT 500'; $result = Db::query($sql); @@ -183,7 +183,7 @@ class Devtest extends Common if(!empty($res['value']) && is_array($res['value'])) { $inventory_arr = []; - $inventory_temp = Db::name('GoodsSpecBase')->where(['id'=>array_column($res['value'], 'base_id')])->field('id,inventory')->select(); + $inventory_temp = Db::name('GoodsSpecBase')->where(['id'=>array_column($res['value'], 'base_id')])->field('id,inventory')->select()->toArray(); if(!empty($inventory_temp)) { foreach($inventory_temp as $rv) @@ -296,7 +296,7 @@ class Devtest extends Common // 获取日志 - $data = Db::name('PayLog')->where(['is_handle'=>0])->limit(0, 500)->select(); + $data = Db::name('PayLog')->where(['is_handle'=>0])->limit(0, 500)->select()->toArray(); if(!empty($data)) { $business_type_list = [ @@ -369,7 +369,7 @@ class Devtest extends Common // 获取日志 - $data = Db::name('RefundLog')->where(['is_handle'=>0])->limit(0, 500)->select(); + $data = Db::name('RefundLog')->where(['is_handle'=>0])->limit(0, 500)->select()->toArray(); if(!empty($data)) { $business_type_list = [ @@ -418,7 +418,7 @@ class Devtest extends Common // 获取日志 - $data = Db::name('Message')->where(['is_handle'=>0])->limit(0, 500)->select(); + $data = Db::name('Message')->where(['is_handle'=>0])->limit(0, 500)->select()->toArray(); if(!empty($data)) { $business_type_list = [ @@ -466,7 +466,7 @@ class Devtest extends Common $fail = 0; // 获取品牌列表 - $data = Db::name('Brand')->select(); + $data = Db::name('Brand')->select()->toArray(); if(!empty($data)) { foreach($data as $v) diff --git a/app/api/controller/Error.php b/app/api/controller/Error.php new file mode 100644 index 000000000..45f3c7176 --- /dev/null +++ b/app/api/controller/Error.php @@ -0,0 +1,44 @@ + \ No newline at end of file diff --git a/application/api/controller/Goods.php b/app/api/controller/Goods.php similarity index 100% rename from application/api/controller/Goods.php rename to app/api/controller/Goods.php diff --git a/application/api/controller/Index.php b/app/api/controller/Index.php similarity index 100% rename from application/api/controller/Index.php rename to app/api/controller/Index.php diff --git a/application/api/controller/Message.php b/app/api/controller/Message.php similarity index 100% rename from application/api/controller/Message.php rename to app/api/controller/Message.php diff --git a/application/api/controller/Navigation.php b/app/api/controller/Navigation.php similarity index 100% rename from application/api/controller/Navigation.php rename to app/api/controller/Navigation.php diff --git a/application/api/controller/Order.php b/app/api/controller/Order.php similarity index 100% rename from application/api/controller/Order.php rename to app/api/controller/Order.php diff --git a/application/api/controller/Orderaftersale.php b/app/api/controller/Orderaftersale.php similarity index 100% rename from application/api/controller/Orderaftersale.php rename to app/api/controller/Orderaftersale.php diff --git a/application/api/controller/Ordernotify.php b/app/api/controller/Ordernotify.php similarity index 100% rename from application/api/controller/Ordernotify.php rename to app/api/controller/Ordernotify.php diff --git a/application/api/controller/Plugins.php b/app/api/controller/Plugins.php similarity index 100% rename from application/api/controller/Plugins.php rename to app/api/controller/Plugins.php diff --git a/application/api/controller/Region.php b/app/api/controller/Region.php similarity index 100% rename from application/api/controller/Region.php rename to app/api/controller/Region.php diff --git a/application/api/controller/Search.php b/app/api/controller/Search.php similarity index 100% rename from application/api/controller/Search.php rename to app/api/controller/Search.php diff --git a/application/api/controller/Ueditor.php b/app/api/controller/Ueditor.php similarity index 100% rename from application/api/controller/Ueditor.php rename to app/api/controller/Ueditor.php diff --git a/application/api/controller/User.php b/app/api/controller/User.php similarity index 100% rename from application/api/controller/User.php rename to app/api/controller/User.php diff --git a/application/api/controller/Useraddress.php b/app/api/controller/Useraddress.php similarity index 100% rename from application/api/controller/Useraddress.php rename to app/api/controller/Useraddress.php diff --git a/application/api/controller/Usergoodsbrowse.php b/app/api/controller/Usergoodsbrowse.php similarity index 100% rename from application/api/controller/Usergoodsbrowse.php rename to app/api/controller/Usergoodsbrowse.php diff --git a/application/api/controller/Usergoodsfavor.php b/app/api/controller/Usergoodsfavor.php similarity index 100% rename from application/api/controller/Usergoodsfavor.php rename to app/api/controller/Usergoodsfavor.php diff --git a/application/api/controller/Userintegral.php b/app/api/controller/Userintegral.php similarity index 100% rename from application/api/controller/Userintegral.php rename to app/api/controller/Userintegral.php diff --git a/application/api/controller/index.html b/app/api/controller/index.html similarity index 100% rename from application/api/controller/index.html rename to app/api/controller/index.html diff --git a/application/api/index.html b/app/api/index.html similarity index 100% rename from application/api/index.html rename to app/api/index.html diff --git a/application/common.php b/app/common.php similarity index 91% rename from application/common.php rename to app/common.php index ef9eae45e..993615f11 100755 --- a/application/common.php +++ b/app/common.php @@ -11,6 +11,175 @@ // 应用公共文件 +/** + * session管理 + * @author Devil + * @blog http://gong.gg/ + * @version 1.0.0 + * @date 2021-07-17 + * @desc description + * @param [string] $name [session名称] + * @param [mixed] $value [session值] + */ +function MySession($name = '', $value = '') +{ + return session($name, $value); +} + +/** + * 缓存管理 + * @author Devil + * @blog http://gong.gg/ + * @version 1.0.0 + * @date 2021-07-17 + * @desc description + * @param [string] $name [缓存名称] + * @param [mixed] $value [缓存值] + * @param [mixed] $options [缓存参数] + * @param [string] $tag [缓存标签] + */ +function MyCache($name = null, $value = '', $options = null, $tag = null) +{ + return cache($name, $value, $options, $tag); +} + +/** + * 环境变量配置 + * @author Devil + * @blog http://gong.gg/ + * @version 1.0.0 + * @date 2021-07-17 + * @desc description + * @param [string] $key [key名称、支持.连接子数据,比如 shopxo.hello] + * @param [mixed] $val [默认值] + */ +function MyEnv($key, $val = null) +{ + return env($key, $val); +} + +/** + * 配置读取 + * @author Devil + * @blog http://gong.gg/ + * @version 1.0.0 + * @date 2021-07-17 + * @desc description + * @param [string] $key [key名称、支持.连接子数据,比如 shopxo.hello ] + */ +function MyConfig($key) +{ + return config($key); +} + +/** + * 重定向 + * @author Devil + * @blog http://gong.gg/ + * @version 1.0.0 + * @date 2021-07-16 + * @desc description + * @param [string] $url [url地址 或 模块地址] + * @param [boolean] $is_exit [是否需要结束运行、默认 false] + */ +function MyRedirect($url, $is_exit = false) +{ + if(!IsUrl($url)) + { + $url = MyUrl($url); + } + if($is_exit) + { + exit(header('location:'.$url)); + } else { + return redirect($url); + } +} + +/** + * 钩子事件定义 + * @author Devil + * @blog http://gong.gg/ + * @version 1.0.0 + * @date 2021-07-16 + * @desc description + * @param [string] $key [钩子名称] + * @param [array] $params [输入参数] + */ +function MyEventTrigger($key, $params = []) +{ + return event($key, $params); +} + +/** + * 视图赋值 + * @author Devil + * @blog http://gong.gg/ + * @version 1.0.0 + * @date 2021-07-16 + * @desc description + * @param [string] $key [key名称] + * @param [mixed] $value [数据值] + */ +function MyViewAssign($key, $value) +{ + \think\facade\View::assign($key, $value); +} + +/** + * 视图调用 + * @author Devil + * @blog http://gong.gg/ + * @version 1.0.0 + * @date 2021-07-16 + * @desc description + * @param [string] $view [视图地址] + * @param [array] $params [输入参数] + */ +function MyView($view = '', $params = []) +{ + return \think\facade\View::fetch($view, $params); +} + +/** + * 当前请求模块组名 + * @author Devil + * @blog http://gong.gg/ + * @version 1.0.0 + * @date 2021-07-16 + * @desc description + */ +function RequestModule() +{ + return strtolower(\think\facade\App::initialize()->http->getName()); +} + +/** + * 当前请求控制器名 + * @author Devil + * @blog http://gong.gg/ + * @version 1.0.0 + * @date 2021-07-16 + * @desc description + */ +function RequestController() +{ + return strtolower(request()->controller()); +} + +/** + * 当前请求方法名 + * @author Devil + * @blog http://gong.gg/ + * @version 1.0.0 + * @date 2021-07-16 + * @desc description + */ +function RequestAction() +{ + return strtolower(request()->action()); +} + /** * 获取链接http状态码 * @author Devil @@ -46,7 +215,7 @@ function GetHttpCode($url, $timeout = 5) */ function IsUrl($value) { - return in_array(substr($value, 0, 6), ['https:', 'http:/']); + return in_array(substr($value, 0, 6), ['http:/', 'https:']); } /** @@ -168,7 +337,7 @@ function MyFileConfig($key, $value = '', $default = null, $mandatory = false) \base\FileUtil::CreateDir($config_dir); // 数据文件 - $file = $config_dir.md5($key).'.php'; + $file = $config_dir.md5($key).'.txt'; // 删除 if($value === null) @@ -178,7 +347,7 @@ function MyFileConfig($key, $value = '', $default = null, $mandatory = false) // 读内容 if($value === '') { - $value = file_exists($file) ? require $file : $default; + $value = file_exists($file) ? unserialize(file_get_contents($file)) : $default; if($mandatory === true) { if(empty($value)) @@ -203,8 +372,7 @@ function MyFileConfig($key, $value = '', $default = null, $mandatory = false) } // 存储内容 - $content = ""; - return (file_put_contents($file, $content) !== false); + return (file_put_contents($file, serialize($value)) !== false); } } } @@ -515,25 +683,25 @@ function SecurityPreventViolence($key, $type = 1, $expire_time = 30) // 清除缓存返 if($type == 0) { - cache($mkey, null); + MyCache($mkey, null); return true; } // 验证并增加次数 - $count = intval(cache($mkey))+1; - $max = config('shopxo.security_prevent_violence_max'); + $count = intval(MyCache($mkey))+1; + $max = MyConfig('shopxo.security_prevent_violence_max'); $status = false; if($count <= $max) { - cache($mkey, $count, $expire_time); + MyCache($mkey, $count, $expire_time); $status = true; } // 验证达到次数限制则清除验证信息 if($count > $max) { - cache($key, null); - cache($mkey, null); + MyCache($key, null); + MyCache($mkey, null); } return $status; @@ -552,12 +720,12 @@ function FormModulePath($params = []) { // 参数变量 $path = ''; - $group = request()->module(); - $controller = request()->controller(); - $action = request()->action(); + $group = RequestModule(); + $controller = RequestController(); + $action = RequestAction(); // 是否插件调用 - if($controller == 'Plugins') + if($controller == 'plugins') { if(!empty($params['pluginsname'])) { @@ -573,7 +741,7 @@ function FormModulePath($params = []) } } } else { - $path = '\app\\'.request()->module().'\form\\'.$controller; + $path = '\app\\'.$group.'\form\\'.$controller; } return [ @@ -622,7 +790,7 @@ function ModuleInclude($template, $data = [], $params = []) * @desc description * @param [array] $data [钩子返回的数据] */ -function HookReturnHandle($data) +function EventReturnHandle($data) { if(!empty($data) && is_array($data)) { @@ -1211,33 +1379,21 @@ function SyncJob($url, $port = 80, $time = 30) } /** - * [DataReturn 公共返回数据] - * @author Devil - * @blog http://gong.gg/ - * @version 0.0.1 - * @datetime 2016-12-07T22:03:40+0800 - * @param [string] $msg [提示信息] - * @param [int] $code [状态码] - * @param [mixed] $data [数据] - * @return [json] [json数据] + * 公共返回数据 + * @author Devil + * @blog http://gong.gg/ + * @version 1.0.0 + * @date 2021-07-16 + * @desc description + * @param [string] $msg [提示信息] + * @param [int] $code [状态码] + * @param [mixed] $data [数据] + * @return [json] [json数据] */ function DataReturn($msg = '', $code = 0, $data = '') -{ - // ajax的时候,success和error错误由当前方法接收 - if(IS_AJAX) - { - if(isset($msg['info'])) - { - // success模式下code=0, error模式下code参数-1 - $result = array('msg'=>$msg['info'], 'code'=>-1, 'data'=>''); - } - } - +{ // 默认情况下,手动调用当前方法 - if(empty($result)) - { - $result = array('msg'=>$msg, 'code'=>$code, 'data'=>$data); - } + $result = ['msg'=>$msg, 'code'=>$code, 'data'=>$data]; // 错误情况下,防止提示信息为空 if($result['code'] != 0 && empty($result['msg'])) @@ -1296,11 +1452,53 @@ function CurrentScriptName() * @param string $path [路径地址] * @param array $params [参数] */ -function MyUrl($path, $params=[]) +function MyUrl($path, $params = []) { + // 当前脚本名称 + $script_name = CurrentScriptName(); + + // url模式 + $url_model = MyC('home_seo_url_model', 0); + + // 模块组状态 + $is_api = (substr($path, 0, 4) == 'api/'); + $is_admin = (substr($path, 0, 6) == 'admin/'); + $is_index = (substr($path, 0, 6) == 'index/'); + $is_install = (substr($path, 0, 8) == 'install/'); + // 调用框架生成url $url = url($path, $params, true, true); + // 非 admin 则使用配置后缀 + if(!$is_admin && !$is_install) + { + $url = $url->suffix(MyFileConfig('home_seo_url_html_suffix', '', 'html', true)); + } + + // 转 url字符串 + $url = (string) $url; + + // 去除组名称 + $join = ($script_name != 'index.php' || $url_model == 0) ? '?s=' : '/'; + $len = $is_api ? 4 : ($is_install ? 8 : 6); + $url = str_replace('/'.$path, $join.substr($path, $len), $url); + + // 避免从后台生成url入口错误 + if((!in_array($script_name, ['index.php', 'api.php'])) && substr($path, 0, 6) != 'admin/' && substr($path, 0, 8) != 'install/') + { + // api、install模块、url模式=兼容模式 + if($is_api || $is_install || $url_model == 0) + { + $url = str_replace($script_name, $index, $url); + } else { + // index并且不是兼容模式则去除入口和?s= + $url = str_replace($script_name.'?s=', '', $url); + } + } + + // 前端则去除 index.php + $url = str_replace('/index.php', '', $url); + // 是否根目录访问项目 if(defined('IS_ROOT_ACCESS')) { @@ -1313,19 +1511,6 @@ function MyUrl($path, $params=[]) $url = 'https'.mb_substr($url, 4, null, 'utf-8'); } - // 避免从后台生成url入口错误 - $script_name = CurrentScriptName(); - if($script_name != 'index.php' && substr($path, 0, 6) != 'admin/') - { - $url = str_replace($script_name, 'index.php', $url); - } - - // 开启伪静态则则去除index.php - if(MyC('home_seo_url_model', 0) != 0) - { - $url = str_replace(['/index.php?s='], '', $url); - } - return $url; } @@ -1356,30 +1541,8 @@ function PluginsHomeUrl($plugins_name, $plugins_control = '', $plugins_action = 'pluginscontrol' => $plugins_control, 'pluginsaction' => $plugins_action, ]; - $url = url('index/plugins/index', $plugins+$params, true, true); - - // 是否根目录访问项目 - if(defined('IS_ROOT_ACCESS')) - { - $url = str_replace('public/', '', $url); - } - - // tp框架url方法是否识别到https - if(__MY_HTTP__ == 'https' && substr($url, 0, 5) != 'https') - { - $url = 'https'.mb_substr($url, 4, null, 'utf-8'); - } - - // 避免从后台生成url入口错误 - $url = str_replace(CurrentScriptName(), 'index.php', $url); - - // 开启伪静态则则去除index.php - if(MyC('home_seo_url_model', 0) != 0) - { - $url = str_replace(['/index.php?s='], '', $url); - } - - return $url; + $path = 'index/plugins/index'; + return MyUrl($path, $plugins+$params); } /** @@ -1396,32 +1559,14 @@ function PluginsHomeUrl($plugins_name, $plugins_control = '', $plugins_action = */ function PluginsAdminUrl($plugins_name, $plugins_control, $plugins_action, $params = []) { + // 插件基础参数 $plugins = [ 'pluginsname' => $plugins_name, 'pluginscontrol' => $plugins_control, 'pluginsaction' => $plugins_action, ]; - $url = url('admin/plugins/index', $plugins+$params, true, true); - - // 是否根目录访问项目 - if(defined('IS_ROOT_ACCESS')) - { - $url = str_replace('public/', '', $url); - } - - // tp框架url方法是否识别到https - if(__MY_HTTP__ == 'https' && substr($url, 0, 5) != 'https') - { - $url = 'https'.mb_substr($url, 4, null, 'utf-8'); - } - - // 开启伪静态则则去除index.php - if(MyC('home_seo_url_model', 0) != 0) - { - $url = str_replace('index.php', '', $url); - } - - return $url; + $path = 'admin/plugins/index'; + return MyUrl($path, $plugins+$params); } /** @@ -1620,9 +1765,8 @@ function UrlParamJoin($param) } if(!empty($string)) { - $url_model= config('URL_MODEL'); - $join_tag = ($url_model == 0 || $url_model == 3) ? '&' : '?'; - $string = $join_tag.substr($string, 0, -1); + $join = (MyC('home_seo_url_model', 0) == 0) ? '&' : '?'; + $string = $join.substr($string, 0, -1); } } return $string; @@ -1642,7 +1786,7 @@ function UrlParamJoin($param) */ function MyC($key, $default = null, $mandatory = false) { - $data = cache($key); + $data = MyCache($key); if($mandatory === true) { return empty($data) ? $default : $data; diff --git a/app/index/config/route.php b/app/index/config/route.php new file mode 100644 index 000000000..141326d59 --- /dev/null +++ b/app/index/config/route.php @@ -0,0 +1,18 @@ + MyFileConfig('home_seo_url_html_suffix', '', 'html', true), +]; diff --git a/application/index/config/template.php b/app/index/config/view.php similarity index 61% rename from application/index/config/template.php rename to app/index/config/view.php index d1c727e46..9bdb052a6 100755 --- a/application/index/config/template.php +++ b/app/index/config/view.php @@ -9,31 +9,27 @@ // | Author: Devil // +---------------------------------------------------------------------- -/** - * 模板设置 - * @author Devil - * @blog http://gong.gg/ - * @version 0.0.1 - * @datetime 2016-12-01T21:51:08+0800 - */ +// +---------------------------------------------------------------------- +// | 模板设置 +// +---------------------------------------------------------------------- return [ - // 模板引擎类型 支持 php think 支持扩展 - 'type' => 'Think', + // 模板引擎类型使用Think + 'type' => 'Think', // 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写 3 保持操作方法 - 'auto_rule' => 1, - // 模板路径 - 'view_path' => APP_PATH.'index'.DS.'view'.DS.strtolower(MyFileConfig('common_default_theme', '', 'default', true)).DS, + 'auto_rule' => 1, + // 模板目录名 + 'view_dir_name' => 'view'.DS.strtolower(MyFileConfig('common_default_theme', '', 'default', true)), // 模板后缀 - 'view_suffix' => 'html', + 'view_suffix' => 'html', // 模板文件名分隔符 - 'view_depr' => DIRECTORY_SEPARATOR, + 'view_depr' => DIRECTORY_SEPARATOR, // 模板引擎普通标签开始标记 - 'tpl_begin' => '{{', + 'tpl_begin' => '{{', // 模板引擎普通标签结束标记 - 'tpl_end' => '}}', + 'tpl_end' => '}}', // 标签库标签开始标记 - 'taglib_begin' => '{{', + 'taglib_begin' => '{{', // 标签库标签结束标记 - 'taglib_end' => '}}', + 'taglib_end' => '}}', ]; ?> \ No newline at end of file diff --git a/application/index/controller/Agreement.php b/app/index/controller/Agreement.php similarity index 87% rename from application/index/controller/Agreement.php rename to app/index/controller/Agreement.php index 443892711..64c49dfe2 100644 --- a/application/index/controller/Agreement.php +++ b/app/index/controller/Agreement.php @@ -58,17 +58,17 @@ class Agreement extends Common // 浏览器标题 if(!empty($ret['data']['name'])) { - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle($ret['data']['name'])); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle($ret['data']['name'])); } $data = $ret['data']; } // 是否仅展示内容 $is_content = (isset($params['is_content']) && $params['is_content'] == 1) ? 0 : 1; - $this->assign('is_header', $is_content); - $this->assign('is_footer', $is_content); - $this->assign('data', $data); - return $this->fetch(); + MyViewAssign('is_header', $is_content); + MyViewAssign('is_footer', $is_content); + MyViewAssign('data', $data); + return MyView(); } } ?> \ No newline at end of file diff --git a/application/index/controller/Answer.php b/app/index/controller/Answer.php similarity index 88% rename from application/index/controller/Answer.php rename to app/index/controller/Answer.php index 3d50c749f..ea185d613 100755 --- a/application/index/controller/Answer.php +++ b/app/index/controller/Answer.php @@ -72,13 +72,13 @@ class Answer extends Common $ret = AnswerService::AnswerList($data_params); // 浏览器名称 - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle('问答/留言', 1)); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle('问答/留言', 1)); // 基础参数赋值 - $this->assign('params', $this->data_request); - $this->assign('page_html', $page->GetPageHtml()); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + MyViewAssign('page_html', $page->GetPageHtml()); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -106,12 +106,12 @@ class Answer extends Common ]; $ret = AnswerService::AnswerList($data_params); $data = (empty($ret['data']) || empty($ret['data'][0])) ? [] : $ret['data'][0]; - $this->assign('data', $data); + MyViewAssign('data', $data); } - $this->assign('is_header', 0); - $this->assign('is_footer', 0); - return $this->fetch(); + MyViewAssign('is_header', 0); + MyViewAssign('is_footer', 0); + return MyView(); } /** diff --git a/application/index/controller/Article.php b/app/index/controller/Article.php similarity index 75% rename from application/index/controller/Article.php rename to app/index/controller/Article.php index 0dfbe4fad..c60f27901 100755 --- a/application/index/controller/Article.php +++ b/app/index/controller/Article.php @@ -47,8 +47,8 @@ class Article extends Common // 获取文章 if(empty($this->data_request['id'])) { - $this->assign('msg', '文章ID有误'); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', '文章ID有误'); + return MyView('public/tips_error'); } // 获取数据 @@ -71,32 +71,32 @@ class Article extends Common // 是否外部链接 if(!empty($ret['data'][0]['jump_url'])) { - return redirect($ret['data'][0]['jump_url']); + return MyRedirect($ret['data'][0]['jump_url']); } // 获取分类 $article_category_content = ArticleService::ArticleCategoryListContent(); - $this->assign('category_list', $article_category_content['data']); + MyViewAssign('category_list', $article_category_content['data']); // seo $seo_title = empty($ret['data'][0]['seo_title']) ? $ret['data'][0]['title'] : $ret['data'][0]['seo_title']; - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle($seo_title, 2)); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle($seo_title, 2)); if(!empty($ret['data'][0]['seo_keywords'])) { - $this->assign('home_seo_site_keywords', $ret['data'][0]['seo_keywords']); + MyViewAssign('home_seo_site_keywords', $ret['data'][0]['seo_keywords']); } if(!empty($ret['data'][0]['seo_desc'])) { - $this->assign('home_seo_site_description', $ret['data'][0]['seo_desc']); + MyViewAssign('home_seo_site_description', $ret['data'][0]['seo_desc']); } - $this->assign('article', $ret['data'][0]); - return $this->fetch(); + MyViewAssign('article', $ret['data'][0]); + return MyView(); } // 无数据 - $this->assign('msg', '文章不存在或已删除'); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', '文章不存在或已删除'); + return MyView('public/tips_error'); } } ?> \ No newline at end of file diff --git a/application/index/controller/Buy.php b/app/index/controller/Buy.php similarity index 78% rename from application/index/controller/Buy.php rename to app/index/controller/Buy.php index bc17352da..8b46fee77 100755 --- a/application/index/controller/Buy.php +++ b/app/index/controller/Buy.php @@ -10,7 +10,6 @@ // +---------------------------------------------------------------------- namespace app\index\controller; -use think\facade\Hook; use app\service\SystemBaseService; use app\service\GoodsService; use app\service\UserService; @@ -55,22 +54,22 @@ class Buy extends Common { if($this->data_post) { - session('buy_post_data', $this->data_post); - return redirect(MyUrl('index/buy/index')); + MySession('buy_post_data', $this->data_post); + return MyRedirect(MyUrl('index/buy/index')); } else { // 站点类型,是否开启了展示型 if(SystemBaseService::SiteTypeValue() == 1) { - $this->assign('msg', '展示型不允许提交订单'); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', '展示型不允许提交订单'); + return MyView('public/tips_error'); } // 获取下单信息 - $data = session('buy_post_data'); + $data = MySession('buy_post_data'); if(empty($data)) { - $this->assign('msg', '商品信息为空'); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', '商品信息为空'); + return MyView('public/tips_error'); } // 参数 @@ -87,13 +86,13 @@ class Buy extends Common // 用户地址 $address = UserAddressService::UserAddressList(['user'=>$this->user]); - $this->assign('user_address_list', $address['data']); + MyViewAssign('user_address_list', $address['data']); // 支付方式 - $this->assign('payment_list', PaymentService::BuyPaymentList(['is_enable'=>1, 'is_open_user'=>1])); + MyViewAssign('payment_list', PaymentService::BuyPaymentList(['is_enable'=>1, 'is_open_user'=>1])); // 公共销售模式 - $this->assign('common_site_type', $buy_base['common_site_type']); + MyViewAssign('common_site_type', $buy_base['common_site_type']); // 地址选中处理 // 防止选中id不存在地址列表中 @@ -104,22 +103,22 @@ class Buy extends Common } // 加载百度地图api - $this->assign('is_load_baidu_map_api', 1); + MyViewAssign('is_load_baidu_map_api', 1); // 钩子 $this->PluginsHook($buy_ret['data'], $params); // 浏览器名称 - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle('订单确认', 1)); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle('订单确认', 1)); // 页面数据 - $this->assign('base', $buy_base); - $this->assign('buy_goods', $buy_goods); - $this->assign('params', $params); - return $this->fetch(); + MyViewAssign('base', $buy_base); + MyViewAssign('buy_goods', $buy_goods); + MyViewAssign('params', $params); + return MyView(); } else { - $this->assign('msg', isset($ret['msg']) ? $ret['msg'] : '参数错误'); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', isset($ret['msg']) ? $ret['msg'] : '参数错误'); + return MyView('public/tips_error'); } } } @@ -169,7 +168,7 @@ class Buy extends Common ]; foreach($hook_arr as $hook_name) { - $this->assign($hook_name.'_data', Hook::listen($hook_name, + MyViewAssign($hook_name.'_data', MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => false, @@ -195,8 +194,8 @@ class Buy extends Common $params['user'] = $this->user; return BuyService::OrderInsert($params); } else { - $this->assign('msg', '非法访问'); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', '非法访问'); + return MyView('public/tips_error'); } } } diff --git a/application/index/controller/Cart.php b/app/index/controller/Cart.php similarity index 93% rename from application/index/controller/Cart.php rename to app/index/controller/Cart.php index 6581268cb..4eeee350c 100755 --- a/application/index/controller/Cart.php +++ b/app/index/controller/Cart.php @@ -48,17 +48,17 @@ class Cart extends Common public function Index() { $cart_list = BuyService::CartList(['user'=>$this->user]); - $this->assign('cart_list', $cart_list['data']); + MyViewAssign('cart_list', $cart_list['data']); $base = [ 'total_price' => empty($cart_list['data']) ? 0 : array_sum(array_column($cart_list['data'], 'total_price')), 'buy_count' => empty($cart_list['data']) ? 0 : array_sum(array_column($cart_list['data'], 'stock')), ]; - $this->assign('base', $base); + MyViewAssign('base', $base); // 浏览器名称 - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle('购物车', 1)); - return $this->fetch(); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle('购物车', 1)); + return MyView(); } /** diff --git a/application/index/controller/Category.php b/app/index/controller/Category.php similarity index 91% rename from application/index/controller/Category.php rename to app/index/controller/Category.php index 15b79410f..c02db61ff 100755 --- a/application/index/controller/Category.php +++ b/app/index/controller/Category.php @@ -44,9 +44,9 @@ class Category extends Common public function Index() { // 浏览器名称 - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle('商品分类', 1)); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle('商品分类', 1)); - return $this->fetch(); + return MyView(); } } ?> \ No newline at end of file diff --git a/app/index/controller/Common.php b/app/index/controller/Common.php new file mode 100755 index 000000000..6496f616a --- /dev/null +++ b/app/index/controller/Common.php @@ -0,0 +1,588 @@ +data_post = input('post.'); + $this->data_get = input('get.'); + $this->data_request = input(); + + // 系统初始化 + $this->SystemInit(); + + // 系统运行开始 + SystemService::SystemBegin($this->data_request); + + // 站点状态校验 + $this->SiteStstusCheck(); + + // 公共数据初始化 + $this->CommonInit(); + + // 菜单 + $this->NavInit(); + + // 视图初始化 + $this->ViewInit(); + + // 动态表格初始化 + $this->FormTableInit(); + + // 公共钩子初始化 + $this->CommonPluginsInit(); + } + + /** + * 析构函数 + * @author Devil + * @blog http://gong.gg/ + * @version 1.0.0 + * @date 2019-03-18 + * @desc description + */ + public function __destruct() + { + // 系统运行结束 + SystemService::SystemEnd($this->data_request); + } + + /** + * 系统初始化 + * @author Devil + * @blog http://gong.gg/ + * @version 1.0.0 + * @date 2018-12-07 + * @desc description + */ + private function SystemInit() + { + // 配置信息初始化 + ConfigService::ConfigInit(); + + // 推荐人 + if(!empty($this->data_request['referrer'])) + { + MySession('share_referrer_id', $this->data_request['referrer']); + } + } + + /** + * [CommonInit 公共数据初始化] + * @author Devil + * @blog http://gong.gg/ + * @version 0.0.1 + * @datetime 2017-03-09T11:43:48+0800 + */ + private function CommonInit() + { + // 用户数据 + $this->user = UserService::LoginUserInfo(); + } + + /** + * [IsLogin 登录校验] + * @author Devil + * @blog http://gong.gg/ + * @version 0.0.1 + * @datetime 2017-03-09T11:43:48+0800 + */ + protected function IsLogin() + { + if(empty($this->user)) + { + if(IS_AJAX) + { + exit(json_encode(DataReturn('登录失效,请重新登录', -400))); + } else { + MyRedirect('index/user/logininfo', true); + } + } + } + + /** + * [ViewInit 视图初始化] + * @author Devil + * @blog http://gong.gg/ + * @version 0.0.1 + * @datetime 2016-12-03T12:30:06+0800 + */ + public function ViewInit() + { + // 公共参数 + MyViewAssign('params', $this->data_request); + + // 货币符号 + MyViewAssign('currency_symbol', ResourcesService::CurrencyDataSymbol()); + + // 站点类型 + MyViewAssign('common_site_type', SystemBaseService::SiteTypeValue()); + + // 预约模式 + MyViewAssign('common_order_is_booking', MyC('common_order_is_booking', 0, true)); + + // 商店信息 + MyViewAssign('common_customer_store_tel', MyC('common_customer_store_tel')); + MyViewAssign('common_customer_store_email', MyC('common_customer_store_email')); + MyViewAssign('common_customer_store_address', MyC('common_customer_store_address')); + MyViewAssign('common_customer_store_qrcode', AttachmentPathViewHandle(MyC('common_customer_store_qrcode'))); + + // 主题 + $default_theme = strtolower(MyC('common_default_theme', 'default', true)); + MyViewAssign('default_theme', $default_theme); + + // 当前操作名称, 兼容插件模块名称 + $this->module_name = RequestModule(); + $this->controller_name = RequestController(); + $this->action_name = RequestAction(); + + // 当前操作名称 + MyViewAssign('module_name', $this->module_name); + MyViewAssign('controller_name', $this->controller_name); + MyViewAssign('action_name', $this->action_name); + + // 分页信息 + $this->page = max(1, isset($this->data_request['page']) ? intval($this->data_request['page']) : 1); + $this->page_size = MyC('common_page_size', 10, true); + MyViewAssign('page', $this->page); + MyViewAssign('page_size', $this->page_size); + + // 控制器静态文件状态css,js + $module_css = $this->module_name.DS.$default_theme.DS.'css'.DS.$this->controller_name; + $module_css .= file_exists(ROOT_PATH.'static'.DS.$module_css.'.'.$this->action_name.'.css') ? '.'.$this->action_name.'.css' : '.css'; + MyViewAssign('module_css', file_exists(ROOT_PATH.'static'.DS.$module_css) ? $module_css : ''); + + $module_js = $this->module_name.DS.$default_theme.DS.'js'.DS.$this->controller_name; + $module_js .= file_exists(ROOT_PATH.'static'.DS.$module_js.'.'.$this->action_name.'.js') ? '.'.$this->action_name.'.js' : '.js'; + MyViewAssign('module_js', file_exists(ROOT_PATH.'static'.DS.$module_js) ? $module_js : ''); + + // 导航 + MyViewAssign('nav_header', $this->nav_header); + MyViewAssign('nav_footer', $this->nav_footer); + MyViewAssign('nav_quick', $this->nav_quick); + + // 导航/底部默认显示 + MyViewAssign('is_header', 1); + MyViewAssign('is_footer', 1); + + // 左侧大分类是否隐藏展开 + $common_goods_category_hidden = ($this->controller_name != 'index' || MyC('home_index_banner_left_status', 1) != 1) ? 1 : 0; + MyViewAssign('common_goods_category_hidden', $common_goods_category_hidden); + + // 价格正则 + MyViewAssign('default_price_regex', lang('common_regex_price')); + + // 附件host地址 + MyViewAssign('attachment_host', SystemBaseService::AttachmentHost()); + + // css/js引入host地址 + MyViewAssign('public_host', MyConfig('shopxo.public_host')); + + // 当前url地址 + MyViewAssign('my_url', __MY_URL__); + + // 项目public目录URL地址 + MyViewAssign('my_public_url', __MY_PUBLIC_URL__); + + // 当前http类型 + MyViewAssign('my_http', __MY_HTTP__); + + // url模式 + MyViewAssign('url_model', MyC('home_seo_url_model', 0)); + + // seo + MyViewAssign('home_seo_site_title', MyC('home_seo_site_title')); + MyViewAssign('home_seo_site_keywords', MyC('home_seo_site_keywords')); + MyViewAssign('home_seo_site_description', MyC('home_seo_site_description')); + + // 用户数据 + MyViewAssign('user', $this->user); + + // 用户中心菜单 + MyViewAssign('user_left_menu', NavigationService::UsersCenterLeftList()); + + // 商品大分类 + MyViewAssign('goods_category_list', GoodsService::GoodsCategoryAll()); + + // 搜索框下热门关键字 + MyViewAssign('home_search_keywords', SearchService::SearchKeywordsList()); + + // 友情链接 + $link = LinkService::LinkList(['where'=>['is_enable'=>1]]); + MyViewAssign('link_list', $link['data']); + + // 开发模式 + MyViewAssign('shopxo_is_develop', MyConfig('shopxo.is_develop')); + + // 顶部右侧导航 + MyViewAssign('common_nav_top_right_list', NavigationService::HomeHavTopRight(['user'=>$this->user])); + + // 底部导航 + MyViewAssign('common_bottom_nav_list', NavigationService::BottomNavigation(['user'=>$this->user])); + + // 编辑器文件存放地址 + MyViewAssign('editor_path_type', ResourcesService::EditorPathTypeValue(empty($this->user['id']) ? 'public' : 'user-'.$this->user['id'])); + + // 分类展示层级模式 + MyViewAssign('category_show_level', MyC('common_show_goods_category_level', 3, true)); + + // 备案信息 + MyViewAssign('home_site_icp', MyC('home_site_icp')); + MyViewAssign('home_site_security_record_name', MyC('home_site_security_record_name')); + MyViewAssign('home_site_security_record_url', MyC('home_site_security_record_url')); + + // 布局样式+管理 + MyViewAssign('is_load_layout', 0); + MyViewAssign('is_load_layout_admin', 0); + + // 默认不加载放大镜 + MyViewAssign('is_load_imagezoom', 0); + + // 默认不加载百度地图api + MyViewAssign('is_load_baidu_map_api', 0); + + // 是否加载附件组件 + MyViewAssign('is_load_upload_editor', (!empty($this->user) || AdminService::LoginInfo()) ? 1 : 0); + + // 存在地图事件则载入 + if(in_array(3, array_column($this->nav_quick, 'event_type'))) + { + MyViewAssign('is_load_baidu_map_api', 1); + } + + // 登录/注册方式 + MyViewAssign('home_user_login_type', MyC('home_user_login_type', [], true)); + MyViewAssign('home_user_reg_type', MyC('home_user_reg_type', [], true)); + + // 底部信息 + MyViewAssign('home_theme_footer_bottom_powered', htmlspecialchars_decode(MyC('home_theme_footer_bottom_powered'))); + } + + /** + * 动态表格初始化 + * @author Devil + * @blog http://gong.gg/ + * @version 1.0.0 + * @date 2020-06-02 + * @desc description + */ + public function FormTableInit() + { + // 获取表格模型 + $module = FormModulePath($this->data_request); + if(!empty($module)) + { + // 调用表格处理 + $params = $this->data_request; + $params['system_user'] = $this->user; + $ret = (new FormHandleModule())->Run($module['module'], $module['action'], $params); + if($ret['code'] == 0) + { + $this->form_table = $ret['data']['table']; + $this->form_where = $ret['data']['where']; + $this->form_params = $ret['data']['params']; + $this->form_md5_key = $ret['data']['md5_key']; + $this->form_user_fields = $ret['data']['user_fields']; + $this->form_order_by = $ret['data']['order_by']; + + MyViewAssign('form_table', $this->form_table); + MyViewAssign('form_params', $this->form_params); + MyViewAssign('form_md5_key', $this->form_md5_key); + MyViewAssign('form_user_fields', $this->form_user_fields); + MyViewAssign('form_order_by', $this->form_order_by); + } else { + $this->form_error = $ret['msg']; + MyViewAssign('form_error', $this->form_error); + } + } + } + + /** + * [NavInit 导航初始化] + * @author Devil + * @blog http://gong.gg/ + * @version 0.0.1 + * @datetime 2016-12-19T22:41:20+0800 + */ + private function NavInit() + { + // 主导航和底部导航 + $nav = NavigationService::Nav(); + $this->nav_header = $nav['header']; + $this->nav_footer = $nav['footer']; + + // 快捷导航 + $this->nav_quick = QuickNavService::QuickNav(); + } + + /** + * [SiteStstusCheck 站点状态校验] + * @author Devil + * @blog http://gong.gg/ + * @version 0.0.1 + * @datetime 2017-02-25T21:43:07+0800 + */ + private function SiteStstusCheck() + { + if(MyC('home_site_state') != 1) + { + // 是否ajax请求 + if(IS_AJAX) + { + exit(json_encode(DataReturn(MyC('home_site_close_reason', '网站维护中...'), -10000))); + } else { + exit('
'.MyC('home_site_close_reason', '网站维护中...', true).'
'); + } + } + } + + /** + * 成功提示 + * @author Devil + * @blog http://gong.gg/ + * @version 1.0.0 + * @date 2021-07-15 + * @desc description + * @param [string] $msg [提示信息、默认(操作成功)] + */ + public function success($msg) + { + if(IS_AJAX) + { + return DataReturn($msg, 0); + } else { + MyViewAssign('msg', $msg); + return MyView('public/jump_success'); + } + } + + /** + * 错误提示 + * @author Devil + * @blog http://gong.gg/ + * @version 1.0.0 + * @date 2021-07-15 + * @desc description + * @param [string] $msg [提示信息、默认(操作失败)] + */ + public function error($msg) + { + if(IS_AJAX) + { + return DataReturn($msg, -1); + } else { + MyViewAssign('msg', $msg); + return MyView('public/jump_error'); + } + } + + /** + * 空方法响应 + * @author Devil + * @blog http://gong.gg/ + * @version 1.0.0 + * @date 2018-11-30 + * @desc description + * @param [string] $method [方法名称] + * @param [array] $args [参数] + */ + public function __call($method, $args) + { + if(IS_AJAX) + { + return DataReturn($method.' 非法访问', -1000); + } else { + MyViewAssign('msg', $method.' 非法访问'); + return MyView('public/tips_error'); + } + } + + /** + * 公共钩子初始化 + * @author Devil + * @blog http://gong.gg/ + * @version 1.0.0 + * @date 2018-12-07 + * @desc description + */ + private function CommonPluginsInit() + { + // css钩子 + MyViewAssign('plugins_css_data', MyEventTrigger('plugins_css', ['hook_name'=>'plugins_css', 'is_backend'=>false])); + + // js钩子 + MyViewAssign('plugins_js_data', MyEventTrigger('plugins_js', ['hook_name'=>'plugins_js', 'is_backend'=>false])); + + // 公共header内钩子 + MyViewAssign('plugins_common_header_data', MyEventTrigger('plugins_common_header', ['hook_name'=>'plugins_common_header', 'is_backend'=>false, 'user'=>$this->user])); + + // 公共页面底部钩子 + MyViewAssign('plugins_common_page_bottom_data', MyEventTrigger('plugins_common_page_bottom', ['hook_name'=>'plugins_common_page_bottom', 'is_backend'=>false, 'user'=>$this->user])); + + // 公共顶部钩子 + MyViewAssign('plugins_view_common_top_data', MyEventTrigger('plugins_view_common_top', ['hook_name'=>'plugins_view_common_top', 'is_backend'=>false, 'user'=>$this->user])); + + // 公共底部钩子 + MyViewAssign('plugins_view_common_bottom_data', MyEventTrigger('plugins_view_common_bottom', ['hook_name'=>'plugins_view_common_bottom', 'is_backend'=>false, 'user'=>$this->user])); + + // 公共顶部小导航钩子-左侧前面 + MyViewAssign('plugins_view_header_navigation_top_left_begin_data', MyEventTrigger('plugins_view_header_navigation_top_left_begin', ['hook_name'=>'plugins_view_header_navigation_top_left_begin', 'is_backend'=>false, 'user'=>$this->user])); + + // 公共顶部小导航钩子-左侧后面 + MyViewAssign('plugins_view_header_navigation_top_left_end_data', MyEventTrigger('plugins_view_header_navigation_top_left_end', ['hook_name'=>'plugins_view_header_navigation_top_left_end', 'is_backend'=>false, 'user'=>$this->user])); + + // 公共顶部小导航钩子-右侧前面 + MyViewAssign('plugins_view_header_navigation_top_right_begin_data', MyEventTrigger('plugins_view_header_navigation_top_right_begin', ['hook_name'=>'plugins_view_header_navigation_top_right_begin', 'is_backend'=>false, 'user'=>$this->user])); + + // 公共顶部小导航钩子-右侧后面 + MyViewAssign('plugins_view_header_navigation_top_right_end_data', MyEventTrigger('plugins_view_header_navigation_top_right_end', ['hook_name'=>'plugins_view_header_navigation_top_right_end', 'is_backend'=>false, 'user'=>$this->user])); + + // 用户登录页面顶部钩子 + MyViewAssign('plugins_view_user_login_info_top_data', MyEventTrigger('plugins_view_user_login_info_top', ['hook_name'=>'plugins_view_user_login_info_top', 'is_backend'=>false, 'user'=>$this->user])); + + // 用户登录内底部钩子 + MyViewAssign('plugins_view_user_login_inside_bottom_data', MyEventTrigger('plugins_view_user_login_inside_bottom', ['hook_name'=>'plugins_view_user_login_inside_bottom', 'is_backend'=>false, 'user'=>$this->user])); + + // 用户登录内容页面底部钩子 + MyViewAssign('plugins_view_user_login_content_bottom_data', MyEventTrigger('plugins_view_user_login_content_bottom', ['hook_name'=>'plugins_view_user_login_content_bottom', 'is_backend'=>false, 'user'=>$this->user])); + + // 用户注册页面钩子 + MyViewAssign('plugins_view_user_reg_info_data', MyEventTrigger('plugins_view_user_reg_info', ['hook_name'=>'plugins_view_user_reg_info', 'is_backend'=>false, 'user'=>$this->user])); + + // 用户注册页面顶部钩子 + MyViewAssign('plugins_view_user_reg_info_top_data', MyEventTrigger('plugins_view_user_reg_info_top', ['hook_name'=>'plugins_view_user_reg_info_top', 'is_backend'=>false, 'user'=>$this->user])); + + // 用户注册页面内底部钩子 + MyViewAssign('plugins_view_user_reg_info_inside_bottom_data', MyEventTrigger('plugins_view_user_reg_info_inside_bottom', ['hook_name'=>'plugins_view_user_reg_info_inside_bottom', 'is_backend'=>false, 'user'=>$this->user])); + + // 用户注册页面底部钩子 + MyViewAssign('plugins_view_user_reg_info_bottom_data', MyEventTrigger('plugins_view_user_reg_info_bottom', ['hook_name'=>'plugins_view_user_reg_info_bottom', 'is_backend'=>false, 'user'=>$this->user])); + + // 底部导航上面钩子 + MyViewAssign('plugins_view_common_footer_top_data', MyEventTrigger('plugins_view_common_footer_top', ['hook_name'=>'plugins_view_common_footer_top', 'is_backend'=>false, 'user'=>$this->user])); + + // logo右侧 + MyViewAssign('plugins_view_common_logo_right_data', MyEventTrigger('plugins_view_common_logo_right', ['hook_name'=>'plugins_view_common_logo_right', 'is_backend'=>false, 'user'=>$this->user])); + + // 公共搜索框右侧 + MyViewAssign('plugins_view_common_search_right_data', MyEventTrigger('plugins_view_common_search_right', ['hook_name'=>'plugins_view_common_search_right', 'is_backend'=>false, 'user'=>$this->user])); + + // 公共表格钩子名称动态处理 + $current = 'plugins_view_index_'.$this->controller_name; + + // 是否插件默认下 + if($this->controller_name == 'plugins') + { + if(!empty($this->data_request['pluginsname'])) + { + $current .= '_'.trim($this->data_request['pluginsname']); + } + } + + // 内容外部顶部 + MyViewAssign('hook_name_content_top', $current.'_content_top'); + // 内容外部底部 + MyViewAssign('hook_name_content_bottom', $current.'_content_bottom'); + // 内容内部顶部 + MyViewAssign('hook_name_content_inside_top', $current.'_content_inside_top'); + // 内容内部底部 + MyViewAssign('hook_name_content_inside_bottom', $current.'_content_inside_bottom'); + // 表格列表顶部操作 + MyViewAssign('hook_name_form_top_operate', $current.'_top_operate'); + // 表格列表底部操作 + MyViewAssign('hook_name_form_bottom_operate', $current.'_bottom_operate'); + // 表格列表后面操作栏 + MyViewAssign('hook_name_form_list_operate', $current.'_list_operate'); + + // 公共详情页面钩子名称动态处理 + // 内容外部顶部 + MyViewAssign('hook_name_detail_top', $current.'_detail_top'); + // 内容外部底部 + MyViewAssign('hook_name_detail_bottom', $current.'_detail_bottom'); + // 内容内部顶部 + MyViewAssign('hook_name_detail_inside_top', $current.'_detail_inside_top'); + // 内容内部底部 + MyViewAssign('hook_name_detail_inside_bottom', $current.'_detail_inside_bottom'); + } +} +?> \ No newline at end of file diff --git a/application/index/controller/Customview.php b/app/index/controller/Customview.php similarity index 77% rename from application/index/controller/Customview.php rename to app/index/controller/Customview.php index 8db1c042c..6d6be1e75 100755 --- a/application/index/controller/Customview.php +++ b/app/index/controller/Customview.php @@ -59,15 +59,15 @@ class CustomView extends Common CustomViewService::CustomViewAccessCountInc(['id'=>$id]); // 浏览器标题 - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle($data['data'][0]['title'])); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle($data['data'][0]['title'])); - $this->assign('data', $data['data'][0]); - $this->assign('is_header', $data['data'][0]['is_header']); - $this->assign('is_footer', $data['data'][0]['is_footer']); - return $this->fetch(); + MyViewAssign('data', $data['data'][0]); + MyViewAssign('is_header', $data['data'][0]['is_header']); + MyViewAssign('is_footer', $data['data'][0]['is_footer']); + return MyView(); } else { - $this->assign('msg', '页面不存在或已删除'); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', '页面不存在或已删除'); + return MyView('public/tips_error'); } } } diff --git a/application/index/controller/Design.php b/app/index/controller/Design.php similarity index 79% rename from application/index/controller/Design.php rename to app/index/controller/Design.php index 2771f74ce..bdf7ddd35 100644 --- a/application/index/controller/Design.php +++ b/app/index/controller/Design.php @@ -69,30 +69,30 @@ class Design extends Common // 配置处理 $layout_data = BaseLayout::ConfigHandle($data['config']); - $this->assign('layout_data', $layout_data); + MyViewAssign('layout_data', $layout_data); // 加载布局样式 - $this->assign('is_load_layout', 1); + MyViewAssign('is_load_layout', 1); // seo $seo_title = empty($data['seo_title']) ? $data['name'] : $data['seo_title']; - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle($seo_title, 2)); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle($seo_title, 2)); if(!empty($data['seo_keywords'])) { - $this->assign('home_seo_site_keywords', $data['seo_keywords']); + MyViewAssign('home_seo_site_keywords', $data['seo_keywords']); } if(!empty($data['seo_desc'])) { - $this->assign('home_seo_site_description', $data['seo_desc']); + MyViewAssign('home_seo_site_description', $data['seo_desc']); } // 头尾 - $this->assign('is_header', $data['is_header']); - $this->assign('is_footer', $data['is_footer']); - return $this->fetch(); + MyViewAssign('is_header', $data['is_header']); + MyViewAssign('is_footer', $data['is_footer']); + return MyView(); } - $this->assign('msg', '页面不存在或已删除'); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', '页面不存在或已删除'); + return MyView('public/tips_error'); } } ?> \ No newline at end of file diff --git a/application/index/controller/Error.php b/app/index/controller/Error.php similarity index 74% rename from application/index/controller/Error.php rename to app/index/controller/Error.php index 3dac69051..a5317e7e8 100755 --- a/application/index/controller/Error.php +++ b/app/index/controller/Error.php @@ -10,8 +10,6 @@ // +---------------------------------------------------------------------- namespace app\index\controller; -use think\Request; - /** * 空控制器响应 * @author Devil @@ -29,16 +27,17 @@ class Error extends Common * @version 1.0.0 * @date 2018-11-30 * @desc description - * @param Request $request [参数] + * @param [string] $method [方法名称] + * @param [array] $args [参数] */ - public function Index(Request $request) + public function __call($method, $args) { if(IS_AJAX) { - exit(json_encode(DataReturn($request->controller().' 控制器不存在', -1000))); + return DataReturn(RequestController().' 控制器不存在', -1000); } else { - $this->assign('msg', $request->controller().' 控制器不存在'); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', RequestController().' 控制器不存在'); + return MyView('public/tips_error'); } } } diff --git a/application/index/controller/Formtable.php b/app/index/controller/Formtable.php similarity index 100% rename from application/index/controller/Formtable.php rename to app/index/controller/Formtable.php diff --git a/application/index/controller/Goods.php b/app/index/controller/Goods.php similarity index 90% rename from application/index/controller/Goods.php rename to app/index/controller/Goods.php index 3fb9049f9..9143938e2 100755 --- a/application/index/controller/Goods.php +++ b/app/index/controller/Goods.php @@ -10,7 +10,6 @@ // +---------------------------------------------------------------------- namespace app\index\controller; -use think\facade\Hook; use app\service\GoodsService; use app\service\GoodsCommentsService; use app\service\GoodsBrowseService; @@ -61,8 +60,8 @@ class Goods extends Common $ret = GoodsService::GoodsList($params); if(empty($ret['data'][0]) || $ret['data'][0]['is_delete_time'] != 0) { - $this->assign('msg', '资源不存在或已被删除'); - return $this->fetch('/public/tips_error'); + MyViewAssign('msg', '资源不存在或已被删除'); + return MyView('/public/tips_error'); } else { // 商品信息 $goods = $ret['data'][0]; @@ -81,24 +80,24 @@ class Goods extends Common $this->PluginsHook($goods_id, $goods); // 商品数据 - $this->assign('goods', $goods); + MyViewAssign('goods', $goods); // seo $seo_title = empty($goods['seo_title']) ? $goods['title'] : $goods['seo_title']; - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle($seo_title, 2)); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle($seo_title, 2)); if(!empty($goods['seo_keywords'])) { - $this->assign('home_seo_site_keywords', $goods['seo_keywords']); + MyViewAssign('home_seo_site_keywords', $goods['seo_keywords']); } if(!empty($goods['seo_desc'])) { - $this->assign('home_seo_site_description', $goods['seo_desc']); + MyViewAssign('home_seo_site_description', $goods['seo_desc']); } // 二维码 $qrcode = GoodsService::GoodsQrcode($goods_id, $goods['add_time']); $qrcode_url = ($qrcode['code'] == 0 && isset($qrcode['data']['url'])) ? $qrcode['data']['url'] : ''; - $this->assign('qrcode_url', $qrcode_url); + MyViewAssign('qrcode_url', $qrcode_url); // 商品访问统计 GoodsService::GoodsAccessCountInc(['goods_id'=>$goods_id]); @@ -108,17 +107,17 @@ class Goods extends Common // 商品购买按钮列表 $buy_button = GoodsService::GoodsBuyButtonList($goods); - $this->assign('buy_button', $buy_button); + MyViewAssign('buy_button', $buy_button); // 中间tabs导航 $middle_tabs_nav = GoodsService::GoodsDetailMiddleTabsNavList($goods); - $this->assign('middle_tabs_nav', $middle_tabs_nav); + MyViewAssign('middle_tabs_nav', $middle_tabs_nav); // 详情商品评分 if(!empty($middle_tabs_nav) && in_array('comments', $middle_tabs_nav['type'])) { $goods_score = GoodsCommentsService::GoodsCommentsScore($goods_id); - $this->assign('goods_score', $goods_score['data']); + MyViewAssign('goods_score', $goods_score['data']); } // 详情tab商品 猜你喜欢 @@ -134,7 +133,7 @@ class Goods extends Common 'n' => 16, ]; $like_goods = GoodsService::GoodsList($params); - $this->assign('detail_like_goods', $like_goods['data']); + MyViewAssign('detail_like_goods', $like_goods['data']); } // 左侧商品 看了又看 @@ -148,15 +147,15 @@ class Goods extends Common 'n' => 10, ]; $right_goods = GoodsService::GoodsList($params); - $this->assign('left_goods', $right_goods['data']); + MyViewAssign('left_goods', $right_goods['data']); // 是否商品详情页展示相册 - $this->assign('common_is_goods_detail_show_photo', MyC('common_is_goods_detail_show_photo', 0, true)); + MyViewAssign('common_is_goods_detail_show_photo', MyC('common_is_goods_detail_show_photo', 0, true)); // 加载放大镜 - $this->assign('is_load_imagezoom', 1); + MyViewAssign('is_load_imagezoom', 1); - return $this->fetch(); + return MyView(); } } @@ -244,7 +243,7 @@ class Goods extends Common ]; foreach($hook_arr as $hook_name) { - $this->assign($hook_name.'_data', Hook::listen($hook_name, + MyViewAssign($hook_name.'_data', MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => false, @@ -372,7 +371,7 @@ class Goods extends Common 'number' => $number, 'total' => $total, 'page_total' => $page_total, - 'data' => $this->fetch(null, ['data'=>$data['data']]), + 'data' => MyView(null, ['data'=>$data['data']]), ]; return DataReturn('请求成功', 0, $result); } diff --git a/application/index/controller/Index.php b/app/index/controller/Index.php similarity index 69% rename from application/index/controller/Index.php rename to app/index/controller/Index.php index 0e8112db7..9a1930f84 100755 --- a/application/index/controller/Index.php +++ b/app/index/controller/Index.php @@ -10,7 +10,6 @@ // +---------------------------------------------------------------------- namespace app\index\controller; -use think\facade\Hook; use app\layout\service\BaseLayout; use app\service\SeoService; use app\service\AdminService; @@ -55,73 +54,73 @@ class Index extends Common { // 首页轮播 $banner = BannerService::Banner(); - $this->assign('banner_list', $banner); + MyViewAssign('banner_list', $banner); // 数据模式 $floor_data_type = MyC('home_index_floor_data_type', 0, true); - $this->assign('floor_data_type', $floor_data_type); + MyViewAssign('floor_data_type', $floor_data_type); // 是否设计模式 $is_design = (!empty($this->data_request['save_url']) && isset($this->data_request['is_design']) && $this->data_request['is_design'] == 1 && $floor_data_type == 2 && AdminService::LoginInfo()) ? 1 : 0; - $this->assign('is_design', $is_design); + MyViewAssign('is_design', $is_design); if($is_design == 1) { // 保存数据地址 - $this->assign('layout_save_url', base64_decode(urldecode($this->data_request['save_url']))); + MyViewAssign('layout_save_url', base64_decode(urldecode($this->data_request['save_url']))); // 设计配置数据 $layout_data = LayoutService::LayoutConfigAdminData('home'); - $this->assign('layout_data', $layout_data); + MyViewAssign('layout_data', $layout_data); // 页面列表 $pages_list = BaseLayout::PagesList(); - $this->assign('pages_list', $pages_list); + MyViewAssign('pages_list', $pages_list); // 商品分类 $goods_category = GoodsService::GoodsCategoryAll(); - $this->assign('goods_category_list', $goods_category); + MyViewAssign('goods_category_list', $goods_category); // 商品搜索分类(分类) - $this->assign('layout_goods_category', $goods_category); - $this->assign('layout_goods_category_field', 'gci.category_id'); + MyViewAssign('layout_goods_category', $goods_category); + MyViewAssign('layout_goods_category_field', 'gci.category_id'); // 品牌 - $this->assign('brand_list', BrandService::CategoryBrand()); + MyViewAssign('brand_list', BrandService::CategoryBrand()); // 静态数据 - $this->assign('border_style_type_list', BaseLayout::$border_style_type_list); - $this->assign('goods_view_list_show_style', BaseLayout::$goods_view_list_show_style); - $this->assign('many_images_view_list_show_style', BaseLayout::$many_images_view_list_show_style); + MyViewAssign('border_style_type_list', BaseLayout::$border_style_type_list); + MyViewAssign('goods_view_list_show_style', BaseLayout::$goods_view_list_show_style); + MyViewAssign('many_images_view_list_show_style', BaseLayout::$many_images_view_list_show_style); // 首页商品排序规则 - $this->assign('goods_order_by_type_list', lang('goods_order_by_type_list')); - $this->assign('goods_order_by_rule_list', lang('goods_order_by_rule_list')); + MyViewAssign('goods_order_by_type_list', lang('goods_order_by_type_list')); + MyViewAssign('goods_order_by_rule_list', lang('goods_order_by_rule_list')); // 浏览器名称 - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle('首页设计', 1)); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle('首页设计', 1)); // 编辑器文件存放地址定义 - $this->assign('editor_path_type', 'index-design'); + MyViewAssign('editor_path_type', 'index-design'); // 加载布局样式+管理 - $this->assign('is_load_layout', 1); - $this->assign('is_load_layout_admin', 1); + MyViewAssign('is_load_layout', 1); + MyViewAssign('is_load_layout_admin', 1); } else { // 数据模式 if($floor_data_type == 2) { // 设计配置数据 $layout_data = LayoutService::LayoutConfigData('home'); - $this->assign('layout_data', $layout_data); + MyViewAssign('layout_data', $layout_data); // 加载布局样式 - $this->assign('is_load_layout', 1); + MyViewAssign('is_load_layout', 1); } else { // H5导航 - $this->assign('navigation', AppHomeNavService::AppHomeNav()); + MyViewAssign('navigation', AppHomeNavService::AppHomeNav()); // 楼层数据 - $this->assign('goods_floor_list', GoodsService::HomeFloorList()); + MyViewAssign('goods_floor_list', GoodsService::HomeFloorList()); // 文章 $params = [ @@ -131,11 +130,11 @@ class Index extends Common 'n' => 9, ]; $article_list = ArticleService::ArticleList($params); - $this->assign('article_list', $article_list['data']); + MyViewAssign('article_list', $article_list['data']); // 用户订单状态 $user_order_status = OrderService::OrderStatusStepTotal(['user_type'=>'user', 'user'=>$this->user, 'is_comments'=>1]); - $this->assign('user_order_status', $user_order_status['data']); + MyViewAssign('user_order_status', $user_order_status['data']); } } @@ -143,13 +142,13 @@ class Index extends Common // 存在地图事件则载入 if(in_array(3, array_column($banner, 'event_type'))) { - $this->assign('is_load_baidu_map_api', 1); + MyViewAssign('is_load_baidu_map_api', 1); } // 钩子 $this->PluginsHook(); - return $this->fetch(); + return MyView(); } /** @@ -175,7 +174,7 @@ class Index extends Common ]; foreach($hook_arr as $hook_name) { - $this->assign($hook_name.'_data', Hook::listen($hook_name, + MyViewAssign($hook_name.'_data', MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => false, diff --git a/application/index/controller/Layout.php b/app/index/controller/Layout.php similarity index 93% rename from application/index/controller/Layout.php rename to app/index/controller/Layout.php index 9166f8d96..da46b688e 100644 --- a/application/index/controller/Layout.php +++ b/app/index/controller/Layout.php @@ -56,8 +56,8 @@ class Layout extends Common $ret = BaseLayout::GoodsSearchList($params); if($ret['code'] == 0) { - $this->assign('data', $ret['data']['data']); - $ret['data']['data'] = $this->fetch('../../../layout/view/public/common/goodssearch'); + MyViewAssign('data', $ret['data']['data']); + $ret['data']['data'] = MyView('../../../layout/view/public/common/goodssearch'); } return $ret; } diff --git a/application/index/controller/Message.php b/app/index/controller/Message.php similarity index 87% rename from application/index/controller/Message.php rename to app/index/controller/Message.php index 2a4b17a12..302fec6ec 100755 --- a/application/index/controller/Message.php +++ b/app/index/controller/Message.php @@ -74,13 +74,13 @@ class Message extends Common MessageService::MessageRead(['user'=>$this->user]); // 浏览器名称 - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle('我的消息', 1)); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle('我的消息', 1)); // 基础参数赋值 - $this->assign('params', $this->data_request); - $this->assign('page_html', $page->GetPageHtml()); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + MyViewAssign('page_html', $page->GetPageHtml()); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -108,12 +108,12 @@ class Message extends Common ]; $ret = MessageService::MessageList($data_params); $data = (empty($ret['data']) || empty($ret['data'][0])) ? [] : $ret['data'][0]; - $this->assign('data', $data); + MyViewAssign('data', $data); } - $this->assign('is_header', 0); - $this->assign('is_footer', 0); - return $this->fetch(); + MyViewAssign('is_header', 0); + MyViewAssign('is_footer', 0); + return MyView(); } } ?> \ No newline at end of file diff --git a/application/index/controller/Order.php b/app/index/controller/Order.php similarity index 77% rename from application/index/controller/Order.php rename to app/index/controller/Order.php index 30422c3c1..cfce5b7d1 100755 --- a/application/index/controller/Order.php +++ b/app/index/controller/Order.php @@ -77,19 +77,19 @@ class Order extends Common $ret = OrderService::OrderList($data_params); // 发起支付 - 支付方式 - $this->assign('buy_payment_list', PaymentService::BuyPaymentList(['is_enable'=>1, 'is_open_user'=>1])); + MyViewAssign('buy_payment_list', PaymentService::BuyPaymentList(['is_enable'=>1, 'is_open_user'=>1])); // 加载百度地图api - $this->assign('is_load_baidu_map_api', 1); + MyViewAssign('is_load_baidu_map_api', 1); // 浏览器名称 - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle('我的订单', 1)); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle('我的订单', 1)); // 基础参数赋值 - $this->assign('params', $this->data_request); - $this->assign('page_html', $page->GetPageHtml()); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + MyViewAssign('page_html', $page->GetPageHtml()); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -106,22 +106,22 @@ class Order extends Common if(!empty($data)) { // 发起支付 - 支付方式 - $this->assign('buy_payment_list', PaymentService::BuyPaymentList(['is_enable'=>1, 'is_open_user'=>1])); + MyViewAssign('buy_payment_list', PaymentService::BuyPaymentList(['is_enable'=>1, 'is_open_user'=>1])); // 虚拟销售配置 $site_fictitious = ConfigService::SiteFictitiousConfig(); - $this->assign('site_fictitious', $site_fictitious['data']); + MyViewAssign('site_fictitious', $site_fictitious['data']); // 加载百度地图api - $this->assign('is_load_baidu_map_api', 1); + MyViewAssign('is_load_baidu_map_api', 1); // 浏览器名称 - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle('订单详情', 1)); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle('订单详情', 1)); // 数据赋值 - $this->assign('data', $data); - $this->assign('params', $this->data_request); - return $this->fetch(); + MyViewAssign('data', $data); + MyViewAssign('params', $this->data_request); + return MyView(); } } @@ -138,18 +138,18 @@ class Order extends Common $data = $this->OrderFirst(); if(!empty($data)) { - $this->assign('referer_url', empty($_SERVER['HTTP_REFERER']) ? MyUrl('index/order/index') : $_SERVER['HTTP_REFERER']); - $this->assign('data', $data); + MyViewAssign('referer_url', empty($_SERVER['HTTP_REFERER']) ? MyUrl('index/order/index') : $_SERVER['HTTP_REFERER']); + MyViewAssign('data', $data); // 浏览器名称 - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle('订单评论', 1)); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle('订单评论', 1)); // 编辑器文件存放地址 - $this->assign('editor_path_type', ResourcesService::EditorPathTypeValue('order_comments-'.$this->user['id'].'-'.$data['id'])); - return $this->fetch(); + MyViewAssign('editor_path_type', ResourcesService::EditorPathTypeValue('order_comments-'.$this->user['id'].'-'.$data['id'])); + return MyView(); } else { - $this->assign('msg', '没有相关数据'); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', '没有相关数据'); + return MyView('public/tips_error'); } } @@ -205,8 +205,8 @@ class Order extends Common $params['business_type'] = 'order'; return GoodsCommentsService::Comments($params); } else { - $this->assign('msg', '非法访问'); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', '非法访问'); + return MyView('public/tips_error'); } } @@ -225,10 +225,10 @@ class Order extends Common $ret = OrderService::Pay($params); if($ret['code'] == 0) { - return redirect($ret['data']['data']); + return MyRedirect($ret['data']['data']); } else { - $this->assign('msg', $ret['msg']); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', $ret['msg']); + return MyView('public/tips_error'); } } @@ -257,16 +257,16 @@ class Order extends Common } // 自定义链接 - $this->assign('to_url', MyUrl('index/order/index')); - $this->assign('to_title', '我的订单'); + MyViewAssign('to_url', MyUrl('index/order/index')); + MyViewAssign('to_title', '我的订单'); // 状态 - $this->assign('msg', $ret['msg']); + MyViewAssign('msg', $ret['msg']); if($ret['code'] == 0) { - return $this->fetch('public/tips_success'); + return MyView('public/tips_success'); } - return $this->fetch('public/tips_error'); + return MyView('public/tips_error'); } /** @@ -287,8 +287,8 @@ class Order extends Common $params['creator_name'] = $this->user['user_name_view']; return OrderService::OrderCancel($params); } else { - $this->assign('msg', '非法访问'); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', '非法访问'); + return MyView('public/tips_error'); } } @@ -310,8 +310,8 @@ class Order extends Common $params['creator_name'] = $this->user['user_name_view']; return OrderService::OrderCollect($params); } else { - $this->assign('msg', '非法访问'); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', '非法访问'); + return MyView('public/tips_error'); } } @@ -334,8 +334,8 @@ class Order extends Common $params['user_type'] = 'user'; return OrderService::OrderDelete($params); } else { - $this->assign('msg', '非法访问'); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', '非法访问'); + return MyView('public/tips_error'); } } @@ -355,8 +355,8 @@ class Order extends Common $params['user'] = $this->user; return OrderService::OrderPayCheck($params); } else { - $this->assign('msg', '非法访问'); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', '非法访问'); + return MyView('public/tips_error'); } } } diff --git a/application/index/controller/Orderaftersale.php b/app/index/controller/Orderaftersale.php similarity index 74% rename from application/index/controller/Orderaftersale.php rename to app/index/controller/Orderaftersale.php index 39a823ac5..b0d091d30 100644 --- a/application/index/controller/Orderaftersale.php +++ b/app/index/controller/Orderaftersale.php @@ -73,13 +73,13 @@ class Orderaftersale extends Common $ret = OrderAftersaleService::OrderAftersaleList($data_params); // 浏览器名称 - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle('订单售后', 1)); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle('订单售后', 1)); // 基础参数赋值 - $this->assign('params', $this->data_request); - $this->assign('page_html', $page->GetPageHtml()); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + MyViewAssign('page_html', $page->GetPageHtml()); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -98,16 +98,16 @@ class Orderaftersale extends Common $ret = OrderAftersaleService::OrdferGoodsRow($order_id, $order_detail_id, $this->user['id']); if($ret['code'] == 0) { - $this->assign('goods', $ret['data']['items']); - $this->assign('order', $ret['data']); + MyViewAssign('goods', $ret['data']['items']); + MyViewAssign('order', $ret['data']); // 仅退款原因 $return_only_money_reason = MyC('home_order_aftersale_return_only_money_reason'); - $this->assign('return_only_money_reason_list', empty($return_only_money_reason) ? [] : explode("\n", $return_only_money_reason)); + MyViewAssign('return_only_money_reason_list', empty($return_only_money_reason) ? [] : explode("\n", $return_only_money_reason)); // 退款退货原因 $return_money_goods_reason = MyC('home_order_aftersale_return_money_goods_reason'); - $this->assign('return_money_goods_reason_list', empty($return_money_goods_reason) ? [] : explode("\n", $return_money_goods_reason)); + MyViewAssign('return_money_goods_reason_list', empty($return_money_goods_reason) ? [] : explode("\n", $return_money_goods_reason)); // 获取当前订单商品售后最新的一条纪录 $data_params = [ @@ -126,35 +126,35 @@ class Orderaftersale extends Common } else { $new_aftersale_data = []; } - $this->assign('new_aftersale_data', $new_aftersale_data); + MyViewAssign('new_aftersale_data', $new_aftersale_data); // 进度 - $this->assign('step_data', OrderAftersaleService::OrderAftersaleStep($new_aftersale_data)); + MyViewAssign('step_data', OrderAftersaleService::OrderAftersaleStep($new_aftersale_data)); // 可退款退货 $returned = OrderAftersaleService::OrderAftersaleCalculation($order_id, $order_detail_id); - $this->assign('returned_data', $returned['data']); + MyViewAssign('returned_data', $returned['data']); // 退货地址 $return_goods_address = OrderAftersaleService::OrderAftersaleReturnGoodsAddress($order_id); - $this->assign('return_goods_address', $return_goods_address); + MyViewAssign('return_goods_address', $return_goods_address); // 静态数据 - $this->assign('common_order_aftersale_type_list', lang('common_order_aftersale_type_list')); + MyViewAssign('common_order_aftersale_type_list', lang('common_order_aftersale_type_list')); // 编辑器文件存放地址 - $this->assign('editor_path_type', ResourcesService::EditorPathTypeValue(OrderAftersaleService::EditorAttachmentPathType($this->user['id'], $order_id, $order_detail_id))); + MyViewAssign('editor_path_type', ResourcesService::EditorPathTypeValue(OrderAftersaleService::EditorAttachmentPathType($this->user['id'], $order_id, $order_detail_id))); // 浏览器名称 - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle('订单售后详情', 1)); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle('订单售后详情', 1)); // 订单售后搜索form key - $this->assign('form_search_keywords_form_key', 'f0p'); - $this->assign('params', $this->data_request); - return $this->fetch(); + MyViewAssign('form_search_keywords_form_key', 'f0p'); + MyViewAssign('params', $this->data_request); + return MyView(); } else { - $this->assign('msg', $ret['msg']); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', $ret['msg']); + return MyView('public/tips_error'); } } @@ -171,8 +171,8 @@ class Orderaftersale extends Common // 是否ajax请求 if(!IS_AJAX) { - $this->assign('msg', '非法访问'); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', '非法访问'); + return MyView('public/tips_error'); } $params = $this->data_request; @@ -193,8 +193,8 @@ class Orderaftersale extends Common // 是否ajax请求 if(!IS_AJAX) { - $this->assign('msg', '非法访问'); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', '非法访问'); + return MyView('public/tips_error'); } $params = $this->data_request; @@ -215,8 +215,8 @@ class Orderaftersale extends Common // 是否ajax请求 if(!IS_AJAX) { - $this->assign('msg', '非法访问'); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', '非法访问'); + return MyView('public/tips_error'); } $params = $this->data_post; diff --git a/application/index/controller/Pay.php b/app/index/controller/Pay.php similarity index 88% rename from application/index/controller/Pay.php rename to app/index/controller/Pay.php index 87d89d2ac..4765713b0 100644 --- a/application/index/controller/Pay.php +++ b/app/index/controller/Pay.php @@ -45,11 +45,11 @@ class Pay extends Common $params = input(); if(empty($params['url']) || empty($params['order_no']) || empty($params['name']) || empty($params['msg'])) { - $this->assign('msg', '参数有误'); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', '参数有误'); + return MyView('public/tips_error'); } else { - $this->assign('params', $params); - return $this->fetch(); + MyViewAssign('params', $params); + return MyView(); } } } diff --git a/application/index/controller/Personal.php b/app/index/controller/Personal.php similarity index 82% rename from application/index/controller/Personal.php rename to app/index/controller/Personal.php index cc6e51332..357d923d1 100755 --- a/application/index/controller/Personal.php +++ b/app/index/controller/Personal.php @@ -49,12 +49,12 @@ class Personal extends Common public function Index() { // 用户展示数据 - $this->assign('personal_show_list', NavigationService::UsersPersonalShowFieldList()); + MyViewAssign('personal_show_list', NavigationService::UsersPersonalShowFieldList()); // 浏览器名称 - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle('个人资料', 1)); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle('个人资料', 1)); - return $this->fetch(); + return MyView(); } /** @@ -67,15 +67,15 @@ class Personal extends Common public function SaveInfo() { // 性别 - $this->assign('common_gender_list', lang('common_gender_list')); + MyViewAssign('common_gender_list', lang('common_gender_list')); // 数据 - $this->assign('data', $this->user); + MyViewAssign('data', $this->user); // 浏览器名称 - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle('个人资料编辑', 1)); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle('个人资料编辑', 1)); - return $this->fetch(); + return MyView(); } /** diff --git a/application/index/controller/Plugins.php b/app/index/controller/Plugins.php similarity index 84% rename from application/index/controller/Plugins.php rename to app/index/controller/Plugins.php index e21ac4cd3..de4a2ba71 100755 --- a/application/index/controller/Plugins.php +++ b/app/index/controller/Plugins.php @@ -62,8 +62,8 @@ class Plugins extends Common { return DataReturn($ret, -5000); } else { - $this->assign('msg', $ret); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', $ret); + return MyView('public/tips_error'); } } @@ -80,7 +80,7 @@ class Plugins extends Common $this->PluginsViewInit($pluginsname, $pluginscontrol, $pluginsaction); // 编辑器文件存放地址定义 - $this->assign('editor_path_type', ResourcesService::EditorPathTypeValue('plugins_'.$pluginsname)); + MyViewAssign('editor_path_type', ResourcesService::EditorPathTypeValue('plugins_'.$pluginsname)); // 调用 $ret = PluginsService::PluginsControlCall($pluginsname, $pluginscontrol, $pluginsaction, 'index', $params); @@ -94,8 +94,8 @@ class Plugins extends Common { return $ret; } else { - $this->assign('msg', $ret['msg']); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', $ret['msg']); + return MyView('public/tips_error'); } } @@ -134,9 +134,9 @@ class Plugins extends Common public function PluginsViewInit($plugins_name, $plugins_control, $plugins_action) { // 应用名称/控制器/方法 - $this->assign('plugins_name', $plugins_name); - $this->assign('plugins_control', $plugins_control); - $this->assign('plugins_action', $plugins_action); + MyViewAssign('plugins_name', $plugins_name); + MyViewAssign('plugins_control', $plugins_control); + MyViewAssign('plugins_action', $plugins_action); // 当前操作名称 $module_name = 'plugins'; @@ -147,17 +147,17 @@ class Plugins extends Common // 控制器静态文件状态css,js $module_css = $module_name.DS.'css'.DS.$plugins_name.DS.$group.DS.$plugins_control; $module_css .= file_exists(ROOT_PATH.'static'.DS.$module_css.'.'.$plugins_action.'.css') ? '.'.$plugins_action.'.css' : '.css'; - $this->assign('module_css', file_exists(ROOT_PATH.'static'.DS.$module_css) ? $module_css : ''); + MyViewAssign('module_css', file_exists(ROOT_PATH.'static'.DS.$module_css) ? $module_css : ''); $module_js = $module_name.DS.'js'.DS.$plugins_name.DS.$group.DS.$plugins_control; $module_js .= file_exists(ROOT_PATH.'static'.DS.$module_js.'.'.$plugins_action.'.js') ? '.'.$plugins_action.'.js' : '.js'; - $this->assign('module_js', file_exists(ROOT_PATH.'static'.DS.$module_js) ? $module_js : ''); + MyViewAssign('module_js', file_exists(ROOT_PATH.'static'.DS.$module_js) ? $module_js : ''); // 应用公共css,js $plugins_css = $module_name.DS.'css'.DS.$plugins_name.DS.$group.DS.'common.css'; - $this->assign('plugins_css', file_exists(ROOT_PATH.'static'.DS.$plugins_css) ? $plugins_css : ''); + MyViewAssign('plugins_css', file_exists(ROOT_PATH.'static'.DS.$plugins_css) ? $plugins_css : ''); $plugins_js = $module_name.DS.'js'.DS.$plugins_name.DS.$group.DS.'common.js'; - $this->assign('plugins_js', file_exists(ROOT_PATH.'static'.DS.$plugins_js) ? $plugins_js : ''); + MyViewAssign('plugins_js', file_exists(ROOT_PATH.'static'.DS.$plugins_js) ? $plugins_js : ''); } } ?> \ No newline at end of file diff --git a/application/index/controller/Qrcode.php b/app/index/controller/Qrcode.php similarity index 88% rename from application/index/controller/Qrcode.php rename to app/index/controller/Qrcode.php index 7e2373cc8..03d00194a 100755 --- a/application/index/controller/Qrcode.php +++ b/app/index/controller/Qrcode.php @@ -39,8 +39,8 @@ class QrCode extends Common $params = input(); if(empty($params['content'])) { - $this->assign('msg', '内容参数为空'); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', '内容参数为空'); + return MyView('public/tips_error'); } (new \base\Qrcode())->View($params); @@ -59,8 +59,8 @@ class QrCode extends Common $ret = (new \base\Qrcode())->Download($params); if(!empty($ret) && isset($ret['code']) && $ret['code'] != 0) { - $this->assign('msg', $ret['msg']); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', $ret['msg']); + return MyView('public/tips_error'); } } } diff --git a/application/index/controller/Region.php b/app/index/controller/Region.php similarity index 100% rename from application/index/controller/Region.php rename to app/index/controller/Region.php diff --git a/application/index/controller/Safety.php b/app/index/controller/Safety.php similarity index 77% rename from application/index/controller/Safety.php rename to app/index/controller/Safety.php index 7ebfcb3a0..196acc41a 100755 --- a/application/index/controller/Safety.php +++ b/app/index/controller/Safety.php @@ -49,19 +49,19 @@ class Safety extends Common public function Index() { // 安全信息列表 - $this->assign('safety_panel_list', NavigationService::UsersSafetyPanelList()); + MyViewAssign('safety_panel_list', NavigationService::UsersSafetyPanelList()); // 数据列表 $data = array( 'mobile' => $this->user['mobile_security'], 'email' => $this->user['email_security'], ); - $this->assign('data', $data); + MyViewAssign('data', $data); // 浏览器名称 - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle('安全设置', 1)); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle('安全设置', 1)); - return $this->fetch(); + return MyView(); } /** @@ -74,9 +74,9 @@ class Safety extends Common public function LoginPwdInfo() { // 浏览器名称 - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle('登录密码修改 - 安全设置', 1)); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle('登录密码修改 - 安全设置', 1)); - return $this->fetch(); + return MyView(); } /** @@ -90,13 +90,12 @@ class Safety extends Common { if(empty($this->user['mobile'])) { - return redirect(MyUrl('index/safety/newmobileinfo')); + return MyRedirect(MyUrl('index/safety/newmobileinfo')); } // 浏览器名称 - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle('手机号码修改 - 安全设置', 1)); - - return $this->fetch(); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle('手机号码修改 - 安全设置', 1)); + return MyView(); } /** @@ -108,15 +107,15 @@ class Safety extends Common */ public function NewMobileInfo() { - if(session('safety_sms') == null && !empty($this->user['mobile'])) + if(MySession('safety_sms') == null && !empty($this->user['mobile'])) { return $this->error('原帐号校验失败', MyUrl('index/safety/mobileinfo')); } // 浏览器名称 - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle('手机号码修改 - 安全设置', 1)); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle('手机号码修改 - 安全设置', 1)); - return $this->fetch(); + return MyView(); } /** @@ -130,13 +129,12 @@ class Safety extends Common { if(empty($this->user['email'])) { - return redirect(MyUrl('index/safety/newemailinfo')); + return MyRedirect(MyUrl('index/safety/newemailinfo')); } // 浏览器名称 - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle('电子邮箱修改 - 安全设置', 1)); - - return $this->fetch(); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle('电子邮箱修改 - 安全设置', 1)); + return MyView(); } /** @@ -148,15 +146,15 @@ class Safety extends Common */ public function NewEmailInfo() { - if(session('safety_email') == null && !empty($this->user['email'])) + if(MySession('safety_email') == null && !empty($this->user['email'])) { return $this->error('原帐号校验失败', MyUrl('index/safety/emailinfo')); } // 浏览器名称 - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle('电子邮箱修改 - 安全设置', 1)); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle('电子邮箱修改 - 安全设置', 1)); - return $this->fetch(); + return MyView(); } /** @@ -211,8 +209,8 @@ class Safety extends Common // 是否ajax请求 if(!IS_AJAX) { - $this->assign('msg', '非法访问'); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', '非法访问'); + return MyView('public/tips_error'); } // 开始处理 @@ -234,8 +232,8 @@ class Safety extends Common // 是否ajax请求 if(!IS_AJAX) { - $this->assign('msg', '非法访问'); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', '非法访问'); + return MyView('public/tips_error'); } // 开始处理 @@ -256,8 +254,8 @@ class Safety extends Common // 是否ajax请求 if(!IS_AJAX) { - $this->assign('msg', '非法访问'); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', '非法访问'); + return MyView('public/tips_error'); } // 开始处理 diff --git a/application/index/controller/Search.php b/app/index/controller/Search.php similarity index 85% rename from application/index/controller/Search.php rename to app/index/controller/Search.php index 861ebc01a..99d4323fb 100755 --- a/application/index/controller/Search.php +++ b/app/index/controller/Search.php @@ -10,7 +10,6 @@ // +---------------------------------------------------------------------- namespace app\index\controller; -use think\facade\Hook; use app\service\SeoService; use app\service\SearchService; @@ -64,7 +63,7 @@ class Search extends Common $keywords = input('post.wd'); if(!empty($keywords)) { - return redirect(MyUrl('index/search/index', ['wd'=>StrToAscii($keywords)])); + return MyRedirect(MyUrl('index/search/index', ['wd'=>StrToAscii($keywords)])); } // 参数初始化 @@ -72,30 +71,30 @@ class Search extends Common // 品牌列表 $brand_list = SearchService::CategoryBrandList($this->data_request); - $this->assign('brand_list', $brand_list); + MyViewAssign('brand_list', $brand_list); // 指定数据 $search_map_info = SearchService::SearchMapInfo($this->data_request); - $this->assign('search_map_info', $search_map_info); + MyViewAssign('search_map_info', $search_map_info); // 商品分类 $category_list = SearchService::GoodsCategoryList($this->data_request); - $this->assign('category_list', $category_list); + MyViewAssign('category_list', $category_list); // 筛选价格区间 $screening_price_list = SearchService::ScreeningPriceList($this->data_request); - $this->assign('screening_price_list', $screening_price_list); + MyViewAssign('screening_price_list', $screening_price_list); // 商品参数 $goods_params_list = SearchService::SearchGoodsParamsValueList($this->data_request); - $this->assign('goods_params_list', $goods_params_list); + MyViewAssign('goods_params_list', $goods_params_list); // 商品规格 $goods_spec_list = SearchService::SearchGoodsSpecValueList($this->data_request); - $this->assign('goods_spec_list', $goods_spec_list); + MyViewAssign('goods_spec_list', $goods_spec_list); // 参数 - $this->assign('params', $this->data_request); + MyViewAssign('params', $this->data_request); // seo $this->SetSeo($search_map_info); @@ -103,7 +102,7 @@ class Search extends Common // 钩子 $this->PluginsHook(); - return $this->fetch(); + return MyView(); } /** @@ -129,14 +128,14 @@ class Search extends Common // 关键字和描述 if(!empty($seo_data['seo_keywords'])) { - $this->assign('home_seo_site_keywords', $seo_data['seo_keywords']); + MyViewAssign('home_seo_site_keywords', $seo_data['seo_keywords']); } if(!empty($seo_data['seo_desc'])) { - $this->assign('home_seo_site_description', $seo_data['seo_desc']); + MyViewAssign('home_seo_site_description', $seo_data['seo_desc']); } } - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle(empty($seo_title) ? '商品搜索' : $seo_title, 1)); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle(empty($seo_title) ? '商品搜索' : $seo_title, 1)); } /** @@ -172,8 +171,8 @@ class Search extends Common } // 返回数据html - $this->assign('data', $ret['data']['data']); - $ret['data']['data'] = $this->fetch('content'); + MyViewAssign('data', $ret['data']['data']); + $ret['data']['data'] = MyView('content'); return $ret; } @@ -229,7 +228,7 @@ class Search extends Common ]; foreach($hook_arr as $hook_name) { - $this->assign($hook_name.'_data', Hook::listen($hook_name, + MyViewAssign($hook_name.'_data', MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => false, diff --git a/application/index/controller/Ueditor.php b/app/index/controller/Ueditor.php similarity index 100% rename from application/index/controller/Ueditor.php rename to app/index/controller/Ueditor.php diff --git a/application/index/controller/User.php b/app/index/controller/User.php similarity index 78% rename from application/index/controller/User.php rename to app/index/controller/User.php index 9d63ed3a0..64b97df41 100755 --- a/application/index/controller/User.php +++ b/app/index/controller/User.php @@ -10,7 +10,6 @@ // +---------------------------------------------------------------------- namespace app\index\controller; -use think\facade\Hook; use app\service\OrderService; use app\service\GoodsService; use app\service\UserService; @@ -98,16 +97,16 @@ class User extends Common // 用户中心基础信息 mini 导航 $mini_navigation = NavigationService::UserCenterMiniNavigation(['user'=>$this->user]); - $this->assign('mini_navigation', $mini_navigation); + MyViewAssign('mini_navigation', $mini_navigation); // 用户订单状态 $user_order_status = OrderService::OrderStatusStepTotal(['user_type'=>'user', 'user'=>$this->user, 'is_comments'=>1, 'is_aftersale'=>1]); - $this->assign('user_order_status', $user_order_status['data']); + MyViewAssign('user_order_status', $user_order_status['data']); // 未读消息总数 $params = ['user'=>$this->user, 'is_more'=>1, 'is_read'=>0, 'user_type'=>'user']; $common_message_total = MessageService::UserMessageTotal($params); - $this->assign('common_message_total', $common_message_total); + MyViewAssign('common_message_total', $common_message_total); // 获取进行中的订单列表 $params = $this->data_request; @@ -123,11 +122,11 @@ class User extends Common 'where' => $where, ); $order = OrderService::OrderList($order_params); - $this->assign('order_list', $order['data']); + MyViewAssign('order_list', $order['data']); // 获取购物车 $cart_list = BuyService::CartList(['user'=>$this->user]); - $this->assign('cart_list', $cart_list['data']); + MyViewAssign('cart_list', $cart_list['data']); // 收藏商品 $favor_params = array( @@ -139,7 +138,7 @@ class User extends Common ], ); $favor = GoodsFavorService::GoodsFavorList($favor_params); - $this->assign('goods_favor_list', $favor['data']); + MyViewAssign('goods_favor_list', $favor['data']); // 我的足迹 $browse_params = array( @@ -151,19 +150,19 @@ class User extends Common ], ); $data = GoodsBrowseService::GoodsBrowseList($browse_params); - $this->assign('goods_browse_list', $data['data']); + MyViewAssign('goods_browse_list', $data['data']); // 订单页面订单状态form key - $this->assign('form_search_order_status_form_key', 'status'); - $this->assign('form_search_order_user_is_comments_form_key', 'user_is_comments'); + MyViewAssign('form_search_order_status_form_key', 'status'); + MyViewAssign('form_search_order_user_is_comments_form_key', 'user_is_comments'); // 钩子 $this->PluginsHook(); // 浏览器名称 - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle('用户中心', 1)); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle('用户中心', 1)); - return $this->fetch(); + return MyView(); } /** @@ -197,7 +196,7 @@ class User extends Common ]; foreach($hook_arr as $hook_name) { - $this->assign($hook_name.'_data', Hook::listen($hook_name, + MyViewAssign($hook_name.'_data', MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => false, @@ -219,16 +218,16 @@ class User extends Common if(empty($this->user)) { // 浏览器名称 - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle('密码找回', 1)); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle('密码找回', 1)); // 左侧图片,随机其中一个 - $left_data = UserService::UserEntranceLeftData(['left_key'=>'forgetpwd', 'cache_key'=>config('shopxo.cache_user_forgetpwd_left_key')]); - $this->assign('user_forgetpwd_left_data', empty($left_data['data']) ? [] : $left_data['data'][array_rand($left_data['data'], 1)]); + $left_data = UserService::UserEntranceLeftData(['left_key'=>'forgetpwd', 'cache_key'=>MyConfig('shopxo.cache_user_forgetpwd_left_key')]); + MyViewAssign('user_forgetpwd_left_data', empty($left_data['data']) ? [] : $left_data['data'][array_rand($left_data['data'], 1)]); - return $this->fetch(); + return MyView(); } else { - $this->assign('msg', '已经登录了,如要重置密码,请先退出当前账户'); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', '已经登录了,如要重置密码,请先退出当前账户'); + return MyView('public/tips_error'); } } @@ -248,22 +247,22 @@ class User extends Common if(empty($this->user)) { // 浏览器名称 - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle('用户注册', 1)); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle('用户注册', 1)); // 返回地址 - $this->assign('referer_url', $this->GetrefererUrl()); + MyViewAssign('referer_url', $this->GetrefererUrl()); // 注册背景图片 - $this->assign('user_register_bg_images', MyC('home_site_user_register_bg_images')); + MyViewAssign('user_register_bg_images', MyC('home_site_user_register_bg_images')); - return $this->fetch(); + return MyView(); } else { - $this->assign('msg', '已经登录了,如要注册新账户,请先退出当前账户'); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', '已经登录了,如要注册新账户,请先退出当前账户'); + return MyView('public/tips_error'); } } else { - $this->assign('msg', '暂时关闭用户注册'); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', '暂时关闭用户注册'); + return MyView('public/tips_error'); } } @@ -282,23 +281,23 @@ class User extends Common if(empty($this->user)) { // 浏览器名称 - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle('用户登录', 1)); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle('用户登录', 1)); // 返回地址 - $this->assign('referer_url', $this->GetrefererUrl()); + MyViewAssign('referer_url', $this->GetrefererUrl()); // 左侧图片,随机其中一个 - $left_data = UserService::UserEntranceLeftData(['left_key'=>'login', 'cache_key'=>config('shopxo.cache_user_login_left_key')]); - $this->assign('user_login_left_data', empty($left_data['data']) ? [] : $left_data['data'][array_rand($left_data['data'], 1)]); + $left_data = UserService::UserEntranceLeftData(['left_key'=>'login', 'cache_key'=>MyConfig('shopxo.cache_user_login_left_key')]); + MyViewAssign('user_login_left_data', empty($left_data['data']) ? [] : $left_data['data'][array_rand($left_data['data'], 1)]); - return $this->fetch(); + return MyView(); } else { - $this->assign('msg', '已经登录了,请勿重复登录'); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', '已经登录了,请勿重复登录'); + return MyView('public/tips_error'); } } else { - $this->assign('msg', '暂时关闭用户登录'); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', '暂时关闭用户登录'); + return MyView('public/tips_error'); } } @@ -312,25 +311,25 @@ class User extends Common */ public function ModalLoginInfo() { - $this->assign('is_header', 0); - $this->assign('is_footer', 0); + MyViewAssign('is_header', 0); + MyViewAssign('is_footer', 0); if(count(MyC('home_user_login_type', [], true)) > 0) { if(empty($this->user)) { // 浏览器名称 - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle('用户登录', 1)); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle('用户登录', 1)); - $this->assign('referer_url', $this->GetrefererUrl()); - return $this->fetch(); + MyViewAssign('referer_url', $this->GetrefererUrl()); + return MyView(); } else { - $this->assign('msg', '已经登录了,请勿重复登录'); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', '已经登录了,请勿重复登录'); + return MyView('public/tips_error'); } } else { - $this->assign('msg', '暂时关闭用户登录'); - return $this->fetch('public/tips_error'); + MyViewAssign('msg', '暂时关闭用户登录'); + return MyView('public/tips_error'); } } @@ -488,10 +487,10 @@ class User extends Common // 登录返回 $body_html = (!empty($ret['data']['body_html']) && is_array($ret['data']['body_html'])) ? implode(' ', $ret['data']['body_html']) : $ret['data']['body_html']; - $this->assign('body_html', $body_html); - $this->assign('msg', $ret['msg']); + MyViewAssign('body_html', $body_html); + MyViewAssign('msg', $ret['msg']); - return $this->fetch(); + return MyView(); } /** diff --git a/application/index/controller/Useraddress.php b/app/index/controller/Useraddress.php similarity index 85% rename from application/index/controller/Useraddress.php rename to app/index/controller/Useraddress.php index 2aac66730..8dd7ae0fd 100755 --- a/application/index/controller/Useraddress.php +++ b/app/index/controller/Useraddress.php @@ -50,12 +50,12 @@ class UserAddress extends Common { // 用户地址列表 $data = UserAddressService::UserAddressList(['user'=>$this->user]); - $this->assign('user_address_list', $data['data']); + MyViewAssign('user_address_list', $data['data']); // 浏览器名称 - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle('我的地址', 1)); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle('我的地址', 1)); - return $this->fetch(); + return MyView(); } /** @@ -67,8 +67,8 @@ class UserAddress extends Common */ public function SaveInfo() { - $this->assign('is_header', 0); - $this->assign('is_footer', 0); + MyViewAssign('is_header', 0); + MyViewAssign('is_footer', 0); $data = []; if(!empty($this->data_request)) @@ -80,12 +80,12 @@ class UserAddress extends Common } // 编辑器文件存放地址 - $this->assign('editor_path_type', ResourcesService::EditorPathTypeValue(UserAddressService::EditorAttachmentPathType($this->user['id']))); + MyViewAssign('editor_path_type', ResourcesService::EditorPathTypeValue(UserAddressService::EditorAttachmentPathType($this->user['id']))); // 加载百度地图api - $this->assign('is_load_baidu_map_api', 1); - $this->assign('data', $data); - return $this->fetch(); + MyViewAssign('is_load_baidu_map_api', 1); + MyViewAssign('data', $data); + return MyView(); } /** diff --git a/application/index/controller/Usergoodsbrowse.php b/app/index/controller/Usergoodsbrowse.php similarity index 88% rename from application/index/controller/Usergoodsbrowse.php rename to app/index/controller/Usergoodsbrowse.php index 6bfeeead6..f3b877d32 100755 --- a/application/index/controller/Usergoodsbrowse.php +++ b/app/index/controller/Usergoodsbrowse.php @@ -71,13 +71,13 @@ class UserGoodsBrowse extends Common $ret = GoodsBrowseService::GoodsBrowseList($data_params); // 浏览器名称 - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle('我的足迹', 1)); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle('我的足迹', 1)); // 基础参数赋值 - $this->assign('params', $this->data_request); - $this->assign('page_html', $page->GetPageHtml()); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + MyViewAssign('page_html', $page->GetPageHtml()); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -105,12 +105,12 @@ class UserGoodsBrowse extends Common ]; $ret = GoodsBrowseService::GoodsBrowseList($data_params); $data = (empty($ret['data']) || empty($ret['data'][0])) ? [] : $ret['data'][0]; - $this->assign('data', $data); + MyViewAssign('data', $data); } - $this->assign('is_header', 0); - $this->assign('is_footer', 0); - return $this->fetch(); + MyViewAssign('is_header', 0); + MyViewAssign('is_footer', 0); + return MyView(); } /** diff --git a/application/index/controller/Usergoodsfavor.php b/app/index/controller/Usergoodsfavor.php similarity index 88% rename from application/index/controller/Usergoodsfavor.php rename to app/index/controller/Usergoodsfavor.php index 1eea254dd..ab7bdf60e 100755 --- a/application/index/controller/Usergoodsfavor.php +++ b/app/index/controller/Usergoodsfavor.php @@ -71,13 +71,13 @@ class UserGoodsFavor extends Common $ret = GoodsFavorService::GoodsFavorList($data_params); // 浏览器名称 - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle('商品收藏', 1)); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle('商品收藏', 1)); // 基础参数赋值 - $this->assign('params', $this->data_request); - $this->assign('page_html', $page->GetPageHtml()); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + MyViewAssign('page_html', $page->GetPageHtml()); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -105,12 +105,12 @@ class UserGoodsFavor extends Common ]; $ret = GoodsFavorService::GoodsFavorList($data_params); $data = (empty($ret['data']) || empty($ret['data'][0])) ? [] : $ret['data'][0]; - $this->assign('data', $data); + MyViewAssign('data', $data); } - $this->assign('is_header', 0); - $this->assign('is_footer', 0); - return $this->fetch(); + MyViewAssign('is_header', 0); + MyViewAssign('is_footer', 0); + return MyView(); } /** diff --git a/application/index/controller/Userintegral.php b/app/index/controller/Userintegral.php similarity index 86% rename from application/index/controller/Userintegral.php rename to app/index/controller/Userintegral.php index 692dd106e..16072c64f 100755 --- a/application/index/controller/Userintegral.php +++ b/app/index/controller/Userintegral.php @@ -73,16 +73,16 @@ class UserIntegral extends Common // 用户积分 $integral = IntegralService::UserIntegral($this->user['id']); - $this->assign('user_integral_data', $integral); + MyViewAssign('user_integral_data', $integral); // 浏览器名称 - $this->assign('home_seo_site_title', SeoService::BrowserSeoTitle('我的积分', 1)); + MyViewAssign('home_seo_site_title', SeoService::BrowserSeoTitle('我的积分', 1)); // 基础参数赋值 - $this->assign('params', $this->data_request); - $this->assign('page_html', $page->GetPageHtml()); - $this->assign('data_list', $ret['data']); - return $this->fetch(); + MyViewAssign('params', $this->data_request); + MyViewAssign('page_html', $page->GetPageHtml()); + MyViewAssign('data_list', $ret['data']); + return MyView(); } /** @@ -110,12 +110,12 @@ class UserIntegral extends Common ]; $ret = IntegralService::IntegralLogList($data_params); $data = (empty($ret['data']) || empty($ret['data'][0])) ? [] : $ret['data'][0]; - $this->assign('data', $data); + MyViewAssign('data', $data); } - $this->assign('is_header', 0); - $this->assign('is_footer', 0); - return $this->fetch(); + MyViewAssign('is_header', 0); + MyViewAssign('is_footer', 0); + return MyView(); } } ?> \ No newline at end of file diff --git a/application/index/controller/index.html b/app/index/controller/index.html similarity index 100% rename from application/index/controller/index.html rename to app/index/controller/index.html diff --git a/application/index/form/Answer.php b/app/index/form/Answer.php similarity index 99% rename from application/index/form/Answer.php rename to app/index/form/Answer.php index 71923a4c6..d563b6959 100644 --- a/application/index/form/Answer.php +++ b/app/index/form/Answer.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\index\form; -use think\Db; +use think\facade\Db; /** * 我的问答动态表格 diff --git a/application/index/form/Message.php b/app/index/form/Message.php similarity index 98% rename from application/index/form/Message.php rename to app/index/form/Message.php index 96dd78123..e7158147a 100644 --- a/application/index/form/Message.php +++ b/app/index/form/Message.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\index\form; -use think\Db; +use think\facade\Db; /** * 用户消息动态表格 @@ -162,7 +162,7 @@ class Message */ public function MessageBusinessTypeList() { - return Db::name('Message')->field('business_type as name')->group('business_type')->select(); + return Db::name('Message')->field('business_type as name')->group('business_type')->select()->toArray(); } } ?> \ No newline at end of file diff --git a/application/index/form/Order.php b/app/index/form/Order.php similarity index 99% rename from application/index/form/Order.php rename to app/index/form/Order.php index 8770878e3..a4bcf44a6 100644 --- a/application/index/form/Order.php +++ b/app/index/form/Order.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\index\form; -use think\Db; +use think\facade\Db; use app\service\PaymentService; use app\service\ExpressService; diff --git a/application/index/form/Orderaftersale.php b/app/index/form/Orderaftersale.php similarity index 98% rename from application/index/form/Orderaftersale.php rename to app/index/form/Orderaftersale.php index 6acd71c8b..bac013ac0 100644 --- a/application/index/form/Orderaftersale.php +++ b/app/index/form/Orderaftersale.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\index\form; -use think\Db; +use think\facade\Db; /** * 用户订单售后动态表格 @@ -275,7 +275,7 @@ class OrderAftersale if(!empty($value)) { // 获取订单详情搜索的订单售后 id - $ids = Db::name('OrderAftersale')->alias('oa')->join(['__ORDER_DETAIL__'=>'od'], 'oa.order_detail_id=od.id')->whereOr('od.title|od.model', 'like', '%'.$value.'%')->whereOr('oa.order_no', '=', $value)->column('oa.id'); + $ids = Db::name('OrderAftersale')->alias('oa')->join('order_detail od', 'oa.order_detail_id=od.id')->whereOr('od.title|od.model', 'like', '%'.$value.'%')->whereOr('oa.order_no', '=', $value)->column('oa.id'); // 避免空条件造成无效的错觉 return empty($ids) ? [0] : $ids; diff --git a/application/index/form/Usergoodsbrowse.php b/app/index/form/Usergoodsbrowse.php similarity index 99% rename from application/index/form/Usergoodsbrowse.php rename to app/index/form/Usergoodsbrowse.php index 8295f0f45..cd5e2c412 100644 --- a/application/index/form/Usergoodsbrowse.php +++ b/app/index/form/Usergoodsbrowse.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\index\form; -use think\Db; +use think\facade\Db; /** * 用户商品浏览管理动态表格 diff --git a/application/index/form/Usergoodsfavor.php b/app/index/form/Usergoodsfavor.php similarity index 99% rename from application/index/form/Usergoodsfavor.php rename to app/index/form/Usergoodsfavor.php index 12cb1bf3f..a89ec977e 100644 --- a/application/index/form/Usergoodsfavor.php +++ b/app/index/form/Usergoodsfavor.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\index\form; -use think\Db; +use think\facade\Db; /** * 用户商品收藏管理动态表格 diff --git a/application/index/form/Userintegral.php b/app/index/form/Userintegral.php similarity index 99% rename from application/index/form/Userintegral.php rename to app/index/form/Userintegral.php index 13c90dcb6..8af6eb937 100644 --- a/application/index/form/Userintegral.php +++ b/app/index/form/Userintegral.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\index\form; -use think\Db; +use think\facade\Db; /** * 用户积分动态表格 diff --git a/application/index/index.html b/app/index/index.html similarity index 100% rename from application/index/index.html rename to app/index/index.html diff --git a/application/index/lang/index.html b/app/index/lang/index.html similarity index 100% rename from application/index/lang/index.html rename to app/index/lang/index.html diff --git a/application/index/lang/zh-cn.php b/app/index/lang/zh-cn.php similarity index 100% rename from application/index/lang/zh-cn.php rename to app/index/lang/zh-cn.php diff --git a/app/index/route/.gitignore b/app/index/route/.gitignore new file mode 100644 index 000000000..7e4a4bae7 --- /dev/null +++ b/app/index/route/.gitignore @@ -0,0 +1 @@ +route.php \ No newline at end of file diff --git a/route/route.config b/app/index/route/route.config old mode 100755 new mode 100644 similarity index 100% rename from route/route.config rename to app/index/route/route.config diff --git a/application/index/view/default/agreement/index.html b/app/index/view/default/agreement/index.html similarity index 100% rename from application/index/view/default/agreement/index.html rename to app/index/view/default/agreement/index.html diff --git a/application/index/view/default/answer/detail.html b/app/index/view/default/answer/detail.html similarity index 100% rename from application/index/view/default/answer/detail.html rename to app/index/view/default/answer/detail.html diff --git a/application/index/view/default/answer/index.html b/app/index/view/default/answer/index.html similarity index 100% rename from application/index/view/default/answer/index.html rename to app/index/view/default/answer/index.html diff --git a/application/index/view/default/answer/module/content.html b/app/index/view/default/answer/module/content.html similarity index 100% rename from application/index/view/default/answer/module/content.html rename to app/index/view/default/answer/module/content.html diff --git a/application/index/view/default/answer/module/operate.html b/app/index/view/default/answer/module/operate.html similarity index 100% rename from application/index/view/default/answer/module/operate.html rename to app/index/view/default/answer/module/operate.html diff --git a/application/index/view/default/answer/module/reply.html b/app/index/view/default/answer/module/reply.html similarity index 100% rename from application/index/view/default/answer/module/reply.html rename to app/index/view/default/answer/module/reply.html diff --git a/application/index/view/default/article/index.html b/app/index/view/default/article/index.html similarity index 100% rename from application/index/view/default/article/index.html rename to app/index/view/default/article/index.html diff --git a/application/index/view/default/buy/index.html b/app/index/view/default/buy/index.html similarity index 98% rename from application/index/view/default/buy/index.html rename to app/index/view/default/buy/index.html index 4306578c6..256f145bf 100755 --- a/application/index/view/default/buy/index.html +++ b/app/index/view/default/buy/index.html @@ -248,7 +248,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_buy_group_nav_inside_begin'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$v]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$v]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -289,7 +289,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_buy_group_nav_inside_middle'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$v]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$v]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -318,7 +318,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_buy_group_nav_inside_end'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$v]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$v]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -341,7 +341,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_buy_group_goods_inside_top'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$v]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$v]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -378,7 +378,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_buy_group_goods_base_top'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$goods]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$goods]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -421,7 +421,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_buy_group_goods_base_bottom'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$goods]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$goods]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -466,7 +466,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_buy_group_goods_inside_bottom'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$v, 'params'=>$params]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$v, 'params'=>$params]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) diff --git a/application/index/view/default/cart/index.html b/app/index/view/default/cart/index.html similarity index 93% rename from application/index/view/default/cart/index.html rename to app/index/view/default/cart/index.html index aa17357a7..b3eaf2219 100755 --- a/application/index/view/default/cart/index.html +++ b/app/index/view/default/cart/index.html @@ -42,7 +42,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_cart_base_begin'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$goods]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$goods]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -90,7 +90,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_cart_base_end'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$goods]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$goods]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -113,7 +113,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_cart_price_begin'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$goods]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$goods]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -143,7 +143,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_cart_price_end'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$goods]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$goods]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -166,7 +166,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_cart_number_begin'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$goods]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$goods]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -202,7 +202,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_cart_number_end'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$goods]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$goods]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -225,7 +225,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_cart_total_price_begin'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$goods]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$goods]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -249,7 +249,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_cart_total_price_end'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$goods]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$goods]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -274,7 +274,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_cart_operate'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$goods]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$goods]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -310,7 +310,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_cart_nav_left_inside'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$cart_list]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$cart_list]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -333,7 +333,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_cart_nav_right_inside'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$cart_list]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$cart_list]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) diff --git a/application/index/view/default/category/index.html b/app/index/view/default/category/index.html similarity index 100% rename from application/index/view/default/category/index.html rename to app/index/view/default/category/index.html diff --git a/application/index/view/default/config.json b/app/index/view/default/config.json similarity index 81% rename from application/index/view/default/config.json rename to app/index/view/default/config.json index e492fe82c..2ef4ef1b6 100755 --- a/application/index/view/default/config.json +++ b/app/index/view/default/config.json @@ -1,6 +1,6 @@ { "name":"默认主题", - "ver":"2.1.0", + "ver":"2.2.0", "author":"Devil", "home":"https://shopxo.net/" } \ No newline at end of file diff --git a/application/index/view/default/customview/index.html b/app/index/view/default/customview/index.html similarity index 100% rename from application/index/view/default/customview/index.html rename to app/index/view/default/customview/index.html diff --git a/application/index/view/default/design/index.html b/app/index/view/default/design/index.html similarity index 100% rename from application/index/view/default/design/index.html rename to app/index/view/default/design/index.html diff --git a/application/index/view/default/goods/comments.html b/app/index/view/default/goods/comments.html similarity index 100% rename from application/index/view/default/goods/comments.html rename to app/index/view/default/goods/comments.html diff --git a/application/index/view/default/goods/index.html b/app/index/view/default/goods/index.html similarity index 100% rename from application/index/view/default/goods/index.html rename to app/index/view/default/goods/index.html diff --git a/application/index/view/default/index.html b/app/index/view/default/index.html similarity index 100% rename from application/index/view/default/index.html rename to app/index/view/default/index.html diff --git a/application/index/view/default/index/index.html b/app/index/view/default/index/index.html similarity index 94% rename from application/index/view/default/index/index.html rename to app/index/view/default/index/index.html index f9a265a7f..405db875f 100755 --- a/application/index/view/default/index/index.html +++ b/app/index/view/default/index/index.html @@ -155,7 +155,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_home_floor_top_'.($key+1); - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'floor_id'=>$key+1, 'floor'=>$floor]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'floor_id'=>$key+1, 'floor'=>$floor]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -196,7 +196,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_home_floor_inside_top'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'floor_id'=>$key+1, 'floor'=>$floor]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'floor_id'=>$key+1, 'floor'=>$floor]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -235,7 +235,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_home_aggregation_inside_bottom'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'floor_id'=>$key+1, 'floor'=>$floor]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'floor_id'=>$key+1, 'floor'=>$floor]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -262,7 +262,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_home_goods_inside_top'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'floor_id'=>$key+1, 'goods_id'=>$goods['id'], 'goods'=>$goods]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'floor_id'=>$key+1, 'goods_id'=>$goods['id'], 'goods'=>$goods]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -289,7 +289,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_home_goods_inside_price_top'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'floor_id'=>$key+1, 'goods_id'=>$goods['id'], 'goods'=>$goods]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'floor_id'=>$key+1, 'goods_id'=>$goods['id'], 'goods'=>$goods]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -312,7 +312,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_home_goods_inside_bottom'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'floor_id'=>$key+1, 'goods_id'=>$goods['id'], 'goods'=>$goods]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'floor_id'=>$key+1, 'goods_id'=>$goods['id'], 'goods'=>$goods]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -337,7 +337,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_home_floor_inside_bottom'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'floor_id'=>$key+1, 'floor'=>$floor]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'floor_id'=>$key+1, 'floor'=>$floor]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -360,7 +360,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_home_floor_bottom_'.($key+1); - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'floor_id'=>$key+1, 'floor'=>$floor]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'floor_id'=>$key+1, 'floor'=>$floor]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) diff --git a/application/index/view/default/lib/enable.html b/app/index/view/default/lib/enable.html similarity index 100% rename from application/index/view/default/lib/enable.html rename to app/index/view/default/lib/enable.html diff --git a/application/index/view/default/lib/gender.html b/app/index/view/default/lib/gender.html similarity index 100% rename from application/index/view/default/lib/gender.html rename to app/index/view/default/lib/gender.html diff --git a/application/index/view/default/lib/index.html b/app/index/view/default/lib/index.html similarity index 100% rename from application/index/view/default/lib/index.html rename to app/index/view/default/lib/index.html diff --git a/application/index/view/default/lib/is_new_window_open.html b/app/index/view/default/lib/is_new_window_open.html similarity index 100% rename from application/index/view/default/lib/is_new_window_open.html rename to app/index/view/default/lib/is_new_window_open.html diff --git a/application/index/view/default/lib/is_show.html b/app/index/view/default/lib/is_show.html similarity index 100% rename from application/index/view/default/lib/is_show.html rename to app/index/view/default/lib/is_show.html diff --git a/application/index/view/default/lib/module/category_brand.html b/app/index/view/default/lib/module/category_brand.html similarity index 100% rename from application/index/view/default/lib/module/category_brand.html rename to app/index/view/default/lib/module/category_brand.html diff --git a/application/index/view/default/lib/module/goods_category.html b/app/index/view/default/lib/module/goods_category.html similarity index 100% rename from application/index/view/default/lib/module/goods_category.html rename to app/index/view/default/lib/module/goods_category.html diff --git a/application/index/view/default/lib/region_linkage.html b/app/index/view/default/lib/region_linkage.html similarity index 100% rename from application/index/view/default/lib/region_linkage.html rename to app/index/view/default/lib/region_linkage.html diff --git a/application/index/view/default/lib/seo.html b/app/index/view/default/lib/seo.html similarity index 100% rename from application/index/view/default/lib/seo.html rename to app/index/view/default/lib/seo.html diff --git a/application/index/view/default/message/detail.html b/app/index/view/default/message/detail.html similarity index 100% rename from application/index/view/default/message/detail.html rename to app/index/view/default/message/detail.html diff --git a/application/index/view/default/message/index.html b/app/index/view/default/message/index.html similarity index 100% rename from application/index/view/default/message/index.html rename to app/index/view/default/message/index.html diff --git a/application/index/view/default/message/module/operate.html b/app/index/view/default/message/module/operate.html similarity index 100% rename from application/index/view/default/message/module/operate.html rename to app/index/view/default/message/module/operate.html diff --git a/application/index/view/default/order/comments.html b/app/index/view/default/order/comments.html similarity index 100% rename from application/index/view/default/order/comments.html rename to app/index/view/default/order/comments.html diff --git a/application/index/view/default/order/detail.html b/app/index/view/default/order/detail.html similarity index 97% rename from application/index/view/default/order/detail.html rename to app/index/view/default/order/detail.html index 426f0771d..e07893ac6 100755 --- a/application/index/view/default/order/detail.html +++ b/app/index/view/default/order/detail.html @@ -30,7 +30,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_user_order_detail_progress_top'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$data]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$data]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -117,7 +117,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_user_order_detail_base_top'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$data]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$data]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -304,7 +304,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_index_order_detail_operate'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'id'=>$data['id'], 'data'=>$data]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'id'=>$data['id'], 'data'=>$data]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -380,7 +380,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_user_order_detail_base_bottom'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$data]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$data]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -424,7 +424,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_user_order_detail_address_bottom'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$data]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$data]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -480,7 +480,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_user_order_detail_fictitious_bottom'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$data]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$data]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -570,7 +570,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_user_order_detail_goods_inside_bottom'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$data]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$data]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -647,7 +647,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_user_order_detail_goods_bottom'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$data]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$data]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) diff --git a/application/index/view/default/order/index.html b/app/index/view/default/order/index.html similarity index 100% rename from application/index/view/default/order/index.html rename to app/index/view/default/order/index.html diff --git a/application/index/view/default/order/module/address.html b/app/index/view/default/order/module/address.html similarity index 100% rename from application/index/view/default/order/module/address.html rename to app/index/view/default/order/module/address.html diff --git a/application/index/view/default/order/module/extension.html b/app/index/view/default/order/module/extension.html similarity index 100% rename from application/index/view/default/order/module/extension.html rename to app/index/view/default/order/module/extension.html diff --git a/application/index/view/default/order/module/goods.html b/app/index/view/default/order/module/goods.html similarity index 92% rename from application/index/view/default/order/module/goods.html rename to app/index/view/default/order/module/goods.html index 6969cf28f..126f078d4 100644 --- a/application/index/view/default/order/module/goods.html +++ b/app/index/view/default/order/module/goods.html @@ -8,7 +8,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_user_order_list_base_top'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$module_data]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$module_data]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -55,7 +55,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_user_order_list_base_nav_bottom'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$module_data]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$module_data]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -78,7 +78,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_user_order_list_base_goods_top'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$module_data]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$module_data]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -142,7 +142,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_user_order_list_base_goods_bottom'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$module_data]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$module_data]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -167,7 +167,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_user_order_list_base_bottom'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$module_data]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$module_data]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) diff --git a/application/index/view/default/order/module/is_comments.html b/app/index/view/default/order/module/is_comments.html similarity index 100% rename from application/index/view/default/order/module/is_comments.html rename to app/index/view/default/order/module/is_comments.html diff --git a/application/index/view/default/order/module/operate.html b/app/index/view/default/order/module/operate.html similarity index 100% rename from application/index/view/default/order/module/operate.html rename to app/index/view/default/order/module/operate.html diff --git a/application/index/view/default/order/module/pay_status.html b/app/index/view/default/order/module/pay_status.html similarity index 100% rename from application/index/view/default/order/module/pay_status.html rename to app/index/view/default/order/module/pay_status.html diff --git a/application/index/view/default/order/module/take.html b/app/index/view/default/order/module/take.html similarity index 100% rename from application/index/view/default/order/module/take.html rename to app/index/view/default/order/module/take.html diff --git a/application/index/view/default/order/payment_popup.html b/app/index/view/default/order/payment_popup.html similarity index 100% rename from application/index/view/default/order/payment_popup.html rename to app/index/view/default/order/payment_popup.html diff --git a/application/index/view/default/orderaftersale/create.html b/app/index/view/default/orderaftersale/create.html similarity index 100% rename from application/index/view/default/orderaftersale/create.html rename to app/index/view/default/orderaftersale/create.html diff --git a/application/index/view/default/orderaftersale/delivery.html b/app/index/view/default/orderaftersale/delivery.html similarity index 100% rename from application/index/view/default/orderaftersale/delivery.html rename to app/index/view/default/orderaftersale/delivery.html diff --git a/application/index/view/default/orderaftersale/detail.html b/app/index/view/default/orderaftersale/detail.html similarity index 93% rename from application/index/view/default/orderaftersale/detail.html rename to app/index/view/default/orderaftersale/detail.html index eab2b0955..8d10e906b 100644 --- a/application/index/view/default/orderaftersale/detail.html +++ b/app/index/view/default/orderaftersale/detail.html @@ -30,7 +30,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_user_orderaftersale_detail_top'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'goods'=>$goods, 'order'=>$order, 'new_aftersale_data'=>$new_aftersale_data, 'step_data'=>$step_data, 'returned_data'=>$returned_data, 'params'=>$params]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'goods'=>$goods, 'order'=>$order, 'new_aftersale_data'=>$new_aftersale_data, 'step_data'=>$step_data, 'returned_data'=>$returned_data, 'params'=>$params]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -56,7 +56,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_user_orderaftersale_detail_goods_inside_top'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'goods'=>$goods, 'order'=>$order, 'new_aftersale_data'=>$new_aftersale_data, 'step_data'=>$step_data, 'returned_data'=>$returned_data, 'params'=>$params]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'goods'=>$goods, 'order'=>$order, 'new_aftersale_data'=>$new_aftersale_data, 'step_data'=>$step_data, 'returned_data'=>$returned_data, 'params'=>$params]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -115,7 +115,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_user_orderaftersale_detail_goods_inside_bottom'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'goods'=>$goods, 'order'=>$order, 'new_aftersale_data'=>$new_aftersale_data, 'step_data'=>$step_data, 'returned_data'=>$returned_data, 'params'=>$params]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'goods'=>$goods, 'order'=>$order, 'new_aftersale_data'=>$new_aftersale_data, 'step_data'=>$step_data, 'returned_data'=>$returned_data, 'params'=>$params]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -181,7 +181,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_user_orderaftersale_detail_goods_inside_base_bottom'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'goods'=>$goods, 'order'=>$order, 'new_aftersale_data'=>$new_aftersale_data, 'step_data'=>$step_data, 'returned_data'=>$returned_data, 'params'=>$params]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'goods'=>$goods, 'order'=>$order, 'new_aftersale_data'=>$new_aftersale_data, 'step_data'=>$step_data, 'returned_data'=>$returned_data, 'params'=>$params]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -205,7 +205,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_user_orderaftersale_detail_goods_bottom'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'goods'=>$goods, 'order'=>$order, 'new_aftersale_data'=>$new_aftersale_data, 'step_data'=>$step_data, 'returned_data'=>$returned_data, 'params'=>$params]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'goods'=>$goods, 'order'=>$order, 'new_aftersale_data'=>$new_aftersale_data, 'step_data'=>$step_data, 'returned_data'=>$returned_data, 'params'=>$params]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -292,7 +292,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_user_orderaftersale_detail_base_top'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'goods'=>$goods, 'order'=>$order, 'new_aftersale_data'=>$new_aftersale_data, 'step_data'=>$step_data, 'returned_data'=>$returned_data, 'params'=>$params]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'goods'=>$goods, 'order'=>$order, 'new_aftersale_data'=>$new_aftersale_data, 'step_data'=>$step_data, 'returned_data'=>$returned_data, 'params'=>$params]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -426,7 +426,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_user_orderaftersale_detail_bottom'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'goods'=>$goods, 'order'=>$order, 'new_aftersale_data'=>$new_aftersale_data, 'step_data'=>$step_data, 'returned_data'=>$returned_data, 'params'=>$params]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'goods'=>$goods, 'order'=>$order, 'new_aftersale_data'=>$new_aftersale_data, 'step_data'=>$step_data, 'returned_data'=>$returned_data, 'params'=>$params]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) diff --git a/application/index/view/default/orderaftersale/index.html b/app/index/view/default/orderaftersale/index.html similarity index 100% rename from application/index/view/default/orderaftersale/index.html rename to app/index/view/default/orderaftersale/index.html diff --git a/application/index/view/default/orderaftersale/module/goods.html b/app/index/view/default/orderaftersale/module/goods.html similarity index 91% rename from application/index/view/default/orderaftersale/module/goods.html rename to app/index/view/default/orderaftersale/module/goods.html index 6b940961a..73354d281 100644 --- a/application/index/view/default/orderaftersale/module/goods.html +++ b/app/index/view/default/orderaftersale/module/goods.html @@ -8,7 +8,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_user_orderaftersale_list_base_top'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$module_data]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$module_data]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -35,7 +35,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_user_orderaftersale_list_base_goods_top'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$module_data]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$module_data]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -81,7 +81,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_user_orderaftersale_list_base_bottom'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$module_data]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'data'=>$module_data]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) diff --git a/application/index/view/default/orderaftersale/module/operate.html b/app/index/view/default/orderaftersale/module/operate.html similarity index 100% rename from application/index/view/default/orderaftersale/module/operate.html rename to app/index/view/default/orderaftersale/module/operate.html diff --git a/application/index/view/default/orderaftersale/module/voucher.html b/app/index/view/default/orderaftersale/module/voucher.html similarity index 100% rename from application/index/view/default/orderaftersale/module/voucher.html rename to app/index/view/default/orderaftersale/module/voucher.html diff --git a/application/index/view/default/orderaftersale/step.html b/app/index/view/default/orderaftersale/step.html similarity index 100% rename from application/index/view/default/orderaftersale/step.html rename to app/index/view/default/orderaftersale/step.html diff --git a/application/index/view/default/pay/qrcode.html b/app/index/view/default/pay/qrcode.html similarity index 100% rename from application/index/view/default/pay/qrcode.html rename to app/index/view/default/pay/qrcode.html diff --git a/application/index/view/default/personal/index.html b/app/index/view/default/personal/index.html similarity index 100% rename from application/index/view/default/personal/index.html rename to app/index/view/default/personal/index.html diff --git a/application/index/view/default/personal/save_info.html b/app/index/view/default/personal/save_info.html similarity index 100% rename from application/index/view/default/personal/save_info.html rename to app/index/view/default/personal/save_info.html diff --git a/application/index/view/default/public/footer.html b/app/index/view/default/public/footer.html similarity index 100% rename from application/index/view/default/public/footer.html rename to app/index/view/default/public/footer.html diff --git a/application/index/view/default/public/footer_nav.html b/app/index/view/default/public/footer_nav.html similarity index 100% rename from application/index/view/default/public/footer_nav.html rename to app/index/view/default/public/footer_nav.html diff --git a/application/index/view/default/public/goods_category.html b/app/index/view/default/public/goods_category.html similarity index 96% rename from application/index/view/default/public/goods_category.html rename to app/index/view/default/public/goods_category.html index 4d8908fb7..7acc5f883 100755 --- a/application/index/view/default/public/goods_category.html +++ b/app/index/view/default/public/goods_category.html @@ -6,7 +6,7 @@ 全部分类 -
+
    {{if !empty($goods_category_list) and is_array($goods_category_list)}} diff --git a/application/index/view/default/public/header.html b/app/index/view/default/public/header.html similarity index 95% rename from application/index/view/default/public/header.html rename to app/index/view/default/public/header.html index 7c376551d..4b27e4a99 100755 --- a/application/index/view/default/public/header.html +++ b/app/index/view/default/public/header.html @@ -1,7 +1,7 @@ - + {{$home_seo_site_title}} @@ -67,7 +67,7 @@ var __my_public_url__ = '{{$my_public_url}}'; var __public__ = '{{$public_host}}'; var __default_theme__ = '{{$default_theme}}'; - var __modal_login_url__ = '{{:Url("index/user/modallogininfo")}}'; + var __modal_login_url__ = '{{:MyUrl("index/user/modallogininfo")}}'; var __attachment_host__ = '{{$attachment_host}}'; var __seo_url_suffix__ = '{{:MyC("home_seo_url_html_suffix", "html", true)}}'; var __user_id__ = {{if empty($user['id'])}}0{{else /}}{{$user.id}}{{/if}}; @@ -83,7 +83,7 @@ {{/foreach}} {{/if}} - + {{if isset($shopxo_is_develop) and $shopxo_is_develop eq true and (!isset($is_header) or $is_header eq 1)}}
    diff --git a/application/index/view/default/public/header_nav.html b/app/index/view/default/public/header_nav.html similarity index 100% rename from application/index/view/default/public/header_nav.html rename to app/index/view/default/public/header_nav.html diff --git a/application/index/view/default/public/header_top_nav.html b/app/index/view/default/public/header_top_nav.html similarity index 100% rename from application/index/view/default/public/header_top_nav.html rename to app/index/view/default/public/header_top_nav.html diff --git a/application/index/view/default/public/home_banner.html b/app/index/view/default/public/home_banner.html similarity index 100% rename from application/index/view/default/public/home_banner.html rename to app/index/view/default/public/home_banner.html diff --git a/application/index/view/default/public/home_nav.html b/app/index/view/default/public/home_nav.html similarity index 100% rename from application/index/view/default/public/home_nav.html rename to app/index/view/default/public/home_nav.html diff --git a/application/index/view/default/public/index.html b/app/index/view/default/public/index.html similarity index 100% rename from application/index/view/default/public/index.html rename to app/index/view/default/public/index.html diff --git a/app/index/view/default/public/jump_error.html b/app/index/view/default/public/jump_error.html new file mode 100755 index 000000000..f4d4975bf --- /dev/null +++ b/app/index/view/default/public/jump_error.html @@ -0,0 +1,46 @@ +{{include file="public/header" /}} + + +{{if isset($is_header) and $is_header eq 1}} + + {{include file="public/header_top_nav" /}} + + + {{include file="public/nav_search" /}} + + + {{include file="public/header_nav" /}} + + + {{include file="public/goods_category" /}} +{{/if}} + + + +
    +
    +

    +

    {{if isset($msg)}}{{$msg}}{{else /}}操作失败{{/if}}

    +

    + 返回上一页 + {{if empty($wait_time)}}5{{else /}}{{$wait_time}}{{/if}}秒自动返回 +

    +
    +
    + + + +{{include file="public/footer" /}} + \ No newline at end of file diff --git a/app/index/view/default/public/jump_success.html b/app/index/view/default/public/jump_success.html new file mode 100755 index 000000000..2b95a0798 --- /dev/null +++ b/app/index/view/default/public/jump_success.html @@ -0,0 +1,46 @@ +{{include file="public/header" /}} + + +{{if isset($is_header) and $is_header eq 1}} + + {{include file="public/header_top_nav" /}} + + + {{include file="public/nav_search" /}} + + + {{include file="public/header_nav" /}} + + + {{include file="public/goods_category" /}} +{{/if}} + + + +
    +
    +

    +

    {{if isset($msg)}}{{$msg}}{{else /}}操作成功{{/if}}

    +

    + 返回上一页 + {{if empty($wait_time)}}5{{else /}}{{$wait_time}}{{/if}}秒自动返回 +

    +
    +
    + + + +{{include file="public/footer" /}} + \ No newline at end of file diff --git a/application/index/view/default/public/loading.html b/app/index/view/default/public/loading.html similarity index 100% rename from application/index/view/default/public/loading.html rename to app/index/view/default/public/loading.html diff --git a/application/index/view/default/public/login_success.html b/app/index/view/default/public/login_success.html similarity index 100% rename from application/index/view/default/public/login_success.html rename to app/index/view/default/public/login_success.html diff --git a/application/index/view/default/public/module/base_form.html b/app/index/view/default/public/module/base_form.html similarity index 100% rename from application/index/view/default/public/module/base_form.html rename to app/index/view/default/public/module/base_form.html diff --git a/application/admin/view/default/public/module/detail.html b/app/index/view/default/public/module/detail.html similarity index 94% rename from application/admin/view/default/public/module/detail.html rename to app/index/view/default/public/module/detail.html index b0db5d1a8..4b702ff12 100644 --- a/application/admin/view/default/public/module/detail.html +++ b/app/index/view/default/public/module/detail.html @@ -7,7 +7,7 @@
    {{/if}} {{php}} - $hook_data = Hook::listen($hook_name_detail_top, ['hook_name'=>$hook_name_detail_top, 'is_backend'=>true]); + $hook_data = MyEventTrigger($hook_name_detail_top, ['hook_name'=>$hook_name_detail_top, 'is_backend'=>true]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -29,7 +29,7 @@
{{/if}} {{php}} - $hook_data = Hook::listen($hook_name_detail_inside_top, ['hook_name'=>$hook_name_detail_inside_top, 'is_backend'=>true]); + $hook_data = MyEventTrigger($hook_name_detail_inside_top, ['hook_name'=>$hook_name_detail_inside_top, 'is_backend'=>true]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -143,7 +143,7 @@
{{/if}} {{php}} - $hook_data = Hook::listen($hook_name_detail_inside_bottom, ['hook_name'=>$hook_name_detail_inside_bottom, 'is_backend'=>true]); + $hook_data = MyEventTrigger($hook_name_detail_inside_bottom, ['hook_name'=>$hook_name_detail_inside_bottom, 'is_backend'=>true]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -165,7 +165,7 @@
{{/if}} {{php}} - $hook_data = Hook::listen($hook_name_detail_bottom, ['hook_name'=>$hook_name_detail_bottom, 'is_backend'=>true]); + $hook_data = MyEventTrigger($hook_name_detail_bottom, ['hook_name'=>$hook_name_detail_bottom, 'is_backend'=>true]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) diff --git a/application/index/view/default/public/module/form.html b/app/index/view/default/public/module/form.html similarity index 90% rename from application/index/view/default/public/module/form.html rename to app/index/view/default/public/module/form.html index b8d0a14ef..12d6293c5 100644 --- a/application/index/view/default/public/module/form.html +++ b/app/index/view/default/public/module/form.html @@ -21,7 +21,7 @@ {{/if}} {{php}} - $hook_data = Hook::listen($hook_name_content_top, ['hook_name'=>$hook_name_content_top, 'is_backend'=>true]); + $hook_data = MyEventTrigger($hook_name_content_top, ['hook_name'=>$hook_name_content_top, 'is_backend'=>true]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -49,7 +49,7 @@ {{/if}} {{php}} - $hook_data = Hook::listen($hook_name_content_inside_top, ['hook_name'=>$hook_name_content_inside_top, 'is_backend'=>true]); + $hook_data = MyEventTrigger($hook_name_content_inside_top, ['hook_name'=>$hook_name_content_inside_top, 'is_backend'=>true]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -117,7 +117,7 @@ {{/if}} {{php}} - $hook_data = Hook::listen($hook_name_content_inside_bottom, ['hook_name'=>$hook_name_content_inside_bottom, 'is_backend'=>true]); + $hook_data = MyEventTrigger($hook_name_content_inside_bottom, ['hook_name'=>$hook_name_content_inside_bottom, 'is_backend'=>true]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -139,7 +139,7 @@ {{/if}} {{php}} - $hook_data = Hook::listen($hook_name_content_bottom, ['hook_name'=>$hook_name_content_bottom, 'is_backend'=>true]); + $hook_data = MyEventTrigger($hook_name_content_bottom, ['hook_name'=>$hook_name_content_bottom, 'is_backend'=>true]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) diff --git a/application/index/view/default/public/module/form_fields_select.html b/app/index/view/default/public/module/form_fields_select.html similarity index 100% rename from application/index/view/default/public/module/form_fields_select.html rename to app/index/view/default/public/module/form_fields_select.html diff --git a/application/index/view/default/public/module/form_operate_bottom.html b/app/index/view/default/public/module/form_operate_bottom.html similarity index 77% rename from application/index/view/default/public/module/form_operate_bottom.html rename to app/index/view/default/public/module/form_operate_bottom.html index a2e50a169..fe8f38c8e 100644 --- a/application/index/view/default/public/module/form_operate_bottom.html +++ b/app/index/view/default/public/module/form_operate_bottom.html @@ -4,7 +4,7 @@ {{/if}} {{php}} - $hook_data = Hook::listen($hook_name_form_bottom_operate, ['hook_name'=>$hook_name_form_bottom_operate, 'is_backend'=>true]); + $hook_data = MyEventTrigger($hook_name_form_bottom_operate, ['hook_name'=>$hook_name_form_bottom_operate, 'is_backend'=>true]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) diff --git a/application/index/view/default/public/module/form_operate_top.html b/app/index/view/default/public/module/form_operate_top.html similarity index 95% rename from application/index/view/default/public/module/form_operate_top.html rename to app/index/view/default/public/module/form_operate_top.html index 985229509..153e81e60 100644 --- a/application/index/view/default/public/module/form_operate_top.html +++ b/app/index/view/default/public/module/form_operate_top.html @@ -20,7 +20,7 @@ {{/if}} {{php}} - $hook_data = Hook::listen($hook_name_form_top_operate, ['hook_name'=>$hook_name_form_top_operate, 'is_backend'=>true]); + $hook_data = MyEventTrigger($hook_name_form_top_operate, ['hook_name'=>$hook_name_form_top_operate, 'is_backend'=>true]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) diff --git a/application/admin/view/default/public/module/form_table.html b/app/index/view/default/public/module/form_table.html similarity index 99% rename from application/admin/view/default/public/module/form_table.html rename to app/index/view/default/public/module/form_table.html index e25e83b94..b6ffedfd4 100644 --- a/application/admin/view/default/public/module/form_table.html +++ b/app/index/view/default/public/module/form_table.html @@ -255,7 +255,7 @@ {{/if}} {{php}} - $hook_data = Hook::listen($hook_name_form_list_operate, [ + $hook_data = MyEventTrigger($hook_name_form_list_operate, [ 'hook_name' => $hook_name_form_list_operate, 'is_backend' => true, 'id' => isset($data_list[$i][$form_table['base']['key_field']]) ? $data_list[$i][$form_table['base']['key_field']] : 0, diff --git a/application/index/view/default/public/module/user_form.html b/app/index/view/default/public/module/user_form.html similarity index 91% rename from application/index/view/default/public/module/user_form.html rename to app/index/view/default/public/module/user_form.html index 3f36a0275..a096044eb 100644 --- a/application/index/view/default/public/module/user_form.html +++ b/app/index/view/default/public/module/user_form.html @@ -29,7 +29,7 @@ {{/if}} {{php}} - $hook_data = Hook::listen($hook_name_content_top, ['hook_name'=>$hook_name_content_top, 'is_backend'=>true]); + $hook_data = MyEventTrigger($hook_name_content_top, ['hook_name'=>$hook_name_content_top, 'is_backend'=>true]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -57,7 +57,7 @@ {{/if}} {{php}} - $hook_data = Hook::listen($hook_name_content_inside_top, ['hook_name'=>$hook_name_content_inside_top, 'is_backend'=>true]); + $hook_data = MyEventTrigger($hook_name_content_inside_top, ['hook_name'=>$hook_name_content_inside_top, 'is_backend'=>true]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -125,7 +125,7 @@ {{/if}} {{php}} - $hook_data = Hook::listen($hook_name_content_inside_bottom, ['hook_name'=>$hook_name_content_inside_bottom, 'is_backend'=>true]); + $hook_data = MyEventTrigger($hook_name_content_inside_bottom, ['hook_name'=>$hook_name_content_inside_bottom, 'is_backend'=>true]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -147,7 +147,7 @@ {{/if}} {{php}} - $hook_data = Hook::listen($hook_name_content_bottom, ['hook_name'=>$hook_name_content_bottom, 'is_backend'=>true]); + $hook_data = MyEventTrigger($hook_name_content_bottom, ['hook_name'=>$hook_name_content_bottom, 'is_backend'=>true]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) diff --git a/application/index/view/default/public/nav.html b/app/index/view/default/public/nav.html similarity index 100% rename from application/index/view/default/public/nav.html rename to app/index/view/default/public/nav.html diff --git a/application/index/view/default/public/nav_search.html b/app/index/view/default/public/nav_search.html similarity index 100% rename from application/index/view/default/public/nav_search.html rename to app/index/view/default/public/nav_search.html diff --git a/application/index/view/default/public/not_data.html b/app/index/view/default/public/not_data.html similarity index 100% rename from application/index/view/default/public/not_data.html rename to app/index/view/default/public/not_data.html diff --git a/application/index/view/default/public/quick.html b/app/index/view/default/public/quick.html similarity index 100% rename from application/index/view/default/public/quick.html rename to app/index/view/default/public/quick.html diff --git a/application/index/view/default/public/tips_error.html b/app/index/view/default/public/tips_error.html similarity index 92% rename from application/index/view/default/public/tips_error.html rename to app/index/view/default/public/tips_error.html index 41206f7c8..a6ec4244a 100755 --- a/application/index/view/default/public/tips_error.html +++ b/app/index/view/default/public/tips_error.html @@ -17,7 +17,7 @@ -
+
{{$msg}} @@ -33,4 +33,5 @@
+ {{include file="public/footer" /}} \ No newline at end of file diff --git a/application/index/view/default/public/tips_success.html b/app/index/view/default/public/tips_success.html similarity index 92% rename from application/index/view/default/public/tips_success.html rename to app/index/view/default/public/tips_success.html index bab67001b..b85c2ffb3 100755 --- a/application/index/view/default/public/tips_success.html +++ b/app/index/view/default/public/tips_success.html @@ -17,7 +17,7 @@ -
+
{{$msg}} @@ -33,4 +33,5 @@
+ {{include file="public/footer" /}} \ No newline at end of file diff --git a/application/index/view/default/public/user_menu.html b/app/index/view/default/public/user_menu.html similarity index 100% rename from application/index/view/default/public/user_menu.html rename to app/index/view/default/public/user_menu.html diff --git a/application/index/view/default/safety/email_info.html b/app/index/view/default/safety/email_info.html similarity index 93% rename from application/index/view/default/safety/email_info.html rename to app/index/view/default/safety/email_info.html index 791dcdfb9..b4b11d33e 100755 --- a/application/index/view/default/safety/email_info.html +++ b/app/index/view/default/safety/email_info.html @@ -56,8 +56,8 @@ diff --git a/application/index/view/default/safety/index.html b/app/index/view/default/safety/index.html similarity index 100% rename from application/index/view/default/safety/index.html rename to app/index/view/default/safety/index.html diff --git a/application/index/view/default/safety/login_pwd_info.html b/app/index/view/default/safety/login_pwd_info.html similarity index 100% rename from application/index/view/default/safety/login_pwd_info.html rename to app/index/view/default/safety/login_pwd_info.html diff --git a/application/index/view/default/safety/mobile_info.html b/app/index/view/default/safety/mobile_info.html similarity index 93% rename from application/index/view/default/safety/mobile_info.html rename to app/index/view/default/safety/mobile_info.html index b97f8c88c..1c036c662 100755 --- a/application/index/view/default/safety/mobile_info.html +++ b/app/index/view/default/safety/mobile_info.html @@ -56,8 +56,8 @@ diff --git a/application/index/view/default/safety/new_email_info.html b/app/index/view/default/safety/new_email_info.html similarity index 93% rename from application/index/view/default/safety/new_email_info.html rename to app/index/view/default/safety/new_email_info.html index f681e17db..097d1ca63 100755 --- a/application/index/view/default/safety/new_email_info.html +++ b/app/index/view/default/safety/new_email_info.html @@ -56,8 +56,8 @@ diff --git a/application/index/view/default/safety/new_mobile_info.html b/app/index/view/default/safety/new_mobile_info.html similarity index 93% rename from application/index/view/default/safety/new_mobile_info.html rename to app/index/view/default/safety/new_mobile_info.html index 7cf38ff60..89a23d7e4 100755 --- a/application/index/view/default/safety/new_mobile_info.html +++ b/app/index/view/default/safety/new_mobile_info.html @@ -56,8 +56,8 @@ diff --git a/application/index/view/default/search/content.html b/app/index/view/default/search/content.html similarity index 89% rename from application/index/view/default/search/content.html rename to app/index/view/default/search/content.html index 64d1ba4d1..1807cc722 100644 --- a/application/index/view/default/search/content.html +++ b/app/index/view/default/search/content.html @@ -11,7 +11,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_search_goods_inside_top'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'goods_id'=>$v['id'], 'goods'=>$v]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'goods_id'=>$v['id'], 'goods'=>$v]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -44,7 +44,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_search_goods_inside_price_top'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'goods_id'=>$v['id'], 'goods'=>$v]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'goods_id'=>$v['id'], 'goods'=>$v]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) @@ -69,7 +69,7 @@ {{/if}} {{php}} $hook_name = 'plugins_view_search_goods_inside_bottom'; - $hook_data = Hook::listen($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'goods_id'=>$v['id'], 'goods'=>$v]); + $hook_data = MyEventTrigger($hook_name, ['hook_name'=>$hook_name, 'is_backend'=>false, 'goods_id'=>$v['id'], 'goods'=>$v]); if(!empty($hook_data) && is_array($hook_data)) { foreach($hook_data as $hook) diff --git a/application/index/view/default/search/index.html b/app/index/view/default/search/index.html similarity index 100% rename from application/index/view/default/search/index.html rename to app/index/view/default/search/index.html diff --git a/application/index/view/default/user/forget_pwd_info.html b/app/index/view/default/user/forget_pwd_info.html similarity index 100% rename from application/index/view/default/user/forget_pwd_info.html rename to app/index/view/default/user/forget_pwd_info.html diff --git a/application/index/view/default/user/images_verify.html b/app/index/view/default/user/images_verify.html similarity index 83% rename from application/index/view/default/user/images_verify.html rename to app/index/view/default/user/images_verify.html index 4c30b142e..0d2cd810e 100644 --- a/application/index/view/default/user/images_verify.html +++ b/app/index/view/default/user/images_verify.html @@ -7,8 +7,8 @@ diff --git a/application/index/view/default/user/index.html b/app/index/view/default/user/index.html similarity index 100% rename from application/index/view/default/user/index.html rename to app/index/view/default/user/index.html diff --git a/application/index/view/default/user/login_content.html b/app/index/view/default/user/login_content.html similarity index 97% rename from application/index/view/default/user/login_content.html rename to app/index/view/default/user/login_content.html index 561a01390..8fba24fa8 100644 --- a/application/index/view/default/user/login_content.html +++ b/app/index/view/default/user/login_content.html @@ -39,8 +39,8 @@ - - 更换一张 + + 更换一张
diff --git a/application/index/view/default/user/login_info.html b/app/index/view/default/user/login_info.html similarity index 100% rename from application/index/view/default/user/login_info.html rename to app/index/view/default/user/login_info.html diff --git a/application/index/view/default/user/logout.html b/app/index/view/default/user/logout.html similarity index 100% rename from application/index/view/default/user/logout.html rename to app/index/view/default/user/logout.html diff --git a/application/index/view/default/user/modal_login_info.html b/app/index/view/default/user/modal_login_info.html similarity index 100% rename from application/index/view/default/user/modal_login_info.html rename to app/index/view/default/user/modal_login_info.html diff --git a/application/index/view/default/user/reg_info.html b/app/index/view/default/user/reg_info.html similarity index 99% rename from application/index/view/default/user/reg_info.html rename to app/index/view/default/user/reg_info.html index e7762ab9b..dba55a1c5 100755 --- a/application/index/view/default/user/reg_info.html +++ b/app/index/view/default/user/reg_info.html @@ -92,8 +92,8 @@ - - 更换一张 + + 更换一张
diff --git a/application/index/view/default/useraddress/index.html b/app/index/view/default/useraddress/index.html similarity index 100% rename from application/index/view/default/useraddress/index.html rename to app/index/view/default/useraddress/index.html diff --git a/application/index/view/default/useraddress/save_info.html b/app/index/view/default/useraddress/save_info.html similarity index 100% rename from application/index/view/default/useraddress/save_info.html rename to app/index/view/default/useraddress/save_info.html diff --git a/application/index/view/default/usergoodsbrowse/detail.html b/app/index/view/default/usergoodsbrowse/detail.html similarity index 100% rename from application/index/view/default/usergoodsbrowse/detail.html rename to app/index/view/default/usergoodsbrowse/detail.html diff --git a/application/index/view/default/usergoodsbrowse/index.html b/app/index/view/default/usergoodsbrowse/index.html similarity index 100% rename from application/index/view/default/usergoodsbrowse/index.html rename to app/index/view/default/usergoodsbrowse/index.html diff --git a/application/index/view/default/usergoodsbrowse/module/goods.html b/app/index/view/default/usergoodsbrowse/module/goods.html similarity index 100% rename from application/index/view/default/usergoodsbrowse/module/goods.html rename to app/index/view/default/usergoodsbrowse/module/goods.html diff --git a/application/index/view/default/usergoodsbrowse/module/operate.html b/app/index/view/default/usergoodsbrowse/module/operate.html similarity index 100% rename from application/index/view/default/usergoodsbrowse/module/operate.html rename to app/index/view/default/usergoodsbrowse/module/operate.html diff --git a/application/index/view/default/usergoodsfavor/detail.html b/app/index/view/default/usergoodsfavor/detail.html similarity index 100% rename from application/index/view/default/usergoodsfavor/detail.html rename to app/index/view/default/usergoodsfavor/detail.html diff --git a/application/index/view/default/usergoodsfavor/index.html b/app/index/view/default/usergoodsfavor/index.html similarity index 100% rename from application/index/view/default/usergoodsfavor/index.html rename to app/index/view/default/usergoodsfavor/index.html diff --git a/application/index/view/default/usergoodsfavor/module/goods.html b/app/index/view/default/usergoodsfavor/module/goods.html similarity index 100% rename from application/index/view/default/usergoodsfavor/module/goods.html rename to app/index/view/default/usergoodsfavor/module/goods.html diff --git a/application/index/view/default/usergoodsfavor/module/operate.html b/app/index/view/default/usergoodsfavor/module/operate.html similarity index 100% rename from application/index/view/default/usergoodsfavor/module/operate.html rename to app/index/view/default/usergoodsfavor/module/operate.html diff --git a/application/index/view/default/userintegral/detail.html b/app/index/view/default/userintegral/detail.html similarity index 100% rename from application/index/view/default/userintegral/detail.html rename to app/index/view/default/userintegral/detail.html diff --git a/application/index/view/default/userintegral/index.html b/app/index/view/default/userintegral/index.html similarity index 100% rename from application/index/view/default/userintegral/index.html rename to app/index/view/default/userintegral/index.html diff --git a/application/index/view/default/userintegral/module/operate.html b/app/index/view/default/userintegral/module/operate.html similarity index 100% rename from application/index/view/default/userintegral/module/operate.html rename to app/index/view/default/userintegral/module/operate.html diff --git a/application/index/view/index.html b/app/index/view/index.html similarity index 100% rename from application/index/view/index.html rename to app/index/view/index.html diff --git a/application/admin/config/template.php b/app/install/config/view.php similarity index 73% rename from application/admin/config/template.php rename to app/install/config/view.php index fcd9519e6..d060727fa 100755 --- a/application/admin/config/template.php +++ b/app/install/config/view.php @@ -12,25 +12,24 @@ // +---------------------------------------------------------------------- // | 模板设置 // +---------------------------------------------------------------------- - return [ - // 模板引擎类型 支持 php think 支持扩展 - 'type' => 'Think', + // 模板引擎类型使用Think + 'type' => 'Think', // 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写 3 保持操作方法 - 'auto_rule' => 1, - // 模板路径 - 'view_path' => APP_PATH.'admin'.DS.'view'.DS.'default'.DS, + 'auto_rule' => 1, + // 模板目录名 + 'view_dir_name' => 'view', // 模板后缀 - 'view_suffix' => 'html', + 'view_suffix' => 'html', // 模板文件名分隔符 - 'view_depr' => DIRECTORY_SEPARATOR, + 'view_depr' => DIRECTORY_SEPARATOR, // 模板引擎普通标签开始标记 - 'tpl_begin' => '{{', + 'tpl_begin' => '{{', // 模板引擎普通标签结束标记 - 'tpl_end' => '}}', + 'tpl_end' => '}}', // 标签库标签开始标记 - 'taglib_begin' => '{{', + 'taglib_begin' => '{{', // 标签库标签结束标记 - 'taglib_end' => '}}', + 'taglib_end' => '}}', ]; ?> \ No newline at end of file diff --git a/application/install/controller/Common.php b/app/install/controller/Common.php similarity index 63% rename from application/install/controller/Common.php rename to app/install/controller/Common.php index 8f4c03cc9..f9bf5d3db 100755 --- a/application/install/controller/Common.php +++ b/app/install/controller/Common.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\install\controller; -use think\Controller; +use app\BaseController; /** * 安装程序-公共 @@ -20,7 +20,7 @@ use think\Controller; * @date 2018-11-30 * @desc description */ -class Common extends Controller +class Common extends BaseController { /** * 构造方法 @@ -32,27 +32,29 @@ class Common extends Controller */ public function __construct() { - parent::__construct(); - - // url模式 - \think\facade\Url::root(__MY_ROOT_PUBLIC__.'index.php?s='); - // 当前方法 - $this->assign('action', strtolower(request()->action())); + MyViewAssign('action', RequestAction()); } /** - * [_empty 空方法操作] + * 空方法响应 * @author Devil - * @blog http://gong.gg/ - * @version 0.0.1 - * @datetime 2017-02-25T15:47:50+0800 - * @param [string] $name [方法名称] + * @blog http://gong.gg/ + * @version 1.0.0 + * @date 2018-11-30 + * @desc description + * @param [string] $method [方法名称] + * @param [array] $args [参数] */ - public function _empty($name) + public function __call($method, $args) { - $this->assign('msg', $name.' 非法访问'); - return $this->fetch('public/tips_error'); + if(IS_AJAX) + { + return DataReturn($method.' 非法访问', -1000); + } else { + MyViewAssign('msg', $method.' 非法访问'); + return MyView('public/error'); + } } } ?> \ No newline at end of file diff --git a/application/install/controller/Error.php b/app/install/controller/Error.php similarity index 71% rename from application/install/controller/Error.php rename to app/install/controller/Error.php index 0bb5d9733..f0620688d 100755 --- a/application/install/controller/Error.php +++ b/app/install/controller/Error.php @@ -10,8 +10,6 @@ // +---------------------------------------------------------------------- namespace app\install\controller; -use think\Request; - /** * 空控制器响应 * @author Devil @@ -29,12 +27,18 @@ class Error extends Common * @version 1.0.0 * @date 2018-11-30 * @desc description - * @param Request $request [参数] + * @param [string] $method [方法名称] + * @param [array] $args [参数] */ - public function Index(Request $request) + public function __call($method, $args) { - $this->assign('msg', $request->controller().' 控制器不存在'); - return $this->fetch('public/tips_error'); + if(IS_AJAX) + { + return DataReturn(RequestController().' 控制器不存在', -1000); + } else { + MyViewAssign('msg', RequestController().' 控制器不存在'); + return MyView('public/error'); + } } } ?> \ No newline at end of file diff --git a/application/install/controller/Index.php b/app/install/controller/Index.php similarity index 87% rename from application/install/controller/Index.php rename to app/install/controller/Index.php index aee4950bf..0738eaf3b 100755 --- a/application/install/controller/Index.php +++ b/app/install/controller/Index.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\install\controller; -use think\Db; +use think\facade\Db; /** * 安装程序 @@ -87,7 +87,7 @@ class Index extends Common { $this->IsInstall(); $this->behavior_obj->ReportInstallLog(['msg'=>'协议阅读']); - return $this->fetch(); + return MyView(); } /** @@ -102,7 +102,7 @@ class Index extends Common { $this->IsInstall(); $this->behavior_obj->ReportInstallLog(['msg'=>'环境检测']); - return $this->fetch(); + return MyView(); } /** @@ -118,8 +118,8 @@ class Index extends Common $this->IsInstall(); $this->behavior_obj->ReportInstallLog(['msg'=>'数据信息填写']); - $this->assign('charset_type_list' , $this->charset_type_list); - return $this->fetch(); + MyViewAssign('charset_type_list' , $this->charset_type_list); + return MyView(); } /** @@ -141,7 +141,7 @@ class Index extends Common exit(header('location:'.$url)); } } - return $this->fetch(); + return MyView(); } /** @@ -249,59 +249,63 @@ class Index extends Common // | 数据库配置 // +---------------------------------------------------------------------- return [ - // 数据库类型 - 'type' => '{$params['DB_TYPE']}', - // 服务器地址 - 'hostname' => '{$params['DB_HOST']}', - // 数据库名 - 'database' => '{$params['DB_NAME']}', - // 用户名 - 'username' => '{$params['DB_USER']}', - // 密码 - 'password' => '{$params['DB_PWD']}', - // 端口 - 'hostport' => '{$params['DB_PORT']}', - // 连接dsn - 'dsn' => '', - // 数据库连接参数 - 'params' => [ - \PDO::ATTR_CASE => \PDO::CASE_LOWER, - \PDO::ATTR_EMULATE_PREPARES => true, - ], - // 数据库编码默认采用utf8mb4 - 'charset' => '{$params['DB_CHARSET']}', - // 数据库表前缀 - 'prefix' => '{$params['DB_PREFIX']}', - // 数据库调试模式 - 'debug' => true, - // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) - 'deploy' => 0, - // 数据库读写是否分离 主从式有效 - 'rw_separate' => false, - // 读写分离后 主服务器数量 - 'master_num' => 1, - // 指定从服务器序号 - 'slave_no' => '', - // 自动读取主库数据 - 'read_master' => false, - // 是否严格检查字段是否存在 - 'fields_strict' => true, - // 数据集返回类型 - 'resultset_type' => 'array', + // 默认使用的数据库连接配置 + 'default' => 'mysql', + + // 自定义时间查询规则 + 'time_query_rule' => [], + // 自动写入时间戳字段 - 'auto_timestamp' => false, + // true为自动识别类型 false关闭 + // 字符串则明确指定时间字段类型 支持 int timestamp datetime date + 'auto_timestamp' => true, + // 时间字段取出后的默认时间格式 'datetime_format' => 'Y-m-d H:i:s', - // 是否需要进行SQL性能分析 - 'sql_explain' => false, - // Builder类 - 'builder' => '', - // Query类 - 'query' => '\\think\\db\\Query', - // 是否需要断线重连 - 'break_reconnect' => false, - // 断线标识字符串 - 'break_match_str' => [], + + // 数据库连接配置信息 + 'connections' => [ + 'mysql' => [ + // 数据库类型 + 'type' => '{$params['DB_TYPE']}', + // 服务器地址 + 'hostname' => '{$params['DB_HOST']}', + // 数据库名 + 'database' => '{$params['DB_NAME']}', + // 用户名 + 'username' => '{$params['DB_USER']}', + // 密码 + 'password' => '{$params['DB_PWD']}', + // 端口 + 'hostport' => '{$params['DB_PORT']}', + // 数据库连接参数 + 'params' => [ + \PDO::ATTR_CASE => \PDO::CASE_LOWER, + \PDO::ATTR_EMULATE_PREPARES => true, + ], + // 数据库编码默认采用utf8 + 'charset' => '{$params['DB_CHARSET']}', + // 数据库表前缀 + 'prefix' => '{$params['DB_PREFIX']}', + + // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) + 'deploy' => 0, + // 数据库读写是否分离 主从式有效 + 'rw_separate' => false, + // 读写分离后 主服务器数量 + 'master_num' => 1, + // 指定从服务器序号 + 'slave_no' => '', + // 是否严格检查字段是否存在 + 'fields_strict' => true, + // 是否需要断线重连 + 'break_reconnect' => false, + // 监听SQL + 'trigger_sql' => true, + // 开启字段缓存 + 'fields_cache' => false, + ] + ] ]; ?> php; diff --git a/application/install/view/index/check.html b/app/install/view/index/check.html similarity index 91% rename from application/install/view/index/check.html rename to app/install/view/index/check.html index f976bb48f..5573e0ac2 100755 --- a/application/install/view/index/check.html +++ b/app/install/view/index/check.html @@ -23,10 +23,10 @@ PHP版本 - >=5.6 + >=7.1 - =7) || ($php_version['0']>=5 && $php_version['1']>=6)): ?> + =7) || ($php_version['0']>=7 && $php_version['1']>=1)): ?> √ × @@ -82,6 +82,60 @@ + + ./app/index/route + 可写 + + + 可写 + + 不可写 + + + + + √ + + × + + + + + ./app/index/view + 可写 + + + 可写 + + 不可写 + + + + + √ + + × + + + + + ./app/plugins + 可写 + + + 可写 + + 不可写 + + + + + √ + + × + + + ./config 可写 @@ -100,24 +154,6 @@ - - ./route - 可写 - - - 可写 - - 不可写 - - - - - √ - - × - - - ./runtime 可写 @@ -244,60 +280,6 @@ - - ./application/index/view - 可写 - - - 可写 - - 不可写 - - - - - √ - - × - - - - - ./application/tags.php - 可写 - - - 可写 - - 不可写 - - - - - √ - - × - - - - - ./application/plugins - 可写 - - - 可写 - - 不可写 - - - - - √ - - × - - - ./public/static/plugins/css 可写 @@ -581,8 +563,8 @@
- 上一步 - + 上一步 +
diff --git a/application/install/view/index/create.html b/app/install/view/index/create.html similarity index 95% rename from application/install/view/index/create.html rename to app/install/view/index/create.html index 7d6e9b3ed..52f67195f 100755 --- a/application/install/view/index/create.html +++ b/app/install/view/index/create.html @@ -80,8 +80,8 @@
- 上一步 - + 上一步 +
diff --git a/application/install/view/index/index.html b/app/install/view/index/index.html similarity index 94% rename from application/install/view/index/index.html rename to app/install/view/index/index.html index f67061140..ad37ba006 100755 --- a/application/install/view/index/index.html +++ b/app/install/view/index/index.html @@ -19,7 +19,7 @@
- 同意 + 同意
diff --git a/application/install/view/index/successful.html b/app/install/view/index/successful.html similarity index 100% rename from application/install/view/index/successful.html rename to app/install/view/index/successful.html diff --git a/app/install/view/public/error.html b/app/install/view/public/error.html new file mode 100755 index 000000000..58c2cf9a8 --- /dev/null +++ b/app/install/view/public/error.html @@ -0,0 +1,16 @@ +{{include file="public/header" /}} + + +{{include file="public/header_nav" /}} + + +
+
+

+

{{if isset($msg)}}{{$msg}}{{else /}}异常错误{{/if}}

+
+
+ + + +{{include file="public/footer" /}} \ No newline at end of file diff --git a/application/install/view/public/footer.html b/app/install/view/public/footer.html similarity index 100% rename from application/install/view/public/footer.html rename to app/install/view/public/footer.html diff --git a/application/install/view/public/footer_nav.html b/app/install/view/public/footer_nav.html similarity index 96% rename from application/install/view/public/footer_nav.html rename to app/install/view/public/footer_nav.html index efcebbb41..c348ec77e 100755 --- a/application/install/view/public/footer_nav.html +++ b/app/install/view/public/footer_nav.html @@ -17,6 +17,6 @@ \ No newline at end of file diff --git a/application/install/view/public/header.html b/app/install/view/public/header.html similarity index 100% rename from application/install/view/public/header.html rename to app/install/view/public/header.html diff --git a/application/install/view/public/header_nav.html b/app/install/view/public/header_nav.html similarity index 100% rename from application/install/view/public/header_nav.html rename to app/install/view/public/header_nav.html diff --git a/application/install/view/public/index.html b/app/install/view/public/index.html similarity index 100% rename from application/install/view/public/index.html rename to app/install/view/public/index.html diff --git a/application/lang/zh-cn.php b/app/lang/zh-cn.php similarity index 99% rename from application/lang/zh-cn.php rename to app/lang/zh-cn.php index 5563b9cb9..d381c3252 100755 --- a/application/lang/zh-cn.php +++ b/app/lang/zh-cn.php @@ -37,6 +37,7 @@ return [ '2.0.2' => ['value' => '2.0.2', 'name' => 'v2.0.2'], '2.0.3' => ['value' => '2.0.3', 'name' => 'v2.0.3'], '2.1.0' => ['value' => '2.1.0', 'name' => 'v2.1.0'], + '2.2.0' => ['value' => '2.2.0', 'name' => 'v2.2.0'], ], // 用户注册类型列表 diff --git a/application/layout/service/BaseLayout.php b/app/layout/service/BaseLayout.php similarity index 99% rename from application/layout/service/BaseLayout.php rename to app/layout/service/BaseLayout.php index 72bb36ce3..c44b805a4 100644 --- a/application/layout/service/BaseLayout.php +++ b/app/layout/service/BaseLayout.php @@ -10,8 +10,7 @@ // +---------------------------------------------------------------------- namespace app\layout\service; -use think\Db; -use think\facade\Hook; +use think\facade\Db; use app\service\ResourcesService; use app\service\GoodsService; @@ -620,7 +619,7 @@ class BaseLayout // url值处理钩子 $hook_name = 'plugins_layout_service_url_value_handle'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'type' => $type, @@ -710,7 +709,7 @@ class BaseLayout // 商品搜索列表读取钩子 $hook_name = 'plugins_layout_service_search_goods_begin'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => $params, @@ -825,7 +824,7 @@ class BaseLayout // 商品数据列表读取钩子 $hook_name = 'plugins_layout_service_goods_data_begin'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => $params, @@ -854,7 +853,7 @@ class BaseLayout // 商品分类 case 'category' : - $ret = GoodsService::GoodsDataHandle(Db::name('Goods')->alias('g')->join(['__GOODS_CATEGORY_JOIN__'=>'gci'], 'g.id=gci.goods_id')->field($field)->where($where)->group('g.id')->order($order_by)->limit($m, $n)->select()); + $ret = GoodsService::GoodsDataHandle(Db::name('Goods')->alias('g')->join('goods_category_join gci', 'g.id=gci.goods_id')->field($field)->where($where)->group('g.id')->order($order_by)->limit($m, $n)->select()->toArray()); break; } if(!empty($ret) && isset($ret['code']) && $ret['code'] == 0 && !empty($ret['data'])) @@ -1065,7 +1064,7 @@ class BaseLayout // 页面列表钩子 $hook_name = 'plugins_layout_service_pages_list'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => $params, diff --git a/application/layout/view/base.html b/app/layout/view/base.html similarity index 100% rename from application/layout/view/base.html rename to app/layout/view/base.html diff --git a/application/layout/view/form_back.html b/app/layout/view/form_back.html similarity index 100% rename from application/layout/view/form_back.html rename to app/layout/view/form_back.html diff --git a/application/layout/view/public/common/goods_category_choice.html b/app/layout/view/public/common/goods_category_choice.html similarity index 100% rename from application/layout/view/public/common/goods_category_choice.html rename to app/layout/view/public/common/goods_category_choice.html diff --git a/application/layout/view/public/common/goodssearch.html b/app/layout/view/public/common/goodssearch.html similarity index 100% rename from application/layout/view/public/common/goodssearch.html rename to app/layout/view/public/common/goodssearch.html diff --git a/application/layout/view/public/common/module_admin.html b/app/layout/view/public/common/module_admin.html similarity index 100% rename from application/layout/view/public/common/module_admin.html rename to app/layout/view/public/common/module_admin.html diff --git a/application/layout/view/public/common/module_view.html b/app/layout/view/public/common/module_view.html similarity index 100% rename from application/layout/view/public/common/module_view.html rename to app/layout/view/public/common/module_view.html diff --git a/application/layout/view/public/content/goods_show_style.html b/app/layout/view/public/content/goods_show_style.html similarity index 100% rename from application/layout/view/public/content/goods_show_style.html rename to app/layout/view/public/content/goods_show_style.html diff --git a/application/layout/view/public/content/many_images_show_style.html b/app/layout/view/public/content/many_images_show_style.html similarity index 100% rename from application/layout/view/public/content/many_images_show_style.html rename to app/layout/view/public/content/many_images_show_style.html diff --git a/application/layout/view/public/content/media_fixed.html b/app/layout/view/public/content/media_fixed.html similarity index 100% rename from application/layout/view/public/content/media_fixed.html rename to app/layout/view/public/content/media_fixed.html diff --git a/application/layout/view/public/content/view_list_number.html b/app/layout/view/public/content/view_list_number.html similarity index 100% rename from application/layout/view/public/content/view_list_number.html rename to app/layout/view/public/content/view_list_number.html diff --git a/application/layout/view/public/modal/modal_module_list_config.html b/app/layout/view/public/modal/modal_module_list_config.html similarity index 100% rename from application/layout/view/public/modal/modal_module_list_config.html rename to app/layout/view/public/modal/modal_module_list_config.html diff --git a/application/layout/view/public/modal/modal_module_pages_select.html b/app/layout/view/public/modal/modal_module_pages_select.html similarity index 100% rename from application/layout/view/public/modal/modal_module_pages_select.html rename to app/layout/view/public/modal/modal_module_pages_select.html diff --git a/application/layout/view/public/modal/modal_module_rolling_config.html b/app/layout/view/public/modal/modal_module_rolling_config.html similarity index 100% rename from application/layout/view/public/modal/modal_module_rolling_config.html rename to app/layout/view/public/modal/modal_module_rolling_config.html diff --git a/application/layout/view/public/modal/modal_module_title_keywords.html b/app/layout/view/public/modal/modal_module_title_keywords.html similarity index 100% rename from application/layout/view/public/modal/modal_module_title_keywords.html rename to app/layout/view/public/modal/modal_module_title_keywords.html diff --git a/application/layout/view/public/offcanvas/offcanvas_layout_config.html b/app/layout/view/public/offcanvas/offcanvas_layout_config.html similarity index 100% rename from application/layout/view/public/offcanvas/offcanvas_layout_config.html rename to app/layout/view/public/offcanvas/offcanvas_layout_config.html diff --git a/application/layout/view/public/offcanvas/offcanvas_module_config_border.html b/app/layout/view/public/offcanvas/offcanvas_module_config_border.html similarity index 100% rename from application/layout/view/public/offcanvas/offcanvas_module_config_border.html rename to app/layout/view/public/offcanvas/offcanvas_module_config_border.html diff --git a/application/layout/view/public/offcanvas/offcanvas_module_config_goods.html b/app/layout/view/public/offcanvas/offcanvas_module_config_goods.html similarity index 100% rename from application/layout/view/public/offcanvas/offcanvas_module_config_goods.html rename to app/layout/view/public/offcanvas/offcanvas_module_config_goods.html diff --git a/application/layout/view/public/offcanvas/offcanvas_module_config_height.html b/app/layout/view/public/offcanvas/offcanvas_module_config_height.html similarity index 100% rename from application/layout/view/public/offcanvas/offcanvas_module_config_height.html rename to app/layout/view/public/offcanvas/offcanvas_module_config_height.html diff --git a/application/layout/view/public/offcanvas/offcanvas_module_config_images.html b/app/layout/view/public/offcanvas/offcanvas_module_config_images.html similarity index 100% rename from application/layout/view/public/offcanvas/offcanvas_module_config_images.html rename to app/layout/view/public/offcanvas/offcanvas_module_config_images.html diff --git a/application/layout/view/public/offcanvas/offcanvas_module_config_many_images.html b/app/layout/view/public/offcanvas/offcanvas_module_config_many_images.html similarity index 100% rename from application/layout/view/public/offcanvas/offcanvas_module_config_many_images.html rename to app/layout/view/public/offcanvas/offcanvas_module_config_many_images.html diff --git a/application/layout/view/public/offcanvas/offcanvas_module_config_title.html b/app/layout/view/public/offcanvas/offcanvas_module_config_title.html similarity index 100% rename from application/layout/view/public/offcanvas/offcanvas_module_config_title.html rename to app/layout/view/public/offcanvas/offcanvas_module_config_title.html diff --git a/application/layout/view/public/offcanvas/offcanvas_module_config_video.html b/app/layout/view/public/offcanvas/offcanvas_module_config_video.html similarity index 100% rename from application/layout/view/public/offcanvas/offcanvas_module_config_video.html rename to app/layout/view/public/offcanvas/offcanvas_module_config_video.html diff --git a/application/layout/view/public/popup/popup_module_goods_category.html b/app/layout/view/public/popup/popup_module_goods_category.html similarity index 100% rename from application/layout/view/public/popup/popup_module_goods_category.html rename to app/layout/view/public/popup/popup_module_goods_category.html diff --git a/application/layout/view/public/popup/popup_module_goods_search.html b/app/layout/view/public/popup/popup_module_goods_search.html similarity index 100% rename from application/layout/view/public/popup/popup_module_goods_search.html rename to app/layout/view/public/popup/popup_module_goods_search.html diff --git a/application/layout/view/public/popup/popup_module_goods_select.html b/app/layout/view/public/popup/popup_module_goods_select.html similarity index 100% rename from application/layout/view/public/popup/popup_module_goods_select.html rename to app/layout/view/public/popup/popup_module_goods_select.html diff --git a/application/layout/view/public/style/background_color.html b/app/layout/view/public/style/background_color.html similarity index 100% rename from application/layout/view/public/style/background_color.html rename to app/layout/view/public/style/background_color.html diff --git a/application/layout/view/public/style/border_radius.html b/app/layout/view/public/style/border_radius.html similarity index 100% rename from application/layout/view/public/style/border_radius.html rename to app/layout/view/public/style/border_radius.html diff --git a/application/layout/view/public/style/border_style.html b/app/layout/view/public/style/border_style.html similarity index 100% rename from application/layout/view/public/style/border_style.html rename to app/layout/view/public/style/border_style.html diff --git a/application/layout/view/public/style/border_style_4.html b/app/layout/view/public/style/border_style_4.html similarity index 100% rename from application/layout/view/public/style/border_style_4.html rename to app/layout/view/public/style/border_style_4.html diff --git a/application/layout/view/public/style/border_width_4.html b/app/layout/view/public/style/border_width_4.html similarity index 100% rename from application/layout/view/public/style/border_width_4.html rename to app/layout/view/public/style/border_width_4.html diff --git a/application/layout/view/public/style/border_width_color.html b/app/layout/view/public/style/border_width_color.html similarity index 100% rename from application/layout/view/public/style/border_width_color.html rename to app/layout/view/public/style/border_width_color.html diff --git a/application/layout/view/public/style/border_width_color_4.html b/app/layout/view/public/style/border_width_color_4.html similarity index 100% rename from application/layout/view/public/style/border_width_color_4.html rename to app/layout/view/public/style/border_width_color_4.html diff --git a/application/layout/view/public/style/color.html b/app/layout/view/public/style/color.html similarity index 100% rename from application/layout/view/public/style/color.html rename to app/layout/view/public/style/color.html diff --git a/application/layout/view/public/style/height.html b/app/layout/view/public/style/height.html similarity index 100% rename from application/layout/view/public/style/height.html rename to app/layout/view/public/style/height.html diff --git a/application/layout/view/public/style/input_color.html b/app/layout/view/public/style/input_color.html similarity index 100% rename from application/layout/view/public/style/input_color.html rename to app/layout/view/public/style/input_color.html diff --git a/application/layout/view/public/style/margin.html b/app/layout/view/public/style/margin.html similarity index 100% rename from application/layout/view/public/style/margin.html rename to app/layout/view/public/style/margin.html diff --git a/application/layout/view/public/style/margin_4.html b/app/layout/view/public/style/margin_4.html similarity index 100% rename from application/layout/view/public/style/margin_4.html rename to app/layout/view/public/style/margin_4.html diff --git a/application/layout/view/public/style/padding.html b/app/layout/view/public/style/padding.html similarity index 100% rename from application/layout/view/public/style/padding.html rename to app/layout/view/public/style/padding.html diff --git a/application/layout/view/public/style/padding_4.html b/app/layout/view/public/style/padding_4.html similarity index 100% rename from application/layout/view/public/style/padding_4.html rename to app/layout/view/public/style/padding_4.html diff --git a/application/layout/view/public/style/width.html b/app/layout/view/public/style/width.html similarity index 100% rename from application/layout/view/public/style/width.html rename to app/layout/view/public/style/width.html diff --git a/application/layout/view/view.html b/app/layout/view/view.html similarity index 100% rename from application/layout/view/view.html rename to app/layout/view/view.html diff --git a/app/middleware.php b/app/middleware.php new file mode 100644 index 000000000..d66d7bf20 --- /dev/null +++ b/app/middleware.php @@ -0,0 +1,21 @@ + \ No newline at end of file diff --git a/application/module/FormHandleModule.php b/app/module/FormHandleModule.php similarity index 99% rename from application/module/FormHandleModule.php rename to app/module/FormHandleModule.php index 847ef1217..92e128d20 100644 --- a/application/module/FormHandleModule.php +++ b/app/module/FormHandleModule.php @@ -10,7 +10,6 @@ // +---------------------------------------------------------------------- namespace app\module; -use think\facade\Hook; use app\service\FormTableService; /** @@ -62,11 +61,11 @@ class FormHandleModule // 钩子 $hv = explode('\\', $module); - if(isset($hv[2]) && isset($hv[4]) && in_array($hv[2], config('shopxo.module_form_hook_group'))) + if(isset($hv[2]) && isset($hv[4]) && in_array($hv[2], MyConfig('shopxo.module_form_hook_group'))) { // 动态钩子名称 plugins_module_form_group_controller_action $hook_name = 'plugins_module_form_'.strtolower($hv[2]).'_'.strtolower($hv[4]).'_'.strtolower($action); - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => $this->out_params, diff --git a/application/module/ViewIncludeModule.php b/app/module/ViewIncludeModule.php similarity index 71% rename from application/module/ViewIncludeModule.php rename to app/module/ViewIncludeModule.php index 1e60751dc..97090a8e6 100644 --- a/application/module/ViewIncludeModule.php +++ b/app/module/ViewIncludeModule.php @@ -10,8 +10,6 @@ // +---------------------------------------------------------------------- namespace app\module; -use think\Controller; - /** * 视图模块引入 * @author Devil @@ -20,22 +18,8 @@ use think\Controller; * @date 2020-05-25 * @desc description */ -class ViewIncludeModule extends Controller +class ViewIncludeModule { - /** - * 构造方法 - * @author Devil - * @blog http://gong.gg/ - * @version 1.0.0 - * @date 2020-05-25 - * @desc description - */ - public function __construct() - { - // 调用父类前置方法 - parent::__construct(); - } - /** * 运行入口 * @author Devil @@ -50,9 +34,9 @@ class ViewIncludeModule extends Controller */ public function Run($template, $data = [], $params = []) { - $this->assign('module_data', $data); - $this->assign('module_params', $params); - return $this->fetch($template); + MyViewAssign('module_data', $data); + MyViewAssign('module_params', $params); + return MyView($template); } } ?> \ No newline at end of file diff --git a/application/plugins/.gitignore b/app/plugins/.gitignore similarity index 100% rename from application/plugins/.gitignore rename to app/plugins/.gitignore diff --git a/application/plugins/index.html b/app/plugins/index.html similarity index 100% rename from application/plugins/index.html rename to app/plugins/index.html diff --git a/application/plugins/view/.gitignore b/app/plugins/view/.gitignore similarity index 100% rename from application/plugins/view/.gitignore rename to app/plugins/view/.gitignore diff --git a/application/plugins/view/index.html b/app/plugins/view/index.html similarity index 100% rename from application/plugins/view/index.html rename to app/plugins/view/index.html diff --git a/application/provider.php b/app/provider.php old mode 100755 new mode 100644 similarity index 76% rename from application/provider.php rename to app/provider.php index 4a1d6569a..8ca8a5396 --- a/application/provider.php +++ b/app/provider.php @@ -8,7 +8,11 @@ // +---------------------------------------------------------------------- // | Author: Devil // +---------------------------------------------------------------------- +use app\ExceptionHandle; +use app\Request; -// 应用容器绑定定义 -return []; -?> \ No newline at end of file +// 容器Provider定义文件 +return [ + 'think\Request' => Request::class, + 'think\exception\Handle' => ExceptionHandle::class, +]; diff --git a/app/service.php b/app/service.php new file mode 100644 index 000000000..eb56e202c --- /dev/null +++ b/app/service.php @@ -0,0 +1,17 @@ +field($field)->where($where)->order($order_by)->select(); + $data = Db::name('Power')->field($field)->where($where)->order($order_by)->select()->toArray(); if(!empty($data)) { foreach($data as &$v) { - $v['item'] = Db::name('Power')->field($field)->where(['pid'=>$v['id']])->order($order_by)->select(); + $v['item'] = Db::name('Power')->field($field)->where(['pid'=>$v['id']])->order($order_by)->select()->toArray(); } } return $data; @@ -189,8 +188,8 @@ class AdminPowerService { foreach($admin as $id) { - cache(config('cache_admin_power_key').$id, null); - cache(config('cache_admin_left_menu_key').$id, null); + MyCache(MyConfig('shopxo.cache_admin_power_key').$id, null); + MyCache(MyConfig('shopxo.cache_admin_left_menu_key').$id, null); } } } @@ -211,20 +210,20 @@ class AdminPowerService $role_id = isset($admin['role_id']) ? intval($admin['role_id']) : 0; // 读取缓存数据 - $admin_left_menu = cache(config('cache_admin_left_menu_key').$admin_id); - $admin_power = cache(config('cache_admin_power_key').$admin_id); + $admin_left_menu = MyCache(MyConfig('shopxo.cache_admin_left_menu_key').$admin_id); + $admin_power = MyCache(MyConfig('shopxo.cache_admin_power_key').$admin_id); // 缓存没数据则从数据库重新读取 - if((($role_id > 0 || $admin_id == 1) && empty($admin_left_menu)) || config('app_debug')) + if((($role_id > 0 || $admin_id == 1) && empty($admin_left_menu)) || MyEnv('app_debug')) { // 获取一级数据 if($admin_id == 1 || $role_id == 1) { $field = 'id,name,control,action,url,is_show,icon'; - $admin_left_menu = Db::name('Power')->where(array('pid' => 0))->field($field)->order('sort')->select(); + $admin_left_menu = Db::name('Power')->where(array('pid' => 0))->field($field)->order('sort')->select()->toArray(); } else { $field = 'p.id,p.name,p.control,p.action,p.url,p.is_show,p.icon'; - $admin_left_menu = Db::name('Power')->alias('p')->join(['__ROLE_POWER__'=>'rp'], 'p.id=rp.power_id')->where(array('rp.role_id' => $role_id, 'p.pid' => 0))->field($field)->order('p.sort')->select(); + $admin_left_menu = Db::name('Power')->alias('p')->join('role_power rp', 'p.id=rp.power_id')->where(array('rp.role_id' => $role_id, 'p.pid' => 0))->field($field)->order('p.sort')->select()->toArray(); } // 有数据,则处理子级数据 @@ -248,9 +247,9 @@ class AdminPowerService // 获取子权限 if(($admin_id == 1 || $role_id == 1) && !empty($v['id'])) { - $items = Db::name('Power')->where(['pid'=>intval($v['id'])])->field($field)->order('sort')->select(); + $items = Db::name('Power')->where(['pid'=>intval($v['id'])])->field($field)->order('sort')->select()->toArray(); } else { - $items = Db::name('Power')->alias('p')->join(['__ROLE_POWER__'=>'rp'], 'p.id=rp.power_id')->where(['rp.role_id'=>$role_id, 'p.pid'=>intval($v['id'])])->field($field)->order('p.sort')->select(); + $items = Db::name('Power')->alias('p')->join('role_power rp', 'p.id=rp.power_id')->where(['rp.role_id'=>$role_id, 'p.pid'=>intval($v['id'])])->field($field)->order('p.sort')->select()->toArray(); } // 权限列表 @@ -296,8 +295,8 @@ class AdminPowerService } } } - cache(config('cache_admin_left_menu_key').$admin_id, $admin_left_menu); - cache(config('cache_admin_power_key').$admin_id, $admin_power); + MyCache(MyConfig('shopxo.cache_admin_left_menu_key').$admin_id, $admin_left_menu); + MyCache(MyConfig('shopxo.cache_admin_power_key').$admin_id, $admin_power); } return true; } @@ -315,12 +314,12 @@ class AdminPowerService $admin = AdminService::LoginInfo(); if(!empty($admin['id'])) { - $data = cache(config('cache_admin_left_menu_key').$admin['id']); + $data = MyCache(MyConfig('shopxo.cache_admin_left_menu_key').$admin['id']); } // 后台左侧菜单钩子 $hook_name = 'plugins_service_admin_menu_data'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'admin' => $admin, @@ -343,12 +342,12 @@ class AdminPowerService $admin = AdminService::LoginInfo(); if(!empty($admin['id'])) { - $data = cache(config('cache_admin_power_key').$admin['id']); + $data = MyCache(MyConfig('shopxo.cache_admin_power_key').$admin['id']); } // 后台左侧菜单权限钩子 $hook_name = 'plugins_service_admin_menu_power_data'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'admin' => $admin, diff --git a/application/service/AdminRoleService.php b/app/service/AdminRoleService.php similarity index 96% rename from application/service/AdminRoleService.php rename to app/service/AdminRoleService.php index c075937f8..6655ff26c 100644 --- a/application/service/AdminRoleService.php +++ b/app/service/AdminRoleService.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; +use think\facade\Db; use app\service\AdminPowerService; /** @@ -39,13 +39,13 @@ class AdminRoleService $n = isset($params['n']) ? intval($params['n']) : 10; // 获取角色列表 - $data = Db::name('Role')->field($field)->where($where)->order($order_by)->limit($m, $n)->select(); + $data = Db::name('Role')->field($field)->where($where)->order($order_by)->limit($m, $n)->select()->toArray(); if(!empty($data)) { // 获取对应权限数据 $powers = []; $ids = array_column($data, 'id'); - $powers_data = Db::name('Role')->alias('r')->join(['__ROLE_POWER__'=>'rp'], 'rp.role_id = r.id')->join(['__POWER__'=>'p'], 'rp.power_id = p.id')->where(['r.id'=>$ids])->field('rp.role_id, rp.power_id, p.name')->select(); + $powers_data = Db::name('Role')->alias('r')->join('role_power rp', 'rp.role_id = r.id')->join('power p', 'rp.power_id = p.id')->where(['r.id'=>$ids])->field('rp.role_id, rp.power_id, p.name')->select()->toArray(); if(!empty($powers_data)) { foreach($powers_data as $p) @@ -141,7 +141,7 @@ class AdminRoleService // 权限列表 $power_field = 'id,name,is_show'; - $power = Db::name('Power')->field($power_field)->where(['pid'=>0])->order('sort')->select(); + $power = Db::name('Power')->field($power_field)->where(['pid'=>0])->order('sort')->select()->toArray(); if(!empty($power)) { foreach($power as &$v) @@ -150,7 +150,7 @@ class AdminRoleService $v['is_power'] = in_array($v['id'], $action) ? 'ok' : 'no'; // 获取子权限 - $item = Db::name('Power')->field($power_field)->where(array('pid'=>$v['id']))->order('sort')->select(); + $item = Db::name('Power')->field($power_field)->where(array('pid'=>$v['id']))->order('sort')->select()->toArray(); if(!empty($item)) { foreach($item as $ks=>$vs) diff --git a/application/service/AdminService.php b/app/service/AdminService.php similarity index 98% rename from application/service/AdminService.php rename to app/service/AdminService.php index e664dba79..5dd84b890 100755 --- a/application/service/AdminService.php +++ b/app/service/AdminService.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; +use think\facade\Db; /** * 管理员服务层 @@ -41,7 +41,7 @@ class AdminService $n = isset($params['n']) ? intval($params['n']) : 10; // 获取管理员列表 - $data = Db::name('Admin')->where($where)->field($field)->order($order_by)->limit($m, $n)->select(); + $data = Db::name('Admin')->where($where)->field($field)->order($order_by)->limit($m, $n)->select()->toArray(); if(!empty($data)) { // 获取当前用户角色名称 @@ -95,7 +95,7 @@ class AdminService { $where = empty($params['where']) ? [] : $params['where']; $field = empty($params['field']) ? '*' : $params['field']; - $data = Db::name('Role')->field($field)->where($where)->select(); + $data = Db::name('Role')->field($field)->where($where)->select()->toArray(); return DataReturn('处理成功', 0, $data); } @@ -505,8 +505,8 @@ class AdminService if(Db::name('Admin')->where(['id'=>$admin['id']])->update($data)) { // 清空权限缓存数据 - cache(config('cache_admin_left_menu_key').$admin['id'], null); - cache(config('cache_admin_power_key').$admin['id'], null); + MyCache(MyConfig('shopxo.cache_admin_left_menu_key').$admin['id'], null); + MyCache(MyConfig('shopxo.cache_admin_power_key').$admin['id'], null); return DataReturn('登录成功'); } @@ -527,7 +527,7 @@ class AdminService */ public static function LoginInfo() { - return session(self::$admin_login_key); + return MySession(self::$admin_login_key); } /** @@ -542,7 +542,7 @@ class AdminService public static function LoginSession($admin) { unset($admin['login_pwd'], $admin['login_salt']); - return session(self::$admin_login_key, $admin); + return MySession(self::$admin_login_key, $admin); } /** @@ -555,7 +555,7 @@ class AdminService */ public static function LoginLogout() { - return session(self::$admin_login_key, null); + return MySession(self::$admin_login_key, null); } /** diff --git a/application/service/AnswerService.php b/app/service/AnswerService.php similarity index 99% rename from application/service/AnswerService.php rename to app/service/AnswerService.php index 517798fe4..4082eee1a 100755 --- a/application/service/AnswerService.php +++ b/app/service/AnswerService.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; +use think\facade\Db; use app\service\UserService; use app\service\AdminService; @@ -55,7 +55,7 @@ class AnswerService $n = isset($params['n']) ? intval($params['n']) : 10; // 获取数据列表 - $data = Db::name('Answer')->field($field)->where($where)->limit($m, $n)->order($order_by)->select(); + $data = Db::name('Answer')->field($field)->where($where)->limit($m, $n)->order($order_by)->select()->toArray(); if(!empty($data)) { foreach($data as &$v) @@ -441,7 +441,7 @@ class AnswerService { if(!empty($params['answer_id'])) { - return Db::name('Answer')->where(['id'=>intval($params['answer_id'])])->setInc('access_count'); + return Db::name('Answer')->where(['id'=>intval($params['answer_id'])])->inc('access_count'); } return false; } diff --git a/application/service/AppCenterNavService.php b/app/service/AppCenterNavService.php similarity index 97% rename from application/service/AppCenterNavService.php rename to app/service/AppCenterNavService.php index feaa13696..c6e58c32d 100755 --- a/application/service/AppCenterNavService.php +++ b/app/service/AppCenterNavService.php @@ -10,8 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; -use think\facade\Hook; +use think\facade\Db; use app\service\ResourcesService; /** @@ -40,7 +39,7 @@ class AppCenterNavService $n = isset($params['n']) ? intval($params['n']) : 10; // 获取品牌列表 - $data = Db::name('AppCenterNav')->where($where)->order($order_by)->limit($m, $n)->select(); + $data = Db::name('AppCenterNav')->where($where)->order($order_by)->limit($m, $n)->select()->toArray(); if(!empty($data)) { $common_platform_type = lang('common_platform_type'); @@ -279,14 +278,14 @@ class AppCenterNavService $platform = ApplicationClientType(); // 缓存 - $key = config('shopxo.cache_app_user_center_navigation_key').$platform; - $data = cache($key); + $key = MyConfig('shopxo.cache_app_user_center_navigation_key').$platform; + $data = MyCache($key); if(empty($data)) { $field = 'id,name,images_url,event_value,event_type,desc'; $order_by = 'sort asc,id asc'; - $data = Db::name('AppCenterNav')->field($field)->where(['platform'=>$platform, 'is_enable'=>1])->order($order_by)->select(); + $data = Db::name('AppCenterNav')->field($field)->where(['platform'=>$platform, 'is_enable'=>1])->order($order_by)->select()->toArray(); if(!empty($data)) { foreach($data as &$v) @@ -297,12 +296,12 @@ class AppCenterNavService } } // 存储缓存 - cache($key, $data, 60); + MyCache($key, $data, 60); } // 手机用户中心导航钩子 $hook_name = 'plugins_service_app_user_center_navigation_'.$platform; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'data' => &$data, diff --git a/application/service/AppHomeNavService.php b/app/service/AppHomeNavService.php similarity index 97% rename from application/service/AppHomeNavService.php rename to app/service/AppHomeNavService.php index c5ec301c2..c1f99c04e 100755 --- a/application/service/AppHomeNavService.php +++ b/app/service/AppHomeNavService.php @@ -10,8 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; -use think\facade\Hook; +use think\facade\Db; use app\service\ResourcesService; /** @@ -40,7 +39,7 @@ class AppHomeNavService $n = isset($params['n']) ? intval($params['n']) : 10; // 获取品牌列表 - $data = Db::name('AppHomeNav')->where($where)->order($order_by)->limit($m, $n)->select(); + $data = Db::name('AppHomeNav')->where($where)->order($order_by)->limit($m, $n)->select()->toArray(); if(!empty($data)) { $common_platform_type = lang('common_platform_type'); @@ -274,15 +273,15 @@ class AppHomeNavService $platform = ApplicationClientType(); // 缓存 - $key = config('shopxo.cache_app_home_navigation_key').$platform; - $data = cache($key); + $key = MyConfig('shopxo.cache_app_home_navigation_key').$platform; + $data = MyCache($key); if(empty($data)) { // 获取导航数据 $field = 'id,name,images_url,event_value,event_type,bg_color,is_need_login'; $order_by = 'sort asc,id asc'; - $data = Db::name('AppHomeNav')->field($field)->where(['platform'=>$platform, 'is_enable'=>1])->order($order_by)->select(); + $data = Db::name('AppHomeNav')->field($field)->where(['platform'=>$platform, 'is_enable'=>1])->order($order_by)->select()->toArray(); if(!empty($data)) { foreach($data as &$v) @@ -308,12 +307,12 @@ class AppHomeNavService } // 存储缓存 - cache($key, $data, 60); + MyCache($key, $data, 60); } // 手机首页导航钩子 $hook_name = 'plugins_service_app_home_navigation_'.$platform; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'data' => &$data, diff --git a/application/service/AppMiniService.php b/app/service/AppMiniService.php similarity index 98% rename from application/service/AppMiniService.php rename to app/service/AppMiniService.php index 778a4a9bd..7051ffa60 100755 --- a/application/service/AppMiniService.php +++ b/app/service/AppMiniService.php @@ -121,7 +121,7 @@ class AppMiniService } $config = $dir.$temp_file.DS.'config.json'; - if(!file_exists($config)) + if(is_file($dir.$temp_file) || !is_dir($dir.$temp_file) || !is_file($config) || !file_exists($config)) { continue; } @@ -326,7 +326,7 @@ class AppMiniService self::Init($params); // 是否开启开发者模式 - if(config('shopxo.is_develop') !== true) + if(MyConfig('shopxo.is_develop') !== true) { return DataReturn('请先开启开发者模式', -1); } @@ -468,7 +468,7 @@ class AppMiniService public static function Created($params = []) { // 是否https - if(config('shopxo.is_develop') !== true) + if(MyConfig('shopxo.is_develop') !== true) { if(__MY_HTTP__ != 'https') { @@ -531,7 +531,7 @@ class AppMiniService __MY_URL__, $title, $describe, - config('shopxo.currency_symbol'), + MyConfig('shopxo.currency_symbol'), ]; $status = file_put_contents($new_dir.DS.'app.js', str_replace($search, $replace, file_get_contents($new_dir.DS.'app.js'))); if($status === false) diff --git a/application/service/ArticleService.php b/app/service/ArticleService.php similarity index 97% rename from application/service/ArticleService.php rename to app/service/ArticleService.php index a125c2f91..fdf0a7677 100755 --- a/application/service/ArticleService.php +++ b/app/service/ArticleService.php @@ -10,8 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; -use think\facade\Hook; +use think\facade\Db; use app\service\ResourcesService; /** @@ -40,7 +39,7 @@ class ArticleService $m = isset($params['m']) ? intval($params['m']) : 0; $n = isset($params['n']) ? intval($params['n']) : 10; - $data = Db::name('Article')->field($field)->where($where)->order($order_by)->limit($m, $n)->select(); + $data = Db::name('Article')->field($field)->where($where)->order($order_by)->limit($m, $n)->select()->toArray(); if(!empty($data)) { $category_names = Db::name('ArticleCategory')->where(['id'=>array_column($data, 'article_category_id')])->column('name', 'id'); @@ -189,7 +188,7 @@ class ArticleService // 文章保存处理钩子 $hook_name = 'plugins_service_article_save_handle'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, @@ -230,12 +229,12 @@ class ArticleService */ public static function ArticleCategoryListContent($params = []) { - $data = Db::name('ArticleCategory')->field('id,name')->where(['is_enable'=>1])->order('id asc, sort asc')->select(); + $data = Db::name('ArticleCategory')->field('id,name')->where(['is_enable'=>1])->order('id asc, sort asc')->select()->toArray(); if(!empty($data)) { foreach($data as &$v) { - $items = Db::name('Article')->field('id,title,title_color')->where(['article_category_id'=>$v['id'], 'is_enable'=>1])->select(); + $items = Db::name('Article')->field('id,title,title_color')->where(['article_category_id'=>$v['id'], 'is_enable'=>1])->select()->toArray(); if(!empty($items)) { foreach($items as &$vs) @@ -263,7 +262,7 @@ class ArticleService { if(!empty($params['id'])) { - return Db::name('Article')->where(array('id'=>intval($params['id'])))->setInc('access_count'); + return Db::name('Article')->where(array('id'=>intval($params['id'])))->inc('access_count'); } return false; } @@ -282,7 +281,7 @@ class ArticleService $field = empty($params['field']) ? '*' : $params['field']; $order_by = empty($params['order_by']) ? 'sort asc' : trim($params['order_by']); - $data = Db::name('ArticleCategory')->where(['is_enable'=>1])->field($field)->order($order_by)->select(); + $data = Db::name('ArticleCategory')->where(['is_enable'=>1])->field($field)->order($order_by)->select()->toArray(); return DataReturn('处理成功', 0, $data); } @@ -376,7 +375,7 @@ class ArticleService // 获取数据 $field = '*'; - $data = Db::name('ArticleCategory')->field($field)->where(['pid'=>$id])->order('sort asc')->select(); + $data = Db::name('ArticleCategory')->field($field)->where(['pid'=>$id])->order('sort asc')->select()->toArray(); if(!empty($data)) { foreach($data as &$v) diff --git a/application/service/BannerService.php b/app/service/BannerService.php similarity index 93% rename from application/service/BannerService.php rename to app/service/BannerService.php index 736b8a2ff..fcbb12513 100755 --- a/application/service/BannerService.php +++ b/app/service/BannerService.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; +use think\facade\Db; use app\service\ResourcesService; /** @@ -37,14 +37,14 @@ class BannerService $platform = ApplicationClientType(); // 缓存 - $key = config('shopxo.cache_banner_list_key').$platform; - $data = cache($key); + $key = MyConfig('shopxo.cache_banner_list_key').$platform; + $data = MyCache($key); if(empty($data)) { // 获取banner数据 $field = 'name,images_url,event_value,event_type,bg_color'; $order_by = 'sort asc,id asc'; - $data = Db::name('Slide')->field($field)->where(['platform'=>$platform, 'is_enable'=>1])->order($order_by)->select(); + $data = Db::name('Slide')->field($field)->where(['platform'=>$platform, 'is_enable'=>1])->order($order_by)->select()->toArray(); if(!empty($data)) { foreach($data as &$v) @@ -69,7 +69,7 @@ class BannerService } // 存储缓存 - cache($key, $data, 60); + MyCache($key, $data, 60); } return $data; } diff --git a/application/service/BrandCategoryService.php b/app/service/BrandCategoryService.php similarity index 97% rename from application/service/BrandCategoryService.php rename to app/service/BrandCategoryService.php index e6d3b2aec..5152108e2 100644 --- a/application/service/BrandCategoryService.php +++ b/app/service/BrandCategoryService.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; +use think\facade\Db; /** * 品牌分类服务层 @@ -35,7 +35,7 @@ class BrandCategoryService $field = empty($params['field']) ? '*' : $params['field']; $order_by = empty($params['order_by']) ? 'sort asc' : trim($params['order_by']); - $data = Db::name('BrandCategory')->where(['is_enable'=>1])->field($field)->order($order_by)->select(); + $data = Db::name('BrandCategory')->where(['is_enable'=>1])->field($field)->order($order_by)->select()->toArray(); return DataReturn('处理成功', 0, $data); } @@ -52,7 +52,7 @@ class BrandCategoryService { // 获取数据 $field = '*'; - $data = Db::name('BrandCategory')->field($field)->order('sort asc')->select(); + $data = Db::name('BrandCategory')->field($field)->order('sort asc')->select()->toArray(); if(!empty($data)) { foreach($data as &$v) diff --git a/application/service/BrandService.php b/app/service/BrandService.php similarity index 98% rename from application/service/BrandService.php rename to app/service/BrandService.php index b2aba6e30..d69a44866 100755 --- a/application/service/BrandService.php +++ b/app/service/BrandService.php @@ -10,8 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; -use think\facade\Hook; +use think\facade\Db; use app\service\GoodsService; use app\service\ResourcesService; @@ -41,7 +40,7 @@ class BrandService $n = isset($params['n']) ? intval($params['n']) : 10; // 获取列表 - $data = self::DataHandle(Db::name('Brand')->where($where)->field($field)->order($order_by)->limit($m, $n)->select()); + $data = self::DataHandle(Db::name('Brand')->where($where)->field($field)->order($order_by)->limit($m, $n)->select()->toArray()); return DataReturn('处理成功', 0, $data); } @@ -67,7 +66,7 @@ class BrandService $category_group = []; if(in_array('id', $keys)) { - $category = Db::name('BrandCategoryJoin')->where(['brand_id'=>array_column($data, 'id')])->field('brand_id,brand_category_id')->select(); + $category = Db::name('BrandCategoryJoin')->where(['brand_id'=>array_column($data, 'id')])->field('brand_id,brand_category_id')->select()->toArray(); if(!empty($category)) { $ids = array_unique(array_column($category, 'brand_category_id')); @@ -156,7 +155,7 @@ class BrandService */ public static function CategoryBrand($params = []) { - return Db::name('Brand')->field('id,name')->where(['is_enable'=>1])->order('sort asc')->select(); + return Db::name('Brand')->field('id,name')->where(['is_enable'=>1])->order('sort asc')->select()->toArray(); } /** @@ -291,7 +290,7 @@ class BrandService // 品牌保存处理钩子 $hook_name = 'plugins_service_brand_save_handle'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, diff --git a/application/service/BuyService.php b/app/service/BuyService.php similarity index 98% rename from application/service/BuyService.php rename to app/service/BuyService.php index e29212546..bd9fdca8c 100755 --- a/application/service/BuyService.php +++ b/app/service/BuyService.php @@ -10,8 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; -use think\facade\Hook; +use think\facade\Db; use app\service\SystemBaseService; use app\service\GoodsService; use app\service\UserService; @@ -238,7 +237,7 @@ class BuyService $where['c.user_id'] = $params['user']['id']; $field = 'c.*, g.inventory_unit, g.is_shelves, g.is_delete_time, g.buy_min_number, g.buy_max_number, g.model, g.site_type'; - $data = Db::name('Cart')->alias('c')->leftJoin(['__GOODS__'=>'g'], 'g.id=c.goods_id')->where($where)->field($field)->order('c.id desc')->select(); + $data = Db::name('Cart')->alias('c')->leftJoin('goods g', 'g.id=c.goods_id')->where($where)->field($field)->order('c.id desc')->select()->toArray(); // 数据处理 if(!empty($data)) @@ -433,7 +432,7 @@ class BuyService $stock = intval($params['stock']); // 获取购物车数据 - $cart = Db::name('Cart')->where($where)->select(); + $cart = Db::name('Cart')->where($where)->select()->toArray(); if(empty($cart)) { return DataReturn('请先加入购物车', -1); @@ -609,7 +608,7 @@ class BuyService { if(!empty($spec)) { - $data = Db::name('GoodsSpecType')->where(['goods_id'=>$goods_id])->field('name,value')->select(); + $data = Db::name('GoodsSpecType')->where(['goods_id'=>$goods_id])->field('name,value')->select()->toArray(); if(!empty($data)) { $spec_images = []; @@ -824,7 +823,7 @@ class BuyService // 生成订单数据处理钩子 $hook_name = 'plugins_service_buy_handle'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => $params, @@ -1014,7 +1013,7 @@ class BuyService return DataReturn('支付方式有误', -1); } $payment_id = $payment[0]['id']; - $is_under_line = in_array($payment[0]['payment'], config('shopxo.under_line_list')) ? 1 : 0; + $is_under_line = in_array($payment[0]['payment'], MyConfig('shopxo.under_line_list')) ? 1 : 0; } // 清单商品 @@ -1094,7 +1093,7 @@ class BuyService // 订单添加前钩子 $hook_name = 'plugins_service_buy_order_insert_begin'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'data' => $v, @@ -1189,7 +1188,7 @@ class BuyService // 订单添加成功钩子 $hook_name = 'plugins_service_buy_order_insert_end'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'order_id' => $order_id, @@ -1215,7 +1214,7 @@ class BuyService // 订单添加成功钩子, 不校验返回值 $hook_name = 'plugins_service_buy_order_insert_success'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'order_ids' => $order_ids, @@ -1288,7 +1287,7 @@ class BuyService // 订单详情添加前钩子 $hook_name = 'plugins_service_buy_order_detail_insert_begin'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'user_id' => $user_id, @@ -1330,7 +1329,7 @@ class BuyService // 订单取货码添加前钩子 $hook_name = 'plugins_service_buy_order_extraction_code_insert_begin'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'user_id' => $user_id, @@ -1374,7 +1373,7 @@ class BuyService // 订单虚拟数据添加前钩子 $hook_name = 'plugins_service_buy_order_fictitious_insert_begin'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'user_id' => $user_id, @@ -1410,7 +1409,7 @@ class BuyService private static function OrderAddressInsert($order_id, $user_id, $address) { // 坐标处理 - if(in_array(APPLICATION_CLIENT_TYPE, config('shopxo.coordinate_transformation'))) + if(in_array(APPLICATION_CLIENT_TYPE, MyConfig('shopxo.coordinate_transformation'))) { // 坐标转换 火星(高德,谷歌,腾讯坐标) 转 百度 if(isset($address['lng']) && isset($address['lat'])) @@ -1450,7 +1449,7 @@ class BuyService // 订单地址添加前钩子 $hook_name = 'plugins_service_buy_order_address_insert_begin'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'user_id' => $user_id, @@ -1554,7 +1553,7 @@ class BuyService if($common_deduction_inventory_rules == 1) { // 获取订单商品 - $order_detail = Db::name('OrderDetail')->field('id,goods_id,buy_number,spec')->where(['order_id'=>$params['order_id']])->select(); + $order_detail = Db::name('OrderDetail')->field('id,goods_id,buy_number,spec')->where(['order_id'=>$params['order_id']])->select()->toArray(); if(empty($order_detail)) { return DataReturn('订单详情有误', -1); @@ -1617,7 +1616,7 @@ class BuyService if($common_deduction_inventory_rules == 1) { // 数据集合 - $detail = Db::name('OrderDetail')->field('id,order_id,goods_id,buy_number,spec')->where(['order_id'=>array_column($params['order_data'], 'id')])->select(); + $detail = Db::name('OrderDetail')->field('id,order_id,goods_id,buy_number,spec')->where(['order_id'=>array_column($params['order_data'], 'id')])->select()->toArray(); if(empty($detail)) { return DataReturn('订单详情有误', -1); @@ -1785,7 +1784,7 @@ class BuyService } // 获取订单商品 - $order_detail = Db::name('OrderDetail')->field('id,goods_id,buy_number,spec')->where(['order_id'=>$params['order_id']])->select(); + $order_detail = Db::name('OrderDetail')->field('id,goods_id,buy_number,spec')->where(['order_id'=>$params['order_id']])->select()->toArray(); if(!empty($order_detail)) { foreach($order_detail as $v) @@ -1804,7 +1803,7 @@ class BuyService } // 扣除操作 - if(!Db::name('Goods')->where(['id'=>$v['goods_id']])->setDec('inventory', $v['buy_number'])) + if(!Db::name('Goods')->where(['id'=>$v['goods_id']])->dec('inventory', $v['buy_number'])) { return DataReturn('商品库存扣减失败['.$params['order_id'].'-'.$v['id'].'-'.$v['goods_id'].'('.$goods['inventory'].'-'.$v['buy_number'].')]', -10); } @@ -1821,7 +1820,7 @@ class BuyService } // 扣除规格操作 - if(!Db::name('GoodsSpecBase')->where(['id'=>$base['data']['spec_base']['id'], 'goods_id'=>$v['goods_id']])->setDec('inventory', $v['buy_number'])) + if(!Db::name('GoodsSpecBase')->where(['id'=>$base['data']['spec_base']['id'], 'goods_id'=>$v['goods_id']])->dec('inventory', $v['buy_number'])) { return DataReturn('规格库存扣减失败['.$params['order_id'].'-'.$v['goods_id'].'('.$goods['inventory'].'-'.$v['buy_number'].')]', -10); } @@ -1911,7 +1910,7 @@ class BuyService } // 获取订单商品 - $order_detail = Db::name('OrderDetail')->field('goods_id,buy_number,spec')->where($detail_where)->select(); + $order_detail = Db::name('OrderDetail')->field('goods_id,buy_number,spec')->where($detail_where)->select()->toArray(); if(!empty($order_detail)) { foreach($order_detail as $v) @@ -1924,7 +1923,7 @@ class BuyService $buy_number = ($appoint_buy_number == 0) ? $v['buy_number'] : $appoint_buy_number; // 回滚操作 - if(!Db::name('Goods')->where(['id'=>$v['goods_id']])->setInc('inventory', $buy_number)) + if(!Db::name('Goods')->where(['id'=>$v['goods_id']])->inc('inventory', $buy_number)) { return DataReturn('商品库存回滚失败['.$params['order_id'].'-'.$v['goods_id'].']', -10); } @@ -1935,7 +1934,7 @@ class BuyService if($base['code'] == 0) { // 回滚规格操作 - if(!Db::name('GoodsSpecBase')->where(['id'=>$base['data']['spec_base']['id'], 'goods_id'=>$v['goods_id']])->setInc('inventory', $buy_number)) + if(!Db::name('GoodsSpecBase')->where(['id'=>$base['data']['spec_base']['id'], 'goods_id'=>$v['goods_id']])->inc('inventory', $buy_number)) { return DataReturn('规格库存回滚失败['.$params['order_id'].'-'.$v['goods_id'].']', -10); } @@ -2012,7 +2011,7 @@ class BuyService // 自提点地址数据钩子 $hook_name = 'plugins_service_site_extraction_address_handle'; - $ret = Hook::listen($hook_name, [ + $ret = MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => $params, diff --git a/application/service/CacheService.php b/app/service/CacheService.php similarity index 100% rename from application/service/CacheService.php rename to app/service/CacheService.php diff --git a/application/service/ConfigService.php b/app/service/ConfigService.php similarity index 94% rename from application/service/ConfigService.php rename to app/service/ConfigService.php index 6713b67df..c28b1995d 100755 --- a/application/service/ConfigService.php +++ b/app/service/ConfigService.php @@ -10,8 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; -use think\facade\Hook; +use think\facade\Db; use app\service\ResourcesService; /** @@ -88,10 +87,6 @@ class ConfigService // session是否开启redis缓存 'common_session_is_use_cache', - 'common_cache_session_redis_host', - 'common_cache_session_redis_port', - 'common_cache_session_redis_password', - 'common_cache_session_redis_expire', 'common_cache_session_redis_prefix', // cdn地址 @@ -116,7 +111,7 @@ class ConfigService public static function ConfigList($params = []) { $field = isset($params['field']) ? $params['field'] : 'only_tag,name,describe,value,error_tips'; - $data = Db::name('Config')->column($field); + $data = Db::name('Config')->column($field, 'only_tag'); if(!empty($data)) { foreach($data as $k=>&$v) @@ -126,7 +121,7 @@ class ConfigService { if($k == $fv) { - $v['value'] = (!isset($v['value']) || $v['value'] == '') ? [] : explode(',', $v['value']); + $v['value'] = (!isset($v['value']) || $v['value'] == '' || is_array($v['value'])) ? [] : explode(',', $v['value']); } } } @@ -190,13 +185,13 @@ class ConfigService $success++; // 单条配置缓存删除 - cache($k, null); + MyCache($k, null); } } if($success > 0) { // 删除所有配置的缓存数据 - cache(config('shopxo.cache_common_my_config_key'), null); + MyCache(MyConfig('shopxo.cache_common_my_config_key'), null); // 所有配置信息更新 self::ConfigInit(1); @@ -249,8 +244,8 @@ class ConfigService */ public static function ConfigInit($status = 0) { - $key = config('shopxo.cache_common_my_config_key'); - $data = cache($key); + $key = MyConfig('shopxo.cache_common_my_config_key'); + $data = MyCache($key); if(empty($data) || $status == 1) { // 所有配置 @@ -276,7 +271,7 @@ class ConfigService } // 公共内置数据缓存 - cache($k, $v); + MyCache($k, $v); // 数据文件缓存 if(in_array($k, self::$file_cache_keys)) @@ -286,7 +281,7 @@ class ConfigService } // 所有配置缓存集合 - cache($key, $data); + MyCache($key, $data); } } @@ -302,11 +297,11 @@ class ConfigService { if(isset($params['home_seo_url_model'])) { - $route_file = ROOT.'route'.DS.'route.config'; - $route_file_php = ROOT.'route'.DS.'route.php'; + $route_file = APP_PATH.'index'.DS.'route'.DS.'route.config'; + $route_file_php = APP_PATH.'index'.DS.'route'.DS.'route.php'; // 文件目录 - if(!is_writable(ROOT.'route')) + if(!is_writable(APP_PATH.'index'.DS.'route')) { return DataReturn('路由目录没有操作权限'.'[./route]', -11); } @@ -356,7 +351,7 @@ class ConfigService public static function ConfigContentRow($key) { // 缓存key,单条新增前缀,与公共配置区分开 - $data = cache('config_content_row_'.$key); + $data = MyCache('config_content_row_'.$key); // 获取内容 if(empty($data)) @@ -371,7 +366,7 @@ class ConfigService } $data['upd_time_time'] = empty($data['upd_time']) ? null : date('Y-m-d H:i:s', $data['upd_time']); } - cache($key, $data); + MyCache($key, $data); } return DataReturn('操作成功', 0, $data); @@ -418,7 +413,7 @@ class ConfigService // 自提点地址列表数据钩子 $hook_name = 'plugins_service_site_extraction_address_list'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'data' => &$data, diff --git a/application/service/CrontabService.php b/app/service/CrontabService.php similarity index 98% rename from application/service/CrontabService.php rename to app/service/CrontabService.php index e90b7fc7a..0cf54d269 100644 --- a/application/service/CrontabService.php +++ b/app/service/CrontabService.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; +use think\facade\Db; use app\service\OrderService; use app\service\BuyService; use app\service\MessageService; @@ -42,7 +42,7 @@ class CrontabService ['add_time', '<', $time], ['status', '=', 1], ]; - $order = Db::name('Order')->where($where)->field('id,status,user_id')->select(); + $order = Db::name('Order')->where($where)->field('id,status,user_id')->select()->toArray(); // 状态 $sucs = 0; @@ -102,7 +102,7 @@ class CrontabService ['delivery_time', '<', $time], ['status', '=', 3], ]; - $order = Db::name('Order')->where($where)->field('id,status,user_id')->select(); + $order = Db::name('Order')->where($where)->field('id,status,user_id')->select()->toArray(); // 状态 $sucs = 0; diff --git a/application/service/CustomViewService.php b/app/service/CustomViewService.php similarity index 98% rename from application/service/CustomViewService.php rename to app/service/CustomViewService.php index 8d099c52f..12e091495 100755 --- a/application/service/CustomViewService.php +++ b/app/service/CustomViewService.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; +use think\facade\Db; use app\service\ResourcesService; /** @@ -39,7 +39,7 @@ class CustomViewService $m = isset($params['m']) ? intval($params['m']) : 0; $n = isset($params['n']) ? intval($params['n']) : 10; - $data = Db::name('CustomView')->field($field)->where($where)->order($order_by)->limit($m, $n)->select(); + $data = Db::name('CustomView')->field($field)->where($where)->order($order_by)->limit($m, $n)->select()->toArray(); if(!empty($data)) { $common_is_enable_list = lang('common_is_enable_list'); @@ -109,7 +109,7 @@ class CustomViewService { if(!empty($params['id'])) { - return Db::name('CustomView')->where(array('id'=>intval($params['id'])))->setInc('access_count'); + return Db::name('CustomView')->where(array('id'=>intval($params['id'])))->inc('access_count'); } return false; } diff --git a/application/service/DesignService.php b/app/service/DesignService.php similarity index 98% rename from application/service/DesignService.php rename to app/service/DesignService.php index 5dcc4c946..541e0f374 100644 --- a/application/service/DesignService.php +++ b/app/service/DesignService.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; +use think\facade\Db; use app\service\ResourcesService; /** @@ -41,7 +41,7 @@ class DesignService $n = isset($params['n']) ? intval($params['n']) : 10; // 获取数据 - $data = Db::name('Design')->where($where)->limit($m, $n)->order($order_by)->select(); + $data = Db::name('Design')->where($where)->limit($m, $n)->order($order_by)->select()->toArray(); if(!empty($data)) { foreach($data as &$v) @@ -225,7 +225,7 @@ class DesignService { if(!empty($params['design_id'])) { - return Db::name('Design')->where(['id'=>intval($params['design_id'])])->setInc('access_count'); + return Db::name('Design')->where(['id'=>intval($params['design_id'])])->inc('access_count'); } return false; } diff --git a/application/service/ExpressService.php b/app/service/ExpressService.php similarity index 98% rename from application/service/ExpressService.php rename to app/service/ExpressService.php index fe409206e..d1422f76e 100755 --- a/application/service/ExpressService.php +++ b/app/service/ExpressService.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; +use think\facade\Db; use app\service\ResourcesService; /** @@ -72,7 +72,7 @@ class ExpressService { $where['is_enable'] = intval($params['is_enable']); } - $data = Db::name('Express')->where($where)->field('id,icon,name,sort,is_enable')->order('sort asc')->select(); + $data = Db::name('Express')->where($where)->field('id,icon,name,sort,is_enable')->order('sort asc')->select()->toArray(); return self::DataHandle($data); } @@ -118,7 +118,7 @@ class ExpressService // 获取数据 $field = 'id,pid,icon,name,sort,is_enable'; - $data = Db::name('Express')->field($field)->where(['pid'=>$id])->order('sort asc')->select(); + $data = Db::name('Express')->field($field)->where(['pid'=>$id])->order('sort asc')->select()->toArray(); if(!empty($data)) { $data = self::DataHandle($data); diff --git a/application/service/FormTableService.php b/app/service/FormTableService.php similarity index 98% rename from application/service/FormTableService.php rename to app/service/FormTableService.php index ebbf782c4..b2a89a69d 100644 --- a/application/service/FormTableService.php +++ b/app/service/FormTableService.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; +use think\facade\Db; use app\service\UserService; use app\service\AdminService; @@ -141,7 +141,7 @@ class FormTableService public static function FieldsSelectData($params = []) { // 模块 - $module_name = strtolower(request()->module()); + $module_name = RequestModule(); // 当前用户 if($module_name == 'admin') diff --git a/application/service/GoodsBrowseService.php b/app/service/GoodsBrowseService.php similarity index 95% rename from application/service/GoodsBrowseService.php rename to app/service/GoodsBrowseService.php index c3e0422ba..0593213f0 100644 --- a/application/service/GoodsBrowseService.php +++ b/app/service/GoodsBrowseService.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; +use think\facade\Db; use app\service\ResourcesService; use app\service\UserService; use app\service\GoodsService; @@ -117,7 +117,7 @@ class GoodsBrowseService */ public static function GoodsBrowseTotal($where = []) { - return (int) Db::name('GoodsBrowse')->alias('b')->join(['__GOODS__'=>'g'], 'g.id=b.goods_id')->where($where)->count(); + return (int) Db::name('GoodsBrowse')->alias('b')->join('goods g', 'g.id=b.goods_id')->where($where)->count(); } /** @@ -138,7 +138,7 @@ class GoodsBrowseService $n = isset($params['n']) ? intval($params['n']) : 10; // 获取数据 - $data = Db::name('GoodsBrowse')->alias('b')->join(['__GOODS__'=>'g'], 'g.id=b.goods_id')->field($field)->where($where)->limit($m, $n)->order($order_by)->select(); + $data = Db::name('GoodsBrowse')->alias('b')->join('goods g', 'g.id=b.goods_id')->field($field)->where($where)->limit($m, $n)->order($order_by)->select()->toArray(); if(!empty($data)) { // 商品数据处理 diff --git a/application/service/GoodsCommentsService.php b/app/service/GoodsCommentsService.php similarity index 99% rename from application/service/GoodsCommentsService.php rename to app/service/GoodsCommentsService.php index 70827a445..4c42e58d7 100644 --- a/application/service/GoodsCommentsService.php +++ b/app/service/GoodsCommentsService.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; +use think\facade\Db; use app\service\UserService; use app\service\GoodsService; @@ -200,7 +200,7 @@ class GoodsCommentsService $n = isset($params['n']) ? intval($params['n']) : 10; // 获取数据列表 - $data = Db::name('GoodsComments')->where($where)->field($field)->limit($m, $n)->order($order_by)->select(); + $data = Db::name('GoodsComments')->where($where)->field($field)->limit($m, $n)->order($order_by)->select()->toArray(); if(!empty($data)) { // 获取商品信息 diff --git a/application/service/GoodsFavorService.php b/app/service/GoodsFavorService.php similarity index 96% rename from application/service/GoodsFavorService.php rename to app/service/GoodsFavorService.php index aa0b70225..97fd7dd72 100644 --- a/application/service/GoodsFavorService.php +++ b/app/service/GoodsFavorService.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; +use think\facade\Db; use app\service\ResourcesService; use app\service\UserService; use app\service\GoodsService; @@ -180,7 +180,7 @@ class GoodsFavorService */ public static function GoodsFavorTotal($where = []) { - return (int) Db::name('GoodsFavor')->alias('f')->join(['__GOODS__'=>'g'], 'g.id=f.goods_id')->where($where)->count(); + return (int) Db::name('GoodsFavor')->alias('f')->join('goods g', 'g.id=f.goods_id')->where($where)->count(); } /** @@ -201,7 +201,7 @@ class GoodsFavorService $n = isset($params['n']) ? intval($params['n']) : 10; // 获取数据 - $data = Db::name('GoodsFavor')->alias('f')->join(['__GOODS__'=>'g'], 'g.id=f.goods_id')->field($field)->where($where)->limit($m, $n)->order($order_by)->select(); + $data = Db::name('GoodsFavor')->alias('f')->join('goods g', 'g.id=f.goods_id')->field($field)->where($where)->limit($m, $n)->order($order_by)->select()->toArray(); if(!empty($data)) { // 商品数据处理 diff --git a/application/service/GoodsParamsService.php b/app/service/GoodsParamsService.php similarity index 97% rename from application/service/GoodsParamsService.php rename to app/service/GoodsParamsService.php index 866517003..aeaffbffb 100755 --- a/application/service/GoodsParamsService.php +++ b/app/service/GoodsParamsService.php @@ -10,8 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; -use think\facade\Hook; +use think\facade\Db; /** * 商品参数服务层 @@ -41,11 +40,11 @@ class GoodsParamsService $n = isset($params['n']) ? intval($params['n']) : 10; // 获取列表 - $data = Db::name('GoodsParamsTemplate')->where($where)->order($order_by)->field($field)->limit($m, $n)->select(); + $data = Db::name('GoodsParamsTemplate')->where($where)->order($order_by)->field($field)->limit($m, $n)->select()->toArray(); if(!empty($data)) { // 获取配置数据 - $res = Db::name('GoodsParamsTemplateConfig')->where(['template_id'=>array_column($data, 'id')])->field('id,template_id,type,name,value')->order('id asc')->select(); + $res = Db::name('GoodsParamsTemplateConfig')->where(['template_id'=>array_column($data, 'id')])->field('id,template_id,type,name,value')->order('id asc')->select()->toArray(); $config = []; if(!empty($res)) { @@ -130,7 +129,7 @@ class GoodsParamsService // 保存处理钩子 $hook_name = 'plugins_service_goods_params_template_save_handle'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, diff --git a/application/service/GoodsService.php b/app/service/GoodsService.php similarity index 97% rename from application/service/GoodsService.php rename to app/service/GoodsService.php index b959cfeab..c4e56a031 100755 --- a/application/service/GoodsService.php +++ b/app/service/GoodsService.php @@ -10,8 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; -use think\facade\Hook; +use think\facade\Db; use app\service\SystemBaseService; use app\service\ResourcesService; use app\service\BrandService; @@ -64,9 +63,9 @@ class GoodsService public static function GoodsCategoryAll($params = []) { // 从缓存获取 - $key = config('shopxo.cache_goods_category_key'); - $data = cache($key); - if(empty($data) || config('app_debug')) + $key = MyConfig('shopxo.cache_goods_category_key'); + $data = MyCache($key); + if(empty($data) || MyEnv('app_debug')) { // 获取分类 $params['where'] = [ @@ -76,7 +75,7 @@ class GoodsService $data = self::GoodsCategory($params); // 存储缓存 - cache($key, $data, 60); + MyCache($key, $data, 60); } return $data; } @@ -164,7 +163,7 @@ class GoodsService $order_by = empty($params['order_by']) ? 'sort asc' : trim($params['order_by']); $field = empty($params['field']) ? 'id,pid,icon,name,vice_name,describe,bg_color,big_images,sort,is_home_recommended,seo_title,seo_keywords,seo_desc' : $params['field']; - $data = Db::name('GoodsCategory')->field($field)->where($where)->order($order_by)->limit($m, $n)->select(); + $data = Db::name('GoodsCategory')->field($field)->where($where)->order($order_by)->limit($m, $n)->select()->toArray(); return self::GoodsCategoryDataHandle($data); } @@ -211,9 +210,9 @@ class GoodsService public static function HomeFloorList($params = []) { // 缓存 - $key = config('shopxo.cache_goods_floor_list_key'); - $data = cache($key); - if(empty($data) || config('app_debug')) + $key = MyConfig('shopxo.cache_goods_floor_list_key'); + $data = MyCache($key); + if(empty($data) || MyEnv('app_debug')) { // 商品大分类 $where = [ @@ -292,7 +291,7 @@ class GoodsService 'gci.category_id' => $category_ids, 'g.is_shelves' => 1, ]; - $v['goods_ids'] = Db::name('Goods')->alias('g')->join(['__GOODS_CATEGORY_JOIN__'=>'gci'], 'g.id=gci.goods_id')->where($where)->group('g.id')->order($order_by)->limit($goods_count)->column('g.id'); + $v['goods_ids'] = Db::name('Goods')->alias('g')->join('goods_category_join gci', 'g.id=gci.goods_id')->where($where)->group('g.id')->order($order_by)->limit($goods_count)->column('g.id'); } break; @@ -322,7 +321,7 @@ class GoodsService } // 存储缓存 - cache($key, $data, 60); + MyCache($key, $data, 60); } // 商品读取、商品信息需要实时读取 @@ -418,7 +417,7 @@ class GoodsService */ public static function CategoryGoodsTotal($where = []) { - return (int) Db::name('Goods')->alias('g')->join(['__GOODS_CATEGORY_JOIN__'=>'gci'], 'g.id=gci.goods_id')->where($where)->count('DISTINCT g.id'); + return (int) Db::name('Goods')->alias('g')->join('goods_category_join gci', 'g.id=gci.goods_id')->where($where)->count('DISTINCT g.id'); } /** @@ -440,7 +439,7 @@ class GoodsService // 商品列表读取前钩子 $hook_name = 'plugins_service_category_goods_list_begin'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, @@ -451,7 +450,7 @@ class GoodsService 'n' => &$n, ]); - $data = Db::name('Goods')->alias('g')->join(['__GOODS_CATEGORY_JOIN__'=>'gci'], 'g.id=gci.goods_id')->field($field)->where($where)->group('g.id')->order($order_by)->limit($m, $n)->select(); + $data = Db::name('Goods')->alias('g')->join('goods_category_join gci', 'g.id=gci.goods_id')->field($field)->where($where)->group('g.id')->order($order_by)->limit($m, $n)->select()->toArray(); // 数据处理 return self::GoodsDataHandle($data, $params); @@ -501,7 +500,7 @@ class GoodsService // 商品处理前钩子 $hook_name = 'plugins_service_goods_handle_begin'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, @@ -573,7 +572,7 @@ class GoodsService if(isset($v['fictitious_goods_value'])) { // 非后台模块移除该字段、避免数据泄露 - if(strtolower(request()->module()) != 'admin') + if(RequestModule() != 'admin') { unset($v['fictitious_goods_value']); } else { @@ -662,7 +661,7 @@ class GoodsService // 商品处理后钩子 $hook_name = 'plugins_service_goods_handle_end'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, @@ -720,7 +719,7 @@ class GoodsService */ public static function GoodsPhotoData($goods_id) { - return Db::name('GoodsPhoto')->where(['goods_id'=>$goods_id, 'is_show'=>1])->order('sort asc')->select(); + return Db::name('GoodsPhoto')->where(['goods_id'=>$goods_id, 'is_show'=>1])->order('sort asc')->select()->toArray(); } /** @@ -735,7 +734,7 @@ class GoodsService */ public static function GoodsContentAppData($params = []) { - $data = Db::name('GoodsContentApp')->where(['goods_id'=>$params['goods_id']])->field('id,images,content')->order('sort asc')->select(); + $data = Db::name('GoodsContentApp')->where(['goods_id'=>$params['goods_id']])->field('id,images,content')->order('sort asc')->select()->toArray(); if(!empty($data)) { foreach($data as &$v) @@ -764,7 +763,7 @@ class GoodsService $where = ['goods_id'=>$goods_id]; // 规格类型 - $choose = Db::name('GoodsSpecType')->where($where)->order('id asc')->select(); + $choose = Db::name('GoodsSpecType')->where($where)->order('id asc')->select()->toArray(); if(!empty($choose)) { // 数据处理 @@ -815,7 +814,7 @@ class GoodsService { $base = []; $detail = []; - $list = Db::name('GoodsParams')->where(['goods_id'=>$goods_id])->order('id asc')->select(); + $list = Db::name('GoodsParams')->where(['goods_id'=>$goods_id])->order('id asc')->select()->toArray(); if(!empty($list)) { foreach($list as $v) @@ -847,7 +846,7 @@ class GoodsService // 商品参数钩子 $hook_name = 'plugins_service_goods_parameters_data'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'data' => &$data, @@ -895,7 +894,7 @@ class GoodsService $title = Db::name('GoodsSpecType')->where($where)->column('name'); // 规格值 - $value = Db::name('GoodsSpecValue')->where($where)->field('goods_spec_base_id,value')->select(); + $value = Db::name('GoodsSpecValue')->where($where)->field('goods_spec_base_id,value')->select()->toArray(); $group = []; if(!empty($value)) { @@ -937,7 +936,7 @@ class GoodsService { if(!empty($params['goods_id'])) { - return Db::name('Goods')->where(['id'=>intval($params['goods_id'])])->setInc('access_count'); + return Db::name('Goods')->where(['id'=>intval($params['goods_id'])])->inc('access_count'); } return false; } @@ -975,7 +974,7 @@ class GoodsService // 商品列表读取前钩子 $hook_name = 'plugins_service_goods_list_begin'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, @@ -986,7 +985,7 @@ class GoodsService 'n' => &$n, ]); - $data = Db::name('Goods')->field($field)->where($where)->order($order_by)->limit($m, $n)->select(); + $data = Db::name('Goods')->field($field)->where($where)->order($order_by)->limit($m, $n)->select()->toArray(); return self::GoodsDataHandle($data, $params); } @@ -1149,7 +1148,7 @@ class GoodsService // 商品保存处理钩子 $hook_name = 'plugins_service_goods_save_handle'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, @@ -1244,7 +1243,7 @@ class GoodsService // 商品保存后钩子 $hook_name = 'plugins_service_goods_save_end'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => $params, @@ -1831,7 +1830,7 @@ class GoodsService // 商品删除钩子 $hook_name = 'plugins_service_goods_delete'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => $params, @@ -1959,7 +1958,7 @@ class GoodsService // 商品删除钩子 $hook_name = 'plugins_service_goods_field_status_update'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => $params, @@ -1991,7 +1990,7 @@ class GoodsService $where = ['goods_id'=>$goods_id]; // 获取规格类型 - $type = Db::name('GoodsSpecType')->where($where)->order('id asc')->field('id,name,value')->select(); + $type = Db::name('GoodsSpecType')->where($where)->order('id asc')->field('id,name,value')->select()->toArray(); $value = []; if(!empty($type)) { @@ -2009,7 +2008,7 @@ class GoodsService // 获取规格值 - $temp_value = Db::name('GoodsSpecValue')->where($where)->field('goods_spec_base_id,value')->order('id asc')->select(); + $temp_value = Db::name('GoodsSpecValue')->where($where)->field('goods_spec_base_id,value')->order('id asc')->select()->toArray(); if(!empty($temp_value)) { foreach($temp_value as $value_v) @@ -2077,7 +2076,7 @@ class GoodsService */ public static function GoodsEditParameters($goods_id) { - return Db::name('GoodsParams')->where(['goods_id'=>$goods_id])->order('id asc')->select(); + return Db::name('GoodsParams')->where(['goods_id'=>$goods_id])->order('id asc')->select()->toArray(); } /** @@ -2132,7 +2131,7 @@ class GoodsService if(!empty($ids)) { // 根据基础值id获取规格值列表 - $temp_data = Db::name('GoodsSpecValue')->where(['goods_spec_base_id'=>$ids])->field('goods_spec_base_id,value')->order('id asc')->select(); + $temp_data = Db::name('GoodsSpecValue')->where(['goods_spec_base_id'=>$ids])->field('goods_spec_base_id,value')->order('id asc')->select()->toArray(); if(!empty($temp_data)) { // 根据基础值id分组 @@ -2182,7 +2181,7 @@ class GoodsService // 商品获取规格钩子 $hook_name = 'plugins_service_goods_spec_base'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => $params, @@ -2249,7 +2248,7 @@ class GoodsService if(!empty($ids)) { // 根据基础值id获取规格值列表 - $temp_data = Db::name('GoodsSpecValue')->where(['goods_spec_base_id'=>$ids])->field('goods_spec_base_id,value')->order('id asc')->select(); + $temp_data = Db::name('GoodsSpecValue')->where(['goods_spec_base_id'=>$ids])->field('goods_spec_base_id,value')->order('id asc')->select()->toArray(); if(!empty($temp_data)) { // 根据基础值id分组 @@ -2287,7 +2286,7 @@ class GoodsService // 商品获取规格类型钩子 $hook_name = 'plugins_service_goods_spec_type'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => $params, @@ -2320,7 +2319,7 @@ class GoodsService // 获取数据 $field = 'id,pid,icon,name,sort,is_enable,bg_color,big_images,vice_name,describe,is_home_recommended,seo_title,seo_keywords,seo_desc'; - $data = Db::name('GoodsCategory')->field($field)->where(['pid'=>$id])->order('sort asc')->select(); + $data = Db::name('GoodsCategory')->field($field)->where(['pid'=>$id])->order('sort asc')->select()->toArray(); if(!empty($data)) { $data = self::GoodsCategoryDataHandle($data); @@ -2445,7 +2444,7 @@ class GoodsService } // 删除大分类缓存 - cache(config('shopxo.cache_goods_category_key'), null); + MyCache(MyConfig('shopxo.cache_goods_category_key'), null); $res = self::GoodsCategoryDataHandle([$data]); return DataReturn('操作成功', 0, json_encode($res[0])); @@ -2488,7 +2487,7 @@ class GoodsService if(Db::name('GoodsCategory')->where(['id'=>$ids])->delete()) { // 删除大分类缓存 - cache(config('shopxo.cache_goods_category_key'), null); + MyCache(MyConfig('shopxo.cache_goods_category_key'), null); return DataReturn('删除成功', 0); } @@ -2506,7 +2505,7 @@ class GoodsService */ public static function GoodsCategoryNames($goods_id) { - $data = Db::name('GoodsCategory')->alias('gc')->join(['__GOODS_CATEGORY_JOIN__'=>'gci'], 'gc.id=gci.category_id')->where(['gci.goods_id'=>$goods_id])->column('gc.name'); + $data = Db::name('GoodsCategory')->alias('gc')->join('goods_category_join gci', 'gc.id=gci.category_id')->where(['gci.goods_id'=>$goods_id])->column('gc.name'); return DataReturn('获取成功', 0, $data); } @@ -2525,7 +2524,7 @@ class GoodsService // 规格扩展数据钩子 $hook_name = 'plugins_service_goods_spec_extends_handle'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => $params, @@ -2673,7 +2672,7 @@ class GoodsService // 商品购买导航按钮钩子 $hook_name = 'plugins_service_goods_buy_nav_button_handle'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'goods' => $goods, @@ -2732,7 +2731,7 @@ class GoodsService // 商品详情中间导航钩子 $hook_name = 'plugins_service_goods_detail_middle_tabs_nav_handle'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'goods' => $goods, diff --git a/application/service/IntegralService.php b/app/service/IntegralService.php similarity index 98% rename from application/service/IntegralService.php rename to app/service/IntegralService.php index ced75fd99..66649019f 100755 --- a/application/service/IntegralService.php +++ b/app/service/IntegralService.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; +use think\facade\Db; use app\service\MessageService; use app\service\UserService; @@ -78,7 +78,7 @@ class IntegralService $n = isset($params['n']) ? intval($params['n']) : 10; // 获取数据列表 - $data = Db::name('UserIntegralLog')->where($where)->field($field)->limit($m, $n)->order($order_by)->select(); + $data = Db::name('UserIntegralLog')->where($where)->field($field)->limit($m, $n)->order($order_by)->select()->toArray(); if(!empty($data)) { $integral_log_type_list = lang('common_integral_log_type_list'); @@ -209,7 +209,7 @@ class IntegralService } // 获取订单商品 - $order_detail = Db::name('OrderDetail')->where(['order_id'=>$params['order_id']])->field('goods_id,total_price')->select(); + $order_detail = Db::name('OrderDetail')->where(['order_id'=>$params['order_id']])->field('goods_id,total_price')->select()->toArray(); if(!empty($order_detail)) { // 获取赠送积分的商品 @@ -229,7 +229,7 @@ class IntegralService { // 用户积分添加 $user_integral = Db::name('User')->where(['id'=>$user['id']])->value('integral'); - if(!Db::name('User')->where(['id'=>$user['id']])->setInc('integral', $give_integral)) + if(!Db::name('User')->where(['id'=>$user['id']])->inc('integral', $give_integral)) { return DataReturn('用户积分赠送失败['.$params['order_id'].'-'.$goods_id.']', -10); } @@ -316,7 +316,7 @@ class IntegralService if($refund_integral >= 1) { // 用户积分添加 - if(!Db::name('User')->where(['id'=>$user['id']])->setDec('integral', $refund_integral)) + if(!Db::name('User')->where(['id'=>$user['id']])->dec('integral', $refund_integral)) { return DataReturn('用户积分释放失败['.$order_detail['order_id'].'-'.$order_detail['goods_id'].']', -10); } diff --git a/application/service/LayoutService.php b/app/service/LayoutService.php similarity index 99% rename from application/service/LayoutService.php rename to app/service/LayoutService.php index dd981f1d1..fb6e54422 100644 --- a/application/service/LayoutService.php +++ b/app/service/LayoutService.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; +use think\facade\Db; use app\layout\service\BaseLayout; /** diff --git a/application/service/LinkService.php b/app/service/LinkService.php similarity index 99% rename from application/service/LinkService.php rename to app/service/LinkService.php index 57009e258..1904fc5b1 100755 --- a/application/service/LinkService.php +++ b/app/service/LinkService.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; +use think\facade\Db; use app\service\GoodsService; /** @@ -36,7 +36,7 @@ class LinkService $field = empty($params['field']) ? '*' : $params['field']; $where = empty($params['where']) ? [] : $params['where']; $order_by = empty($params['order_by']) ? 'sort asc,id desc' : trim($params['order_by']); - $data = Db::name('Link')->field($field)->where($where)->order($order_by)->select(); + $data = Db::name('Link')->field($field)->where($where)->order($order_by)->select()->toArray(); if(!empty($data)) { foreach($data as &$v) diff --git a/application/service/MessageService.php b/app/service/MessageService.php similarity index 98% rename from application/service/MessageService.php rename to app/service/MessageService.php index ed4bf0bc2..f33103afb 100755 --- a/application/service/MessageService.php +++ b/app/service/MessageService.php @@ -10,8 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; -use think\facade\Hook; +use think\facade\Db; use app\service\UserService; /** @@ -55,7 +54,7 @@ class MessageService { // 消息添加钩子 $hook_name = 'plugins_service_message_add'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'data' => $data, @@ -191,7 +190,7 @@ class MessageService $n = isset($params['n']) ? intval($params['n']) : 10; // 获取数据列表 - $data = Db::name('Message')->where($where)->field($field)->limit($m, $n)->order($order_by)->select(); + $data = Db::name('Message')->where($where)->field($field)->limit($m, $n)->order($order_by)->select()->toArray(); if(!empty($data)) { // 字段列表 diff --git a/application/service/NavigationService.php b/app/service/NavigationService.php similarity index 96% rename from application/service/NavigationService.php rename to app/service/NavigationService.php index 82d28e31a..0ccccdbec 100755 --- a/application/service/NavigationService.php +++ b/app/service/NavigationService.php @@ -10,8 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; -use think\facade\Hook; +use think\facade\Db; use app\service\BuyService; use app\service\MessageService; use app\service\OrderService; @@ -41,18 +40,18 @@ class NavigationService public static function Nav($params = []) { // 读取缓存数据 - $header = cache(config('shopxo.cache_common_home_nav_header_key')); - $footer = cache(config('shopxo.cache_common_home_nav_footer_key')); + $header = MyCache(MyConfig('shopxo.cache_common_home_nav_header_key')); + $footer = MyCache(MyConfig('shopxo.cache_common_home_nav_footer_key')); // 缓存没数据则从数据库重新读取,顶部菜单 - if(empty($header) || config('app_debug')) + if(empty($header) || MyEnv('app_debug')) { // 获取导航数据 $header = self::NavDataAll('header'); } // 底部导航 - if(empty($footer) || config('app_debug')) + if(empty($footer) || MyEnv('app_debug')) { // 获取导航数据 $footer = self::NavDataAll('footer'); @@ -119,13 +118,13 @@ class NavigationService // 获取导航数据 $field = 'id,pid,name,url,value,data_type,is_new_window_open'; $order_by = 'sort asc,id asc'; - $data = self::NavDataDealWith(Db::name('Navigation')->field($field)->where(array('nav_type'=>$nav_type, 'is_show'=>1, 'pid'=>0))->order($order_by)->select()); + $data = self::NavDataDealWith(Db::name('Navigation')->field($field)->where(array('nav_type'=>$nav_type, 'is_show'=>1, 'pid'=>0))->order($order_by)->select()->toArray()); if(!empty($data)) { // 获取子数据 $items = []; $ids = array_column($data, 'id'); - $items_data = self::NavDataDealWith(Db::name('Navigation')->field($field)->where(array('nav_type'=>$nav_type, 'is_show'=>1, 'pid'=>$ids))->order($order_by)->select()); + $items_data = self::NavDataDealWith(Db::name('Navigation')->field($field)->where(array('nav_type'=>$nav_type, 'is_show'=>1, 'pid'=>$ids))->order($order_by)->select()->toArray()); if(!empty($items_data)) { foreach($items_data as $it) @@ -143,7 +142,7 @@ class NavigationService // 大导航钩子 $hook_name = 'plugins_service_navigation_'.$nav_type.'_handle'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, @@ -152,7 +151,7 @@ class NavigationService ]); // 缓存 - cache(config('shopxo.cache_common_home_nav_'.$nav_type.'_key'), $data, 60); + MyCache(MyConfig('shopxo.cache_common_home_nav_'.$nav_type.'_key'), $data, 60); return $data; } @@ -214,14 +213,14 @@ class NavigationService // 获取数据 $where1 = $where; $where1[] = ['pid', '=', 0]; - $data = self::NavigationHandle(self::NavDataDealWith(Db::name('Navigation')->field($field)->where($where1)->order($order_by)->select())); + $data = self::NavigationHandle(self::NavDataDealWith(Db::name('Navigation')->field($field)->where($where1)->order($order_by)->select()->toArray())); $result = []; if(!empty($data)) { // 子级数据组合 $where2 = $where; $where2[] = ['pid', 'in', array_column($data, 'id')]; - $items_data = self::NavigationHandle(self::NavDataDealWith(Db::name('Navigation')->field($field)->where($where2)->order($order_by)->select())); + $items_data = self::NavigationHandle(self::NavDataDealWith(Db::name('Navigation')->field($field)->where($where2)->order($order_by)->select()->toArray())); $items_group = []; if(!empty($items_data)) { @@ -296,7 +295,7 @@ class NavigationService return []; } - return Db::name('Navigation')->field('id,name')->where(['is_show'=>1, 'pid'=>0, 'nav_type'=>$params['nav_type']])->select(); + return Db::name('Navigation')->field('id,name')->where(['is_show'=>1, 'pid'=>0, 'nav_type'=>$params['nav_type']])->select()->toArray(); } /** @@ -462,11 +461,11 @@ class NavigationService break; } // 只截取16个字符 - $params['name'] = mb_substr($temp_name, 0, 16, config('shopxo.default_charset')); + $params['name'] = mb_substr($temp_name, 0, 16, MyConfig('shopxo.default_charset')); } // 清除缓存 - cache(config('cache_common_home_nav_'.$params['nav_type'].'_key'), null); + MyCache(MyConfig('cache_common_home_nav_'.$params['nav_type'].'_key'), null); // 数据 $data = [ @@ -488,7 +487,7 @@ class NavigationService if(Db::name('Navigation')->insertGetId($data) > 0) { // 清除缓存 - cache(config('cache_common_home_nav_'.$params['nav_type'].'_key'), null); + MyCache(MyConfig('cache_common_home_nav_'.$params['nav_type'].'_key'), null); return DataReturn('新增成功', 0); } else { @@ -499,7 +498,7 @@ class NavigationService if(Db::name('Navigation')->where(['id'=>intval($params['id'])])->update($data)) { // 清除缓存 - cache(config('cache_common_home_nav_'.$params['nav_type'].'_key'), null); + MyCache(MyConfig('cache_common_home_nav_'.$params['nav_type'].'_key'), null); return DataReturn('编辑成功', 0); } else { @@ -540,8 +539,8 @@ class NavigationService Db::commit(); // 清除缓存 - cache(config('shopxo.cache_common_home_nav_header_key'), null); - cache(config('shopxo.cache_common_home_nav_footer_key'), null); + MyCache(MyConfig('shopxo.cache_common_home_nav_header_key'), null); + MyCache(MyConfig('shopxo.cache_common_home_nav_footer_key'), null); return DataReturn('删除成功'); } @@ -590,8 +589,8 @@ class NavigationService if(Db::name('Navigation')->where(['id'=>intval($params['id'])])->update([$params['field']=>intval($params['state']), 'upd_time'=>time()])) { // 清除缓存 - cache(config('shopxo.cache_common_home_nav_header_key'), null); - cache(config('shopxo.cache_common_home_nav_footer_key'), null); + MyCache(MyConfig('shopxo.cache_common_home_nav_header_key'), null); + MyCache(MyConfig('shopxo.cache_common_home_nav_footer_key'), null); return DataReturn('编辑成功'); } @@ -678,7 +677,7 @@ class NavigationService // 顶部小导航右侧钩子 $hook_name = 'plugins_service_header_navigation_top_right_handle'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, @@ -735,7 +734,7 @@ class NavigationService // 用户中心资料修改展示字段钩子 $hook_name = 'plugins_service_users_personal_show_field_list_handle'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, @@ -783,7 +782,7 @@ class NavigationService // 用户安全项列表钩子 $hook_name = 'plugins_service_users_safety_panel_list_handle'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, @@ -938,7 +937,7 @@ class NavigationService // 用户中心左侧菜单钩子 $hook_name = 'plugins_service_users_center_left_menu_handle'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, @@ -1004,7 +1003,7 @@ class NavigationService // 网站底部导航 $hook_name = 'plugins_service_bottom_navigation_handle'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, @@ -1071,7 +1070,7 @@ class NavigationService // 用户中心基础信息中mini导航 $hook_name = 'plugins_service_user_center_mini_navigation_handle'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, diff --git a/application/service/OrderAftersaleService.php b/app/service/OrderAftersaleService.php similarity index 97% rename from application/service/OrderAftersaleService.php rename to app/service/OrderAftersaleService.php index 94c58bb85..b00421e57 100644 --- a/application/service/OrderAftersaleService.php +++ b/app/service/OrderAftersaleService.php @@ -10,8 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; -use think\facade\Hook; +use think\facade\Db; use app\service\UserService; use app\service\ResourcesService; use app\service\RefundLogService; @@ -230,7 +229,7 @@ class OrderAftersaleService // 订单售后添加前钩子 $hook_name = 'plugins_service_order_aftersale_insert_begin'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'data' => &$data, @@ -248,7 +247,7 @@ class OrderAftersaleService { // 订单售后添加成功钩子 $hook_name = 'plugins_service_order_aftersale_insert_end'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'data_id' => $data_id, @@ -341,7 +340,7 @@ class OrderAftersaleService // 订单售后单退货前钩子 $hook_name = 'plugins_service_order_aftersale_delivery_begin'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'data_id' => $params['id'], @@ -359,7 +358,7 @@ class OrderAftersaleService { // 订单售后退货成功钩子 $hook_name = 'plugins_service_order_aftersale_delivery_end'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'data_id' => $params['id'], @@ -395,7 +394,7 @@ class OrderAftersaleService $n = isset($params['n']) ? intval($params['n']) : 10; // 获取数据列表 - $data = Db::name('OrderAftersale')->field($field)->where($where)->limit($m, $n)->order($order_by)->select(); + $data = Db::name('OrderAftersale')->field($field)->where($where)->limit($m, $n)->order($order_by)->select()->toArray(); if(!empty($data)) { $type_list = lang('common_order_aftersale_type_list'); @@ -633,7 +632,7 @@ class OrderAftersaleService // 订单售后单取消前钩子 $hook_name = 'plugins_service_order_aftersale_cacnel_begin'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'data_id' => $params['id'], @@ -651,7 +650,7 @@ class OrderAftersaleService { // 订单售后取消成功钩子 $hook_name = 'plugins_service_order_aftersale_cacnel_end'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'data_id' => $params['id'], @@ -729,7 +728,7 @@ class OrderAftersaleService // 订单售后单确认前钩子 $hook_name = 'plugins_service_order_aftersale_confirm_begin'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'data_id' => $params['id'], @@ -747,7 +746,7 @@ class OrderAftersaleService { // 订单售后单确认成功钩子 $hook_name = 'plugins_service_order_aftersale_confirm_end'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'data_id' => $params['id'], @@ -843,7 +842,7 @@ class OrderAftersaleService } // 订单支付方式校验 - $pay_log = Db::name('PayLog')->alias('pl')->join(['__PAY_LOG_VALUE__'=>'plv'], 'pl.id=plv.pay_log_id')->where(['plv.business_id'=>$order['data']['id'], 'pl.business_type'=>OrderService::$business_type_name, 'pl.status'=>1])->field('pl.*')->find(); + $pay_log = Db::name('PayLog')->alias('pl')->join('pay_log_value plv', 'pl.id=plv.pay_log_id')->where(['plv.business_id'=>$order['data']['id'], 'pl.business_type'=>OrderService::$business_type_name, 'pl.status'=>1])->field('pl.*')->find(); // 手动处理不校验支付日志 if($params['refundment'] != 2) @@ -857,7 +856,7 @@ class OrderAftersaleService // 原路退回 if($params['refundment'] == 0) { - if(in_array($pay_log['payment'], config('shopxo.under_line_list'))) + if(in_array($pay_log['payment'], MyConfig('shopxo.under_line_list'))) { return DataReturn('线下支付方式不能原路退回[ '.$pay_log['payment_name'].' ]', -1); } else { @@ -992,7 +991,7 @@ class OrderAftersaleService $order_status = (MyC('common_goods_sales_count_inc_rules', 1) == 1) ? 4 : 2; if($order['data']['status'] == $order_status && $aftersale['number'] > 0) { - if(!Db::name('Goods')->where(['id'=>intval($aftersale['goods_id'])])->setDec('sales_count', $aftersale['number'])) + if(!Db::name('Goods')->where(['id'=>intval($aftersale['goods_id'])])->dec('sales_count', $aftersale['number'])) { Db::rollback(); return DataReturn('商品销量释放失败', -1); @@ -1027,7 +1026,7 @@ class OrderAftersaleService // 订单售后单审核前钩子 $hook_name = 'plugins_service_order_aftersale_audit_handle_begin'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'data_id' => $aftersale['id'], @@ -1050,7 +1049,7 @@ class OrderAftersaleService // 订单售后审核处理完毕钩子 $hook_name = 'plugins_service_order_aftersale_audit_handle_end'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => $params, @@ -1262,7 +1261,7 @@ class OrderAftersaleService // 订单售后单拒绝前钩子 $hook_name = 'plugins_service_order_aftersale_refuse_begin'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'data_id' => $params['id'], @@ -1280,7 +1279,7 @@ class OrderAftersaleService { // 订单售后单拒绝成功钩子 $hook_name = 'plugins_service_order_aftersale_refuse_end'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'data_id' => $params['id'], @@ -1342,7 +1341,7 @@ class OrderAftersaleService { // 订单售后单删除成功钩子 $hook_name = 'plugins_service_order_aftersale_delete_success'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'data_id' => $params['id'], @@ -1387,7 +1386,7 @@ class OrderAftersaleService $order = Db::name('Order')->where(['id'=>$order_id])->field('id,status,pay_status,buy_number_count,increase_price,preferential_price,price,total_price,pay_price,refund_price,returned_quantity')->find(); if(!empty($order)) { - $dateil = Db::name('OrderDetail')->where(['order_id'=>$order_id])->field('id,price,total_price,buy_number,refund_price,returned_quantity')->select(); + $dateil = Db::name('OrderDetail')->where(['order_id'=>$order_id])->field('id,price,total_price,buy_number,refund_price,returned_quantity')->select()->toArray(); if(!empty($dateil)) { foreach($dateil as $v) @@ -1662,7 +1661,7 @@ class OrderAftersaleService // 订单售后退货地址钩子 $hook_name = 'plugins_service_order_aftersale_return_address'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'order_id' => $order_id, diff --git a/application/service/OrderCurrencyService.php b/app/service/OrderCurrencyService.php similarity index 97% rename from application/service/OrderCurrencyService.php rename to app/service/OrderCurrencyService.php index 4fd5a6241..ec6786c91 100644 --- a/application/service/OrderCurrencyService.php +++ b/app/service/OrderCurrencyService.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; +use think\facade\Db; use app\service\ResourcesService; /** @@ -64,7 +64,7 @@ class OrderCurrencyService */ public static function OrderCurrencyGroupList($order_ids) { - $data = Db::name('OrderCurrency')->where(['order_id'=>$order_ids])->select(); + $data = Db::name('OrderCurrency')->where(['order_id'=>$order_ids])->select()->toArray(); $result = []; if(!empty($data) && is_array($order_ids)) { diff --git a/application/service/OrderService.php b/app/service/OrderService.php similarity index 98% rename from application/service/OrderService.php rename to app/service/OrderService.php index 2a593b596..fd5925780 100755 --- a/application/service/OrderService.php +++ b/app/service/OrderService.php @@ -10,8 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; -use think\facade\Hook; +use think\facade\Db; use app\service\PaymentService; use app\service\BuyService; use app\service\IntegralService; @@ -138,7 +137,7 @@ class OrderService { Db::name('Order')->where(['id'=>$ids])->update([ 'payment_id' => $payment['id'], - 'is_under_line' => in_array($payment['payment'], config('shopxo.under_line_list')) ? 1 : 0, + 'is_under_line' => in_array($payment['payment'], MyConfig('shopxo.under_line_list')) ? 1 : 0, 'upd_time' => time(), ]); } @@ -224,7 +223,7 @@ class OrderService // 发起支付前处理钩子 $hook_name = 'plugins_service_order_pay_launch_begin'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'user' => $params['user'], @@ -276,7 +275,7 @@ class OrderService // 发起支付处理钩子 $hook_name = 'plugins_service_order_pay_launch_handle'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'order_ids' => $order_ids, @@ -307,7 +306,7 @@ class OrderService $weixin_params['ids'] = urldecode(implode(',', $order_ids)); $url = MyUrl('index/order/index', $weixin_params); } - session('plugins_weixinwebauth_pay_callback_view_url', $url); + MySession('plugins_weixinwebauth_pay_callback_view_url', $url); } // 发起支付 @@ -336,7 +335,7 @@ class OrderService ]; // 是否线下支付 - if(in_array($payment['payment'], config('shopxo.under_line_list'))) + if(in_array($payment['payment'], MyConfig('shopxo.under_line_list'))) { $ret['data']['is_payment_type'] = 1; } else { @@ -507,7 +506,7 @@ class OrderService { if(!empty($params['order']) && !empty($params['payment']) && !empty($params['user'])) { - if(in_array($params['payment']['payment'], config('shopxo.under_line_list'))) + if(in_array($params['payment']['payment'], MyConfig('shopxo.under_line_list'))) { // 新增支付日志 $pay_log = self::OrderPayLogInsert([ @@ -595,7 +594,7 @@ class OrderService $order = Db::name('Order')->where($where)->find(); // 线下支付方式处理 - if(in_array($payment_name, config('shopxo.under_line_list'))) + if(in_array($payment_name, MyConfig('shopxo.under_line_list'))) { return DataReturn('提交成功、待管理员确认', 0); } @@ -658,18 +657,12 @@ class OrderService } // 获取订单 - $order_list = Db::name('Order')->where(['id'=>$pay_log_value, 'status'=>1])->select(); + $order_list = Db::name('Order')->where(['id'=>$pay_log_value, 'status'=>1])->select()->toArray(); if(empty($order_list)) { return DataReturn('订单信息有误', -1); } - // 订单数量是否一致 - if(count($order_list) != count($pay_log_value)) - { - return DataReturn('订单与日志记录数量不一致', -1); - } - // 支付金额是否小于订单金额 if(MyC('common_is_pay_price_must_max_equal', 0) == 1) { @@ -694,7 +687,7 @@ class OrderService // 支付成功异步通知处理钩子 $hook_name = 'plugins_service_order_pay_notify_handle'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'payment' => $payment, @@ -755,7 +748,7 @@ class OrderService // 订单支付成功处理前钩子 $hook_name = 'plugins_service_order_pay_handle_begin'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, @@ -783,7 +776,7 @@ class OrderService ]; // 是否线下支付 - $upd_data['is_under_line'] = in_array($params['payment']['payment'], config('shopxo.under_line_list')) ? 1 : 0; + $upd_data['is_under_line'] = in_array($params['payment']['payment'], MyConfig('shopxo.under_line_list')) ? 1 : 0; // 更新订单状态 if(!Db::name('Order')->where(['id'=>$order['id']])->update($upd_data)) @@ -821,7 +814,7 @@ class OrderService // 订单支付成功处理完毕钩子 $hook_name = 'plugins_service_order_pay_success_handle_end'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => $params, @@ -1049,7 +1042,7 @@ class OrderService $n = isset($params['n']) ? intval($params['n']) : 10; // 获取订单 - $data = Db::name('Order')->where($where)->field($field)->limit($m, $n)->order($order_by)->select(); + $data = Db::name('Order')->where($where)->field($field)->limit($m, $n)->order($order_by)->select()->toArray(); // 数据处理 return self::OrderDataHandle($data, $params); @@ -1088,7 +1081,7 @@ class OrderService if(in_array('warehouse_id', $keys)) { $we_ids = array_unique(array_column($data, 'warehouse_id')); - $warehouse_list = WarehouseService::DataHandle(Db::name('Warehouse')->where(['id'=>$we_ids])->field('id,name')->select()); + $warehouse_list = WarehouseService::DataHandle(Db::name('Warehouse')->where(['id'=>$we_ids])->field('id,name')->select()->toArray()); if(!empty($warehouse_list)) { $warehouse_list = array_column($warehouse_list, null, 'id'); @@ -1124,7 +1117,7 @@ class OrderService { // 订单处理前钩子 $hook_name = 'plugins_service_order_handle_begin'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, @@ -1263,7 +1256,7 @@ class OrderService // 订单处理后钩子 $hook_name = 'plugins_service_order_handle_end'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, @@ -1321,7 +1314,7 @@ class OrderService */ public static function OrderItemList($order_id, $order_model, $status, $pay_status, $is_orderaftersale = 0) { - $items = Db::name('OrderDetail')->where(['order_id'=>$order_id])->select(); + $items = Db::name('OrderDetail')->where(['order_id'=>$order_id])->select()->toArray(); if(!empty($items)) { // 虚拟商品取货码 @@ -1514,7 +1507,7 @@ class OrderService { // 订单状态改变添加日志钩子 $hook_name = 'plugins_service_order_status_change_history_success_handle'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'data' => $data, @@ -2037,7 +2030,7 @@ class OrderService } $field = 'COUNT(DISTINCT id) AS count, status'; - $data = Db::name('Order')->where($where)->field($field)->group('status')->select(); + $data = Db::name('Order')->where($where)->field($field)->group('status')->select()->toArray(); // 数据处理 if(!empty($data)) @@ -2147,12 +2140,12 @@ class OrderService if($status) { // 获取订单商品 - $order_detail = Db::name('OrderDetail')->field('id,goods_id,title,buy_number')->where(['order_id'=>$params['order_id']])->select(); + $order_detail = Db::name('OrderDetail')->field('id,goods_id,title,buy_number')->where(['order_id'=>$params['order_id']])->select()->toArray(); if(!empty($order_detail)) { foreach($order_detail as $v) { - if(Db::name('Goods')->where(['id'=>$v['goods_id']])->setInc('sales_count', $v['buy_number']) === false) + if(Db::name('Goods')->where(['id'=>$v['goods_id']])->inc('sales_count', $v['buy_number']) === false) { return DataReturn('订单商品销量增加失败['.$v['title'].']', -10); } diff --git a/application/service/OrderSplitService.php b/app/service/OrderSplitService.php similarity index 97% rename from application/service/OrderSplitService.php rename to app/service/OrderSplitService.php index ed5cacb8a..04ad6fe75 100644 --- a/application/service/OrderSplitService.php +++ b/app/service/OrderSplitService.php @@ -10,8 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; -use think\facade\Hook; +use think\facade\Db; use app\service\WarehouseService; /** @@ -62,7 +61,7 @@ class OrderSplitService // 生成订单仓库分组商品数据处理钩子 $hook_name = 'plugins_service_buy_group_goods_handle'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => $params, @@ -258,7 +257,7 @@ class OrderSplitService ['w.is_delete_time', '=', 0], ]; $field = 'distinct w.id,w.name,w.alias,w.lng,w.lat,w.province,w.city,w.county,w.address,wgs.inventory,w.is_default,w.level'; - $warehouse = Db::name('WarehouseGoodsSpec')->alias('wgs')->join(['__WAREHOUSE_GOODS__'=>'wg'], 'wgs.warehouse_id=wg.warehouse_id')->join(['__WAREHOUSE__'=>'w'], 'wg.warehouse_id=w.id')->where($where)->field($field)->order('w.level desc,w.is_default desc,wgs.inventory desc')->select(); + $warehouse = Db::name('WarehouseGoodsSpec')->alias('wgs')->join('warehouse_goods wg', 'wgs.warehouse_id=wg.warehouse_id')->join('warehouse w', 'wg.warehouse_id=w.id')->where($where)->field($field)->order('w.level desc,w.is_default desc,wgs.inventory desc')->select()->toArray(); // 商品仓库分组 if(!empty($warehouse)) diff --git a/application/service/PackageInstallService.php b/app/service/PackageInstallService.php similarity index 98% rename from application/service/PackageInstallService.php rename to app/service/PackageInstallService.php index 7056f0230..f190cb1eb 100644 --- a/application/service/PackageInstallService.php +++ b/app/service/PackageInstallService.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; +use think\facade\Db; use app\service\PluginsAdminService; use app\service\PaymentService; use app\service\ThemeService; @@ -178,7 +178,7 @@ class PackageInstallService } // 移除session - session($params['key'], null); + MySession($params['key'], null); // 删除本地文件 \base\FileUtil::UnlinkFile($res['url']); @@ -198,7 +198,7 @@ class PackageInstallService public static function DownloadHandle($key) { // 获取下载地址 - $url = session($key); + $url = MySession($key); if(empty($url)) { return DataReturn('下载地址为空', -1); @@ -230,7 +230,7 @@ class PackageInstallService public static function UrlHandle($params) { // 获取下载地址 - $url = config('shopxo.store_download_url'); + $url = MyConfig('shopxo.store_download_url'); $data = [ 'goods_id' => $params['id'], 'url' => __MY_URL__, @@ -247,7 +247,7 @@ class PackageInstallService if(!empty($ret) && isset($ret['code']) && $ret['code'] == 0) { $key = md5($ret['data']); - session($key, $ret['data']); + MySession($key, $ret['data']); $ret['data'] = $key; } return $ret; diff --git a/application/service/PayLogService.php b/app/service/PayLogService.php similarity index 97% rename from application/service/PayLogService.php rename to app/service/PayLogService.php index 9e1afba3c..4018ba55a 100755 --- a/application/service/PayLogService.php +++ b/app/service/PayLogService.php @@ -10,8 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; -use think\facade\Hook; +use think\facade\Db; /** * 支付日志服务层 @@ -111,7 +110,7 @@ class PayLogService // 支付日志添加成功钩子 $hook_name = 'plugins_service_paylog_insert_success'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => $params, @@ -178,7 +177,7 @@ class PayLogService */ public static function PayLogTypeList($params = []) { - $data = Db::name('PayLog')->field('payment as id, payment_name as name')->group('payment,payment_name')->select(); + $data = Db::name('PayLog')->field('payment as id, payment_name as name')->group('payment,payment_name')->select()->toArray(); return DataReturn('处理成功', 0, $data); } @@ -200,7 +199,7 @@ class PayLogService $n = isset($params['n']) ? intval($params['n']) : 10; // 获取数据列表 - $data = Db::name('PayLog')->where($where)->field($field)->limit($m, $n)->order($order_by)->select(); + $data = Db::name('PayLog')->where($where)->field($field)->limit($m, $n)->order($order_by)->select()->toArray(); if(!empty($data)) { // 字段列表 @@ -208,7 +207,7 @@ class PayLogService // 获取支付业务关联数据 $log_value_list = []; - $log_value = Db::name('PayLogValue')->field('pay_log_id,business_id,business_no')->where(['pay_log_id'=>array_column($data, 'id')])->select(); + $log_value = Db::name('PayLogValue')->field('pay_log_id,business_id,business_no')->where(['pay_log_id'=>array_column($data, 'id')])->select()->toArray(); if(!empty($log_value)) { foreach($log_value as $lv) diff --git a/application/service/PayRequestLogService.php b/app/service/PayRequestLogService.php similarity index 98% rename from application/service/PayRequestLogService.php rename to app/service/PayRequestLogService.php index d26ed4cff..933e3112e 100644 --- a/application/service/PayRequestLogService.php +++ b/app/service/PayRequestLogService.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; +use think\facade\Db; /** * 支付请求日志服务层 @@ -114,7 +114,7 @@ class PayRequestLogService $n = isset($params['n']) ? intval($params['n']) : 10; // 获取数据列表 - $data = Db::name('PayRequestLog')->where($where)->field($field)->limit($m, $n)->order($order_by)->select(); + $data = Db::name('PayRequestLog')->where($where)->field($field)->limit($m, $n)->order($order_by)->select()->toArray(); if(!empty($data)) { // 循环处理数据 diff --git a/application/service/PaymentService.php b/app/service/PaymentService.php similarity index 92% rename from application/service/PaymentService.php rename to app/service/PaymentService.php index b012d5a47..e21521096 100755 --- a/application/service/PaymentService.php +++ b/app/service/PaymentService.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; +use think\facade\Db; use app\service\ResourcesService; use app\service\StoreService; @@ -50,7 +50,7 @@ class PaymentService self::$payment_dir = ROOT.'extend'.DS.'payment'.DS; // 支付业务类型 - self::$payment_business_type_all = config('shopxo.payment_business_type_all'); + self::$payment_business_type_all = MyConfig('shopxo.payment_business_type_all'); // 不删除的支付方式 self::$cannot_deleted_list = ['DeliveryPayment', 'CashPayment']; @@ -202,7 +202,7 @@ class PaymentService $where['is_open_user'] = intval($params['is_open_user']); } - $data = Db::name('Payment')->where($where)->field('id,logo,name,sort,payment,config,apply_terminal,apply_terminal_old,element,is_enable,is_open_user')->order('sort asc')->select(); + $data = Db::name('Payment')->where($where)->field('id,logo,name,sort,payment,config,apply_terminal,apply_terminal_old,element,is_enable,is_open_user')->order('sort asc')->select()->toArray(); if(!empty($data) && is_array($data)) { foreach($data as &$v) @@ -269,7 +269,7 @@ class PaymentService } if(!empty($business_ids)) { - $res = Db::name('PayLog')->alias('pl')->join(['__PAY_LOG_VALUE__'=>'plv'], 'pl.id=plv.pay_log_id')->where(['plv.business_id'=>$business_ids])->order('pl.id desc')->field('plv.business_id,pl.payment_name')->select(); + $res = Db::name('PayLog')->alias('pl')->join('pay_log_value plv', 'pl.id=plv.pay_log_id')->where(['plv.business_id'=>$business_ids])->order('pl.id desc')->field('plv.business_id,pl.payment_name')->select()->toArray(); $data = []; if(!empty($res) && is_array($res)) { @@ -763,8 +763,26 @@ class PaymentService return '支付唯一标记不能为空'; } + // 获取地址所属模块名称、地址标记去除模块名称 + $module_notify = 'index'; + $module_respond = 'index'; + if(substr($params['notify'], 0, 5) == '/api/') + { + $module_notify = 'api'; + $params['notify'] = substr($params['notify'], 5); + } else { + $params['notify'] = substr($params['notify'], 7); + } + if(substr($params['respond'], 0, 5) == '/api/') + { + $module_respond = 'api'; + $params['respond'] = substr($params['respond'], 5); + } else { + $params['respond'] = substr($params['respond'], 7); + } + // 不生成异步入口 - $not_notify = empty($params['not_notify']) ? config('shopxo.under_line_list') : $params['not_notify']; + $not_notify = empty($params['not_notify']) ? MyConfig('shopxo.under_line_list') : $params['not_notify']; // 处理业务 $business_all = empty($params['business']) ? self::$payment_business_type_all : $params['business']; @@ -782,6 +800,7 @@ $notify=<<http; +\$response = \$http->name('{$module_notify}')->run(); +\$response->send(); +\$http->end(\$response); ?> php; @@ -804,6 +832,7 @@ $respond=<<http; +\$response = \$http->name('{$module_respond}')->run(); +\$response->send(); +\$http->end(\$response); ?> php; @@ -828,6 +866,7 @@ $notify=<<http; +\$response = \$http->name('{$module_notify}')->run(); +\$response->send(); +\$http->end(\$response); ?> php; @@ -847,6 +895,7 @@ $respond=<<http; +\$response = \$http->name('{$module_respond}')->run(); +\$response->send(); +\$http->end(\$response); ?> php; } @@ -937,7 +995,7 @@ php; } // 线下支付不生成异步入口文件 - if(!in_array($payment, config('shopxo.under_line_list'))) + if(!in_array($payment, MyConfig('shopxo.under_line_list'))) { if(!file_exists(self::$dir_root_path.'payment_'.strtolower($name).'_'.strtolower($payment).'_notify.php')) { diff --git a/application/service/PluginsAdminService.php b/app/service/PluginsAdminService.php similarity index 97% rename from application/service/PluginsAdminService.php rename to app/service/PluginsAdminService.php index 503cac6e4..6d3aad0b0 100755 --- a/application/service/PluginsAdminService.php +++ b/app/service/PluginsAdminService.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; +use think\facade\Db; use app\service\PluginsService; use app\service\ResourcesService; use app\service\SqlconsoleService; @@ -290,33 +290,36 @@ class PluginsAdminService private static function PluginsHookDeployment() { // 钩子配置文件 - $tags_file = APP_PATH.'tags.php'; - if(!is_writable($tags_file)) + $event_file = APP_PATH.'event.php'; + if(file_exists($event_file)) { - return DataReturn('钩子配置文件没有操作权限'.'['.$tags_file.']', -3); + if(!is_writable($event_file)) + { + return DataReturn('文件没有权限'.'['.$event_file.']', -3); + } + } else { + // 文件不存在则确认目录是否可写 + if(!is_writable(APP_PATH)) + { + return DataReturn('目录操作权限'.'['.$event_file.']', -3); + } } // 钩子容器 $result = []; // 系统自带钩子处理 - if(file_exists($tags_file)) + if(file_exists($event_file)) { - $tags = require $tags_file; + $tags = require $event_file; if(!empty($tags) && is_array($tags)) { $system_hook_list = [ - 'app_init', - 'app_dispatch', - 'app_begin', - 'module_init', - 'action_begin', - 'view_filter', - 'app_end', - 'log_write', - 'log_level', - 'response_send', - 'response_end' + 'AppInit', + 'HttpRun', + 'HttpEnd', + 'RouteLoaded', + 'LogRecord' ]; foreach($system_hook_list as $system_hook) { @@ -354,7 +357,7 @@ class PluginsAdminService } // 部署钩子到文件 - $ret = @file_put_contents($tags_file, ""); +// 应用行为扩展定义文件\nreturn ".var_export(['listen'=>$result], true).";\n?>"); if($ret === false) { return DataReturn('应用钩子部署失败', -10); @@ -598,7 +601,7 @@ $admin=<<assign('data', ['hello', 'world!']); - \$this->assign('msg', 'hello world! admin'); - return \$this->fetch('../../../plugins/view/$plugins/admin/admin/index'); + \MyViewAssign('data', ['hello', 'world!']); + \MyViewAssign('msg', 'hello world! admin'); + return \MyView('../../../plugins/view/$plugins/admin/admin/index'); } } ?> @@ -631,7 +634,7 @@ $hook=<<assign('data', ['hello', 'world!']); - \$this->assign('msg', 'hello world! index'); - return \$this->fetch('../../../plugins/view/$plugins/index/index/index'); + \MyViewAssign('data', ['hello', 'world!']); + \MyViewAssign('msg', 'hello world! index'); + return \MyView('../../../plugins/view/$plugins/index/index/index'); } } ?> @@ -1266,7 +1269,7 @@ php; } // 是否开启开发者模式 - if(config('shopxo.is_develop') !== true) + if(MyConfig('shopxo.is_develop') !== true) { return DataReturn('请先开启开发者模式', -1); } diff --git a/application/service/PluginsService.php b/app/service/PluginsService.php similarity index 95% rename from application/service/PluginsService.php rename to app/service/PluginsService.php index 42210019c..145b81a47 100755 --- a/application/service/PluginsService.php +++ b/app/service/PluginsService.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; +use think\facade\Db; use app\service\ResourcesService; use app\service\PluginsAdminService; use app\service\StoreService; @@ -90,7 +90,7 @@ class PluginsService } } else { // 所有附件后缀名称 - $attachment_ext = config('ueditor.fileManagerAllowFiles'); + $attachment_ext = MyConfig('ueditor.fileManagerAllowFiles'); // 未自定义附件则自动根据内容判断处理附件,建议自定义附件字段名称处理更高效 if(!empty($attachment_ext) && is_array($attachment_ext)) @@ -187,7 +187,7 @@ class PluginsService */ public static function PluginsCacheStorage($plugins, $data) { - return cache(config('shopxo.cache_plugins_data_key').$plugins, $data); + return MyCache(MyConfig('shopxo.cache_plugins_data_key').$plugins, $data); } /** @@ -201,7 +201,7 @@ class PluginsService */ public static function PluginsCacheData($plugins) { - $data = cache(config('shopxo.cache_plugins_data_key').$plugins); + $data = MyCache(MyConfig('shopxo.cache_plugins_data_key').$plugins); return empty($data) ? '' : $data; } @@ -216,7 +216,7 @@ class PluginsService */ public static function PluginsCacheDelete($plugins) { - cache(config('shopxo.cache_plugins_data_key').$plugins, null); + MyCache(MyConfig('shopxo.cache_plugins_data_key').$plugins, null); } /** @@ -317,10 +317,10 @@ class PluginsService } // 安全判断 - if(config('shopxo.is_develop') === false && strtolower(request()->module()) == 'admin') + if(MyConfig('shopxo.is_develop') === false && RequestModule() == 'admin') { $key = 'plugins_legal_check_'.$plugins; - $ret = cache($key); + $ret = MyCache($key); if(empty($ret)) { $config = PluginsAdminService::GetPluginsConfig($plugins); @@ -337,7 +337,7 @@ class PluginsService 'ver' => $config['base']['version'], ]; $ret = StoreService::PluginsLegalCheck($check_params); - cache($key, $ret, 3600); + MyCache($key, $ret, 3600); } if($ret['code'] != 0) { @@ -395,7 +395,7 @@ class PluginsService */ public static function PluginsBaseList($params = []) { - $data = Db::name('Plugins')->where(['is_enable'=>1])->order(PluginsAdminService::$plugins_order_by)->field('id,plugins,data')->select(); + $data = Db::name('Plugins')->where(['is_enable'=>1])->order(PluginsAdminService::$plugins_order_by)->field('id,plugins,data')->select()->toArray(); if(!empty($data)) { foreach($data as &$v) @@ -425,7 +425,7 @@ class PluginsService // 缓存记录 $time = 3600; $key = 'plugins_upgrade_check_info'; - $res = cache($key); + $res = MyCache($key); if(empty($res)) { if(!empty($params) && !empty($params['db_data']) && is_array($params['db_data'])) @@ -463,11 +463,11 @@ class PluginsService } // 存储缓存 - cache($key, $result, $time); + MyCache($key, $result, $time); } } else { // 存储缓存 - cache($key, $result, $time); + MyCache($key, $result, $time); } } } else { diff --git a/application/service/PluginsUpgradeService.php b/app/service/PluginsUpgradeService.php similarity index 98% rename from application/service/PluginsUpgradeService.php rename to app/service/PluginsUpgradeService.php index d9d9ef86b..35419ea69 100644 --- a/application/service/PluginsUpgradeService.php +++ b/app/service/PluginsUpgradeService.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; +use think\facade\Db; use app\service\PluginsAdminService; use app\service\PaymentService; use app\service\ThemeService; @@ -130,7 +130,7 @@ class PluginsUpgradeService } // 移除session - session($params['key'], null); + MySession($params['key'], null); // 删除本地文件 \base\FileUtil::UnlinkFile($res['url']); @@ -155,7 +155,7 @@ class PluginsUpgradeService public static function DownloadHandle($key) { // 获取下载地址 - $url = session($key); + $url = MySession($key); if(empty($url)) { return DataReturn('下载地址为空', -1); @@ -199,7 +199,7 @@ class PluginsUpgradeService if(!empty($ret) && isset($ret['code']) && $ret['code'] == 0) { $key = md5($ret['data']); - session($key, $ret['data']); + MySession($key, $ret['data']); $ret['data'] = $key; } return $ret; diff --git a/application/service/QuickNavService.php b/app/service/QuickNavService.php similarity index 97% rename from application/service/QuickNavService.php rename to app/service/QuickNavService.php index 93a37e569..57fd25d4a 100755 --- a/application/service/QuickNavService.php +++ b/app/service/QuickNavService.php @@ -10,8 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; -use think\facade\Hook; +use think\facade\Db; use app\service\ResourcesService; /** @@ -40,7 +39,7 @@ class QuickNavService $n = isset($params['n']) ? intval($params['n']) : 10; // 获取品牌列表 - $data = Db::name('QuickNav')->where($where)->order($order_by)->limit($m, $n)->select(); + $data = Db::name('QuickNav')->where($where)->order($order_by)->limit($m, $n)->select()->toArray(); if(!empty($data)) { $common_platform_type = lang('common_platform_type'); @@ -273,15 +272,15 @@ class QuickNavService $platform = ApplicationClientType(); // 缓存 - $key = config('shopxo.cache_quick_navigation_key').$platform; - $data = cache($key); + $key = MyConfig('shopxo.cache_quick_navigation_key').$platform; + $data = MyCache($key); if(empty($data)) { // 获取导航数据 $field = 'id,name,images_url,event_value,event_type,bg_color'; $order_by = 'sort asc,id asc'; - $data = Db::name('QuickNav')->field($field)->where(['platform'=>$platform, 'is_enable'=>1])->order($order_by)->select(); + $data = Db::name('QuickNav')->field($field)->where(['platform'=>$platform, 'is_enable'=>1])->order($order_by)->select()->toArray(); if(!empty($data)) { foreach($data as &$v) @@ -307,14 +306,14 @@ class QuickNavService } // 存储缓存 - cache($key, $data, 60); + MyCache($key, $data, 60); } // 快捷导航钩子 // web端数据参数可以自定义新增 class_name 名称、方便非url事件使用js控制点击事件 // 支持标签自定义数据值 data_value 名称、方便自定义事件响应需要依赖的数据 $hook_name = 'plugins_service_quick_navigation_'.$platform; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'data' => &$data, diff --git a/application/service/RefundLogService.php b/app/service/RefundLogService.php similarity index 97% rename from application/service/RefundLogService.php rename to app/service/RefundLogService.php index 3d608b910..42600a45b 100644 --- a/application/service/RefundLogService.php +++ b/app/service/RefundLogService.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; +use think\facade\Db; use app\service\UserService; /** @@ -73,7 +73,7 @@ class RefundLogService */ public static function RefundLogTypeList($params = []) { - $data = Db::name('RefundLog')->field('payment as id, payment_name as name')->group('payment,payment_name')->select(); + $data = Db::name('RefundLog')->field('payment as id, payment_name as name')->group('payment,payment_name')->select()->toArray(); return DataReturn('处理成功', 0, $data); } @@ -95,7 +95,7 @@ class RefundLogService $n = isset($params['n']) ? intval($params['n']) : 10; // 获取数据列表 - $data = Db::name('RefundLog')->where($where)->field($field)->limit($m, $n)->order($order_by)->select(); + $data = Db::name('RefundLog')->where($where)->field($field)->limit($m, $n)->order($order_by)->select()->toArray(); if(!empty($data)) { $refundment_list = lang('common_order_aftersale_refundment_list'); diff --git a/application/service/RegionService.php b/app/service/RegionService.php similarity index 97% rename from application/service/RegionService.php rename to app/service/RegionService.php index e9c7b43bb..a53802f45 100755 --- a/application/service/RegionService.php +++ b/app/service/RegionService.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; +use think\facade\Db; /** * 地区服务层 @@ -68,7 +68,7 @@ class RegionService $pid = isset($params['pid']) ? intval($params['pid']) : 0; $field = empty($params['field']) ? '*' : $params['field']; $order_by = empty($params['order_by']) ? 'sort asc,id asc' : trim($params['order_by']); - return Db::name('Region')->field($field)->where(['pid'=>$pid, 'is_enable'=>1])->order($order_by)->select(); + return Db::name('Region')->field($field)->where(['pid'=>$pid, 'is_enable'=>1])->order($order_by)->select()->toArray(); } /** @@ -89,7 +89,7 @@ class RegionService // 基础条件 $where['is_enable'] = 1; - return Db::name('Region')->where($where)->field($field)->order($order_by)->select(); + return Db::name('Region')->where($where)->field($field)->order($order_by)->select()->toArray(); } /** @@ -107,7 +107,7 @@ class RegionService // 获取数据 $field = 'id,pid,name,sort,is_enable'; - $data = Db::name('Region')->field($field)->where(['pid'=>$id])->order('sort asc,id asc')->select(); + $data = Db::name('Region')->field($field)->where(['pid'=>$id])->order('sort asc,id asc')->select()->toArray(); if(!empty($data)) { foreach($data as &$v) @@ -258,8 +258,8 @@ class RegionService public static function RegionAll($params = []) { // 缓存 - $key = config('shopxo.cache_region_all_key'); - $data = cache($key); + $key = MyConfig('shopxo.cache_region_all_key'); + $data = MyCache($key); if(empty($data)) { // 所有一级 @@ -315,7 +315,7 @@ class RegionService } // 存储缓存 - cache($key, $data, 60); + MyCache($key, $data, 60); } } diff --git a/application/service/ResourcesService.php b/app/service/ResourcesService.php similarity index 95% rename from application/service/ResourcesService.php rename to app/service/ResourcesService.php index 88668e9d3..35969bce8 100755 --- a/application/service/ResourcesService.php +++ b/app/service/ResourcesService.php @@ -10,8 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; -use think\facade\Hook; +use think\facade\Db; use app\service\UserService; use app\service\SystemBaseService; @@ -153,7 +152,7 @@ class ResourcesService } // 配置信息 - $config = config('ueditor.'); + $config = MyConfig('ueditor.'); // 文件信息 $info = pathinfo($file); @@ -245,7 +244,7 @@ class ResourcesService // 附件上传前处理钩子 $hook_name = 'plugins_service_attachment_handle_begin'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => $params, @@ -258,7 +257,7 @@ class ResourcesService { // 附件上传后处理钩子 $hook_name = 'plugins_service_attachment_handle_end'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, @@ -305,14 +304,14 @@ class ResourcesService { $m = max(0, isset($params['m']) ? intval($params['m']) : 0); $n = max(1, isset($params['n']) ? intval($params['n']) : 20); - $data = Db::name('Attachment')->where($params['where'])->order('id desc')->limit($m, $n)->select(); + $data = Db::name('Attachment')->where($params['where'])->order('id desc')->limit($m, $n)->select()->toArray(); if(!empty($data)) { foreach($data as &$v) { // 附件列表处理前钩子 $hook_name = 'plugins_service_attachment_list_handle_begin'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'data' => &$v, @@ -328,7 +327,7 @@ class ResourcesService // 附件列表处理后钩子 $hook_name = 'plugins_service_attachment_list_handle_end'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'data' => &$v, @@ -405,7 +404,7 @@ class ResourcesService { // 附件删除成功后处理钩子 $hook_name = 'plugins_service_attachment_delete_success'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'data' => $data, @@ -426,7 +425,7 @@ class ResourcesService { // 获取附件数据 $where = ['path_type'=>$path_type]; - $data = DB::name('Attachment')->where($where)->select(); + $data = DB::name('Attachment')->where($where)->select()->toArray(); if(!empty($data)) { // 删除数据库数据 @@ -449,7 +448,7 @@ class ResourcesService // 附件删除成功后处理钩子 $hook_name = 'plugins_service_attachment_path_type_delete_success'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'data' => $data, @@ -625,15 +624,15 @@ class ResourcesService { // 默认从配置文件读取货币信息 $data = [ - 'currency_symbol' => config('shopxo.currency_symbol'), - 'currency_code' => config('shopxo.currency_code'), - 'currency_rate' => config('shopxo.currency_rate'), - 'currency_name' => config('shopxo.currency_name'), + 'currency_symbol' => MyConfig('shopxo.currency_symbol'), + 'currency_code' => MyConfig('shopxo.currency_code'), + 'currency_rate' => MyConfig('shopxo.currency_rate'), + 'currency_name' => MyConfig('shopxo.currency_name'), ]; // 钩子 $hook_name = 'plugins_service_currency_data'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'data' => &$data, @@ -653,7 +652,7 @@ class ResourcesService public static function CurrencyDataSymbol() { $res = self::CurrencyData(); - return empty($res['currency_symbol']) ? config('shopxo.currency_symbol') : $res['currency_symbol']; + return empty($res['currency_symbol']) ? MyConfig('shopxo.currency_symbol') : $res['currency_symbol']; } /** @@ -668,13 +667,13 @@ class ResourcesService public static function EditorPathTypeValue($value) { // 当前操作名称, 兼容插件模块名称 - $module_name = strtolower(request()->module()); - $controller_name = strtolower(request()->controller()); - $action_name = strtolower(request()->action()); + $module_name = RequestModule(); + $controller_name = RequestController(); + $action_name = RequestAction(); // 钩子 $hook_name = 'plugins_service_editor_path_type_'.$module_name.'_'.$controller_name.'_'.$action_name; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'value' => &$value, diff --git a/application/service/SafetyService.php b/app/service/SafetyService.php similarity index 98% rename from application/service/SafetyService.php rename to app/service/SafetyService.php index d022b43c7..713ec6bec 100755 --- a/application/service/SafetyService.php +++ b/app/service/SafetyService.php @@ -10,8 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; -use think\facade\Hook; +use think\facade\Db; use app\service\UserService; /** @@ -113,7 +112,7 @@ class SafetyService { // 用户登录密码修改钩子 $hook_name = 'plugins_service_user_login_pwd_update'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => ['accounts'=>$accounts, 'pwd'=>$pwd], @@ -339,7 +338,7 @@ class SafetyService if($obj->CheckCorrect($params['verify'])) { // 校验成功标记 - session('safety_'.$params['type'], true); + MySession('safety_'.$params['type'], true); // 清除验证码 $obj->Remove(); @@ -433,14 +432,14 @@ class SafetyService UserService::UserLoginRecord($params['user']['id']); // 校验成功标记 - session('safety_'.$params['type'], null); + MySession('safety_'.$params['type'], null); // 清除验证码 $obj->Remove(); // 账号修改钩子 $hook_name = 'plugins_service_user_accounts_update'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => ['accounts'=>$user[$field], 'new_accounts'=>$params['accounts'], 'field'=>$field], diff --git a/application/service/ScreeningPriceService.php b/app/service/ScreeningPriceService.php similarity index 98% rename from application/service/ScreeningPriceService.php rename to app/service/ScreeningPriceService.php index 20e47382b..9c509c0ff 100755 --- a/application/service/ScreeningPriceService.php +++ b/app/service/ScreeningPriceService.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; +use think\facade\Db; use app\service\ResourcesService; /** @@ -37,7 +37,7 @@ class ScreeningPriceService // 获取数据 $field = 'id,name,sort,is_enable,min_price,max_price'; - $data = Db::name('ScreeningPrice')->field($field)->where(['pid'=>$id])->order('sort asc')->select(); + $data = Db::name('ScreeningPrice')->field($field)->where(['pid'=>$id])->order('sort asc')->select()->toArray(); if(!empty($data)) { foreach($data as &$v) diff --git a/application/service/SearchService.php b/app/service/SearchService.php similarity index 94% rename from application/service/SearchService.php rename to app/service/SearchService.php index 8704ffccd..8c201477b 100755 --- a/application/service/SearchService.php +++ b/app/service/SearchService.php @@ -10,8 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; -use think\facade\Hook; +use think\facade\Db; use app\service\GoodsService; use app\service\BrandService; use app\service\ResourcesService; @@ -65,7 +64,7 @@ class SearchService // 搜索商品列表读取前钩子 $hook_name = 'plugins_service_search_goods_list_begin'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, @@ -80,7 +79,7 @@ class SearchService ]); // 获取商品总数 - $result['total'] = (int) Db::name('Goods')->alias('g')->join(['__GOODS_CATEGORY_JOIN__'=>'gci'], 'g.id=gci.goods_id')->where($where_base)->where(function($query) use($where_keywords) { + $result['total'] = (int) Db::name('Goods')->alias('g')->join('goods_category_join gci', 'g.id=gci.goods_id')->where($where_base)->where(function($query) use($where_keywords) { self::SearchKeywordsWhereJoinType($query, $where_keywords); })->where(function($query) use($where_screening_price) { $query->whereOr($where_screening_price); @@ -90,11 +89,11 @@ class SearchService if($result['total'] > 0) { // 查询数据 - $data = Db::name('Goods')->alias('g')->join(['__GOODS_CATEGORY_JOIN__'=>'gci'], 'g.id=gci.goods_id')->field($field)->where($where_base)->where(function($query) use($where_keywords) { + $data = Db::name('Goods')->alias('g')->join('goods_category_join gci', 'g.id=gci.goods_id')->field($field)->where($where_base)->where(function($query) use($where_keywords) { self::SearchKeywordsWhereJoinType($query, $where_keywords); })->where(function($query) use($where_screening_price) { $query->whereOr($where_screening_price); - })->group('g.id')->order($order_by)->limit($m, $n)->select(); + })->group('g.id')->order($order_by)->limit($m, $n)->select()->toArray(); // 数据处理 $goods = GoodsService::GoodsDataHandle($data); @@ -144,7 +143,7 @@ class SearchService { // 搜索商品条件处理钩子 $hook_name = 'plugins_service_search_goods_list_where'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, @@ -427,7 +426,7 @@ class SearchService // 一维数组、参数值去重 if(!empty($where_base) || !empty($where_keywords) || !empty($where_screening_price)) { - $ids = Db::name('Goods')->alias('g')->join(['__GOODS_CATEGORY_JOIN__'=>'gci'], 'g.id=gci.goods_id')->where($where_base)->where(function($query) use($where_keywords) { + $ids = Db::name('Goods')->alias('g')->join('goods_category_join gci', 'g.id=gci.goods_id')->where($where_base)->where(function($query) use($where_keywords) { self::SearchKeywordsWhereJoinType($query, $where_keywords); })->where(function($query) use($where_screening_price) { $query->whereOr($where_screening_price); @@ -466,7 +465,7 @@ class SearchService // 查询分类条件处理钩子 $hook_name = 'plugins_service_search_category_list_where'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, @@ -497,7 +496,7 @@ class SearchService $data = []; if(MyC('home_search_is_price', 0) == 1) { - $data = Db::name('ScreeningPrice')->field('id,name,min_price,max_price')->where(['is_enable'=>1])->order('sort asc')->select(); + $data = Db::name('ScreeningPrice')->field('id,name,min_price,max_price')->where(['is_enable'=>1])->order('sort asc')->select()->toArray(); } return $data; } @@ -526,11 +525,11 @@ class SearchService $where_base[] = ['gp.type', 'in', self::SearchParamsWhereTypeValue()]; // 一维数组、参数值去重 - $data = Db::name('Goods')->alias('g')->join(['__GOODS_CATEGORY_JOIN__'=>'gci'], 'g.id=gci.goods_id')->join(['__GOODS_PARAMS__'=>'gp'], 'g.id=gp.goods_id')->where($where_base)->where(function($query) use($where_keywords) { + $data = Db::name('Goods')->alias('g')->join('goods_category_join gci', 'g.id=gci.goods_id')->join('goods_params gp', 'g.id=gp.goods_id')->where($where_base)->where(function($query) use($where_keywords) { self::SearchKeywordsWhereJoinType($query, $where_keywords); })->where(function($query) use($where_screening_price) { $query->whereOr($where_screening_price); - })->group('gp.value')->field('gp.value')->select(); + })->group('gp.value')->field('gp.value')->select()->toArray(); } return $data; } @@ -556,11 +555,11 @@ class SearchService $where_screening_price = $where['screening_price']; // 一维数组、参数值去重 - $data = Db::name('Goods')->alias('g')->join(['__GOODS_CATEGORY_JOIN__'=>'gci'], 'g.id=gci.goods_id')->join(['__GOODS_SPEC_VALUE__'=>'gsv'], 'g.id=gsv.goods_id')->where($where_base)->where(function($query) use($where_keywords) { + $data = Db::name('Goods')->alias('g')->join('goods_category_join gci', 'g.id=gci.goods_id')->join('goods_spec_value gsv', 'g.id=gsv.goods_id')->where($where_base)->where(function($query) use($where_keywords) { self::SearchKeywordsWhereJoinType($query, $where_keywords); })->where(function($query) use($where_screening_price) { $query->whereOr($where_screening_price); - })->group('gsv.value')->field('gsv.value')->select(); + })->group('gsv.value')->field('gsv.value')->select()->toArray(); } return $data; } diff --git a/application/service/SeoService.php b/app/service/SeoService.php similarity index 100% rename from application/service/SeoService.php rename to app/service/SeoService.php diff --git a/application/service/SiteService.php b/app/service/SiteService.php similarity index 99% rename from application/service/SiteService.php rename to app/service/SiteService.php index 1ad2c1ade..f176385ac 100644 --- a/application/service/SiteService.php +++ b/app/service/SiteService.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; +use think\facade\Db; use app\service\GoodsService; /** diff --git a/application/service/SlideService.php b/app/service/SlideService.php similarity index 99% rename from application/service/SlideService.php rename to app/service/SlideService.php index ea1efeaf3..39f4307be 100755 --- a/application/service/SlideService.php +++ b/app/service/SlideService.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; +use think\facade\Db; use app\service\ResourcesService; /** @@ -39,7 +39,7 @@ class SlideService $m = isset($params['m']) ? intval($params['m']) : 0; $n = isset($params['n']) ? intval($params['n']) : 10; - $data = Db::name('Slide')->field($field)->where($where)->order($order_by)->limit($m, $n)->select(); + $data = Db::name('Slide')->field($field)->where($where)->order($order_by)->limit($m, $n)->select()->toArray(); if(!empty($data)) { $common_platform_type = lang('common_platform_type'); diff --git a/application/service/SqlconsoleService.php b/app/service/SqlconsoleService.php similarity index 90% rename from application/service/SqlconsoleService.php rename to app/service/SqlconsoleService.php index 5b040effa..8c10f4503 100755 --- a/application/service/SqlconsoleService.php +++ b/app/service/SqlconsoleService.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; +use think\facade\Db; /** * SQL控制台服务层 @@ -47,8 +47,9 @@ class SqlconsoleService } // 表前缀,编码替换 - $sql = str_replace('{PREFIX}', config('database.prefix'), $params['sql']); - $sql = str_replace('{CHARSET}', config('database.charset'), $sql); + $config = MyConfig('database.connections.mysql'); + $sql = str_replace('{PREFIX}', $config['prefix'], $params['sql']); + $sql = str_replace('{CHARSET}', $config['charset'], $sql); // 转为数组 $sql_all = preg_split("/;[\r\n]+/", $sql); diff --git a/application/service/StatisticalService.php b/app/service/StatisticalService.php similarity index 99% rename from application/service/StatisticalService.php rename to app/service/StatisticalService.php index 7aa9b3810..508865ff6 100755 --- a/application/service/StatisticalService.php +++ b/app/service/StatisticalService.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; +use think\facade\Db; /** * 数据统计服务层 @@ -593,7 +593,7 @@ class StatisticalService { $data = []; } else { - $data = Db::name('OrderDetail')->field('goods_id, sum(buy_number) AS value')->where('order_id', 'IN', $order_ids)->group('goods_id')->order('value desc')->limit(10)->select(); + $data = Db::name('OrderDetail')->field('goods_id, sum(buy_number) AS value')->where('order_id', 'IN', $order_ids)->group('goods_id')->order('value desc')->limit(10)->select()->toArray(); } if(!empty($data)) diff --git a/application/service/StoreService.php b/app/service/StoreService.php similarity index 96% rename from application/service/StoreService.php rename to app/service/StoreService.php index 9f3a7125a..16a0c212b 100644 --- a/application/service/StoreService.php +++ b/app/service/StoreService.php @@ -47,7 +47,7 @@ class StoreService */ public static function StoreUrl($params = []) { - return config('shopxo.store_url').self::RequestParamsString($params); + return MyConfig('shopxo.store_url').self::RequestParamsString($params); } /** @@ -61,7 +61,7 @@ class StoreService */ public static function StorePaymentUrl($params = []) { - return config('shopxo.store_payment_url').self::RequestParamsString($params); + return MyConfig('shopxo.store_payment_url').self::RequestParamsString($params); } /** @@ -75,7 +75,7 @@ class StoreService */ public static function StoreThemeUrl($params = []) { - return config('shopxo.store_theme_url').self::RequestParamsString($params); + return MyConfig('shopxo.store_theme_url').self::RequestParamsString($params); } /** @@ -106,7 +106,7 @@ class StoreService */ public static function SiteStoreInfo() { - $res = cache(self::$site_store_info_key); + $res = MyCache(self::$site_store_info_key); return empty($res) ? [] : $res; } @@ -181,7 +181,7 @@ class StoreService { // 存储缓存、取远程给的时间,未拿到时间则默认60分钟 $cache_time = (empty($res['data']['base']) || empty($res['data']['base']['cache_time'])) ? 3600 : intval($res['data']['base']['cache_time']); - cache(self::$site_store_info_key, $res['data'], $cache_time); + MyCache(self::$site_store_info_key, $res['data'], $cache_time); return DataReturn('绑定成功', 0); } @@ -288,11 +288,11 @@ class StoreService // http状态验证 $key = 'cache_store_url_http_code'; $time = 600; - $code = cache($key); + $code = MyCache($key); if($code == null) { $code = GetHttpCode(self::StoreUrl(), 2); - cache($key, $code, $time); + MyCache($key, $code, $time); } if($code != 200) { @@ -327,7 +327,7 @@ class StoreService if(empty($result)) { // 网络不通、返回非有效json数据则认为网络不通 - cache($key, 0, $time); + MyCache($key, 0, $time); return DataReturn('商店网络不通', 0); } diff --git a/application/service/SystemBaseService.php b/app/service/SystemBaseService.php similarity index 97% rename from application/service/SystemBaseService.php rename to app/service/SystemBaseService.php index 21e29144b..d45747a3c 100644 --- a/application/service/SystemBaseService.php +++ b/app/service/SystemBaseService.php @@ -10,8 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; -use think\facade\Hook; +use think\facade\Db; use app\service\ResourcesService; use app\service\QuickNavService; use app\service\PluginsService; @@ -200,7 +199,7 @@ class SystemBaseService // 公共配置信息钩子 $hook_name = 'plugins_service_base_commin'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'data' => &$data, @@ -251,13 +250,13 @@ class SystemBaseService public static function DataReturn($data = []) { // 当前操作名称, 兼容插件模块名称 - $module_name = strtolower(request()->module()); - $controller_name = strtolower(request()->controller()); - $action_name = strtolower(request()->action()); + $module_name = RequestModule(); + $controller_name = RequestController(); + $action_name = RequestAction(); // 钩子 $hook_name = 'plugins_service_base_data_return_'.$module_name.'_'.$controller_name.'_'.$action_name; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'data' => &$data, @@ -282,7 +281,7 @@ class SystemBaseService // 钩子 $hook_name = 'plugins_service_base_site_type_value'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'value' => &$value, @@ -340,7 +339,7 @@ class SystemBaseService { $data[] = $plugins; } - session($key, $data); + MySession($key, $data); } else { if($index !== false) { @@ -349,7 +348,7 @@ class SystemBaseService } } - session($key, empty($data) ? null : $data); + MySession($key, empty($data) ? null : $data); return true; } @@ -364,7 +363,7 @@ class SystemBaseService */ public static function GetGoodsDiscountRecord($goods_id) { - $res = session(self::$plugins_goods_discount_record_key.$goods_id); + $res = MySession(self::$plugins_goods_discount_record_key.$goods_id); return empty($res) ? [] : $res; } @@ -485,7 +484,7 @@ class SystemBaseService */ public static function AttachmentHost() { - return config('shopxo.attachment_host'); + return MyConfig('shopxo.attachment_host'); } } ?> \ No newline at end of file diff --git a/application/service/SystemService.php b/app/service/SystemService.php similarity index 76% rename from application/service/SystemService.php rename to app/service/SystemService.php index 48eb6ced1..901d8c65d 100644 --- a/application/service/SystemService.php +++ b/app/service/SystemService.php @@ -10,8 +10,6 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\facade\Hook; - /** * 配置服务层 * @author Devil @@ -33,7 +31,7 @@ class SystemService public static function SystemBegin($params = []) { $hook_name = 'plugins_service_system_begin'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, @@ -52,11 +50,28 @@ class SystemService public static function SystemEnd($params = []) { $hook_name = 'plugins_service_system_end'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, ]); } + + /** + * 系统安装检查 + * @author Devil + * @blog http://gong.gg/ + * @version 1.0.0 + * @date 2021-07-18 + * @desc description + * @param [array] $params [输入参数] + */ + public static function SystemInstallCheck($params = []) + { + if(!file_exists(ROOT.'config/database.php')) + { + MyRedirect(__MY_URL__.'install.php?s=index/index', true); + } + } } ?> \ No newline at end of file diff --git a/application/service/SystemUpgradeService.php b/app/service/SystemUpgradeService.php similarity index 95% rename from application/service/SystemUpgradeService.php rename to app/service/SystemUpgradeService.php index c2cf35c67..ccac3fde2 100644 --- a/application/service/SystemUpgradeService.php +++ b/app/service/SystemUpgradeService.php @@ -85,14 +85,14 @@ class SystemUpgradeService public static function UpgradeHandle($params = []) { // 系统包 - $system_url = session(self::$package_system_dir_key); + $system_url = MySession(self::$package_system_dir_key); if(empty($system_url) || !file_exists($system_url)) { return DataReturn('系统包不存在、请重新下载', -1); } // 升级包 - $upgrade_url = session(self::$package_upgrade_dir_key); + $upgrade_url = MySession(self::$package_upgrade_dir_key); if(empty($upgrade_url) || !file_exists($upgrade_url)) { return DataReturn('升级包不存在、请重新下载', -1); @@ -113,9 +113,9 @@ class SystemUpgradeService } // 移除session - session(self::$package_url_key, null); - session(self::$package_system_dir_key, null); - session(self::$package_upgrade_dir_key, null); + MySession(self::$package_url_key, null); + MySession(self::$package_system_dir_key, null); + MySession(self::$package_upgrade_dir_key, null); // 删除本地文件 \base\FileUtil::UnlinkFile($system_url); @@ -246,7 +246,7 @@ class SystemUpgradeService public static function DownloadHandle($params = []) { // 获取下载地址 - $data = session(self::$package_url_key); + $data = MySession(self::$package_url_key); if(empty($data) || !is_array($data) || empty($data[$params['opt']])) { return DataReturn('下载地址为空', -1); @@ -264,7 +264,7 @@ class SystemUpgradeService if(@file_put_contents($res['url'], RequestGet($url, 300000)) !== false) { // 存储已下载文件地址session - session(self::SaveDirPathUrl($params['opt']), $res['url']); + MySession(self::SaveDirPathUrl($params['opt']), $res['url']); return DataReturn('success', 0); } return DataReturn('包下载失败', -1); @@ -311,7 +311,7 @@ class SystemUpgradeService $ret = StoreService::RemoteStoreData($accounts, $password, self::$store_plugins_upgrade_url, $params); if(!empty($ret) && isset($ret['code']) && $ret['code'] == 0) { - session(self::$package_url_key, $ret['data']); + MySession(self::$package_url_key, $ret['data']); return DataReturn('获取成功', 0); } return $ret; diff --git a/application/service/ThemeService.php b/app/service/ThemeService.php similarity index 99% rename from application/service/ThemeService.php rename to app/service/ThemeService.php index 72073b7cf..3910b8e8f 100755 --- a/application/service/ThemeService.php +++ b/app/service/ThemeService.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; +use think\facade\Db; use app\service\ResourcesService; /** @@ -300,7 +300,7 @@ class ThemeService } // 是否开启开发者模式 - if(config('shopxo.is_develop') !== true) + if(MyConfig('shopxo.is_develop') !== true) { return DataReturn('请先开启开发者模式', -1); } diff --git a/application/service/UeditorService.php b/app/service/UeditorService.php similarity index 99% rename from application/service/UeditorService.php rename to app/service/UeditorService.php index 29006289b..cac6fe3ee 100644 --- a/application/service/UeditorService.php +++ b/app/service/UeditorService.php @@ -40,7 +40,7 @@ class UeditorService { // 配置信息 self::$params = $params; - self::$current_config = config('ueditor.'); + self::$current_config = MyConfig('ueditor'); self::$current_action = isset($params['action']) ? $params['action'] : ''; self::$path_type = isset($params['path_type']) ? $params['path_type'] : PathToParams('path_type', 'other'); diff --git a/application/service/UserAddressService.php b/app/service/UserAddressService.php similarity index 98% rename from application/service/UserAddressService.php rename to app/service/UserAddressService.php index 64940ed2f..690cf8193 100644 --- a/application/service/UserAddressService.php +++ b/app/service/UserAddressService.php @@ -10,8 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; -use think\facade\Hook; +use think\facade\Db; use app\service\RegionService; use app\service\ResourcesService; @@ -42,7 +41,7 @@ class UserAddressService $n = isset($params['n']) ? intval($params['n']) : 10; // 获取列表 - $data = self::DataHandle(Db::name('UserAddress')->where($where)->order($order_by)->limit($m, $n)->select(), 0); + $data = self::DataHandle(Db::name('UserAddress')->where($where)->order($order_by)->limit($m, $n)->select()->toArray(), 0); return DataReturn('处理成功', 0, $data); } @@ -188,7 +187,7 @@ class UserAddressService // 获取用户地址 $field = 'id,alias,name,tel,province,city,county,address,lng,lat,is_default,idcard_name,idcard_number,idcard_front,idcard_back'; - $data = self::DataHandle(Db::name('UserAddress')->where($where)->field($field)->order('id desc')->select()); + $data = self::DataHandle(Db::name('UserAddress')->where($where)->field($field)->order('id desc')->select()->toArray()); if(!empty($data)) { $is_default = false; @@ -211,7 +210,7 @@ class UserAddressService // 用户地址列表钩子 $hook_name = 'plugins_service_user_address_list'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => $params, @@ -309,7 +308,7 @@ class UserAddressService // 用户默认地址钩子 $hook_name = 'plugins_service_user_address_default_row'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => $params, @@ -373,7 +372,7 @@ class UserAddressService // 用户地址保存前钩子 $hook_name = 'plugins_service_user_address_save_begin'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => $params, @@ -423,7 +422,7 @@ class UserAddressService // 用户地址保存后钩子 $hook_name = 'plugins_service_user_address_save_end'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => $params, @@ -524,7 +523,7 @@ class UserAddressService { // 用户地址删除钩子 $hook_name = 'plugins_service_user_address_delete'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => $params, @@ -578,7 +577,7 @@ class UserAddressService { // 用户地址删除钩子 $hook_name = 'plugins_service_user_address_default'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => $params, diff --git a/application/service/UserService.php b/app/service/UserService.php similarity index 98% rename from application/service/UserService.php rename to app/service/UserService.php index 755c42036..3359093c6 100755 --- a/application/service/UserService.php +++ b/app/service/UserService.php @@ -10,8 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; -use think\facade\Hook; +use think\facade\Db; use app\service\RegionService; use app\service\SafetyService; use app\service\ResourcesService; @@ -27,7 +26,7 @@ use app\service\SystemBaseService; class UserService { // user登录session key - public static $user_login_key = 'user_login'; + public static $user_login_key = 'user_login_info'; /** * 获取用户登录信息 @@ -47,7 +46,7 @@ class UserService if(APPLICATION == 'web') { // web用户session - $user = session(self::$user_login_key); + $user = MySession(self::$user_login_key); // 用户信息为空,指定了token则设置登录信息 if(empty($user) && !empty($params['token'])) @@ -79,7 +78,7 @@ class UserService */ private static function UserTokenData($token) { - $user = cache(config('shopxo.cache_user_info').$token); + $user = MyCache(MyConfig('shopxo.cache_user_info').$token); if($user !== null && isset($user['id'])) { return $user; @@ -137,7 +136,7 @@ class UserService $n = isset($params['n']) ? intval($params['n']) : 10; // 获取用户列表 - $data = Db::name('User')->where($where)->order($order_by)->field($field)->limit($m, $n)->select(); + $data = Db::name('User')->where($where)->order($order_by)->field($field)->limit($m, $n)->select()->toArray(); if(!empty($data)) { $common_gender_list = lang('common_gender_list'); @@ -311,7 +310,7 @@ class UserService // 用户保存处理钩子 $hook_name = 'plugins_service_user_save_handle'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, @@ -352,7 +351,7 @@ class UserService // 添加用户后处理钩子 $hook_name = 'plugins_service_user_save_success_handle'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, @@ -435,7 +434,7 @@ class UserService // 用户登录成功信息纪录钩子 $hook_name = 'plugins_service_user_login_success_record'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'user' => &$user, @@ -446,8 +445,8 @@ class UserService if(APPLICATION == 'web') { // 存储session - session(self::$user_login_key, $user); - return (session(self::$user_login_key) !== null); + MySession(self::$user_login_key, $user); + return (MySession(self::$user_login_key) !== null); } return true; } @@ -514,7 +513,7 @@ class UserService { $user['avatar'] = ResourcesService::AttachmentPathViewHandle($user['avatar']); } else { - $user['avatar'] = SystemBaseService::AttachmentHost().'/static/index/'.strtolower(config('DEFAULT_THEME', 'default')).'/images/default-user-avatar.jpg'; + $user['avatar'] = SystemBaseService::AttachmentHost().'/static/index/'.strtolower(MyFileConfig('common_default_theme', '', 'default', true)).'/images/default-user-avatar.jpg'; } // 移除特殊数据 @@ -627,7 +626,7 @@ class UserService { // 用户登录前校验钩子 $hook_name = 'plugins_service_user_login_begin_check'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, @@ -770,7 +769,7 @@ class UserService // 用户登录前钩子 $hook_name = 'plugins_service_user_login_begin'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, @@ -825,7 +824,7 @@ class UserService // 用户登录后钩子 $user = Db::name('User')->field('id,username,nickname,mobile,email,gender,avatar,province,city,birthday')->where(['id'=>$user_id])->find(); $hook_name = 'plugins_service_user_login_end'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, @@ -896,7 +895,7 @@ class UserService // 用户注册前校验钩子 $hook_name = 'plugins_service_user_register_begin_check'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, @@ -1908,7 +1907,7 @@ class UserService // 用户信息钩子 $hook_name = 'plugins_service_user_app_info_handle'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'user_id' => $user_id, @@ -1944,7 +1943,7 @@ class UserService $user['token'] = self::CreatedUserToken($user_id); if(Db::name('User')->where(['id'=>$user_id])->update(['token'=>$user['token'], 'upd_time'=>time()])) { - cache(config('shopxo.cache_user_info').$user['token'], $user); + MyCache(MyConfig('shopxo.cache_user_info').$user['token'], $user); } // web端用户登录纪录处理 @@ -2037,7 +2036,7 @@ class UserService // 清除推荐id if(isset($data['referrer'])) { - session('share_referrer_id', null); + MySession('share_referrer_id', null); } // 返回前端html代码 @@ -2046,7 +2045,7 @@ class UserService // 注册成功后钩子 $user = Db::name('User')->field('id,username,nickname,mobile,email,gender,avatar,province,city,birthday')->where(['id'=>$user_id])->find(); $hook_name = 'plugins_service_user_register_end'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, @@ -2102,7 +2101,7 @@ class UserService // 用户手机绑定前校验钩子 $hook_name = 'plugins_service_user_app_mobile_bind_begin_check'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, @@ -2345,14 +2344,14 @@ class UserService $user = self::LoginUserInfo(); // 清除session - session(self::$user_login_key, null); + MySession(self::$user_login_key, null); // html代码 $body_html = []; // 用户退出钩子 $hook_name = 'plugins_service_user_logout_handle'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => [], @@ -2428,7 +2427,7 @@ class UserService public static function UserEntranceLeftData($params = []) { // 从缓存获取 - $data = empty($params['cache_key']) ? [] : cache($params['cache_key']); + $data = empty($params['cache_key']) ? [] : MyCache($params['cache_key']); // 获取数据 if(empty($data)) @@ -2454,7 +2453,7 @@ class UserService // 存储缓存 if(!empty($params['cache_key'])) { - cache($params['cache_key'], $data); + MyCache($params['cache_key'], $data); } } } @@ -2487,7 +2486,7 @@ class UserService public static function UserReferrerDecrypt($params = []) { // 推荐人 - $referrer = empty($params['referrer']) ? session('share_referrer_id') : $params['referrer']; + $referrer = empty($params['referrer']) ? MySession('share_referrer_id') : $params['referrer']; // 查看用户id是否已加密 if(preg_match('/[a-zA-Z]/', $referrer)) diff --git a/application/service/WarehouseGoodsService.php b/app/service/WarehouseGoodsService.php similarity index 98% rename from application/service/WarehouseGoodsService.php rename to app/service/WarehouseGoodsService.php index cc1331018..1965921d8 100644 --- a/application/service/WarehouseGoodsService.php +++ b/app/service/WarehouseGoodsService.php @@ -10,8 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; -use think\facade\Hook; +use think\facade\Db; use app\service\ResourcesService; use app\service\GoodsService; use app\service\UserService; @@ -44,7 +43,7 @@ class WarehouseGoodsService $n = isset($params['n']) ? intval($params['n']) : 10; $order_by = empty($params['order_by']) ? 'id desc' : trim($params['order_by']); - $data = Db::name('WarehouseGoods')->field($field)->where($where)->order($order_by)->limit($m, $n)->select(); + $data = Db::name('WarehouseGoods')->field($field)->where($where)->order($order_by)->limit($m, $n)->select()->toArray(); return DataReturn('处理成功', 0, self::DataHandle($data)); } @@ -759,7 +758,7 @@ class WarehouseGoodsService } // 获取商品仓库 - $warehouse_goods = Db::name('WarehouseGoods')->where(['goods_id'=>$goods_id])->select(); + $warehouse_goods = Db::name('WarehouseGoods')->where(['goods_id'=>$goods_id])->select()->toArray(); if(!empty($warehouse_goods)) { // 循环根据仓库处理库存 @@ -859,7 +858,7 @@ class WarehouseGoodsService // 商品仓库库存修改钩子 $hook_name = 'plugins_service_warehouse_goods_inventory_sync'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'goods_id' => $goods_id @@ -948,7 +947,7 @@ class WarehouseGoodsService { return DataReturn('仓库商品规格库存不足['.$warehouse_id.'-'.$goods_id.'('.$inventory.'<'.$buy_number.')]', -11); } - if(!Db::name('WarehouseGoodsSpec')->where($where)->setDec('inventory', $buy_number)) + if(!Db::name('WarehouseGoodsSpec')->where($where)->dec('inventory', $buy_number)) { return DataReturn('仓库商品规格库存扣减失败['.$warehouse_id.'-'.$goods_id.'('.$buy_number.')]', -11); } @@ -960,14 +959,14 @@ class WarehouseGoodsService { return DataReturn('仓库商品库存不足['.$warehouse_id.'-'.$goods_id.'('.$inventory.'<'.$buy_number.')]', -11); } - if(!Db::name('WarehouseGoods')->where($where)->setDec('inventory', $buy_number)) + if(!Db::name('WarehouseGoods')->where($where)->dec('inventory', $buy_number)) { return DataReturn('仓库商品库存扣减失败['.$warehouse_id.'-'.$goods_id.'('.$buy_number.')]', -12); } // 商品库存扣除钩子 $hook_name = 'plugins_service_warehouse_goods_inventory_deduct'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'order_id' => $order_id, @@ -1018,21 +1017,21 @@ class WarehouseGoodsService // 扣除仓库商品规格库存 $where = ['warehouse_id'=>$warehouse_id, 'goods_id'=>$goods_id, 'md5_key'=>$md5_key]; - if(!Db::name('WarehouseGoodsSpec')->where($where)->setInc('inventory', $buy_number)) + if(!Db::name('WarehouseGoodsSpec')->where($where)->inc('inventory', $buy_number)) { return DataReturn('仓库商品规格库存回滚失败['.$warehouse_id.'-'.$goods_id.'('.$buy_number.')]', -11); } // 扣除仓库商品库存 $where = ['warehouse_id'=>$warehouse_id, 'goods_id'=>$goods_id]; - if(!Db::name('WarehouseGoods')->where($where)->setInc('inventory', $buy_number)) + if(!Db::name('WarehouseGoods')->where($where)->inc('inventory', $buy_number)) { return DataReturn('仓库商品库存回滚失败['.$warehouse_id.'-'.$goods_id.'('.$buy_number.')]', -12); } // 商品库存回滚钩子 $hook_name = 'plugins_service_warehouse_goods_inventory_rollback'; - $ret = HookReturnHandle(Hook::listen($hook_name, [ + $ret = EventReturnHandle(MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'order_id' => $order_id, diff --git a/application/service/WarehouseService.php b/app/service/WarehouseService.php similarity index 98% rename from application/service/WarehouseService.php rename to app/service/WarehouseService.php index bf40d3076..38a48ee4b 100644 --- a/application/service/WarehouseService.php +++ b/app/service/WarehouseService.php @@ -10,8 +10,7 @@ // +---------------------------------------------------------------------- namespace app\service; -use think\Db; -use think\facade\Hook; +use think\facade\Db; use app\service\RegionService; use app\service\WarehouseGoodsService; use app\service\SystemBaseService; @@ -40,7 +39,7 @@ class WarehouseService $where = empty($params['where']) ? [] : $params['where']; $field = empty($params['field']) ? '*' : $params['field']; $order_by = empty($params['order_by']) ? 'level desc, id desc' : trim($params['order_by']); - $data = Db::name('Warehouse')->field($field)->where($where)->order($order_by)->select(); + $data = Db::name('Warehouse')->field($field)->where($where)->order($order_by)->select()->toArray(); return DataReturn('处理成功', 0, self::DataHandle($data, $params)); } @@ -86,7 +85,7 @@ class WarehouseService // 仓库处理前钩子 $hook_name = 'plugins_service_warehouse_handle_inside_begin'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, @@ -124,7 +123,7 @@ class WarehouseService // 仓库处理后钩子 $hook_name = 'plugins_service_warehouse_handle_inside_end'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, @@ -135,7 +134,7 @@ class WarehouseService // 仓库处理列表钩子 $hook_name = 'plugins_service_warehouse_handle_end'; - Hook::listen($hook_name, [ + MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => true, 'params' => &$params, @@ -399,7 +398,7 @@ class WarehouseService public static function WarehouseIdsAllList($ids) { $result = []; - $data = Db::name('Warehouse')->field('id,name,is_enable,is_delete_time')->where(['id'=>array_unique($ids)])->select(); + $data = Db::name('Warehouse')->field('id,name,is_enable,is_delete_time')->where(['id'=>array_unique($ids)])->select()->toArray(); if(!empty($data)) { foreach($data as $v) diff --git a/application/service/index.html b/app/service/index.html similarity index 100% rename from application/service/index.html rename to app/service/index.html diff --git a/application/admin/config/app.php b/application/admin/config/app.php deleted file mode 100755 index 1d19d91b5..000000000 --- a/application/admin/config/app.php +++ /dev/null @@ -1,40 +0,0 @@ - 'html', - - // 默认AJAX 数据返回格式,可选json xml ... - 'default_ajax_return' => 'json', - - // 缓存key列表 - // 权限缓存存储key - 'cache_admin_power_key' => 'cache_admin_power_', - - // 菜单列表 - 'cache_admin_left_menu_key' => 'cache_admin_left_menu_', - - // URL模式 - 'URL_MODEL' => 0, - - // 设置默认的模板主题 - 'DEFAULT_THEME' => 'Default', -]; -?> \ No newline at end of file diff --git a/application/admin/view/default/public/jump_error.html b/application/admin/view/default/public/jump_error.html deleted file mode 100755 index 202650ddc..000000000 --- a/application/admin/view/default/public/jump_error.html +++ /dev/null @@ -1,45 +0,0 @@ - - - - -跳转提示 - - - -
- -

:)

-

- -

:(

-

-{{/if}} -

-

-页面自动 跳转 等待时间: -

-
- - - \ No newline at end of file diff --git a/application/admin/view/default/public/jump_success.html b/application/admin/view/default/public/jump_success.html deleted file mode 100755 index 202650ddc..000000000 --- a/application/admin/view/default/public/jump_success.html +++ /dev/null @@ -1,45 +0,0 @@ - - - - -跳转提示 - - - -
- -

:)

-

- -

:(

-

-{{/if}} -

-

-页面自动 跳转 等待时间: -

-
- - - \ No newline at end of file diff --git a/application/http/middleware/SystemEnvCheck.php b/application/http/middleware/SystemEnvCheck.php deleted file mode 100755 index 8959e671d..000000000 --- a/application/http/middleware/SystemEnvCheck.php +++ /dev/null @@ -1,69 +0,0 @@ -EnvironmentCheck(); - if($ret['code'] != 0) - { - exit(json_encode($ret)); - } - - return $next($request); - } - - /** - * 环境校验 - * @author Devil - * @blog http://gong.gg/ - * @version 1.0.0 - * @date 2018-12-07 - * @desc description - */ - public function EnvironmentCheck() - { - if(IS_AJAX) - { - // 请求参数数量校验是否超出php.ini限制 - $max_input_vars = intval(ini_get('max_input_vars'))-5; - $params_counbt = count(input('post.')); - if($params_counbt >= $max_input_vars) - { - return DataReturn('请求参数数量已超出php.ini限制[max_input_vars]', -1000); - } - } - - return DataReturn('success', 0); - } -} -?> \ No newline at end of file diff --git a/application/index/config/app.php b/application/index/config/app.php deleted file mode 100755 index 41cf10a8f..000000000 --- a/application/index/config/app.php +++ /dev/null @@ -1,32 +0,0 @@ - 'html', - - // 默认AJAX 数据返回格式,可选json xml ... - 'default_ajax_return' => 'json', - - // 默认JSONP格式返回的处理方法 - 'default_jsonp_handler' => 'jsonpReturn', - - // 伪静态后缀 - 'url_html_suffix' => MyFileConfig('home_seo_url_html_suffix', '', 'html', true), -]; -?> \ No newline at end of file diff --git a/application/index/controller/Common.php b/application/index/controller/Common.php deleted file mode 100755 index 39b8137bd..000000000 --- a/application/index/controller/Common.php +++ /dev/null @@ -1,545 +0,0 @@ -data_post = input('post.'); - $this->data_get = input('get.'); - $this->data_request = input(); - - // 系统初始化 - $this->SystemInit(); - - // 系统运行开始 - SystemService::SystemBegin($this->data_request); - - // 站点状态校验 - $this->SiteStstusCheck(); - - // 公共数据初始化 - $this->CommonInit(); - - // 菜单 - $this->NavInit(); - - // 视图初始化 - $this->ViewInit(); - - // 动态表格初始化 - $this->FormTableInit(); - - // 公共钩子初始化 - $this->CommonPluginsInit(); - } - - /** - * 析构函数 - * @author Devil - * @blog http://gong.gg/ - * @version 1.0.0 - * @date 2019-03-18 - * @desc description - */ - public function __destruct() - { - // 系统运行结束 - SystemService::SystemEnd($this->data_request); - } - - /** - * 公共钩子初始化 - * @author Devil - * @blog http://gong.gg/ - * @version 1.0.0 - * @date 2018-12-07 - * @desc description - */ - private function CommonPluginsInit() - { - // css钩子 - $this->assign('plugins_css_data', Hook::listen('plugins_css', ['hook_name'=>'plugins_css', 'is_backend'=>false])); - - // js钩子 - $this->assign('plugins_js_data', Hook::listen('plugins_js', ['hook_name'=>'plugins_js', 'is_backend'=>false])); - - // 公共header内钩子 - $this->assign('plugins_common_header_data', Hook::listen('plugins_common_header', ['hook_name'=>'plugins_common_header', 'is_backend'=>false, 'user'=>$this->user])); - - // 公共页面底部钩子 - $this->assign('plugins_common_page_bottom_data', Hook::listen('plugins_common_page_bottom', ['hook_name'=>'plugins_common_page_bottom', 'is_backend'=>false, 'user'=>$this->user])); - - // 公共顶部钩子 - $this->assign('plugins_view_common_top_data', Hook::listen('plugins_view_common_top', ['hook_name'=>'plugins_view_common_top', 'is_backend'=>false, 'user'=>$this->user])); - - // 公共底部钩子 - $this->assign('plugins_view_common_bottom_data', Hook::listen('plugins_view_common_bottom', ['hook_name'=>'plugins_view_common_bottom', 'is_backend'=>false, 'user'=>$this->user])); - - // 公共顶部小导航钩子-左侧前面 - $this->assign('plugins_view_header_navigation_top_left_begin_data', Hook::listen('plugins_view_header_navigation_top_left_begin', ['hook_name'=>'plugins_view_header_navigation_top_left_begin', 'is_backend'=>false, 'user'=>$this->user])); - - // 公共顶部小导航钩子-左侧后面 - $this->assign('plugins_view_header_navigation_top_left_end_data', Hook::listen('plugins_view_header_navigation_top_left_end', ['hook_name'=>'plugins_view_header_navigation_top_left_end', 'is_backend'=>false, 'user'=>$this->user])); - - // 公共顶部小导航钩子-右侧前面 - $this->assign('plugins_view_header_navigation_top_right_begin_data', Hook::listen('plugins_view_header_navigation_top_right_begin', ['hook_name'=>'plugins_view_header_navigation_top_right_begin', 'is_backend'=>false, 'user'=>$this->user])); - - // 公共顶部小导航钩子-右侧后面 - $this->assign('plugins_view_header_navigation_top_right_end_data', Hook::listen('plugins_view_header_navigation_top_right_end', ['hook_name'=>'plugins_view_header_navigation_top_right_end', 'is_backend'=>false, 'user'=>$this->user])); - - // 用户登录页面顶部钩子 - $this->assign('plugins_view_user_login_info_top_data', Hook::listen('plugins_view_user_login_info_top', ['hook_name'=>'plugins_view_user_login_info_top', 'is_backend'=>false, 'user'=>$this->user])); - - // 用户登录内底部钩子 - $this->assign('plugins_view_user_login_inside_bottom_data', Hook::listen('plugins_view_user_login_inside_bottom', ['hook_name'=>'plugins_view_user_login_inside_bottom', 'is_backend'=>false, 'user'=>$this->user])); - - // 用户登录内容页面底部钩子 - $this->assign('plugins_view_user_login_content_bottom_data', Hook::listen('plugins_view_user_login_content_bottom', ['hook_name'=>'plugins_view_user_login_content_bottom', 'is_backend'=>false, 'user'=>$this->user])); - - // 用户注册页面钩子 - $this->assign('plugins_view_user_reg_info_data', Hook::listen('plugins_view_user_reg_info', ['hook_name'=>'plugins_view_user_reg_info', 'is_backend'=>false, 'user'=>$this->user])); - - // 用户注册页面顶部钩子 - $this->assign('plugins_view_user_reg_info_top_data', Hook::listen('plugins_view_user_reg_info_top', ['hook_name'=>'plugins_view_user_reg_info_top', 'is_backend'=>false, 'user'=>$this->user])); - - // 用户注册页面内底部钩子 - $this->assign('plugins_view_user_reg_info_inside_bottom_data', Hook::listen('plugins_view_user_reg_info_inside_bottom', ['hook_name'=>'plugins_view_user_reg_info_inside_bottom', 'is_backend'=>false, 'user'=>$this->user])); - - // 用户注册页面底部钩子 - $this->assign('plugins_view_user_reg_info_bottom_data', Hook::listen('plugins_view_user_reg_info_bottom', ['hook_name'=>'plugins_view_user_reg_info_bottom', 'is_backend'=>false, 'user'=>$this->user])); - - // 底部导航上面钩子 - $this->assign('plugins_view_common_footer_top_data', Hook::listen('plugins_view_common_footer_top', ['hook_name'=>'plugins_view_common_footer_top', 'is_backend'=>false, 'user'=>$this->user])); - - // logo右侧 - $this->assign('plugins_view_common_logo_right_data', Hook::listen('plugins_view_common_logo_right', ['hook_name'=>'plugins_view_common_logo_right', 'is_backend'=>false, 'user'=>$this->user])); - - // 公共搜索框右侧 - $this->assign('plugins_view_common_search_right_data', Hook::listen('plugins_view_common_search_right', ['hook_name'=>'plugins_view_common_search_right', 'is_backend'=>false, 'user'=>$this->user])); - - // 公共表格钩子名称动态处理 - $current = 'plugins_view_index_'.$this->controller_name; - - // 是否插件默认下 - if($this->controller_name == 'plugins') - { - if(!empty($this->data_request['pluginsname'])) - { - $current .= '_'.trim($this->data_request['pluginsname']); - } - } - - // 内容外部顶部 - $this->assign('hook_name_content_top', $current.'_content_top'); - // 内容外部底部 - $this->assign('hook_name_content_bottom', $current.'_content_bottom'); - // 内容内部顶部 - $this->assign('hook_name_content_inside_top', $current.'_content_inside_top'); - // 内容内部底部 - $this->assign('hook_name_content_inside_bottom', $current.'_content_inside_bottom'); - // 表格列表顶部操作 - $this->assign('hook_name_form_top_operate', $current.'_top_operate'); - // 表格列表底部操作 - $this->assign('hook_name_form_bottom_operate', $current.'_bottom_operate'); - // 表格列表后面操作栏 - $this->assign('hook_name_form_list_operate', $current.'_list_operate'); - - // 公共详情页面钩子名称动态处理 - // 内容外部顶部 - $this->assign('hook_name_detail_top', $current.'_detail_top'); - // 内容外部底部 - $this->assign('hook_name_detail_bottom', $current.'_detail_bottom'); - // 内容内部顶部 - $this->assign('hook_name_detail_inside_top', $current.'_detail_inside_top'); - // 内容内部底部 - $this->assign('hook_name_detail_inside_bottom', $current.'_detail_inside_bottom'); - } - - /** - * 系统初始化 - * @author Devil - * @blog http://gong.gg/ - * @version 1.0.0 - * @date 2018-12-07 - * @desc description - */ - private function SystemInit() - { - // 配置信息初始化 - ConfigService::ConfigInit(); - - // url模式 - if(MyC('home_seo_url_model', 0) == 0) - { - \think\facade\Url::root(__MY_ROOT_PUBLIC__.'index.php?s='); - } - - // 推荐人 - if(!empty($this->data_request['referrer'])) - { - session('share_referrer_id', $this->data_request['referrer']); - } - } - - /** - * [CommonInit 公共数据初始化] - * @author Devil - * @blog http://gong.gg/ - * @version 0.0.1 - * @datetime 2017-03-09T11:43:48+0800 - */ - private function CommonInit() - { - // 用户数据 - $this->user = UserService::LoginUserInfo(); - } - - /** - * [IsLogin 登录校验] - * @author Devil - * @blog http://gong.gg/ - * @version 0.0.1 - * @datetime 2017-03-09T11:43:48+0800 - */ - protected function IsLogin() - { - if(empty($this->user)) - { - if(IS_AJAX) - { - exit(json_encode(DataReturn('登录失效,请重新登录', -400))); - } else { - return $this->redirect('index/user/logininfo'); - } - } - } - - /** - * [ViewInit 视图初始化] - * @author Devil - * @blog http://gong.gg/ - * @version 0.0.1 - * @datetime 2016-12-03T12:30:06+0800 - */ - public function ViewInit() - { - // 公共参数 - $this->assign('params', $this->data_request); - - // 货币符号 - $this->assign('currency_symbol', ResourcesService::CurrencyDataSymbol()); - - // 站点类型 - $this->assign('common_site_type', SystemBaseService::SiteTypeValue()); - - // 预约模式 - $this->assign('common_order_is_booking', MyC('common_order_is_booking', 0, true)); - - // 商店信息 - $this->assign('common_customer_store_tel', MyC('common_customer_store_tel')); - $this->assign('common_customer_store_email', MyC('common_customer_store_email')); - $this->assign('common_customer_store_address', MyC('common_customer_store_address')); - $this->assign('common_customer_store_qrcode', AttachmentPathViewHandle(MyC('common_customer_store_qrcode'))); - - // 主题 - $default_theme = strtolower(MyC('common_default_theme', 'default', true)); - $this->assign('default_theme', $default_theme); - - // 当前操作名称, 兼容插件模块名称 - $this->module_name = strtolower(request()->module()); - $this->controller_name = strtolower(request()->controller()); - $this->action_name = strtolower(request()->action()); - - // 当前操作名称 - $this->assign('module_name', $this->module_name); - $this->assign('controller_name', $this->controller_name); - $this->assign('action_name', $this->action_name); - - // 分页信息 - $this->page = max(1, isset($this->data_request['page']) ? intval($this->data_request['page']) : 1); - $this->page_size = MyC('common_page_size', 10, true); - $this->assign('page', $this->page); - $this->assign('page_size', $this->page_size); - - // 控制器静态文件状态css,js - $module_css = $this->module_name.DS.$default_theme.DS.'css'.DS.$this->controller_name; - $module_css .= file_exists(ROOT_PATH.'static'.DS.$module_css.'.'.$this->action_name.'.css') ? '.'.$this->action_name.'.css' : '.css'; - $this->assign('module_css', file_exists(ROOT_PATH.'static'.DS.$module_css) ? $module_css : ''); - - $module_js = $this->module_name.DS.$default_theme.DS.'js'.DS.$this->controller_name; - $module_js .= file_exists(ROOT_PATH.'static'.DS.$module_js.'.'.$this->action_name.'.js') ? '.'.$this->action_name.'.js' : '.js'; - $this->assign('module_js', file_exists(ROOT_PATH.'static'.DS.$module_js) ? $module_js : ''); - - // 导航 - $this->assign('nav_header', $this->nav_header); - $this->assign('nav_footer', $this->nav_footer); - $this->assign('nav_quick', $this->nav_quick); - - // 导航/底部默认显示 - $this->assign('is_header', 1); - $this->assign('is_footer', 1); - - // 价格正则 - $this->assign('default_price_regex', lang('common_regex_price')); - - // 附件host地址 - $this->assign('attachment_host', SystemBaseService::AttachmentHost()); - - // css/js引入host地址 - $this->assign('public_host', config('shopxo.public_host')); - - // 当前url地址 - $this->assign('my_url', __MY_URL__); - - // 项目public目录URL地址 - $this->assign('my_public_url', __MY_PUBLIC_URL__); - - // 当前http类型 - $this->assign('my_http', __MY_HTTP__); - - // seo - $this->assign('home_seo_site_title', MyC('home_seo_site_title')); - $this->assign('home_seo_site_keywords', MyC('home_seo_site_keywords')); - $this->assign('home_seo_site_description', MyC('home_seo_site_description')); - - // 用户数据 - $this->assign('user', $this->user); - - // 用户中心菜单 - $this->assign('user_left_menu', NavigationService::UsersCenterLeftList()); - - // 商品大分类 - $this->assign('goods_category_list', GoodsService::GoodsCategoryAll()); - - // 搜索框下热门关键字 - $this->assign('home_search_keywords', SearchService::SearchKeywordsList()); - - // 友情链接 - $link = LinkService::LinkList(['where'=>['is_enable'=>1]]); - $this->assign('link_list', $link['data']); - - // 开发模式 - $this->assign('shopxo_is_develop', config('shopxo.is_develop')); - - // 顶部右侧导航 - $this->assign('common_nav_top_right_list', NavigationService::HomeHavTopRight(['user'=>$this->user])); - - // 底部导航 - $this->assign('common_bottom_nav_list', NavigationService::BottomNavigation(['user'=>$this->user])); - - // 编辑器文件存放地址 - $this->assign('editor_path_type', ResourcesService::EditorPathTypeValue(empty($this->user['id']) ? 'public' : 'user-'.$this->user['id'])); - - // 分类展示层级模式 - $this->assign('category_show_level', MyC('common_show_goods_category_level', 3, true)); - - // 备案信息 - $this->assign('home_site_icp', MyC('home_site_icp')); - $this->assign('home_site_security_record_name', MyC('home_site_security_record_name')); - $this->assign('home_site_security_record_url', MyC('home_site_security_record_url')); - - // 布局样式+管理 - $this->assign('is_load_layout', 0); - $this->assign('is_load_layout_admin', 0); - - // 默认不加载放大镜 - $this->assign('is_load_imagezoom', 0); - - // 默认不加载百度地图api - $this->assign('is_load_baidu_map_api', 0); - - // 是否加载附件组件 - $this->assign('is_load_upload_editor', (!empty($this->user) || AdminService::LoginInfo()) ? 1 : 0); - - // 存在地图事件则载入 - if(in_array(3, array_column($this->nav_quick, 'event_type'))) - { - $this->assign('is_load_baidu_map_api', 1); - } - - // 登录/注册方式 - $this->assign('home_user_login_type', MyC('home_user_login_type', [], true)); - $this->assign('home_user_reg_type', MyC('home_user_reg_type', [], true)); - - // 底部信息 - $this->assign('home_theme_footer_bottom_powered', htmlspecialchars_decode(MyC('home_theme_footer_bottom_powered'))); - } - - /** - * 动态表格初始化 - * @author Devil - * @blog http://gong.gg/ - * @version 1.0.0 - * @date 2020-06-02 - * @desc description - */ - public function FormTableInit() - { - // 获取表格模型 - $module = FormModulePath($this->data_request); - if(!empty($module)) - { - // 调用表格处理 - $params = $this->data_request; - $params['system_user'] = $this->user; - $ret = (new FormHandleModule())->Run($module['module'], $module['action'], $params); - if($ret['code'] == 0) - { - $this->form_table = $ret['data']['table']; - $this->form_where = $ret['data']['where']; - $this->form_params = $ret['data']['params']; - $this->form_md5_key = $ret['data']['md5_key']; - $this->form_user_fields = $ret['data']['user_fields']; - $this->form_order_by = $ret['data']['order_by']; - - $this->assign('form_table', $this->form_table); - $this->assign('form_params', $this->form_params); - $this->assign('form_md5_key', $this->form_md5_key); - $this->assign('form_user_fields', $this->form_user_fields); - $this->assign('form_order_by', $this->form_order_by); - } else { - $this->form_error = $ret['msg']; - $this->assign('form_error', $this->form_error); - } - } - } - - /** - * [NavInit 导航初始化] - * @author Devil - * @blog http://gong.gg/ - * @version 0.0.1 - * @datetime 2016-12-19T22:41:20+0800 - */ - private function NavInit() - { - // 主导航和底部导航 - $nav = NavigationService::Nav(); - $this->nav_header = $nav['header']; - $this->nav_footer = $nav['footer']; - - // 快捷导航 - $this->nav_quick = QuickNavService::QuickNav(); - } - - /** - * [_empty 空方法操作] - * @author Devil - * @blog http://gong.gg/ - * @version 0.0.1 - * @datetime 2017-02-25T15:47:50+0800 - * @param [string] $name [方法名称] - */ - public function _empty($name) - { - if(IS_AJAX) - { - exit(json_encode(DataReturn($name.' 非法访问', -1000))); - } else { - $this->assign('msg', $name.' 非法访问'); - return $this->fetch('public/tips_error'); - } - } - - /** - * [SiteStstusCheck 站点状态校验] - * @author Devil - * @blog http://gong.gg/ - * @version 0.0.1 - * @datetime 2017-02-25T21:43:07+0800 - */ - private function SiteStstusCheck() - { - if(MyC('home_site_state') != 1) - { - // 是否ajax请求 - if(IS_AJAX) - { - exit(json_encode(DataReturn(MyC('home_site_close_reason', '网站维护中...'), -10000))); - } else { - exit('
'.MyC('home_site_close_reason', '网站维护中...', true).'
'); - } - } - } -} -?> \ No newline at end of file diff --git a/application/index/view/default/public/jump_error.html b/application/index/view/default/public/jump_error.html deleted file mode 100755 index 357ae3c61..000000000 --- a/application/index/view/default/public/jump_error.html +++ /dev/null @@ -1,45 +0,0 @@ - - - - - -跳转提示 - - - -
- -

:)

-

- -

:(

-

-
-

-

-页面自动 跳转 等待时间: -

-
- - - \ No newline at end of file diff --git a/application/index/view/default/public/jump_success.html b/application/index/view/default/public/jump_success.html deleted file mode 100755 index 357ae3c61..000000000 --- a/application/index/view/default/public/jump_success.html +++ /dev/null @@ -1,45 +0,0 @@ - - - - - -跳转提示 - - - -
- -

:)

-

- -

:(

-

-
-

-

-页面自动 跳转 等待时间: -

-
- - - \ No newline at end of file diff --git a/application/install/view/public/error.html b/application/install/view/public/error.html deleted file mode 100755 index 31f72778c..000000000 --- a/application/install/view/public/error.html +++ /dev/null @@ -1,16 +0,0 @@ -{{include file="public/header" /}} - - -{{include file="public/header_nav" /}} - - -
-
-
-
{{$msg}}
-
-
-
- - -{{include file="public/footer" /}} \ No newline at end of file diff --git a/changelog.txt b/changelog.txt index b78c4d7e1..eff22395a 100755 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,17 @@ ++=========================================================+ + ShopXO 2.2.0 Release --- http://shopxo.net ++=========================================================+ +全局 + 1. 底层框架 thinkphp v5.1 升级到 thinkphp v6.x + +web端 + 1. 图片验证码增加随机数优化 + 2. 可视化DIY拖拽、页面设计支持同步到首页(待开发) + +插件 + 1. 多商户可视化DIY拖拽、页面设计支持同步到首页(待开发) + + +=========================================================+ ShopXO 2.1.0 Release 20210712 http://shopxo.net +=========================================================+ diff --git a/composer.json b/composer.json old mode 100755 new mode 100644 index c02d6b246..7c39df059 --- a/composer.json +++ b/composer.json @@ -1,35 +1,52 @@ -{ - "name": "shopxo/shopxo", - "description": "ShopXO domestic leading enterprise-class B2C free open source e-commerce system!", - "type": "project", - "keywords": [ - "shop", - "shopxo", - "b2c", - "mall", - "商城", - "开源商城", - "小程序", - "thinkphp", - "ORM" - ], - "homepage": "http://shopxo.net/", - "license": "Apache-2.0", - "authors": [ - { - "name": "Devil", - "email": "fuxiang.gong@qq.com" - } - ], - "require": { - "php": "5.6.35" - }, - "autoload": { - "psr-4": { - "app\\": "application" - } - }, - "config": { - "preferred-install": "dist" - } -} +{ + "name": "shopxo/shopxo", + "description": "ShopXO domestic leading enterprise-class B2C free open source e-commerce system!", + "type": "project", + "keywords": [ + "shop", + "shopxo", + "b2c", + "mall", + "商城", + "开源商城", + "小程序", + "thinkphp", + "ORM" + ], + "homepage": "http://shopxo.net/", + "license": "MIT", + "authors": [ + { + "name": "Devil", + "email": "fuxiang.gong@qq.com" + } + ], + "require": { + "php": ">=7.1.0", + "topthink/framework": "^6.0.0", + "topthink/think-orm": "^2.0", + "topthink/think-multi-app": "^1.0", + "topthink/think-view": "^1.0" + }, + "require-dev": { + "symfony/var-dumper": "^4.2", + "topthink/think-trace":"^1.0" + }, + "autoload": { + "psr-4": { + "app\\": "app" + }, + "psr-0": { + "": "extend/" + } + }, + "config": { + "preferred-install": "dist" + }, + "scripts": { + "post-autoload-dump": [ + "@php think service:discover", + "@php think vendor:publish" + ] + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 000000000..af283a458 --- /dev/null +++ b/composer.lock @@ -0,0 +1,1093 @@ +{ + "_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": "af4c1d3fa817eb8c58caa9a7ec0362b0", + "packages": [ + { + "name": "league/flysystem", + "version": "1.1.4", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "f3ad69181b8afed2c9edf7be5a2918144ff4ea32" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/f3ad69181b8afed2c9edf7be5a2918144ff4ea32", + "reference": "f3ad69181b8afed2c9edf7be5a2918144ff4ea32", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "league/mime-type-detection": "^1.3", + "php": "^7.2.5 || ^8.0" + }, + "conflict": { + "league/flysystem-sftp": "<1.0.6" + }, + "require-dev": { + "phpspec/prophecy": "^1.11.1", + "phpunit/phpunit": "^8.5.8" + }, + "suggest": { + "ext-ftp": "Allows you to use FTP server storage", + "ext-openssl": "Allows you to use FTPS server storage", + "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2", + "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3", + "league/flysystem-azure": "Allows you to use Windows Azure Blob storage", + "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching", + "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem", + "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files", + "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib", + "league/flysystem-webdav": "Allows you to use WebDAV storage", + "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter", + "spatie/flysystem-dropbox": "Allows you to use Dropbox storage", + "srmklive/flysystem-dropbox-v2": "Allows you to use Dropbox storage for PHP 5 applications" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Flysystem\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frenky.net" + } + ], + "description": "Filesystem abstraction: Many filesystems, one API.", + "keywords": [ + "Cloud Files", + "WebDAV", + "abstraction", + "aws", + "cloud", + "copy.com", + "dropbox", + "file systems", + "files", + "filesystem", + "filesystems", + "ftp", + "rackspace", + "remote", + "s3", + "sftp", + "storage" + ], + "support": { + "issues": "https://github.com/thephpleague/flysystem/issues", + "source": "https://github.com/thephpleague/flysystem/tree/1.1.4" + }, + "funding": [ + { + "url": "https://offset.earth/frankdejonge", + "type": "other" + } + ], + "time": "2021-06-23T21:56:05+00:00" + }, + { + "name": "league/flysystem-cached-adapter", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem-cached-adapter.git", + "reference": "d1925efb2207ac4be3ad0c40b8277175f99ffaff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem-cached-adapter/zipball/d1925efb2207ac4be3ad0c40b8277175f99ffaff", + "reference": "d1925efb2207ac4be3ad0c40b8277175f99ffaff", + "shasum": "" + }, + "require": { + "league/flysystem": "~1.0", + "psr/cache": "^1.0.0" + }, + "require-dev": { + "mockery/mockery": "~0.9", + "phpspec/phpspec": "^3.4", + "phpunit/phpunit": "^5.7", + "predis/predis": "~1.0", + "tedivm/stash": "~0.12" + }, + "suggest": { + "ext-phpredis": "Pure C implemented extension for PHP" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Flysystem\\Cached\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "frankdejonge", + "email": "info@frenky.net" + } + ], + "description": "An adapter decorator to enable meta-data caching.", + "support": { + "issues": "https://github.com/thephpleague/flysystem-cached-adapter/issues", + "source": "https://github.com/thephpleague/flysystem-cached-adapter/tree/master" + }, + "time": "2020-07-25T15:56:04+00:00" + }, + { + "name": "league/mime-type-detection", + "version": "1.7.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/mime-type-detection.git", + "reference": "3b9dff8aaf7323590c1d2e443db701eb1f9aa0d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/3b9dff8aaf7323590c1d2e443db701eb1f9aa0d3", + "reference": "3b9dff8aaf7323590c1d2e443db701eb1f9aa0d3", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.18", + "phpstan/phpstan": "^0.12.68", + "phpunit/phpunit": "^8.5.8 || ^9.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\MimeTypeDetection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "Mime-type detection for Flysystem", + "support": { + "issues": "https://github.com/thephpleague/mime-type-detection/issues", + "source": "https://github.com/thephpleague/mime-type-detection/tree/1.7.0" + }, + "funding": [ + { + "url": "https://github.com/frankdejonge", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/flysystem", + "type": "tidelift" + } + ], + "time": "2021-01-18T20:58:21+00:00" + }, + { + "name": "psr/cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/master" + }, + "time": "2016-08-06T20:24:11+00:00" + }, + { + "name": "psr/container", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/8622567409010282b7aeebe4bb841fe98b58dcaf", + "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "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/1.1.1" + }, + "time": "2021-03-05T17:36:06+00:00" + }, + { + "name": "psr/log", + "version": "1.1.4", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "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/1.1.4" + }, + "time": "2021-05-03T11:20:27+00:00" + }, + { + "name": "psr/simple-cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/master" + }, + "time": "2017-10-23T01:57:42+00:00" + }, + { + "name": "topthink/framework", + "version": "v6.0.8", + "source": { + "type": "git", + "url": "https://github.com/top-think/framework.git", + "reference": "4789343672aef06d571d556da369c0e156609bce" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/framework/zipball/4789343672aef06d571d556da369c0e156609bce", + "reference": "4789343672aef06d571d556da369c0e156609bce", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "league/flysystem": "^1.0", + "league/flysystem-cached-adapter": "^1.0", + "php": ">=7.1.0", + "psr/container": "~1.0", + "psr/log": "~1.0", + "psr/simple-cache": "^1.0", + "topthink/think-helper": "^3.1.1", + "topthink/think-orm": "^2.0" + }, + "require-dev": { + "mikey179/vfsstream": "^1.6", + "mockery/mockery": "^1.2", + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "autoload": { + "files": [], + "psr-4": { + "think\\": "src/think/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + }, + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "description": "The ThinkPHP Framework.", + "homepage": "http://thinkphp.cn/", + "keywords": [ + "framework", + "orm", + "thinkphp" + ], + "support": { + "issues": "https://github.com/top-think/framework/issues", + "source": "https://github.com/top-think/framework/tree/v6.0.8" + }, + "time": "2021-04-27T00:41:08+00:00" + }, + { + "name": "topthink/think-helper", + "version": "v3.1.5", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-helper.git", + "reference": "f98e3ad44acd27ae85a4d923b1bdfd16c6d8d905" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-helper/zipball/f98e3ad44acd27ae85a4d923b1bdfd16c6d8d905", + "reference": "f98e3ad44acd27ae85a4d923b1bdfd16c6d8d905", + "shasum": "" + }, + "require": { + "php": ">=7.1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "think\\": "src" + }, + "files": [ + "src/helper.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "description": "The ThinkPHP6 Helper Package", + "support": { + "issues": "https://github.com/top-think/think-helper/issues", + "source": "https://github.com/top-think/think-helper/tree/v3.1.5" + }, + "time": "2021-06-21T06:17:31+00:00" + }, + { + "name": "topthink/think-multi-app", + "version": "v1.0.14", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-multi-app.git", + "reference": "ccaad7c2d33f42cb1cc2a78d6610aaec02cea4c3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-multi-app/zipball/ccaad7c2d33f42cb1cc2a78d6610aaec02cea4c3", + "reference": "ccaad7c2d33f42cb1cc2a78d6610aaec02cea4c3", + "shasum": "" + }, + "require": { + "php": ">=7.1.0", + "topthink/framework": "^6.0.0" + }, + "type": "library", + "extra": { + "think": { + "services": [ + "think\\app\\Service" + ] + } + }, + "autoload": { + "psr-4": { + "think\\app\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "thinkphp6 multi app support", + "support": { + "issues": "https://github.com/top-think/think-multi-app/issues", + "source": "https://github.com/top-think/think-multi-app/tree/master" + }, + "time": "2020-07-12T13:50:37+00:00" + }, + { + "name": "topthink/think-orm", + "version": "v2.0.40", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-orm.git", + "reference": "1119d979b850849f3725856460cf108eec1c3eb8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-orm/zipball/1119d979b850849f3725856460cf108eec1c3eb8", + "reference": "1119d979b850849f3725856460cf108eec1c3eb8", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-pdo": "*", + "php": ">=7.1.0", + "psr/log": "~1.0", + "psr/simple-cache": "^1.0", + "topthink/think-helper": "^3.1" + }, + "require-dev": { + "phpunit/phpunit": "^7|^8|^9.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "think\\": "src" + }, + "files": [ + "stubs/load_stubs.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "think orm", + "keywords": [ + "database", + "orm" + ], + "support": { + "issues": "https://github.com/top-think/think-orm/issues", + "source": "https://github.com/top-think/think-orm/tree/v2.0.40" + }, + "time": "2021-04-19T13:29:37+00:00" + }, + { + "name": "topthink/think-template", + "version": "v2.0.8", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-template.git", + "reference": "abfc293f74f9ef5127b5c416310a01fe42e59368" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-template/zipball/abfc293f74f9ef5127b5c416310a01fe42e59368", + "reference": "abfc293f74f9ef5127b5c416310a01fe42e59368", + "shasum": "" + }, + "require": { + "php": ">=7.1.0", + "psr/simple-cache": "^1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "think\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "the php template engine", + "support": { + "issues": "https://github.com/top-think/think-template/issues", + "source": "https://github.com/top-think/think-template/tree/v2.0.8" + }, + "time": "2020-12-10T07:52:03+00:00" + }, + { + "name": "topthink/think-view", + "version": "v1.0.14", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-view.git", + "reference": "edce0ae2c9551ab65f9e94a222604b0dead3576d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-view/zipball/edce0ae2c9551ab65f9e94a222604b0dead3576d", + "reference": "edce0ae2c9551ab65f9e94a222604b0dead3576d", + "shasum": "" + }, + "require": { + "php": ">=7.1.0", + "topthink/think-template": "^2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "think\\view\\driver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "thinkphp template driver", + "support": { + "issues": "https://github.com/top-think/think-view/issues", + "source": "https://github.com/top-think/think-view/tree/v1.0.14" + }, + "time": "2019-11-06T11:40:13+00:00" + } + ], + "packages-dev": [ + { + "name": "symfony/polyfill-mbstring", + "version": "v1.23.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "2df51500adbaebdc4c38dea4c89a2e131c45c8a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/2df51500adbaebdc4c38dea4c89a2e131c45c8a1", + "reference": "2df51500adbaebdc4c38dea4c89a2e131c45c8a1", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.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": "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.23.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": "2021-05-27T09:27:20+00:00" + }, + { + "name": "symfony/polyfill-php72", + "version": "v1.23.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "9a142215a36a3888e30d0a9eeea9766764e96976" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/9a142215a36a3888e30d0a9eeea9766764e96976", + "reference": "9a142215a36a3888e30d0a9eeea9766764e96976", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + }, + "files": [ + "bootstrap.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": "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.23.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": "2021-05-27T09:17:38+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.23.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/eca0bf41ed421bed1b57c4958bab16aa86b757d0", + "reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.23.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": "2021-02-19T12:13:01+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v4.4.26", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "a586efdf2aa832d05b9249e9115d24f6a2691160" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/a586efdf2aa832d05b9249e9115d24f6a2691160", + "reference": "a586efdf2aa832d05b9249e9115d24f6a2691160", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php72": "~1.5", + "symfony/polyfill-php80": "^1.15" + }, + "conflict": { + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/console": "<3.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/process": "^4.4|^5.0", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "suggest": { + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump", + "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" + }, + "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/v4.4.26" + }, + "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": "2021-06-17T06:35:48+00:00" + }, + { + "name": "topthink/think-trace", + "version": "v1.4", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-trace.git", + "reference": "9a9fa8f767b6c66c5a133ad21ca1bc96ad329444" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-trace/zipball/9a9fa8f767b6c66c5a133ad21ca1bc96ad329444", + "reference": "9a9fa8f767b6c66c5a133ad21ca1bc96ad329444", + "shasum": "" + }, + "require": { + "php": ">=7.1.0", + "topthink/framework": "^6.0.0" + }, + "type": "library", + "extra": { + "think": { + "services": [ + "think\\trace\\Service" + ], + "config": { + "trace": "src/config.php" + } + } + }, + "autoload": { + "psr-4": { + "think\\trace\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "thinkphp debug trace", + "support": { + "issues": "https://github.com/top-think/think-trace/issues", + "source": "https://github.com/top-think/think-trace/tree/v1.4" + }, + "time": "2020-06-29T05:27:28+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=7.1.0" + }, + "platform-dev": [], + "plugin-api-version": "2.1.0" +} diff --git a/config/.gitignore b/config/.gitignore old mode 100755 new mode 100644 diff --git a/config/app.php b/config/app.php old mode 100755 new mode 100644 index 726db50bb..d4c08edc5 --- a/config/app.php +++ b/config/app.php @@ -1,146 +1,42 @@ - '', - // 应用地址 - 'app_host' => '', - // 应用调试模式 - 'app_debug' => false, - // 应用Trace - 'app_trace' => false, - // 是否支持多模块 - 'app_multi_module' => true, - // 入口自动绑定模块 - 'auto_bind_module' => false, - // 注册的根命名空间 - 'root_namespace' => [], - // 默认输出类型 - 'default_return_type' => 'html', - // 默认AJAX 数据返回格式,可选json xml ... - 'default_ajax_return' => 'json', - // 默认JSONP格式返回的处理方法 - 'default_jsonp_handler' => 'jsonpReturn', - // 默认JSONP处理方法 - 'var_jsonp_handler' => 'callback', - // 默认时区 - 'default_timezone' => MyFileConfig('common_timezone', '', 'Asia/Shanghai', true), - // 是否开启多语言 - 'lang_switch_on' => false, - // 默认全局过滤方法 用逗号分隔多个 - 'default_filter' => 'htmlspecialchars', - // 默认语言 - 'default_lang' => 'zh-cn', - // 应用类库后缀 - 'class_suffix' => false, - // 控制器类后缀 - 'controller_suffix' => false, - - // +---------------------------------------------------------------------- - // | 模块设置 - // +---------------------------------------------------------------------- - - // 默认模块名 - 'default_module' => 'index', - // 禁止访问模块 - 'deny_module_list' => ['common', 'service', 'admin', 'form'], - // 默认控制器名 - 'default_controller' => 'index', - // 默认操作名 - 'default_action' => 'index', - // 默认验证器 - 'default_validate' => '', - // 默认的空模块名 - 'empty_module' => 'index', - // 默认的空控制器名 - 'empty_controller' => 'Error', - // 操作方法前缀 - 'use_action_prefix' => false, - // 操作方法后缀 - 'action_suffix' => '', - // 自动搜索控制器 - 'controller_auto_search' => false, - - // +---------------------------------------------------------------------- - // | URL设置 - // +---------------------------------------------------------------------- - - // PATHINFO变量名 用于兼容模式 - 'var_pathinfo' => 's', - // 兼容PATH_INFO获取 - 'pathinfo_fetch' => ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO', 'REDIRECT_URL'], - // pathinfo分隔符 - 'pathinfo_depr' => '/', - // HTTPS代理标识 - 'https_agent_name' => '', - // IP代理获取标识 - 'http_agent_ip' => 'X-REAL-IP', - // URL伪静态后缀 - 'url_html_suffix' => 'html', - // URL普通方式参数 用于自动生成 - 'url_common_param' => false, - // URL参数方式 0 按名称成对解析 1 按顺序解析 - 'url_param_type' => 0, - // 是否开启路由延迟解析 - 'url_lazy_route' => false, - // 是否强制使用路由 - 'url_route_must' => false, - // 合并路由规则 - 'route_rule_merge' => false, - // 路由是否完全匹配 - 'route_complete_match' => false, - // 使用注解路由 - 'route_annotation' => false, - // 域名根,如thinkphp.cn - 'url_domain_root' => '', - // 是否自动转换URL中的控制器和操作名 - 'url_convert' => true, - // 默认的访问控制器层 - 'url_controller_layer' => 'controller', - // 表单请求类型伪装变量 - 'var_method' => '_method', - // 表单ajax伪装变量 - 'var_ajax' => '_ajax', - // 表单pjax伪装变量 - 'var_pjax' => '_pjax', - // 是否开启请求缓存 true自动缓存 支持设置请求缓存规则 - 'request_cache' => false, - // 请求缓存有效期 - 'request_cache_expire' => null, - // 全局请求缓存排除规则 - 'request_cache_except' => [], - // 是否开启路由缓存 - 'route_check_cache' => false, - // 路由缓存的Key自定义设置(闭包),默认为当前URL和请求类型的md5 - 'route_check_cache_key' => '', - // 路由缓存类型及参数 - 'route_cache_option' => [], - - // 默认跳转页面对应的模板文件 - 'dispatch_success_tmpl' => Env::get('think_path') . 'tpl/dispatch_jump.tpl', - 'dispatch_error_tmpl' => Env::get('think_path') . 'tpl/dispatch_jump.tpl', - - // 异常页面的模板文件 - 'exception_tmpl' => Env::get('think_path') . 'tpl/think_exception.tpl', - - // 错误显示信息,非调试模式有效 - 'error_message' => '系统出现错误、请联系管理员或到'.implode('', ['S','h','o','p','X','O']).'社区查阅~', - // 显示错误信息 - 'show_error_msg' => false, - // 异常处理handle类 留空使用 \think\exception\Handle - 'exception_handle' => '\\app\\common\\Http', -]; + '', + // 应用的命名空间 + 'app_namespace' => '', + // 是否启用路由 + 'with_route' => true, + // 默认应用 + 'default_app' => 'index', + // 默认时区 + 'default_timezone' => MyFileConfig('common_timezone', '', 'Asia/Shanghai', true), + + // 应用映射(自动多应用模式有效) + 'app_map' => [], + // 域名绑定(自动多应用模式有效) + 'domain_bind' => [], + // 禁止URL访问的应用列表(自动多应用模式有效) + 'deny_app_list' => [], + + // 异常页面的模板文件 + 'exception_tmpl' => ROOT . 'tpl/think_exception.tpl', + + // 错误显示信息,非调试模式有效 + 'error_message' => '系统出现错误、请联系管理员或到'.implode('', ['S','h','o','p','X','O']).'社区查阅~', + // 显示错误信息 + 'show_error_msg' => false, +]; ?> \ No newline at end of file diff --git a/config/cache.php b/config/cache.php old mode 100755 new mode 100644 index bd7e70bdc..d3ef22fb3 --- a/config/cache.php +++ b/config/cache.php @@ -9,37 +9,45 @@ // | Author: Devil // +---------------------------------------------------------------------- -// 是否开启redis -$common_data_is_use_cache = MyFileConfig('common_data_is_use_cache', '', 0, true); -if($common_data_is_use_cache == 1) -{ - // redis配置 - $config = [ - // 使用redis - 'type' => 'redis', - // 连接地址 - 'host' => MyFileConfig('common_cache_data_redis_host', '', '127.0.0.1', true), - // 端口号 - 'port' => MyFileConfig('common_cache_data_redis_port', '', 6379, true), - // 密码 - 'password' => MyFileConfig('common_cache_data_redis_password', '', '', true), - // 全局缓存有效期(0为永久有效) - 'expire' => MyFileConfig('common_cache_data_redis_expire', '', 0, true), - // 缓存前缀 - 'prefix' => MyFileConfig('common_cache_data_redis_prefix', '', 'shopxo', true), - ]; -} else { - // 默认配置 - $config = [ - // 驱动方式 - 'type' => 'File', - // 缓存保存目录 - 'path' => '', - // 缓存前缀 - 'prefix' => 'shopxo', - // 缓存有效期 0表示永久缓存 - 'expire' => 0, - ]; -} -return $config; +// +---------------------------------------------------------------------- +// | 缓存设置 +// +---------------------------------------------------------------------- +return [ + // 默认缓存驱动 + 'default' => (MyFileConfig('common_data_is_use_cache', '', 0, true) == 1) ? 'redis' : 'file', + + // 缓存连接方式配置 + 'stores' => [ + // 文件缓存 + 'file' => [ + // 驱动方式 + 'type' => 'File', + // 缓存保存目录 + 'path' => '', + // 缓存前缀 + 'prefix' => 'shopxo', + // 缓存有效期 0表示永久缓存 + 'expire' => 0, + // 缓存标签前缀 + 'tag_prefix' => 'tag:', + // 序列化机制 例如 ['serialize', 'unserialize'] + 'serialize' => [], + ], + // redis缓存 + 'redis' => [ + // 驱动方式 + 'type' => 'redis', + // 连接地址 + 'host' => MyFileConfig('common_cache_data_redis_host', '', '127.0.0.1', true), + // 端口号 + 'port' => MyFileConfig('common_cache_data_redis_port', '', 6379, true), + // 密码 + 'password' => MyFileConfig('common_cache_data_redis_password', '', '', true), + // 全局缓存有效期(0为永久有效) + 'expire' => MyFileConfig('common_cache_data_redis_expire', '', 0, true), + // 缓存前缀 + 'prefix' => MyFileConfig('common_cache_data_redis_prefix', '', 'redis_shopxo', true), + ], + ], +]; ?> \ No newline at end of file diff --git a/config/console.php b/config/console.php old mode 100755 new mode 100644 index 37bf58c7f..9d314a754 --- a/config/console.php +++ b/config/console.php @@ -13,9 +13,8 @@ // | 控制台配置 // +---------------------------------------------------------------------- return [ - 'name' => 'ShopXO Console', - 'version' => '0.1', - 'user' => null, - 'auto_path' => env('app_path') . 'command' . DIRECTORY_SEPARATOR, + // 指令定义 + 'commands' => [ + ], ]; ?> \ No newline at end of file diff --git a/config/cookie.php b/config/cookie.php old mode 100755 new mode 100644 index a65dfbeba..63da24746 --- a/config/cookie.php +++ b/config/cookie.php @@ -13,8 +13,6 @@ // | Cookie设置 // +---------------------------------------------------------------------- return [ - // cookie 名称前缀 - 'prefix' => '', // cookie 保存时间 'expire' => 0, // cookie 保存路径 @@ -24,8 +22,10 @@ return [ // cookie 启用安全传输 'secure' => false, // httponly设置 - 'httponly' => '', + 'httponly' => false, // 是否使用 setcookie 'setcookie' => true, + // samesite 设置,支持 'strict' 'lax' + 'samesite' => '', ]; ?> \ No newline at end of file diff --git a/config/filesystem.php b/config/filesystem.php new file mode 100644 index 000000000..b3a842020 --- /dev/null +++ b/config/filesystem.php @@ -0,0 +1,37 @@ + 'local', + // 磁盘列表 + 'disks' => [ + 'local' => [ + 'type' => 'local', + 'root' => app()->getRuntimePath() . 'storage', + ], + 'public' => [ + // 磁盘类型 + 'type' => 'local', + // 磁盘路径 + 'root' => app()->getRootPath() . 'public/storage', + // 磁盘路径对应的外部URL路径 + 'url' => '/storage', + // 可见性 + 'visibility' => 'public', + ], + // 更多的磁盘配置信息 + ], +]; +?> \ No newline at end of file diff --git a/config/lang.php b/config/lang.php new file mode 100644 index 000000000..c44c1a583 --- /dev/null +++ b/config/lang.php @@ -0,0 +1,37 @@ + 'zh-cn', + // 允许的语言列表 + 'allow_lang_list' => [], + // 多语言自动侦测变量名 + 'detect_var' => 'lang', + // 是否使用Cookie记录 + 'use_cookie' => true, + // 多语言cookie变量 + 'cookie_var' => 'think_lang', + // 多语言header变量 + 'header_var' => 'think-lang', + // 扩展语言包 + 'extend_list' => [], + // Accept-Language转义为对应语言包名称 + 'accept_language' => [ + 'zh-hans-cn' => 'zh-cn', + ], + // 是否支持语言分组 + 'allow_group' => false, +]; +?> \ No newline at end of file diff --git a/config/log.php b/config/log.php old mode 100755 new mode 100644 index 7abd908f9..960a36ace --- a/config/log.php +++ b/config/log.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ShopXO 国内领先企业级B2C免费开源电商系统 // +---------------------------------------------------------------------- -// | Copyright (c) 2011~2099 http://shopxo.net All rights reserved. +// | Copyright (c) 2011~2018 http://shopxo.net All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( https://opensource.org/licenses/mit-license.php ) // +---------------------------------------------------------------------- @@ -13,19 +13,43 @@ // | 日志设置 // +---------------------------------------------------------------------- return [ - // 日志记录方式,内置 file socket 支持扩展 - 'type' => 'File', - // 日志保存目录 - 'path' => '', + // 默认日志记录通道 + 'default' => 'file', // 日志记录级别 - 'level' => [], - // 单文件日志写入 - 'single' => false, - // 独立日志级别 - 'apart_level' => [], - // 最大日志文件数量 - 'max_files' => 0, - // 是否关闭日志写入 - 'close' => false, + 'level' => [], + // 日志类型记录的通道 ['error'=>'email',...] + 'type_channel' => [], + // 关闭全局日志写入 + 'close' => false, + // 全局日志处理 支持闭包 + 'processor' => null, + + // 日志通道列表 + 'channels' => [ + 'file' => [ + // 日志记录方式 + 'type' => 'File', + // 日志保存目录 + 'path' => '', + // 单文件日志写入 + 'single' => false, + // 独立日志级别 + 'apart_level' => [], + // 最大日志文件数量 + 'max_files' => 0, + // 使用JSON格式记录 + 'json' => false, + // 日志处理 + 'processor' => null, + // 关闭通道日志写入 + 'close' => false, + // 日志输出格式化 + 'format' => '[%s][%s] %s', + // 是否实时写入 + 'realtime_write' => false, + ], + // 其它日志通道配置 + ], + ]; ?> \ No newline at end of file diff --git a/config/middleware.php b/config/middleware.php old mode 100755 new mode 100644 index 5793bf446..8090a3491 --- a/config/middleware.php +++ b/config/middleware.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ShopXO 国内领先企业级B2C免费开源电商系统 // +---------------------------------------------------------------------- -// | Copyright (c) 2011~2099 http://shopxo.net All rights reserved. +// | Copyright (c) 2011~2018 http://shopxo.net All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( https://opensource.org/licenses/mit-license.php ) // +---------------------------------------------------------------------- @@ -13,7 +13,9 @@ // | 中间件配置 // +---------------------------------------------------------------------- return [ - // 默认中间件命名空间 - 'default_namespace' => 'app\\http\\middleware\\', + // 别名或分组 + 'alias' => [], + // 优先级设置,此数组中的中间件会按照数组中的顺序优先执行 + 'priority' => [], ]; ?> \ No newline at end of file diff --git a/config/route.php b/config/route.php new file mode 100644 index 000000000..4051a350c --- /dev/null +++ b/config/route.php @@ -0,0 +1,55 @@ + '/', + // URL伪静态后缀 + 'url_html_suffix' => 'html', + // URL普通方式参数 用于自动生成 + 'url_common_param' => false, + // 是否开启路由延迟解析 + 'url_lazy_route' => false, + // 是否强制使用路由 + 'url_route_must' => false, + // 合并路由规则 + 'route_rule_merge' => false, + // 路由是否完全匹配 + 'route_complete_match' => false, + // 访问控制器层名称 + 'controller_layer' => 'controller', + // 空控制器名 + 'empty_controller' => 'Error', + // 是否使用控制器后缀 + 'controller_suffix' => false, + // 默认的路由变量规则 + 'default_route_pattern' => '[\w\.]+', + // 是否开启请求缓存 true自动缓存 支持设置请求缓存规则 + 'request_cache_key' => false, + // 请求缓存有效期 + 'request_cache_expire' => null, + // 全局请求缓存排除规则 + 'request_cache_except' => [], + // 默认控制器名 + 'default_controller' => 'Index', + // 默认操作名 + 'default_action' => 'index', + // 操作方法后缀 + 'action_suffix' => '', + // 默认JSONP格式返回的处理方法 + 'default_jsonp_handler' => 'jsonpReturn', + // 默认JSONP处理方法 + 'var_jsonp_handler' => 'callback', +]; +?> \ No newline at end of file diff --git a/config/session.php b/config/session.php old mode 100755 new mode 100644 index 1c12d55c3..a3fbaaffc --- a/config/session.php +++ b/config/session.php @@ -9,38 +9,33 @@ // | Author: Devil // +---------------------------------------------------------------------- -// 是否开启redis -$common_session_is_use_cache = MyFileConfig('common_session_is_use_cache', '', 0, true); -if($common_session_is_use_cache == 1) +// +---------------------------------------------------------------------- +// | 会话设置 +// +---------------------------------------------------------------------- +if(MyFileConfig('common_session_is_use_cache', '', 0, true) == 1) { // redis配置 + // 请确保缓存配置文件cache.php中的stores中已经添加了redis缓存配置 $config = [ - // 使用redis - 'type' => 'redis', - // 连接地址 - 'host' => MyFileConfig('common_cache_session_redis_host', '', '127.0.0.1', true), - // 端口号 - 'port' => MyFileConfig('common_cache_session_redis_port', '', 6379, true), - // 密码 - 'password' => MyFileConfig('common_cache_session_redis_password', '', '', true), - // 全局缓存有效期、默认3600秒 - 'expire' => MyFileConfig('common_cache_session_redis_expire', '', 3600, true), - // 缓存前缀 - 'prefix' => MyFileConfig('common_cache_session_redis_prefix', '', 'shopxo', true), + 'type' => 'cache', + 'store' => 'redis', + 'prefix' => MyFileConfig('common_cache_session_redis_prefix', '', 'shopxo', true), ]; } else { // 默认配置 $config = [ - // session_id - 'id' => '', + // session name + 'name' => 'PHPSESSID', // SESSION_ID的提交变量,解决flash上传跨域 - 'var_session_id' => '', - // SESSION 前缀 - 'prefix' => 'shopxo', - // 驱动方式 支持redis memcache memcached - 'type' => '', - // 是否自动开启 SESSION - 'auto_start' => true, + 'var_session_id' => '', + // 驱动方式 支持file cache + 'type' => 'file', + // 存储连接标识 当type使用cache的时候有效 + 'store' => null, + // 过期时间 + 'expire' => 3600, + // 前缀 + 'prefix' => 'shopxo', ]; } return $config; diff --git a/config/shopxo.php b/config/shopxo.php index 622f218aa..107d2b565 100755 --- a/config/shopxo.php +++ b/config/shopxo.php @@ -33,7 +33,15 @@ return [ // 默认编码 'default_charset' => 'utf-8', - // 缓存key列表 + // 后端缓存key列表 + // 权限缓存存储key + 'cache_admin_power_key' => 'cache_admin_power_', + + // 菜单列表 + 'cache_admin_left_menu_key' => 'cache_admin_left_menu_', + + + // 公共缓存key列表 // 公共系统配置信息key 'cache_common_my_config_key' => 'cache_common_my_config_data', diff --git a/config/trace.php b/config/trace.php old mode 100755 new mode 100644 index 445025220..c360f6657 --- a/config/trace.php +++ b/config/trace.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ShopXO 国内领先企业级B2C免费开源电商系统 // +---------------------------------------------------------------------- -// | Copyright (c) 2011~2099 http://shopxo.net All rights reserved. +// | Copyright (c) 2011~2018 http://shopxo.net All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( https://opensource.org/licenses/mit-license.php ) // +---------------------------------------------------------------------- @@ -10,10 +10,12 @@ // +---------------------------------------------------------------------- // +---------------------------------------------------------------------- -// | Trace设置 开启 app_trace 后 有效 +// | Trace设置 开启调试模式后有效 // +---------------------------------------------------------------------- return [ - // 内置Html Console 支持扩展 - 'type' => 'Html', + // 内置Html和Console两种方式 支持扩展 + 'type' => 'Html', + // 读取的日志通道名 + 'channel' => '', ]; ?> \ No newline at end of file diff --git a/extend/base/Baidu.php b/extend/base/Baidu.php index 2ced5d4f9..b87896443 100755 --- a/extend/base/Baidu.php +++ b/extend/base/Baidu.php @@ -57,7 +57,7 @@ class Baidu { // 登录授权session $login_key = 'baidu_user_login_'.$openid; - $session_data = cache($login_key); + $session_data = MyCache($login_key); if(empty($session_data)) { return ['status'=>-1, 'msg'=>'session key不存在']; @@ -113,7 +113,7 @@ class Baidu // 缓存存储 $data_key = 'baidu_'.$key.'_'.$openid; - cache($data_key, $data); + MyCache($data_key, $data); return ['status'=>0, 'data'=>$data]; } @@ -150,7 +150,7 @@ class Baidu $key = 'baidu_user_login_'.$result['openid']; // 缓存存储 - cache($key, $result); + MyCache($key, $result); return ['status'=>0, 'msg'=>'授权成功', 'data'=>$result['openid']]; } return ['status'=>-1, 'msg'=>$result['error_description']]; @@ -228,7 +228,7 @@ class Baidu { // 缓存key $key = $this->_appid.'_access_token'; - $result = cache($key); + $result = MyCache($key); if(!empty($result)) { if($result['expires_in'] > time()) @@ -244,7 +244,7 @@ class Baidu { // 缓存存储 $result['expires_in'] += time(); - cache($key, $result); + MyCache($key, $result); return $result['access_token']; } return false; diff --git a/extend/base/Email.php b/extend/base/Email.php index aaa93d429..5796a2c16 100755 --- a/extend/base/Email.php +++ b/extend/base/Email.php @@ -180,7 +180,7 @@ class Email 'code' => $code, 'time' => time(), ); - cache($this->key_code, $data, $this->expire_time); + MyCache($this->key_code, $data, $this->expire_time); } /** @@ -193,7 +193,7 @@ class Email */ public function CheckExpire() { - $data = cache($this->key_code); + $data = MyCache($this->key_code); if(!empty($data)) { return (time() <= $data['time']+$this->expire_time); @@ -216,7 +216,7 @@ class Email if(SecurityPreventViolence($this->key_code, 1, $this->expire_time)) { // 验证是否正确 - $data = cache($this->key_code); + $data = MyCache($this->key_code); if(!empty($data)) { if(empty($code) && isset($_POST['code'])) @@ -239,7 +239,7 @@ class Email */ public function Remove() { - cache($this->key_code, null); + MyCache($this->key_code, null); SecurityPreventViolence($this->key_code, 0); } @@ -253,7 +253,7 @@ class Email */ private function IntervalTimeCheck() { - $data = cache($this->key_code); + $data = MyCache($this->key_code); if(!empty($data)) { return (time() > $data['time']+$this->interval_time); diff --git a/extend/base/QQ.php b/extend/base/QQ.php index cc4dfd63b..6b5adf7e6 100644 --- a/extend/base/QQ.php +++ b/extend/base/QQ.php @@ -56,7 +56,7 @@ class QQ { // 登录授权session $login_key = 'qq_user_login_'.$openid; - $session_data = cache($login_key); + $session_data = MyCache($login_key); if(empty($session_data)) { return 'session key不存在'; @@ -88,7 +88,7 @@ class QQ // 缓存存储 $data_key = 'qq_user_info_'.$openid; - cache($data_key, $data); + MyCache($data_key, $data); return $data; } @@ -113,7 +113,7 @@ class QQ $key = 'qq_user_login_'.$result['openid']; // 缓存存储 - cache($key, $result); + MyCache($key, $result); return $result['openid']; } return false; @@ -131,7 +131,7 @@ class QQ { // 缓存key $key = $this->_appid.'_access_token'; - $result = cache($key); + $result = MyCache($key); if(!empty($result)) { if($result['expires_in'] > time()) @@ -147,7 +147,7 @@ class QQ { // 缓存存储 $result['expires_in'] += time(); - cache($key, $result); + MyCache($key, $result); return $result['access_token']; } return false; diff --git a/extend/base/Sms.php b/extend/base/Sms.php index ad4624c41..18eda6afd 100755 --- a/extend/base/Sms.php +++ b/extend/base/Sms.php @@ -216,7 +216,7 @@ class Sms 'code' => $code, 'time' => time(), ); - cache($this->key_code, $data, $this->expire_time); + MyCache($this->key_code, $data, $this->expire_time); } /** @@ -229,7 +229,7 @@ class Sms */ public function CheckExpire() { - $data = cache($this->key_code); + $data = MyCache($this->key_code); if(!empty($data)) { return (time() <= $data['time']+$this->expire_time); @@ -252,7 +252,7 @@ class Sms if(SecurityPreventViolence($this->key_code, 1, $this->expire_time)) { // 验证是否正确 - $data = cache($this->key_code); + $data = MyCache($this->key_code); if(!empty($data)) { if(empty($code) && isset($_POST['code'])) @@ -275,7 +275,7 @@ class Sms */ public function Remove() { - cache($this->key_code, null); + MyCache($this->key_code, null); SecurityPreventViolence($this->key_code, 0); } @@ -289,7 +289,7 @@ class Sms */ private function IntervalTimeCheck() { - $data = cache($this->key_code); + $data = MyCache($this->key_code); if(!empty($data)) { return (time() > $data['time']+$this->interval_time); diff --git a/extend/base/Toutiao.php b/extend/base/Toutiao.php index 3a2feeac7..50798cf39 100644 --- a/extend/base/Toutiao.php +++ b/extend/base/Toutiao.php @@ -162,7 +162,7 @@ class Toutiao { // 缓存key $key = $this->config['appid'].'_access_token'; - $result = cache($key); + $result = MyCache($key); if(!empty($result)) { if($result['expires_in'] > time()) @@ -178,7 +178,7 @@ class Toutiao { // 缓存存储 $result['expires_in'] += time(); - cache($key, $result); + MyCache($key, $result); return $result['access_token']; } return false; diff --git a/extend/base/Verify.php b/extend/base/Verify.php index ac149889f..e98f8af5c 100755 --- a/extend/base/Verify.php +++ b/extend/base/Verify.php @@ -155,9 +155,9 @@ class Verify // 空uid则存储session if(empty($this->uid)) { - $data = session($this->key_verify); + $data = MySession($this->key_verify); } else { - $data = cache($this->key_verify.$this->uid); + $data = MyCache($this->key_verify.$this->uid); } if(!empty($data) && isset($data['time'])) @@ -181,9 +181,9 @@ class Verify // 空uid则存储session if(empty($this->uid)) { - $data = session($this->key_verify); + $data = MySession($this->key_verify); } else { - $data = cache($this->key_verify.$this->uid); + $data = MyCache($this->key_verify.$this->uid); } if(!empty($data) && isset($data['verify'])) { @@ -209,9 +209,9 @@ class Verify // 空uid则处理session if(empty($this->uid)) { - session($this->key_verify, null); + MySession($this->key_verify, null); } else { - cache($this->key_verify.$this->uid, null); + MyCache($this->key_verify.$this->uid, null); } } @@ -232,9 +232,9 @@ class Verify // 空uid则存储session if(empty($this->uid)) { - session($this->key_verify, $data); + MySession($this->key_verify, $data); } else { - cache($this->key_verify.$this->uid, $data, $this->expire_time); + MyCache($this->key_verify.$this->uid, $data, $this->expire_time); } } diff --git a/extend/base/Wechat.php b/extend/base/Wechat.php index 6af3af9dc..fd4c6136a 100755 --- a/extend/base/Wechat.php +++ b/extend/base/Wechat.php @@ -56,7 +56,7 @@ class Wechat { // 登录授权session $login_key = 'wechat_user_login_'.$openid; - $session_data = cache($login_key); + $session_data = MyCache($login_key); if(empty($session_data)) { return ['status'=>-1, 'msg'=>'session key不存在']; @@ -87,7 +87,7 @@ class Wechat // 缓存存储 $data_key = 'wechat_user_info_'.$openid; - cache($data_key, $data); + MyCache($data_key, $data); return ['status'=>0, 'data'=>$data]; } @@ -117,7 +117,7 @@ class Wechat $key = 'wechat_user_login_'.$result['openid']; // 缓存存储 - cache($key, $result); + MyCache($key, $result); return ['status'=>0, 'msg'=>'授权成功', 'data'=>$result]; } return ['status'=>-1, 'msg'=>$result['errmsg']]; @@ -267,7 +267,7 @@ class Wechat { // 缓存key $key = $this->_appid.'_access_token'; - $result = cache($key); + $result = MyCache($key); if(!empty($result)) { if($result['expires_in'] > time()) @@ -283,7 +283,7 @@ class Wechat { // 缓存存储 $result['expires_in'] += time(); - cache($key, $result); + MyCache($key, $result); return $result['access_token']; } return false; @@ -303,7 +303,7 @@ class Wechat { // 缓存key $key = $this->_appid.'_get_ticket'; - $result = cache($key); + $result = MyCache($key); if(!empty($result)) { if($result['expires_in'] > time()) @@ -319,7 +319,7 @@ class Wechat { // 缓存存储 $result['expires_in'] += time(); - cache($key, $result); + MyCache($key, $result); return $result['ticket']; } return false; diff --git a/extend/payment/Alipay.php b/extend/payment/Alipay.php index 0fbc38af9..d82d2d055 100755 --- a/extend/payment/Alipay.php +++ b/extend/payment/Alipay.php @@ -53,7 +53,7 @@ class Alipay 'version' => '1.1.3', // 插件版本 'apply_version' => '不限', // 适用系统版本描述 'apply_terminal'=> ['pc','h5', 'ios', 'android'], // 适用终端 默认全部 ['pc', 'h5', 'ios', 'android', 'alipay', 'weixin', 'baidu', 'toutiao'] - 'desc' => '2.0版本,适用PC+H5+APP+头条小程序,即时到帐支付方式,买家的交易资金直接打入卖家支付宝账户,快速回笼交易资金。 立即申请', // 插件描述(支持html) + 'desc' => '2.0版本,适用PC+H5+APP,即时到帐支付方式,买家的交易资金直接打入卖家支付宝账户,快速回笼交易资金。 立即申请', // 插件描述(支持html) 'author' => 'Devil', // 开发者 'author_url' => 'http://shopxo.net/', // 开发者主页 ]; diff --git a/index.php b/index.php index e54d5b9c9..d6492fa44 100755 --- a/index.php +++ b/index.php @@ -9,7 +9,7 @@ // | Author: Devil // +---------------------------------------------------------------------- -// 根目录入口 +// [ 前端入口文件 ] define('IS_ROOT_ACCESS', true); // 引入公共入口文件 diff --git a/install.php b/install.php new file mode 100644 index 000000000..975ce4a33 --- /dev/null +++ b/install.php @@ -0,0 +1,17 @@ + \ No newline at end of file diff --git a/public/admin.php b/public/admin.php index ea1418a90..9e29c6499 100644 --- a/public/admin.php +++ b/public/admin.php @@ -13,13 +13,14 @@ namespace think; // 加载基础文件 -require __DIR__ . '/../thinkphp/base.php'; - -// 支持事先使用静态方法设置Request对象和Config对象 +require __DIR__ . '/../vendor/autoload.php'; // 引入公共入口文件 require __DIR__.'/core.php'; -// 执行应用并响应 -Container::get('app')->bind('admin')->run()->send(); +// 执行HTTP应用并响应 +$http = (new App())->http; +$response = $http->name('admin')->run(); +$response->send(); +$http->end($response); ?> \ No newline at end of file diff --git a/public/api.php b/public/api.php new file mode 100644 index 000000000..f8c94dd59 --- /dev/null +++ b/public/api.php @@ -0,0 +1,26 @@ +http; +$response = $http->name('api')->run(); +$response->send(); +$http->end($response); +?> \ No newline at end of file diff --git a/public/core.php b/public/core.php index 4adf54faa..3686cbea7 100755 --- a/public/core.php +++ b/public/core.php @@ -10,10 +10,10 @@ // +---------------------------------------------------------------------- // 检测PHP环境 -if(version_compare(PHP_VERSION,'5.6.0','<')) die('PHP版本最低 5.6.0'); +if(version_compare(PHP_VERSION,'7.1.0','<')) die('PHP版本最低 7.1.0'); // 系统版本 -define('APPLICATION_VERSION', 'v2.1.0'); +define('APPLICATION_VERSION', 'v2.2.0'); // 定义系统目录分隔符 define('DS', '/'); @@ -62,7 +62,7 @@ define('ROOT_PATH', str_replace('\\', DS, dirname(__FILE__)).DS); define('ROOT', substr(ROOT_PATH, 0, -7)); // 定义应用目录 -define('APP_PATH', ROOT.'application'.DS); +define('APP_PATH', ROOT.'app'.DS); // 请求应用 [web, app] 默认web(ios|android|小程序 均为app) define('APPLICATION', empty($_REQUEST['application']) ? 'web' : trim($_REQUEST['application'])); @@ -78,14 +78,4 @@ define('IS_POST', isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD' // 是否ajax define('IS_AJAX', ((isset($_SERVER['HTTP_X_REQUESTED_WITH']) && 'xmlhttprequest' == strtolower($_SERVER['HTTP_X_REQUESTED_WITH'])) || isset($_REQUEST['ajax']) && $_REQUEST['ajax'] == 'ajax')); - -// 检测是否是新安装 -if(!file_exists(ROOT.'config/database.php')) -{ - if(empty($_GET['s']) || stripos($_GET['s'], 'install') === false) - { - $url = __MY_URL__.'index.php?s=/install/index/index'; - exit(header('location:'.$url)); - } -} ?> \ No newline at end of file diff --git a/public/index.php b/public/index.php old mode 100755 new mode 100644 index 7e912bb9d..4b464382f --- a/public/index.php +++ b/public/index.php @@ -9,17 +9,18 @@ // | Author: Devil // +---------------------------------------------------------------------- -// [ 应用入口文件 ] +// [ 前端入口文件 ] namespace think; // 加载基础文件 -require __DIR__ . '/../thinkphp/base.php'; - -// 支持事先使用静态方法设置Request对象和Config对象 +require __DIR__ . '/../vendor/autoload.php'; // 引入公共入口文件 require __DIR__.'/core.php'; -// 执行应用并响应 -Container::get('app')->run()->send(); +// 执行HTTP应用并响应 +$http = (new App())->http; +$response = $http->name('index')->run(); +$response->send(); +$http->end($response); ?> \ No newline at end of file diff --git a/public/install.php b/public/install.php new file mode 100644 index 000000000..ea6139794 --- /dev/null +++ b/public/install.php @@ -0,0 +1,26 @@ +http; +$response = $http->name('install')->run(); +$response->send(); +$http->end($response); +?> \ No newline at end of file diff --git a/public/router.php b/public/router.php old mode 100755 new mode 100644 index cebbc4b91..9b39a62c9 --- a/public/router.php +++ b/public/router.php @@ -1,17 +1,19 @@ // +---------------------------------------------------------------------- +// $Id$ if (is_file($_SERVER["DOCUMENT_ROOT"] . $_SERVER["SCRIPT_NAME"])) { return false; } else { + $_SERVER["SCRIPT_FILENAME"] = __DIR__ . '/index.php'; + require __DIR__ . "/index.php"; } -?> \ No newline at end of file diff --git a/public/static/common/lib/ueditor/dialogs/attachment/attachment.js b/public/static/common/lib/ueditor/dialogs/attachment/attachment.js index e00d007b9..afbc4002f 100755 --- a/public/static/common/lib/ueditor/dialogs/attachment/attachment.js +++ b/public/static/common/lib/ueditor/dialogs/attachment/attachment.js @@ -794,7 +794,9 @@ window.event.stopPropagation(); //阻止事件的传播 } finally { if(!confirm("确定要删除吗?")) return; - $.post(editor.getOpt("serverUrl") + "?action=deletefile", { "id": del.attr("data-id") }, function(response) { + var url = editor.getOpt("serverUrl"); + var join = (url.indexOf('?') == -1) ? '?' : '&'; + $.post(url + join+"?action=deletefile", { "id": del.attr("data-id") }, function(response) { if (response.code == 0) { del.parent().remove(); diff --git a/public/static/common/lib/ueditor/dialogs/image/image.js b/public/static/common/lib/ueditor/dialogs/image/image.js index f7b644237..20aa135bf 100755 --- a/public/static/common/lib/ueditor/dialogs/image/image.js +++ b/public/static/common/lib/ueditor/dialogs/image/image.js @@ -969,7 +969,9 @@ window.event.stopPropagation(); //阻止事件的传播 } finally { if(!confirm("确定要删除吗?")) return; - $.post(editor.getOpt("serverUrl") + "?action=deletefile", { "id": del.attr("data-id") }, function(response) { + var url = editor.getOpt("serverUrl"); + var join = (url.indexOf('?') == -1) ? '?' : '&'; + $.post(url + join+"action=deletefile", { "id": del.attr("data-id") }, function(response) { if (response.code == 0) { del.parent().remove(); diff --git a/public/static/common/lib/ueditor/dialogs/map/map.html b/public/static/common/lib/ueditor/dialogs/map/map.html index 58f416bac..8a6259b1c 100755 --- a/public/static/common/lib/ueditor/dialogs/map/map.html +++ b/public/static/common/lib/ueditor/dialogs/map/map.html @@ -4,7 +4,7 @@ - + - + diff --git a/public/static/common/lib/ueditor/dialogs/video/video.js b/public/static/common/lib/ueditor/dialogs/video/video.js index 0c98749d8..5a9224bb7 100755 --- a/public/static/common/lib/ueditor/dialogs/video/video.js +++ b/public/static/common/lib/ueditor/dialogs/video/video.js @@ -342,7 +342,9 @@ window.event.stopPropagation(); //阻止事件的传播 } finally { if(!confirm("确定要删除吗?")) return; - $.post(editor.getOpt("serverUrl") + "?action=deletefile", { "id": del.attr("data-id") }, function(response) { + var url = editor.getOpt("serverUrl"); + var join = (url.indexOf('?') == -1) ? '?' : '&'; + $.post(url + join+"?action=deletefile", { "id": del.attr("data-id") }, function(response) { if (response.code == 0) { del.parent().remove(); diff --git a/public/static/index/default/js/goods.js b/public/static/index/default/js/goods.js index 0246125de..6b28b1193 100755 --- a/public/static/index/default/js/goods.js +++ b/public/static/index/default/js/goods.js @@ -498,6 +498,7 @@ $(function() { } } }); + // 确认 $('.theme-popover .confirm').on('click', function() { // 是否登录 diff --git a/robots.txt b/robots.txt deleted file mode 100755 index 4ae1c9787..000000000 --- a/robots.txt +++ /dev/null @@ -1,10 +0,0 @@ -User-agent: * -Disallow: /index.php?s=/admin* -Disallow: /index.php?s=/install* -Disallow: /index.php?s=/api* -Disallow: /admin* -Disallow: /api* -Disallow: /install* -Disallow: /*respond.php -Disallow: /*notify.php -Disallow: /public* \ No newline at end of file diff --git a/sourcecode/alipay/default/pages/common/copyright.axml b/sourcecode/alipay/default/pages/common/copyright.axml index 294a02cb2..b8f9b153d 100644 --- a/sourcecode/alipay/default/pages/common/copyright.axml +++ b/sourcecode/alipay/default/pages/common/copyright.axml @@ -1,5 +1,5 @@ \ No newline at end of file diff --git a/sourcecode/baidu/default/pages/common/copyright.swan b/sourcecode/baidu/default/pages/common/copyright.swan index 294a02cb2..b8f9b153d 100755 --- a/sourcecode/baidu/default/pages/common/copyright.swan +++ b/sourcecode/baidu/default/pages/common/copyright.swan @@ -1,5 +1,5 @@ \ No newline at end of file diff --git a/sourcecode/qq/default/pages/common/copyright.qml b/sourcecode/qq/default/pages/common/copyright.qml index 294a02cb2..b8f9b153d 100755 --- a/sourcecode/qq/default/pages/common/copyright.qml +++ b/sourcecode/qq/default/pages/common/copyright.qml @@ -1,5 +1,5 @@ \ No newline at end of file diff --git a/sourcecode/toutiao/default/pages/common/copyright.ttml b/sourcecode/toutiao/default/pages/common/copyright.ttml index 294a02cb2..b8f9b153d 100755 --- a/sourcecode/toutiao/default/pages/common/copyright.ttml +++ b/sourcecode/toutiao/default/pages/common/copyright.ttml @@ -1,5 +1,5 @@ \ No newline at end of file diff --git a/sourcecode/weixin/default/pages/common/copyright.wxml b/sourcecode/weixin/default/pages/common/copyright.wxml index 294a02cb2..b8f9b153d 100755 --- a/sourcecode/weixin/default/pages/common/copyright.wxml +++ b/sourcecode/weixin/default/pages/common/copyright.wxml @@ -1,5 +1,5 @@ \ No newline at end of file diff --git a/think b/think old mode 100755 new mode 100644 index 366164799..276b2ffc6 --- a/think +++ b/think @@ -1,25 +1,13 @@ #!/usr/bin/env php path(__DIR__ . '/application/')->initialize(); - -// 控制台初始化 -Console::init(); +(new App())->console->run(); \ No newline at end of file diff --git a/thinkphp/.htaccess b/thinkphp/.htaccess deleted file mode 100755 index 3418e55a6..000000000 --- a/thinkphp/.htaccess +++ /dev/null @@ -1 +0,0 @@ -deny from all \ No newline at end of file diff --git a/thinkphp/README.md b/thinkphp/README.md deleted file mode 100755 index b2a791b8b..000000000 --- a/thinkphp/README.md +++ /dev/null @@ -1,93 +0,0 @@ -![](https://box.kancloud.cn/5a0aaa69a5ff42657b5c4715f3d49221) - -ThinkPHP 5.1(LTS) —— 12载初心,你值得信赖的PHP框架 -=============== - -[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/top-think/framework/badges/quality-score.png?b=5.1)](https://scrutinizer-ci.com/g/top-think/framework/?branch=5.1) -[![Build Status](https://travis-ci.org/top-think/framework.svg?branch=master)](https://travis-ci.org/top-think/framework) -[![Total Downloads](https://poser.pugx.org/topthink/framework/downloads)](https://packagist.org/packages/topthink/framework) -[![Latest Stable Version](https://poser.pugx.org/topthink/framework/v/stable)](https://packagist.org/packages/topthink/framework) -[![PHP Version](https://img.shields.io/badge/php-%3E%3D5.6-8892BF.svg)](http://www.php.net/) -[![License](https://poser.pugx.org/topthink/framework/license)](https://packagist.org/packages/topthink/framework) - -ThinkPHP5.1对底层架构做了进一步的改进,减少依赖,其主要特性包括: - - + 采用容器统一管理对象 - + 支持Facade - + 更易用的路由 - + 注解路由支持 - + 路由跨域请求支持 - + 验证类增强 - + 配置和路由目录独立 - + 取消系统常量 - + 类库别名机制 - + 模型和数据库增强 - + 依赖注入完善 - + 支持PSR-3日志规范 - + 中间件支持(`V5.1.6+`) - + 支持`Swoole`/`Workerman`运行(`V5.1.18+`) - -官方已经正式宣布`5.1.27`版本为LTS版本。 - -### 废除的功能: - - + 聚合模型 - + 内置控制器扩展类 - + 模型自动验证 - -> ThinkPHP5.1的运行环境要求PHP5.6+。 - - -## 安装 - -使用composer安装 - -~~~ -composer create-project topthink/think tp -~~~ - -启动服务 - -~~~ -cd tp -php think run -~~~ - -然后就可以在浏览器中访问 - -~~~ -http://localhost:8000 -~~~ - -更新框架 -~~~ -composer update topthink/framework -~~~ - - -## 在线手册 - -+ [完全开发手册](https://www.kancloud.cn/manual/thinkphp5_1/content) -+ [升级指导](https://www.kancloud.cn/manual/thinkphp5_1/354155) - -## 命名规范 - -`ThinkPHP5.1`遵循PSR-2命名规范和PSR-4自动加载规范。 - -## 参与开发 - -请参阅 [ThinkPHP5 核心框架包](https://github.com/top-think/framework)。 - -## 版权信息 - -ThinkPHP遵循Apache2开源协议发布,并提供免费使用。 - -本项目包含的第三方源码和二进制文件之版权信息另行标注。 - -版权所有Copyright © 2006-2018 by ThinkPHP (http://thinkphp.cn) - -All rights reserved。 - -ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。 - -更多细节参阅 [LICENSE.txt](LICENSE.txt) diff --git a/thinkphp/base.php b/thinkphp/base.php deleted file mode 100755 index d7238cc6a..000000000 --- a/thinkphp/base.php +++ /dev/null @@ -1,52 +0,0 @@ - -// +---------------------------------------------------------------------- -namespace think; - -// 载入Loader类 -require __DIR__ . '/library/think/Loader.php'; - -// 注册自动加载 -Loader::register(); - -// 注册错误和异常处理机制 -Error::register(); - -// 实现日志接口 -if (interface_exists('Psr\Log\LoggerInterface')) { - interface LoggerInterface extends \Psr\Log\LoggerInterface - {} -} else { - interface LoggerInterface - {} -} - -// 注册类库别名 -Loader::addClassAlias([ - 'App' => facade\App::class, - 'Build' => facade\Build::class, - 'Cache' => facade\Cache::class, - 'Config' => facade\Config::class, - 'Cookie' => facade\Cookie::class, - 'Db' => Db::class, - 'Debug' => facade\Debug::class, - 'Env' => facade\Env::class, - 'Facade' => Facade::class, - 'Hook' => facade\Hook::class, - 'Lang' => facade\Lang::class, - 'Log' => facade\Log::class, - 'Request' => facade\Request::class, - 'Response' => facade\Response::class, - 'Route' => facade\Route::class, - 'Session' => facade\Session::class, - 'Url' => facade\Url::class, - 'Validate' => facade\Validate::class, - 'View' => facade\View::class, -]); diff --git a/thinkphp/convention.php b/thinkphp/convention.php deleted file mode 100755 index 1d85e56ef..000000000 --- a/thinkphp/convention.php +++ /dev/null @@ -1,327 +0,0 @@ - [ - // 应用名称 - 'app_name' => '', - // 应用地址 - 'app_host' => '', - // 应用调试模式 - 'app_debug' => false, - // 应用Trace - 'app_trace' => false, - // 应用模式状态 - 'app_status' => '', - // 是否HTTPS - 'is_https' => false, - // 入口自动绑定模块 - 'auto_bind_module' => false, - // 注册的根命名空间 - 'root_namespace' => [], - // 默认输出类型 - 'default_return_type' => 'html', - // 默认AJAX 数据返回格式,可选json xml ... - 'default_ajax_return' => 'json', - // 默认JSONP格式返回的处理方法 - 'default_jsonp_handler' => 'jsonpReturn', - // 默认JSONP处理方法 - 'var_jsonp_handler' => 'callback', - // 默认时区 - 'default_timezone' => 'Asia/Shanghai', - // 是否开启多语言 - 'lang_switch_on' => false, - // 默认验证器 - 'default_validate' => '', - // 默认语言 - 'default_lang' => 'zh-cn', - - // +---------------------------------------------------------------------- - // | 模块设置 - // +---------------------------------------------------------------------- - - // 自动搜索控制器 - 'controller_auto_search' => false, - // 操作方法前缀 - 'use_action_prefix' => false, - // 操作方法后缀 - 'action_suffix' => '', - // 默认的空控制器名 - 'empty_controller' => 'Error', - // 默认的空模块名 - 'empty_module' => '', - // 默认模块名 - 'default_module' => 'index', - // 是否支持多模块 - 'app_multi_module' => true, - // 禁止访问模块 - 'deny_module_list' => ['common'], - // 默认控制器名 - 'default_controller' => 'Index', - // 默认操作名 - 'default_action' => 'index', - // 是否自动转换URL中的控制器和操作名 - 'url_convert' => true, - // 默认的访问控制器层 - 'url_controller_layer' => 'controller', - // 应用类库后缀 - 'class_suffix' => false, - // 控制器类后缀 - 'controller_suffix' => false, - - // +---------------------------------------------------------------------- - // | URL请求设置 - // +---------------------------------------------------------------------- - - // 默认全局过滤方法 用逗号分隔多个 - 'default_filter' => '', - // PATHINFO变量名 用于兼容模式 - 'var_pathinfo' => 's', - // 兼容PATH_INFO获取 - 'pathinfo_fetch' => ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO', 'REDIRECT_URL'], - // HTTPS代理标识 - 'https_agent_name' => '', - // IP代理获取标识 - 'http_agent_ip' => 'HTTP_X_REAL_IP', - // URL伪静态后缀 - 'url_html_suffix' => 'html', - // 域名根,如thinkphp.cn - 'url_domain_root' => '', - // 表单请求类型伪装变量 - 'var_method' => '_method', - // 表单ajax伪装变量 - 'var_ajax' => '_ajax', - // 表单pjax伪装变量 - 'var_pjax' => '_pjax', - // 是否开启请求缓存 true自动缓存 支持设置请求缓存规则 - 'request_cache' => false, - // 请求缓存有效期 - 'request_cache_expire' => null, - // 全局请求缓存排除规则 - 'request_cache_except' => [], - - // +---------------------------------------------------------------------- - // | 路由设置 - // +---------------------------------------------------------------------- - - // pathinfo分隔符 - 'pathinfo_depr' => '/', - // URL普通方式参数 用于自动生成 - 'url_common_param' => false, - // URL参数方式 0 按名称成对解析 1 按顺序解析 - 'url_param_type' => 0, - // 是否开启路由延迟解析 - 'url_lazy_route' => false, - // 是否强制使用路由 - 'url_route_must' => false, - // 合并路由规则 - 'route_rule_merge' => false, - // 路由是否完全匹配 - 'route_complete_match' => false, - // 使用注解路由 - 'route_annotation' => false, - // 默认的路由变量规则 - 'default_route_pattern' => '\w+', - // 是否开启路由缓存 - 'route_check_cache' => false, - // 路由缓存的Key自定义设置(闭包),默认为当前URL和请求类型的md5 - 'route_check_cache_key' => '', - // 路由缓存的设置 - 'route_cache_option' => [], - - // +---------------------------------------------------------------------- - // | 异常及错误设置 - // +---------------------------------------------------------------------- - - // 默认跳转页面对应的模板文件 - 'dispatch_success_tmpl' => __DIR__ . '/tpl/dispatch_jump.tpl', - 'dispatch_error_tmpl' => __DIR__ . '/tpl/dispatch_jump.tpl', - // 异常页面的模板文件 - 'exception_tmpl' => __DIR__ . '/tpl/think_exception.tpl', - // 错误显示信息,非调试模式有效 - 'error_message' => '页面错误!请稍后再试~', - // 显示错误信息 - 'show_error_msg' => false, - // 异常处理handle类 留空使用 \think\exception\Handle - 'exception_handle' => '', - ], - - // +---------------------------------------------------------------------- - // | 模板设置 - // +---------------------------------------------------------------------- - - 'template' => [ - // 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写 - 'auto_rule' => 1, - // 模板引擎类型 支持 php think 支持扩展 - 'type' => 'Think', - // 视图基础目录,配置目录为所有模块的视图起始目录 - 'view_base' => '', - // 当前模板的视图目录 留空为自动获取 - 'view_path' => '', - // 模板后缀 - 'view_suffix' => 'html', - // 模板文件名分隔符 - 'view_depr' => DIRECTORY_SEPARATOR, - // 模板引擎普通标签开始标记 - 'tpl_begin' => '{', - // 模板引擎普通标签结束标记 - 'tpl_end' => '}', - // 标签库标签开始标记 - 'taglib_begin' => '{', - // 标签库标签结束标记 - 'taglib_end' => '}', - ], - - // +---------------------------------------------------------------------- - // | 日志设置 - // +---------------------------------------------------------------------- - - 'log' => [ - // 日志记录方式,内置 file socket 支持扩展 - 'type' => 'File', - // 日志保存目录 - //'path' => LOG_PATH, - // 日志记录级别 - 'level' => [], - // 是否记录trace信息到日志 - 'record_trace' => false, - // 是否JSON格式记录 - 'json' => false, - ], - - // +---------------------------------------------------------------------- - // | Trace设置 开启 app_trace 后 有效 - // +---------------------------------------------------------------------- - - 'trace' => [ - // 内置Html Console 支持扩展 - 'type' => 'Html', - 'file' => __DIR__ . '/tpl/page_trace.tpl', - ], - - // +---------------------------------------------------------------------- - // | 缓存设置 - // +---------------------------------------------------------------------- - - 'cache' => [ - // 驱动方式 - 'type' => 'File', - // 缓存保存目录 - //'path' => CACHE_PATH, - // 缓存前缀 - 'prefix' => '', - // 缓存有效期 0表示永久缓存 - 'expire' => 0, - ], - - // +---------------------------------------------------------------------- - // | 会话设置 - // +---------------------------------------------------------------------- - - 'session' => [ - 'id' => '', - // SESSION_ID的提交变量,解决flash上传跨域 - 'var_session_id' => '', - // SESSION 前缀 - 'prefix' => 'think', - // 驱动方式 支持redis memcache memcached - 'type' => '', - // 是否自动开启 SESSION - 'auto_start' => true, - 'httponly' => true, - 'secure' => false, - ], - - // +---------------------------------------------------------------------- - // | Cookie设置 - // +---------------------------------------------------------------------- - - 'cookie' => [ - // cookie 名称前缀 - 'prefix' => '', - // cookie 保存时间 - 'expire' => 0, - // cookie 保存路径 - 'path' => '/', - // cookie 有效域名 - 'domain' => '', - // cookie 启用安全传输 - 'secure' => false, - // httponly设置 - 'httponly' => '', - // 是否使用 setcookie - 'setcookie' => true, - ], - - // +---------------------------------------------------------------------- - // | 数据库设置 - // +---------------------------------------------------------------------- - - 'database' => [ - // 数据库类型 - 'type' => 'mysql', - // 数据库连接DSN配置 - 'dsn' => '', - // 服务器地址 - 'hostname' => '127.0.0.1', - // 数据库名 - 'database' => '', - // 数据库用户名 - 'username' => 'root', - // 数据库密码 - 'password' => '', - // 数据库连接端口 - 'hostport' => '', - // 数据库连接参数 - 'params' => [], - // 数据库编码默认采用utf8 - 'charset' => 'utf8', - // 数据库表前缀 - 'prefix' => '', - // 数据库调试模式 - 'debug' => false, - // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) - 'deploy' => 0, - // 数据库读写是否分离 主从式有效 - 'rw_separate' => false, - // 读写分离后 主服务器数量 - 'master_num' => 1, - // 指定从服务器序号 - 'slave_no' => '', - // 是否严格检查字段是否存在 - 'fields_strict' => true, - // 数据集返回类型 - 'resultset_type' => 'array', - // 自动写入时间戳字段 - 'auto_timestamp' => false, - // 时间字段取出后的默认时间格式 - 'datetime_format' => 'Y-m-d H:i:s', - // 是否需要进行SQL性能分析 - 'sql_explain' => false, - // 查询对象 - 'query' => '\\think\\db\\Query', - ], - - //分页配置 - 'paginate' => [ - 'type' => 'bootstrap', - 'var_page' => 'page', - 'list_rows' => 15, - ], - - //控制台配置 - 'console' => [ - 'name' => 'Think Console', - 'version' => '0.1', - 'user' => null, - 'auto_path' => '', - ], - - // 中间件配置 - 'middleware' => [ - 'default_namespace' => 'app\\http\\middleware\\', - ], -]; diff --git a/thinkphp/helper.php b/thinkphp/helper.php deleted file mode 100755 index 9c4653350..000000000 --- a/thinkphp/helper.php +++ /dev/null @@ -1,720 +0,0 @@ - -// +---------------------------------------------------------------------- - -//------------------------ -// ThinkPHP 助手函数 -//------------------------- - -use think\Container; -use think\Db; -use think\exception\HttpException; -use think\exception\HttpResponseException; -use think\facade\Cache; -use think\facade\Config; -use think\facade\Cookie; -use think\facade\Debug; -use think\facade\Env; -use think\facade\Hook; -use think\facade\Lang; -use think\facade\Log; -use think\facade\Request; -use think\facade\Route; -use think\facade\Session; -use think\facade\Url; -use think\Response; -use think\route\RuleItem; - -if (!function_exists('abort')) { - /** - * 抛出HTTP异常 - * @param integer|Response $code 状态码 或者 Response对象实例 - * @param string $message 错误信息 - * @param array $header 参数 - */ - function abort($code, $message = null, $header = []) - { - if ($code instanceof Response) { - throw new HttpResponseException($code); - } else { - throw new HttpException($code, $message, null, $header); - } - } -} - -if (!function_exists('action')) { - /** - * 调用模块的操作方法 参数格式 [模块/控制器/]操作 - * @param string $url 调用地址 - * @param string|array $vars 调用参数 支持字符串和数组 - * @param string $layer 要调用的控制层名称 - * @param bool $appendSuffix 是否添加类名后缀 - * @return mixed - */ - function action($url, $vars = [], $layer = 'controller', $appendSuffix = false) - { - return app()->action($url, $vars, $layer, $appendSuffix); - } -} - -if (!function_exists('app')) { - /** - * 快速获取容器中的实例 支持依赖注入 - * @param string $name 类名或标识 默认获取当前应用实例 - * @param array $args 参数 - * @param bool $newInstance 是否每次创建新的实例 - * @return mixed|\think\App - */ - function app($name = 'think\App', $args = [], $newInstance = false) - { - return Container::get($name, $args, $newInstance); - } -} - -if (!function_exists('behavior')) { - /** - * 执行某个行为(run方法) 支持依赖注入 - * @param mixed $behavior 行为类名或者别名 - * @param mixed $args 参数 - * @return mixed - */ - function behavior($behavior, $args = null) - { - return Hook::exec($behavior, $args); - } -} - -if (!function_exists('bind')) { - /** - * 绑定一个类到容器 - * @access public - * @param string $abstract 类标识、接口 - * @param mixed $concrete 要绑定的类、闭包或者实例 - * @return Container - */ - function bind($abstract, $concrete = null) - { - return Container::getInstance()->bindTo($abstract, $concrete); - } -} - -if (!function_exists('cache')) { - /** - * 缓存管理 - * @param mixed $name 缓存名称,如果为数组表示进行缓存设置 - * @param mixed $value 缓存值 - * @param mixed $options 缓存参数 - * @param string $tag 缓存标签 - * @return mixed - */ - function cache($name, $value = '', $options = null, $tag = null) - { - if (is_array($options)) { - // 缓存操作的同时初始化 - Cache::connect($options); - } elseif (is_array($name)) { - // 缓存初始化 - return Cache::connect($name); - } - - if ('' === $value) { - // 获取缓存 - return 0 === strpos($name, '?') ? Cache::has(substr($name, 1)) : Cache::get($name); - } elseif (is_null($value)) { - // 删除缓存 - return Cache::rm($name); - } - - // 缓存数据 - if (is_array($options)) { - $expire = isset($options['expire']) ? $options['expire'] : null; //修复查询缓存无法设置过期时间 - } else { - $expire = is_numeric($options) ? $options : null; //默认快捷缓存设置过期时间 - } - - if (is_null($tag)) { - return Cache::set($name, $value, $expire); - } else { - return Cache::tag($tag)->set($name, $value, $expire); - } - } -} - -if (!function_exists('call')) { - /** - * 调用反射执行callable 支持依赖注入 - * @param mixed $callable 支持闭包等callable写法 - * @param array $args 参数 - * @return mixed - */ - function call($callable, $args = []) - { - return Container::getInstance()->invoke($callable, $args); - } -} - -if (!function_exists('class_basename')) { - /** - * 获取类名(不包含命名空间) - * - * @param string|object $class - * @return string - */ - function class_basename($class) - { - $class = is_object($class) ? get_class($class) : $class; - return basename(str_replace('\\', '/', $class)); - } -} - -if (!function_exists('class_uses_recursive')) { - /** - *获取一个类里所有用到的trait,包括父类的 - * - * @param $class - * @return array - */ - function class_uses_recursive($class) - { - if (is_object($class)) { - $class = get_class($class); - } - - $results = []; - $classes = array_merge([$class => $class], class_parents($class)); - foreach ($classes as $class) { - $results += trait_uses_recursive($class); - } - - return array_unique($results); - } -} - -if (!function_exists('config')) { - /** - * 获取和设置配置参数 - * @param string|array $name 参数名 - * @param mixed $value 参数值 - * @return mixed - */ - function config($name = '', $value = null) - { - if (is_null($value) && is_string($name)) { - if ('.' == substr($name, -1)) { - return Config::pull(substr($name, 0, -1)); - } - - return 0 === strpos($name, '?') ? Config::has(substr($name, 1)) : Config::get($name); - } else { - return Config::set($name, $value); - } - } -} - -if (!function_exists('container')) { - /** - * 获取容器对象实例 - * @return Container - */ - function container() - { - return Container::getInstance(); - } -} - -if (!function_exists('controller')) { - /** - * 实例化控制器 格式:[模块/]控制器 - * @param string $name 资源地址 - * @param string $layer 控制层名称 - * @param bool $appendSuffix 是否添加类名后缀 - * @return \think\Controller - */ - function controller($name, $layer = 'controller', $appendSuffix = false) - { - return app()->controller($name, $layer, $appendSuffix); - } -} - -if (!function_exists('cookie')) { - /** - * Cookie管理 - * @param string|array $name cookie名称,如果为数组表示进行cookie设置 - * @param mixed $value cookie值 - * @param mixed $option 参数 - * @return mixed - */ - function cookie($name, $value = '', $option = null) - { - if (is_array($name)) { - // 初始化 - Cookie::init($name); - } elseif (is_null($name)) { - // 清除 - Cookie::clear($value); - } elseif ('' === $value) { - // 获取 - return 0 === strpos($name, '?') ? Cookie::has(substr($name, 1), $option) : Cookie::get($name); - } elseif (is_null($value)) { - // 删除 - return Cookie::delete($name); - } else { - // 设置 - return Cookie::set($name, $value, $option); - } - } -} - -if (!function_exists('db')) { - /** - * 实例化数据库类 - * @param string $name 操作的数据表名称(不含前缀) - * @param array|string $config 数据库配置参数 - * @param bool $force 是否强制重新连接 - * @return \think\db\Query - */ - function db($name = '', $config = [], $force = true) - { - return Db::connect($config, $force)->name($name); - } -} - -if (!function_exists('debug')) { - /** - * 记录时间(微秒)和内存使用情况 - * @param string $start 开始标签 - * @param string $end 结束标签 - * @param integer|string $dec 小数位 如果是m 表示统计内存占用 - * @return mixed - */ - function debug($start, $end = '', $dec = 6) - { - if ('' == $end) { - Debug::remark($start); - } else { - return 'm' == $dec ? Debug::getRangeMem($start, $end) : Debug::getRangeTime($start, $end, $dec); - } - } -} - -if (!function_exists('download')) { - /** - * 获取\think\response\Download对象实例 - * @param string $filename 要下载的文件 - * @param string $name 显示文件名 - * @param bool $content 是否为内容 - * @param integer $expire 有效期(秒) - * @return \think\response\Download - */ - function download($filename, $name = '', $content = false, $expire = 360, $openinBrower = false) - { - return Response::create($filename, 'download')->name($name)->isContent($content)->expire($expire)->openinBrower($openinBrower); - } -} - -if (!function_exists('dump')) { - /** - * 浏览器友好的变量输出 - * @param mixed $var 变量 - * @param boolean $echo 是否输出 默认为true 如果为false 则返回输出字符串 - * @param string $label 标签 默认为空 - * @return void|string - */ - function dump($var, $echo = true, $label = null) - { - return Debug::dump($var, $echo, $label); - } -} - -if (!function_exists('env')) { - /** - * 获取环境变量值 - * @access public - * @param string $name 环境变量名(支持二级 .号分割) - * @param string $default 默认值 - * @return mixed - */ - function env($name = null, $default = null) - { - return Env::get($name, $default); - } -} - -if (!function_exists('exception')) { - /** - * 抛出异常处理 - * - * @param string $msg 异常消息 - * @param integer $code 异常代码 默认为0 - * @param string $exception 异常类 - * - * @throws Exception - */ - function exception($msg, $code = 0, $exception = '') - { - $e = $exception ?: '\think\Exception'; - throw new $e($msg, $code); - } -} - -if (!function_exists('halt')) { - /** - * 调试变量并且中断输出 - * @param mixed $var 调试变量或者信息 - */ - function halt($var) - { - dump($var); - - throw new HttpResponseException(new Response); - } -} - -if (!function_exists('input')) { - /** - * 获取输入数据 支持默认值和过滤 - * @param string $key 获取的变量名 - * @param mixed $default 默认值 - * @param string $filter 过滤方法 - * @return mixed - */ - function input($key = '', $default = null, $filter = '') - { - if (0 === strpos($key, '?')) { - $key = substr($key, 1); - $has = true; - } - - if ($pos = strpos($key, '.')) { - // 指定参数来源 - $method = substr($key, 0, $pos); - if (in_array($method, ['get', 'post', 'put', 'patch', 'delete', 'route', 'param', 'request', 'session', 'cookie', 'server', 'env', 'path', 'file'])) { - $key = substr($key, $pos + 1); - } else { - $method = 'param'; - } - } else { - // 默认为自动判断 - $method = 'param'; - } - - if (isset($has)) { - return request()->has($key, $method, $default); - } else { - return request()->$method($key, $default, $filter); - } - } -} - -if (!function_exists('json')) { - /** - * 获取\think\response\Json对象实例 - * @param mixed $data 返回的数据 - * @param integer $code 状态码 - * @param array $header 头部 - * @param array $options 参数 - * @return \think\response\Json - */ - function json($data = [], $code = 200, $header = [], $options = []) - { - return Response::create($data, 'json', $code, $header, $options); - } -} - -if (!function_exists('jsonp')) { - /** - * 获取\think\response\Jsonp对象实例 - * @param mixed $data 返回的数据 - * @param integer $code 状态码 - * @param array $header 头部 - * @param array $options 参数 - * @return \think\response\Jsonp - */ - function jsonp($data = [], $code = 200, $header = [], $options = []) - { - return Response::create($data, 'jsonp', $code, $header, $options); - } -} - -if (!function_exists('lang')) { - /** - * 获取语言变量值 - * @param string $name 语言变量名 - * @param array $vars 动态变量值 - * @param string $lang 语言 - * @return mixed - */ - function lang($name, $vars = [], $lang = '') - { - return Lang::get($name, $vars, $lang); - } -} - -if (!function_exists('model')) { - /** - * 实例化Model - * @param string $name Model名称 - * @param string $layer 业务层名称 - * @param bool $appendSuffix 是否添加类名后缀 - * @return \think\Model - */ - function model($name = '', $layer = 'model', $appendSuffix = false) - { - return app()->model($name, $layer, $appendSuffix); - } -} - -if (!function_exists('parse_name')) { - /** - * 字符串命名风格转换 - * type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格 - * @param string $name 字符串 - * @param integer $type 转换类型 - * @param bool $ucfirst 首字母是否大写(驼峰规则) - * @return string - */ - function parse_name($name, $type = 0, $ucfirst = true) - { - if ($type) { - $name = preg_replace_callback('/_([a-zA-Z])/', function ($match) { - return strtoupper($match[1]); - }, $name); - - return $ucfirst ? ucfirst($name) : lcfirst($name); - } else { - return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_")); - } - } -} - -if (!function_exists('redirect')) { - /** - * 获取\think\response\Redirect对象实例 - * @param mixed $url 重定向地址 支持Url::build方法的地址 - * @param array|integer $params 额外参数 - * @param integer $code 状态码 - * @return \think\response\Redirect - */ - function redirect($url = [], $params = [], $code = 302) - { - if (is_integer($params)) { - $code = $params; - $params = []; - } - - return Response::create($url, 'redirect', $code)->params($params); - } -} - -if (!function_exists('request')) { - /** - * 获取当前Request对象实例 - * @return Request - */ - function request() - { - return app('request'); - } -} - -if (!function_exists('response')) { - /** - * 创建普通 Response 对象实例 - * @param mixed $data 输出数据 - * @param int|string $code 状态码 - * @param array $header 头信息 - * @param string $type - * @return Response - */ - function response($data = [], $code = 200, $header = [], $type = 'html') - { - return Response::create($data, $type, $code, $header); - } -} - -if (!function_exists('route')) { - /** - * 路由注册 - * @param string $rule 路由规则 - * @param mixed $route 路由地址 - * @param array $option 路由参数 - * @param array $pattern 变量规则 - * @return RuleItem - */ - function route($rule, $route, $option = [], $pattern = []) - { - return Route::rule($rule, $route, '*', $option, $pattern); - } -} - -if (!function_exists('session')) { - /** - * Session管理 - * @param string|array $name session名称,如果为数组表示进行session设置 - * @param mixed $value session值 - * @param string $prefix 前缀 - * @return mixed - */ - function session($name, $value = '', $prefix = null) - { - if (is_array($name)) { - // 初始化 - Session::init($name); - } elseif (is_null($name)) { - // 清除 - Session::clear($value); - } elseif ('' === $value) { - // 判断或获取 - return 0 === strpos($name, '?') ? Session::has(substr($name, 1), $prefix) : Session::get($name, $prefix); - } elseif (is_null($value)) { - // 删除 - return Session::delete($name, $prefix); - } else { - // 设置 - return Session::set($name, $value, $prefix); - } - } -} - -if (!function_exists('token')) { - /** - * 生成表单令牌 - * @param string $name 令牌名称 - * @param mixed $type 令牌生成方法 - * @return string - */ - function token($name = '__token__', $type = 'md5') - { - $token = Request::token($name, $type); - - return ''; - } -} - -if (!function_exists('trace')) { - /** - * 记录日志信息 - * @param mixed $log log信息 支持字符串和数组 - * @param string $level 日志级别 - * @return array|void - */ - function trace($log = '[think]', $level = 'log') - { - if ('[think]' === $log) { - return Log::getLog(); - } else { - Log::record($log, $level); - } - } -} - -if (!function_exists('trait_uses_recursive')) { - /** - * 获取一个trait里所有引用到的trait - * - * @param string $trait - * @return array - */ - function trait_uses_recursive($trait) - { - $traits = class_uses($trait); - foreach ($traits as $trait) { - $traits += trait_uses_recursive($trait); - } - - return $traits; - } -} - -if (!function_exists('url')) { - /** - * Url生成 - * @param string $url 路由地址 - * @param string|array $vars 变量 - * @param bool|string $suffix 生成的URL后缀 - * @param bool|string $domain 域名 - * @return string - */ - function url($url = '', $vars = '', $suffix = true, $domain = false) - { - return Url::build($url, $vars, $suffix, $domain); - } -} - -if (!function_exists('validate')) { - /** - * 实例化验证器 - * @param string $name 验证器名称 - * @param string $layer 业务层名称 - * @param bool $appendSuffix 是否添加类名后缀 - * @return \think\Validate - */ - function validate($name = '', $layer = 'validate', $appendSuffix = false) - { - return app()->validate($name, $layer, $appendSuffix); - } -} - -if (!function_exists('view')) { - /** - * 渲染模板输出 - * @param string $template 模板文件 - * @param array $vars 模板变量 - * @param integer $code 状态码 - * @param callable $filter 内容过滤 - * @return \think\response\View - */ - function view($template = '', $vars = [], $code = 200, $filter = null) - { - return Response::create($template, 'view', $code)->assign($vars)->filter($filter); - } -} - -if (!function_exists('widget')) { - /** - * 渲染输出Widget - * @param string $name Widget名称 - * @param array $data 传入的参数 - * @return mixed - */ - function widget($name, $data = []) - { - return app()->action($name, $data, 'widget'); - } -} - -if (!function_exists('xml')) { - /** - * 获取\think\response\Xml对象实例 - * @param mixed $data 返回的数据 - * @param integer $code 状态码 - * @param array $header 头部 - * @param array $options 参数 - * @return \think\response\Xml - */ - function xml($data = [], $code = 200, $header = [], $options = []) - { - return Response::create($data, 'xml', $code, $header, $options); - } -} - -if (!function_exists('yaconf')) { - /** - * 获取yaconf配置 - * - * @param string $name 配置参数名 - * @param mixed $default 默认值 - * @return mixed - */ - function yaconf($name, $default = null) - { - return Config::yaconf($name, $default); - } -} diff --git a/thinkphp/library/think/App.php b/thinkphp/library/think/App.php deleted file mode 100755 index ac8b0e91b..000000000 --- a/thinkphp/library/think/App.php +++ /dev/null @@ -1,981 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think; - -use think\exception\ClassNotFoundException; -use think\exception\HttpResponseException; -use think\route\Dispatch; - -/** - * App 应用管理 - */ -class App extends Container -{ - const VERSION = '5.1.32 LTS'; - - /** - * 当前模块路径 - * @var string - */ - protected $modulePath; - - /** - * 应用调试模式 - * @var bool - */ - protected $appDebug = true; - - /** - * 应用开始时间 - * @var float - */ - protected $beginTime; - - /** - * 应用内存初始占用 - * @var integer - */ - protected $beginMem; - - /** - * 应用类库命名空间 - * @var string - */ - protected $namespace = 'app'; - - /** - * 应用类库后缀 - * @var bool - */ - protected $suffix = false; - - /** - * 严格路由检测 - * @var bool - */ - protected $routeMust; - - /** - * 应用类库目录 - * @var string - */ - protected $appPath; - - /** - * 框架目录 - * @var string - */ - protected $thinkPath; - - /** - * 应用根目录 - * @var string - */ - protected $rootPath; - - /** - * 运行时目录 - * @var string - */ - protected $runtimePath; - - /** - * 配置目录 - * @var string - */ - protected $configPath; - - /** - * 路由目录 - * @var string - */ - protected $routePath; - - /** - * 配置后缀 - * @var string - */ - protected $configExt; - - /** - * 应用调度实例 - * @var Dispatch - */ - protected $dispatch; - - /** - * 绑定模块(控制器) - * @var string - */ - protected $bindModule; - - /** - * 初始化 - * @var bool - */ - protected $initialized = false; - - public function __construct($appPath = '') - { - $this->thinkPath = dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR; - $this->path($appPath); - } - - /** - * 绑定模块或者控制器 - * @access public - * @param string $bind - * @return $this - */ - public function bind($bind) - { - $this->bindModule = $bind; - return $this; - } - - /** - * 设置应用类库目录 - * @access public - * @param string $path 路径 - * @return $this - */ - public function path($path) - { - $this->appPath = $path ? realpath($path) . DIRECTORY_SEPARATOR : $this->getAppPath(); - - return $this; - } - - /** - * 初始化应用 - * @access public - * @return void - */ - public function initialize() - { - if ($this->initialized) { - return; - } - - $this->initialized = true; - $this->beginTime = microtime(true); - $this->beginMem = memory_get_usage(); - - $this->rootPath = dirname($this->appPath) . DIRECTORY_SEPARATOR; - $this->runtimePath = $this->rootPath . 'runtime' . DIRECTORY_SEPARATOR; - $this->routePath = $this->rootPath . 'route' . DIRECTORY_SEPARATOR; - $this->configPath = $this->rootPath . 'config' . DIRECTORY_SEPARATOR; - - static::setInstance($this); - - $this->instance('app', $this); - - $this->configExt = $this->env->get('config_ext', '.php'); - - // 加载惯例配置文件 - $this->config->set(include $this->thinkPath . 'convention.php'); - - // 设置路径环境变量 - $this->env->set([ - 'think_path' => $this->thinkPath, - 'root_path' => $this->rootPath, - 'app_path' => $this->appPath, - 'config_path' => $this->configPath, - 'route_path' => $this->routePath, - 'runtime_path' => $this->runtimePath, - 'extend_path' => $this->rootPath . 'extend' . DIRECTORY_SEPARATOR, - 'vendor_path' => $this->rootPath . 'vendor' . DIRECTORY_SEPARATOR, - ]); - - // 加载环境变量配置文件 - if (is_file($this->rootPath . '.env')) { - $this->env->load($this->rootPath . '.env'); - } - - $this->namespace = $this->env->get('app_namespace', $this->namespace); - $this->env->set('app_namespace', $this->namespace); - - // 注册应用命名空间 - Loader::addNamespace($this->namespace, $this->appPath); - - // 初始化应用 - $this->init(); - - // 开启类名后缀 - $this->suffix = $this->config('app.class_suffix'); - - // 应用调试模式 - $this->appDebug = $this->env->get('app_debug', $this->config('app.app_debug')); - $this->env->set('app_debug', $this->appDebug); - - if (!$this->appDebug) { - ini_set('display_errors', 'Off'); - } elseif (PHP_SAPI != 'cli') { - //重新申请一块比较大的buffer - if (ob_get_level() > 0) { - $output = ob_get_clean(); - } - ob_start(); - if (!empty($output)) { - echo $output; - } - } - - // 注册异常处理类 - if ($this->config('app.exception_handle')) { - Error::setExceptionHandler($this->config('app.exception_handle')); - } - - // 注册根命名空间 - if (!empty($this->config('app.root_namespace'))) { - Loader::addNamespace($this->config('app.root_namespace')); - } - - // 加载composer autofile文件 - Loader::loadComposerAutoloadFiles(); - - // 注册类库别名 - Loader::addClassAlias($this->config->pull('alias')); - - // 数据库配置初始化 - Db::init($this->config->pull('database')); - - // 设置系统时区 - date_default_timezone_set($this->config('app.default_timezone')); - - // 读取语言包 - $this->loadLangPack(); - - // 路由初始化 - $this->routeInit(); - } - - /** - * 初始化应用或模块 - * @access public - * @param string $module 模块名 - * @return void - */ - public function init($module = '') - { - // 定位模块目录 - $module = $module ? $module . DIRECTORY_SEPARATOR : ''; - $path = $this->appPath . $module; - - // 加载初始化文件 - if (is_file($path . 'init.php')) { - include $path . 'init.php'; - } elseif (is_file($this->runtimePath . $module . 'init.php')) { - include $this->runtimePath . $module . 'init.php'; - } else { - // 加载行为扩展文件 - if (is_file($path . 'tags.php')) { - $tags = include $path . 'tags.php'; - if (is_array($tags)) { - $this->hook->import($tags); - } - } - - // 加载公共文件 - if (is_file($path . 'common.php')) { - include_once $path . 'common.php'; - } - - if ('' == $module) { - // 加载系统助手函数 - include $this->thinkPath . 'helper.php'; - } - - // 加载中间件 - if (is_file($path . 'middleware.php')) { - $middleware = include $path . 'middleware.php'; - if (is_array($middleware)) { - $this->middleware->import($middleware); - } - } - - // 注册服务的容器对象实例 - if (is_file($path . 'provider.php')) { - $provider = include $path . 'provider.php'; - if (is_array($provider)) { - $this->bindTo($provider); - } - } - - // 自动读取配置文件 - if (is_dir($path . 'config')) { - $dir = $path . 'config' . DIRECTORY_SEPARATOR; - } elseif (is_dir($this->configPath . $module)) { - $dir = $this->configPath . $module; - } - - $files = isset($dir) ? scandir($dir) : []; - - foreach ($files as $file) { - if ('.' . pathinfo($file, PATHINFO_EXTENSION) === $this->configExt) { - $this->config->load($dir . $file, pathinfo($file, PATHINFO_FILENAME)); - } - } - } - - $this->setModulePath($path); - - if ($module) { - // 对容器中的对象实例进行配置更新 - $this->containerConfigUpdate($module); - } - } - - protected function containerConfigUpdate($module) - { - $config = $this->config->get(); - - // 注册异常处理类 - if ($config['app']['exception_handle']) { - Error::setExceptionHandler($config['app']['exception_handle']); - } - - Db::init($config['database']); - $this->middleware->setConfig($config['middleware']); - $this->route->setConfig($config['app']); - $this->request->init($config['app']); - $this->cookie->init($config['cookie']); - $this->view->init($config['template']); - $this->log->init($config['log']); - $this->session->setConfig($config['session']); - $this->debug->setConfig($config['trace']); - $this->cache->init($config['cache'], true); - - // 加载当前模块语言包 - $this->lang->load($this->appPath . $module . DIRECTORY_SEPARATOR . 'lang' . DIRECTORY_SEPARATOR . $this->request->langset() . '.php'); - - // 模块请求缓存检查 - $this->checkRequestCache( - $config['app']['request_cache'], - $config['app']['request_cache_expire'], - $config['app']['request_cache_except'] - ); - } - - /** - * 执行应用程序 - * @access public - * @return Response - * @throws Exception - */ - public function run() - { - try { - // 初始化应用 - $this->initialize(); - - // 监听app_init - $this->hook->listen('app_init'); - - if ($this->bindModule) { - // 模块/控制器绑定 - $this->route->bind($this->bindModule); - } elseif ($this->config('app.auto_bind_module')) { - // 入口自动绑定 - $name = pathinfo($this->request->baseFile(), PATHINFO_FILENAME); - if ($name && 'index' != $name && is_dir($this->appPath . $name)) { - $this->route->bind($name); - } - } - - // 监听app_dispatch - $this->hook->listen('app_dispatch'); - - $dispatch = $this->dispatch; - - if (empty($dispatch)) { - // 路由检测 - $dispatch = $this->routeCheck()->init(); - } - - // 记录当前调度信息 - $this->request->dispatch($dispatch); - - // 记录路由和请求信息 - if ($this->appDebug) { - $this->log('[ ROUTE ] ' . var_export($this->request->routeInfo(), true)); - $this->log('[ HEADER ] ' . var_export($this->request->header(), true)); - $this->log('[ PARAM ] ' . var_export($this->request->param(), true)); - } - - // 监听app_begin - $this->hook->listen('app_begin'); - - // 请求缓存检查 - $this->checkRequestCache( - $this->config('request_cache'), - $this->config('request_cache_expire'), - $this->config('request_cache_except') - ); - - $data = null; - } catch (HttpResponseException $exception) { - $dispatch = null; - $data = $exception->getResponse(); - } - - $this->middleware->add(function (Request $request, $next) use ($dispatch, $data) { - return is_null($data) ? $dispatch->run() : $data; - }); - - $response = $this->middleware->dispatch($this->request); - - // 监听app_end - $this->hook->listen('app_end', $response); - - return $response; - } - - protected function getRouteCacheKey() - { - if ($this->config->get('route_check_cache_key')) { - $closure = $this->config->get('route_check_cache_key'); - $routeKey = $closure($this->request); - } else { - $routeKey = md5($this->request->baseUrl(true) . ':' . $this->request->method()); - } - - return $routeKey; - } - - protected function loadLangPack() - { - // 读取默认语言 - $this->lang->range($this->config('app.default_lang')); - - if ($this->config('app.lang_switch_on')) { - // 开启多语言机制 检测当前语言 - $this->lang->detect(); - } - - $this->request->setLangset($this->lang->range()); - - // 加载系统语言包 - $this->lang->load([ - $this->thinkPath . 'lang' . DIRECTORY_SEPARATOR . $this->request->langset() . '.php', - $this->appPath . 'lang' . DIRECTORY_SEPARATOR . $this->request->langset() . '.php', - ]); - } - - /** - * 设置当前地址的请求缓存 - * @access public - * @param string $key 缓存标识,支持变量规则 ,例如 item/:name/:id - * @param mixed $expire 缓存有效期 - * @param array $except 缓存排除 - * @param string $tag 缓存标签 - * @return void - */ - public function checkRequestCache($key, $expire = null, $except = [], $tag = null) - { - $cache = $this->request->cache($key, $expire, $except, $tag); - - if ($cache) { - $this->setResponseCache($cache); - } - } - - public function setResponseCache($cache) - { - list($key, $expire, $tag) = $cache; - - if (strtotime($this->request->server('HTTP_IF_MODIFIED_SINCE')) + $expire > $this->request->server('REQUEST_TIME')) { - // 读取缓存 - $response = Response::create()->code(304); - throw new HttpResponseException($response); - } elseif ($this->cache->has($key)) { - list($content, $header) = $this->cache->get($key); - - $response = Response::create($content)->header($header); - throw new HttpResponseException($response); - } - } - - /** - * 设置当前请求的调度信息 - * @access public - * @param Dispatch $dispatch 调度信息 - * @return $this - */ - public function dispatch(Dispatch $dispatch) - { - $this->dispatch = $dispatch; - return $this; - } - - /** - * 记录调试信息 - * @access public - * @param mixed $msg 调试信息 - * @param string $type 信息类型 - * @return void - */ - public function log($msg, $type = 'info') - { - $this->appDebug && $this->log->record($msg, $type); - } - - /** - * 获取配置参数 为空则获取所有配置 - * @access public - * @param string $name 配置参数名(支持二级配置 .号分割) - * @return mixed - */ - public function config($name = '') - { - return $this->config->get($name); - } - - /** - * 路由初始化 导入路由定义规则 - * @access public - * @return void - */ - public function routeInit() - { - // 路由检测 - $files = scandir($this->routePath); - foreach ($files as $file) { - if (strpos($file, '.php')) { - $filename = $this->routePath . $file; - // 导入路由配置 - $rules = include $filename; - if (is_array($rules)) { - $this->route->import($rules); - } - } - } - - if ($this->route->config('route_annotation')) { - // 自动生成路由定义 - if ($this->appDebug) { - $suffix = $this->route->config('controller_suffix') || $this->route->config('class_suffix'); - $this->build->buildRoute($suffix); - } - - $filename = $this->runtimePath . 'build_route.php'; - - if (is_file($filename)) { - include $filename; - } - } - } - - /** - * URL路由检测(根据PATH_INFO) - * @access public - * @return Dispatch - */ - public function routeCheck() - { - // 检测路由缓存 - if (!$this->appDebug && $this->config->get('route_check_cache')) { - $routeKey = $this->getRouteCacheKey(); - $option = $this->config->get('route_cache_option'); - - if ($option && $this->cache->connect($option)->has($routeKey)) { - return $this->cache->connect($option)->get($routeKey); - } elseif ($this->cache->has($routeKey)) { - return $this->cache->get($routeKey); - } - } - - // 获取应用调度信息 - $path = $this->request->path(); - - // 是否强制路由模式 - $must = !is_null($this->routeMust) ? $this->routeMust : $this->route->config('url_route_must'); - - // 路由检测 返回一个Dispatch对象 - $dispatch = $this->route->check($path, $must); - - if (!empty($routeKey)) { - try { - if ($option) { - $this->cache->connect($option)->tag('route_cache')->set($routeKey, $dispatch); - } else { - $this->cache->tag('route_cache')->set($routeKey, $dispatch); - } - } catch (\Exception $e) { - // 存在闭包的时候缓存无效 - } - } - - return $dispatch; - } - - /** - * 设置应用的路由检测机制 - * @access public - * @param bool $must 是否强制检测路由 - * @return $this - */ - public function routeMust($must = false) - { - $this->routeMust = $must; - return $this; - } - - /** - * 解析模块和类名 - * @access protected - * @param string $name 资源地址 - * @param string $layer 验证层名称 - * @param bool $appendSuffix 是否添加类名后缀 - * @return array - */ - protected function parseModuleAndClass($name, $layer, $appendSuffix) - { - if (false !== strpos($name, '\\')) { - $class = $name; - $module = $this->request->module(); - } else { - if (strpos($name, '/')) { - list($module, $name) = explode('/', $name, 2); - } else { - $module = $this->request->module(); - } - - $class = $this->parseClass($module, $layer, $name, $appendSuffix); - } - - return [$module, $class]; - } - - /** - * 实例化应用类库 - * @access public - * @param string $name 类名称 - * @param string $layer 业务层名称 - * @param bool $appendSuffix 是否添加类名后缀 - * @param string $common 公共模块名 - * @return object - * @throws ClassNotFoundException - */ - public function create($name, $layer, $appendSuffix = false, $common = 'common') - { - $guid = $name . $layer; - - if ($this->__isset($guid)) { - return $this->__get($guid); - } - - list($module, $class) = $this->parseModuleAndClass($name, $layer, $appendSuffix); - - if (class_exists($class)) { - $object = $this->__get($class); - } else { - $class = str_replace('\\' . $module . '\\', '\\' . $common . '\\', $class); - if (class_exists($class)) { - $object = $this->__get($class); - } else { - throw new ClassNotFoundException('class not exists:' . $class, $class); - } - } - - $this->__set($guid, $class); - - return $object; - } - - /** - * 实例化(分层)模型 - * @access public - * @param string $name Model名称 - * @param string $layer 业务层名称 - * @param bool $appendSuffix 是否添加类名后缀 - * @param string $common 公共模块名 - * @return Model - * @throws ClassNotFoundException - */ - public function model($name = '', $layer = 'model', $appendSuffix = false, $common = 'common') - { - return $this->create($name, $layer, $appendSuffix, $common); - } - - /** - * 实例化(分层)控制器 格式:[模块名/]控制器名 - * @access public - * @param string $name 资源地址 - * @param string $layer 控制层名称 - * @param bool $appendSuffix 是否添加类名后缀 - * @param string $empty 空控制器名称 - * @return object - * @throws ClassNotFoundException - */ - public function controller($name, $layer = 'controller', $appendSuffix = false, $empty = '') - { - list($module, $class) = $this->parseModuleAndClass($name, $layer, $appendSuffix); - - if (class_exists($class)) { - return $this->make($class, true); - } elseif ($empty && class_exists($emptyClass = $this->parseClass($module, $layer, $empty, $appendSuffix))) { - return $this->make($emptyClass, true); - } - - throw new ClassNotFoundException('class not exists:' . $class, $class); - } - - /** - * 实例化验证类 格式:[模块名/]验证器名 - * @access public - * @param string $name 资源地址 - * @param string $layer 验证层名称 - * @param bool $appendSuffix 是否添加类名后缀 - * @param string $common 公共模块名 - * @return Validate - * @throws ClassNotFoundException - */ - public function validate($name = '', $layer = 'validate', $appendSuffix = false, $common = 'common') - { - $name = $name ?: $this->config('default_validate'); - - if (empty($name)) { - return new Validate; - } - - return $this->create($name, $layer, $appendSuffix, $common); - } - - /** - * 数据库初始化 - * @access public - * @param mixed $config 数据库配置 - * @param bool|string $name 连接标识 true 强制重新连接 - * @return \think\db\Query - */ - public function db($config = [], $name = false) - { - return Db::connect($config, $name); - } - - /** - * 远程调用模块的操作方法 参数格式 [模块/控制器/]操作 - * @access public - * @param string $url 调用地址 - * @param string|array $vars 调用参数 支持字符串和数组 - * @param string $layer 要调用的控制层名称 - * @param bool $appendSuffix 是否添加类名后缀 - * @return mixed - * @throws ClassNotFoundException - */ - public function action($url, $vars = [], $layer = 'controller', $appendSuffix = false) - { - $info = pathinfo($url); - $action = $info['basename']; - $module = '.' != $info['dirname'] ? $info['dirname'] : $this->request->controller(); - $class = $this->controller($module, $layer, $appendSuffix); - - if (is_scalar($vars)) { - if (strpos($vars, '=')) { - parse_str($vars, $vars); - } else { - $vars = [$vars]; - } - } - - return $this->invokeMethod([$class, $action . $this->config('action_suffix')], $vars); - } - - /** - * 解析应用类的类名 - * @access public - * @param string $module 模块名 - * @param string $layer 层名 controller model ... - * @param string $name 类名 - * @param bool $appendSuffix - * @return string - */ - public function parseClass($module, $layer, $name, $appendSuffix = false) - { - $name = str_replace(['/', '.'], '\\', $name); - $array = explode('\\', $name); - $class = Loader::parseName(array_pop($array), 1) . ($this->suffix || $appendSuffix ? ucfirst($layer) : ''); - $path = $array ? implode('\\', $array) . '\\' : ''; - - return $this->namespace . '\\' . ($module ? $module . '\\' : '') . $layer . '\\' . $path . $class; - } - - /** - * 获取框架版本 - * @access public - * @return string - */ - public function version() - { - return static::VERSION; - } - - /** - * 是否为调试模式 - * @access public - * @return bool - */ - public function isDebug() - { - return $this->appDebug; - } - - /** - * 获取模块路径 - * @access public - * @return string - */ - public function getModulePath() - { - return $this->modulePath; - } - - /** - * 设置模块路径 - * @access public - * @param string $path 路径 - * @return void - */ - public function setModulePath($path) - { - $this->modulePath = $path; - $this->env->set('module_path', $path); - } - - /** - * 获取应用根目录 - * @access public - * @return string - */ - public function getRootPath() - { - return $this->rootPath; - } - - /** - * 获取应用类库目录 - * @access public - * @return string - */ - public function getAppPath() - { - if (is_null($this->appPath)) { - $this->appPath = Loader::getRootPath() . 'application' . DIRECTORY_SEPARATOR; - } - - return $this->appPath; - } - - /** - * 获取应用运行时目录 - * @access public - * @return string - */ - public function getRuntimePath() - { - return $this->runtimePath; - } - - /** - * 获取核心框架目录 - * @access public - * @return string - */ - public function getThinkPath() - { - return $this->thinkPath; - } - - /** - * 获取路由目录 - * @access public - * @return string - */ - public function getRoutePath() - { - return $this->routePath; - } - - /** - * 获取应用配置目录 - * @access public - * @return string - */ - public function getConfigPath() - { - return $this->configPath; - } - - /** - * 获取配置后缀 - * @access public - * @return string - */ - public function getConfigExt() - { - return $this->configExt; - } - - /** - * 获取应用类库命名空间 - * @access public - * @return string - */ - public function getNamespace() - { - return $this->namespace; - } - - /** - * 设置应用类库命名空间 - * @access public - * @param string $namespace 命名空间名称 - * @return $this - */ - public function setNamespace($namespace) - { - $this->namespace = $namespace; - return $this; - } - - /** - * 是否启用类库后缀 - * @access public - * @return bool - */ - public function getSuffix() - { - return $this->suffix; - } - - /** - * 获取应用开启时间 - * @access public - * @return float - */ - public function getBeginTime() - { - return $this->beginTime; - } - - /** - * 获取应用初始内存占用 - * @access public - * @return integer - */ - public function getBeginMem() - { - return $this->beginMem; - } - -} diff --git a/thinkphp/library/think/Build.php b/thinkphp/library/think/Build.php deleted file mode 100755 index 7a531d74c..000000000 --- a/thinkphp/library/think/Build.php +++ /dev/null @@ -1,415 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think; - -class Build -{ - /** - * 应用对象 - * @var App - */ - protected $app; - - /** - * 应用目录 - * @var string - */ - protected $basePath; - - public function __construct(App $app) - { - $this->app = $app; - $this->basePath = $this->app->getAppPath(); - } - - /** - * 根据传入的build资料创建目录和文件 - * @access public - * @param array $build build列表 - * @param string $namespace 应用类库命名空间 - * @param bool $suffix 类库后缀 - * @return void - */ - public function run(array $build = [], $namespace = 'app', $suffix = false) - { - // 锁定 - $lockfile = $this->basePath . 'build.lock'; - - if (is_writable($lockfile)) { - return; - } elseif (!touch($lockfile)) { - throw new Exception('应用目录[' . $this->basePath . ']不可写,目录无法自动生成!
请手动生成项目目录~', 10006); - } - - foreach ($build as $module => $list) { - if ('__dir__' == $module) { - // 创建目录列表 - $this->buildDir($list); - } elseif ('__file__' == $module) { - // 创建文件列表 - $this->buildFile($list); - } else { - // 创建模块 - $this->module($module, $list, $namespace, $suffix); - } - } - - // 解除锁定 - unlink($lockfile); - } - - /** - * 创建目录 - * @access protected - * @param array $list 目录列表 - * @return void - */ - protected function buildDir($list) - { - foreach ($list as $dir) { - $this->checkDirBuild($this->basePath . $dir); - } - } - - /** - * 创建文件 - * @access protected - * @param array $list 文件列表 - * @return void - */ - protected function buildFile($list) - { - foreach ($list as $file) { - if (!is_dir($this->basePath . dirname($file))) { - // 创建目录 - mkdir($this->basePath . dirname($file), 0755, true); - } - - if (!is_file($this->basePath . $file)) { - file_put_contents($this->basePath . $file, 'php' == pathinfo($file, PATHINFO_EXTENSION) ? "basePath . $module)) { - // 创建模块目录 - mkdir($this->basePath . $module); - } - - if (basename($this->app->getRuntimePath()) != $module) { - // 创建配置文件和公共文件 - $this->buildCommon($module); - // 创建模块的默认页面 - $this->buildHello($module, $namespace, $suffix); - } - - if (empty($list)) { - // 创建默认的模块目录和文件 - $list = [ - '__file__' => ['common.php'], - '__dir__' => ['controller', 'model', 'view', 'config'], - ]; - } - - // 创建子目录和文件 - foreach ($list as $path => $file) { - $modulePath = $this->basePath . $module . DIRECTORY_SEPARATOR; - if ('__dir__' == $path) { - // 生成子目录 - foreach ($file as $dir) { - $this->checkDirBuild($modulePath . $dir); - } - } elseif ('__file__' == $path) { - // 生成(空白)文件 - foreach ($file as $name) { - if (!is_file($modulePath . $name)) { - file_put_contents($modulePath . $name, 'php' == pathinfo($name, PATHINFO_EXTENSION) ? "checkDirBuild(dirname($filename)); - $content = ''; - break; - default: - // 其他文件 - $content = "app->getNameSpace(); - $content = 'app->config('app.url_controller_layer'); - } - - if ($this->app->config('app.app_multi_module')) { - $modules = glob($this->basePath . '*', GLOB_ONLYDIR); - - foreach ($modules as $module) { - $module = basename($module); - - if (in_array($module, $this->app->config('app.deny_module_list'))) { - continue; - } - - $path = $this->basePath . $module . DIRECTORY_SEPARATOR . $layer . DIRECTORY_SEPARATOR; - $content .= $this->buildDirRoute($path, $namespace, $module, $suffix, $layer); - } - } else { - $path = $this->basePath . $layer . DIRECTORY_SEPARATOR; - $content .= $this->buildDirRoute($path, $namespace, '', $suffix, $layer); - } - - $filename = $this->app->getRuntimePath() . 'build_route.php'; - file_put_contents($filename, $content); - - return $filename; - } - - /** - * 生成子目录控制器类的路由规则 - * @access protected - * @param string $path 控制器目录 - * @param string $namespace 应用命名空间 - * @param string $module 模块 - * @param bool $suffix 类库后缀 - * @param string $layer 控制器层目录名 - * @return string - */ - protected function buildDirRoute($path, $namespace, $module, $suffix, $layer) - { - $content = ''; - $controllers = glob($path . '*.php'); - - foreach ($controllers as $controller) { - $controller = basename($controller, '.php'); - - $class = new \ReflectionClass($namespace . '\\' . ($module ? $module . '\\' : '') . $layer . '\\' . $controller); - - if (strpos($layer, '\\')) { - // 多级控制器 - $level = str_replace(DIRECTORY_SEPARATOR, '.', substr($layer, 11)); - $controller = $level . '.' . $controller; - $length = strlen(strstr($layer, '\\', true)); - } else { - $length = strlen($layer); - } - - if ($suffix) { - $controller = substr($controller, 0, -$length); - } - - $content .= $this->getControllerRoute($class, $module, $controller); - } - - $subDir = glob($path . '*', GLOB_ONLYDIR); - - foreach ($subDir as $dir) { - $content .= $this->buildDirRoute($dir . DIRECTORY_SEPARATOR, $namespace, $module, $suffix, $layer . '\\' . basename($dir)); - } - - return $content; - } - - /** - * 生成控制器类的路由规则 - * @access protected - * @param string $class 控制器完整类名 - * @param string $module 模块名 - * @param string $controller 控制器名 - * @return string - */ - protected function getControllerRoute($class, $module, $controller) - { - $content = ''; - $comment = $class->getDocComment(); - - if (false !== strpos($comment, '@route(')) { - $comment = $this->parseRouteComment($comment); - $route = ($module ? $module . '/' : '') . $controller; - $comment = preg_replace('/route\(\s?([\'\"][\-\_\/\:\<\>\?\$\[\]\w]+[\'\"])\s?\)/is', 'Route::resource(\1,\'' . $route . '\')', $comment); - $content .= PHP_EOL . $comment; - } elseif (false !== strpos($comment, '@alias(')) { - $comment = $this->parseRouteComment($comment, '@alias('); - $route = ($module ? $module . '/' : '') . $controller; - $comment = preg_replace('/alias\(\s?([\'\"][\-\_\/\w]+[\'\"])\s?\)/is', 'Route::alias(\1,\'' . $route . '\')', $comment); - $content .= PHP_EOL . $comment; - } - - $methods = $class->getMethods(\ReflectionMethod::IS_PUBLIC); - - foreach ($methods as $method) { - $comment = $this->getMethodRouteComment($module, $controller, $method); - if ($comment) { - $content .= PHP_EOL . $comment; - } - } - - return $content; - } - - /** - * 解析路由注释 - * @access protected - * @param string $comment - * @param string $tag - * @return string - */ - protected function parseRouteComment($comment, $tag = '@route(') - { - $comment = substr($comment, 3, -2); - $comment = explode(PHP_EOL, substr(strstr(trim($comment), $tag), 1)); - $comment = array_map(function ($item) {return trim(trim($item), ' \t*');}, $comment); - - if (count($comment) > 1) { - $key = array_search('', $comment); - $comment = array_slice($comment, 0, false === $key ? 1 : $key); - } - - $comment = implode(PHP_EOL . "\t", $comment) . ';'; - - if (strpos($comment, '{')) { - $comment = preg_replace_callback('/\{\s?.*?\s?\}/s', function ($matches) { - return false !== strpos($matches[0], '"') ? '[' . substr(var_export(json_decode($matches[0], true), true), 7, -1) . ']' : $matches[0]; - }, $comment); - } - return $comment; - } - - /** - * 获取方法的路由注释 - * @access protected - * @param string $module 模块 - * @param string $controller 控制器名 - * @param \ReflectMethod $reflectMethod - * @return string|void - */ - protected function getMethodRouteComment($module, $controller, $reflectMethod) - { - $comment = $reflectMethod->getDocComment(); - - if (false !== strpos($comment, '@route(')) { - $comment = $this->parseRouteComment($comment); - $action = $reflectMethod->getName(); - - if ($suffix = $this->app->config('app.action_suffix')) { - $action = substr($action, 0, -strlen($suffix)); - } - - $route = ($module ? $module . '/' : '') . $controller . '/' . $action; - $comment = preg_replace('/route\s?\(\s?([\'\"][\-\_\/\:\<\>\?\$\[\]\w]+[\'\"])\s?\,?\s?[\'\"]?(\w+?)[\'\"]?\s?\)/is', 'Route::\2(\1,\'' . $route . '\')', $comment); - $comment = preg_replace('/route\s?\(\s?([\'\"][\-\_\/\:\<\>\?\$\[\]\w]+[\'\"])\s?\)/is', 'Route::rule(\1,\'' . $route . '\')', $comment); - - return $comment; - } - } - - /** - * 创建模块的欢迎页面 - * @access protected - * @param string $module 模块名 - * @param string $namespace 应用类库命名空间 - * @param bool $suffix 类库后缀 - * @return void - */ - protected function buildHello($module, $namespace, $suffix = false) - { - $filename = $this->basePath . ($module ? $module . DIRECTORY_SEPARATOR : '') . 'controller' . DIRECTORY_SEPARATOR . 'Index' . ($suffix ? 'Controller' : '') . '.php'; - if (!is_file($filename)) { - $content = file_get_contents($this->app->getThinkPath() . 'tpl' . DIRECTORY_SEPARATOR . 'default_index.tpl'); - $content = str_replace(['{$app}', '{$module}', '{layer}', '{$suffix}'], [$namespace, $module ? $module . '\\' : '', 'controller', $suffix ? 'Controller' : ''], $content); - $this->checkDirBuild(dirname($filename)); - - file_put_contents($filename, $content); - } - } - - /** - * 创建模块的公共文件 - * @access protected - * @param string $module 模块名 - * @return void - */ - protected function buildCommon($module) - { - $filename = $this->app->getConfigPath() . ($module ? $module . DIRECTORY_SEPARATOR : '') . 'app.php'; - $this->checkDirBuild(dirname($filename)); - - if (!is_file($filename)) { - file_put_contents($filename, "basePath . ($module ? $module . DIRECTORY_SEPARATOR : '') . 'common.php'; - - if (!is_file($filename)) { - file_put_contents($filename, " -// +---------------------------------------------------------------------- - -namespace think; - -use think\cache\Driver; - -/** - * Class Cache - * - * @package think - * - * @mixin Driver - * @mixin \think\cache\driver\File - */ -class Cache -{ - /** - * 缓存实例 - * @var array - */ - protected $instance = []; - - /** - * 缓存配置 - * @var array - */ - protected $config = []; - - /** - * 操作句柄 - * @var object - */ - protected $handler; - - public function __construct(array $config = []) - { - $this->config = $config; - $this->init($config); - } - - /** - * 连接缓存 - * @access public - * @param array $options 配置数组 - * @param bool|string $name 缓存连接标识 true 强制重新连接 - * @return Driver - */ - public function connect(array $options = [], $name = false) - { - if (false === $name) { - $name = md5(serialize($options)); - } - - if (true === $name || !isset($this->instance[$name])) { - $type = !empty($options['type']) ? $options['type'] : 'File'; - - if (true === $name) { - $name = md5(serialize($options)); - } - - $this->instance[$name] = Loader::factory($type, '\\think\\cache\\driver\\', $options); - } - - return $this->instance[$name]; - } - - /** - * 自动初始化缓存 - * @access public - * @param array $options 配置数组 - * @param bool $force 强制更新 - * @return Driver - */ - public function init(array $options = [], $force = false) - { - if (is_null($this->handler) || $force) { - - if ('complex' == $options['type']) { - $default = $options['default']; - $options = isset($options[$default['type']]) ? $options[$default['type']] : $default; - } - - $this->handler = $this->connect($options); - } - - return $this->handler; - } - - public static function __make(Config $config) - { - return new static($config->pull('cache')); - } - - public function getConfig() - { - return $this->config; - } - - public function setConfig(array $config) - { - $this->config = array_merge($this->config, $config); - } - - /** - * 切换缓存类型 需要配置 cache.type 为 complex - * @access public - * @param string $name 缓存标识 - * @return Driver - */ - public function store($name = '') - { - if ('' !== $name && 'complex' == $this->config['type']) { - return $this->connect($this->config[$name], strtolower($name)); - } - - return $this->init(); - } - - public function __call($method, $args) - { - return call_user_func_array([$this->init(), $method], $args); - } - -} diff --git a/thinkphp/library/think/Config.php b/thinkphp/library/think/Config.php deleted file mode 100755 index bec6222ad..000000000 --- a/thinkphp/library/think/Config.php +++ /dev/null @@ -1,398 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think; - -use Yaconf; - -class Config implements \ArrayAccess -{ - /** - * 配置参数 - * @var array - */ - protected $config = []; - - /** - * 配置前缀 - * @var string - */ - protected $prefix = 'app'; - - /** - * 配置文件目录 - * @var string - */ - protected $path; - - /** - * 配置文件后缀 - * @var string - */ - protected $ext; - - /** - * 是否支持Yaconf - * @var bool - */ - protected $yaconf; - - /** - * 构造方法 - * @access public - */ - public function __construct($path = '', $ext = '.php') - { - $this->path = $path; - $this->ext = $ext; - $this->yaconf = class_exists('Yaconf'); - } - - public static function __make(App $app) - { - $path = $app->getConfigPath(); - $ext = $app->getConfigExt(); - return new static($path, $ext); - } - - /** - * 设置开启Yaconf - * @access public - * @param bool|string $yaconf 是否使用Yaconf - * @return void - */ - public function setYaconf($yaconf) - { - if ($this->yaconf) { - $this->yaconf = $yaconf; - } - } - - /** - * 设置配置参数默认前缀 - * @access public - * @param string $prefix 前缀 - * @return void - */ - public function setDefaultPrefix($prefix) - { - $this->prefix = $prefix; - } - - /** - * 解析配置文件或内容 - * @access public - * @param string $config 配置文件路径或内容 - * @param string $type 配置解析类型 - * @param string $name 配置名(如设置即表示二级配置) - * @return mixed - */ - public function parse($config, $type = '', $name = '') - { - if (empty($type)) { - $type = pathinfo($config, PATHINFO_EXTENSION); - } - - $object = Loader::factory($type, '\\think\\config\\driver\\', $config); - - return $this->set($object->parse(), $name); - } - - /** - * 加载配置文件(多种格式) - * @access public - * @param string $file 配置文件名 - * @param string $name 一级配置名 - * @return mixed - */ - public function load($file, $name = '') - { - if (is_file($file)) { - $filename = $file; - } elseif (is_file($this->path . $file . $this->ext)) { - $filename = $this->path . $file . $this->ext; - } - - if (isset($filename)) { - return $this->loadFile($filename, $name); - } elseif ($this->yaconf && Yaconf::has($file)) { - return $this->set(Yaconf::get($file), $name); - } - - return $this->config; - } - - /** - * 获取实际的yaconf配置参数 - * @access protected - * @param string $name 配置参数名 - * @return string - */ - protected function getYaconfName($name) - { - if ($this->yaconf && is_string($this->yaconf)) { - return $this->yaconf . '.' . $name; - } - - return $name; - } - - /** - * 获取yaconf配置 - * @access public - * @param string $name 配置参数名 - * @param mixed $default 默认值 - * @return mixed - */ - public function yaconf($name, $default = null) - { - if ($this->yaconf) { - $yaconfName = $this->getYaconfName($name); - - if (Yaconf::has($yaconfName)) { - return Yaconf::get($yaconfName); - } - } - - return $default; - } - - protected function loadFile($file, $name) - { - $name = strtolower($name); - $type = pathinfo($file, PATHINFO_EXTENSION); - - if ('php' == $type) { - return $this->set(include $file, $name); - } elseif ('yaml' == $type && function_exists('yaml_parse_file')) { - return $this->set(yaml_parse_file($file), $name); - } - - return $this->parse($file, $type, $name); - } - - /** - * 检测配置是否存在 - * @access public - * @param string $name 配置参数名(支持多级配置 .号分割) - * @return bool - */ - public function has($name) - { - if (false === strpos($name, '.')) { - $name = $this->prefix . '.' . $name; - } - - return !is_null($this->get($name)); - } - - /** - * 获取一级配置 - * @access public - * @param string $name 一级配置名 - * @return array - */ - public function pull($name) - { - $name = strtolower($name); - - if ($this->yaconf) { - $yaconfName = $this->getYaconfName($name); - - if (Yaconf::has($yaconfName)) { - $config = Yaconf::get($yaconfName); - return isset($this->config[$name]) ? array_merge($this->config[$name], $config) : $config; - } - } - - return isset($this->config[$name]) ? $this->config[$name] : []; - } - - /** - * 获取配置参数 为空则获取所有配置 - * @access public - * @param string $name 配置参数名(支持多级配置 .号分割) - * @param mixed $default 默认值 - * @return mixed - */ - public function get($name = null, $default = null) - { - if ($name && false === strpos($name, '.')) { - $name = $this->prefix . '.' . $name; - } - - // 无参数时获取所有 - if (empty($name)) { - return $this->config; - } - - if ('.' == substr($name, -1)) { - return $this->pull(substr($name, 0, -1)); - } - - if ($this->yaconf) { - $yaconfName = $this->getYaconfName($name); - - if (Yaconf::has($yaconfName)) { - return Yaconf::get($yaconfName); - } - } - - $name = explode('.', $name); - $name[0] = strtolower($name[0]); - $config = $this->config; - - // 按.拆分成多维数组进行判断 - foreach ($name as $val) { - if (isset($config[$val])) { - $config = $config[$val]; - } else { - return $default; - } - } - - return $config; - } - - /** - * 设置配置参数 name为数组则为批量设置 - * @access public - * @param string|array $name 配置参数名(支持三级配置 .号分割) - * @param mixed $value 配置值 - * @return mixed - */ - public function set($name, $value = null) - { - if (is_string($name)) { - if (false === strpos($name, '.')) { - $name = $this->prefix . '.' . $name; - } - - $name = explode('.', $name, 3); - - if (count($name) == 2) { - $this->config[strtolower($name[0])][$name[1]] = $value; - } else { - $this->config[strtolower($name[0])][$name[1]][$name[2]] = $value; - } - - return $value; - } elseif (is_array($name)) { - // 批量设置 - if (!empty($value)) { - if (isset($this->config[$value])) { - $result = array_merge($this->config[$value], $name); - } else { - $result = $name; - } - - $this->config[$value] = $result; - } else { - $result = $this->config = array_merge($this->config, $name); - } - } else { - // 为空直接返回 已有配置 - $result = $this->config; - } - - return $result; - } - - /** - * 移除配置 - * @access public - * @param string $name 配置参数名(支持三级配置 .号分割) - * @return void - */ - public function remove($name) - { - if (false === strpos($name, '.')) { - $name = $this->prefix . '.' . $name; - } - - $name = explode('.', $name, 3); - - if (count($name) == 2) { - unset($this->config[strtolower($name[0])][$name[1]]); - } else { - unset($this->config[strtolower($name[0])][$name[1]][$name[2]]); - } - } - - /** - * 重置配置参数 - * @access public - * @param string $prefix 配置前缀名 - * @return void - */ - public function reset($prefix = '') - { - if ('' === $prefix) { - $this->config = []; - } else { - $this->config[$prefix] = []; - } - } - - /** - * 设置配置 - * @access public - * @param string $name 参数名 - * @param mixed $value 值 - */ - public function __set($name, $value) - { - return $this->set($name, $value); - } - - /** - * 获取配置参数 - * @access public - * @param string $name 参数名 - * @return mixed - */ - public function __get($name) - { - return $this->get($name); - } - - /** - * 检测是否存在参数 - * @access public - * @param string $name 参数名 - * @return bool - */ - public function __isset($name) - { - return $this->has($name); - } - - // ArrayAccess - public function offsetSet($name, $value) - { - $this->set($name, $value); - } - - public function offsetExists($name) - { - return $this->has($name); - } - - public function offsetUnset($name) - { - $this->remove($name); - } - - public function offsetGet($name) - { - return $this->get($name); - } -} diff --git a/thinkphp/library/think/Container.php b/thinkphp/library/think/Container.php deleted file mode 100755 index cd7954c06..000000000 --- a/thinkphp/library/think/Container.php +++ /dev/null @@ -1,568 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think; - -use ArrayAccess; -use ArrayIterator; -use Closure; -use Countable; -use InvalidArgumentException; -use IteratorAggregate; -use ReflectionClass; -use ReflectionException; -use ReflectionFunction; -use ReflectionMethod; -use think\exception\ClassNotFoundException; - -/** - * @package think - * @property Build $build - * @property Cache $cache - * @property Config $config - * @property Cookie $cookie - * @property Debug $debug - * @property Env $env - * @property Hook $hook - * @property Lang $lang - * @property Middleware $middleware - * @property Request $request - * @property Response $response - * @property Route $route - * @property Session $session - * @property Template $template - * @property Url $url - * @property Validate $validate - * @property View $view - * @property route\RuleName $rule_name - * @property Log $log - */ -class Container implements ArrayAccess, IteratorAggregate, Countable -{ - /** - * 容器对象实例 - * @var Container - */ - protected static $instance; - - /** - * 容器中的对象实例 - * @var array - */ - protected $instances = []; - - /** - * 容器绑定标识 - * @var array - */ - protected $bind = [ - 'app' => App::class, - 'build' => Build::class, - 'cache' => Cache::class, - 'config' => Config::class, - 'cookie' => Cookie::class, - 'debug' => Debug::class, - 'env' => Env::class, - 'hook' => Hook::class, - 'lang' => Lang::class, - 'log' => Log::class, - 'middleware' => Middleware::class, - 'request' => Request::class, - 'response' => Response::class, - 'route' => Route::class, - 'session' => Session::class, - 'template' => Template::class, - 'url' => Url::class, - 'validate' => Validate::class, - 'view' => View::class, - 'rule_name' => route\RuleName::class, - // 接口依赖注入 - 'think\LoggerInterface' => Log::class, - ]; - - /** - * 容器标识别名 - * @var array - */ - protected $name = []; - - /** - * 获取当前容器的实例(单例) - * @access public - * @return static - */ - public static function getInstance() - { - if (is_null(static::$instance)) { - static::$instance = new static; - } - - return static::$instance; - } - - /** - * 设置当前容器的实例 - * @access public - * @param object $instance - * @return void - */ - public static function setInstance($instance) - { - static::$instance = $instance; - } - - /** - * 获取容器中的对象实例 - * @access public - * @param string $abstract 类名或者标识 - * @param array|true $vars 变量 - * @param bool $newInstance 是否每次创建新的实例 - * @return object - */ - public static function get($abstract, $vars = [], $newInstance = false) - { - return static::getInstance()->make($abstract, $vars, $newInstance); - } - - /** - * 绑定一个类、闭包、实例、接口实现到容器 - * @access public - * @param string $abstract 类标识、接口 - * @param mixed $concrete 要绑定的类、闭包或者实例 - * @return Container - */ - public static function set($abstract, $concrete = null) - { - return static::getInstance()->bindTo($abstract, $concrete); - } - - /** - * 移除容器中的对象实例 - * @access public - * @param string $abstract 类标识、接口 - * @return void - */ - public static function remove($abstract) - { - return static::getInstance()->delete($abstract); - } - - /** - * 清除容器中的对象实例 - * @access public - * @return void - */ - public static function clear() - { - return static::getInstance()->flush(); - } - - /** - * 绑定一个类、闭包、实例、接口实现到容器 - * @access public - * @param string|array $abstract 类标识、接口 - * @param mixed $concrete 要绑定的类、闭包或者实例 - * @return $this - */ - public function bindTo($abstract, $concrete = null) - { - if (is_array($abstract)) { - $this->bind = array_merge($this->bind, $abstract); - } elseif ($concrete instanceof Closure) { - $this->bind[$abstract] = $concrete; - } elseif (is_object($concrete)) { - if (isset($this->bind[$abstract])) { - $abstract = $this->bind[$abstract]; - } - $this->instances[$abstract] = $concrete; - } else { - $this->bind[$abstract] = $concrete; - } - - return $this; - } - - /** - * 绑定一个类实例当容器 - * @access public - * @param string $abstract 类名或者标识 - * @param object|\Closure $instance 类的实例 - * @return $this - */ - public function instance($abstract, $instance) - { - if ($instance instanceof \Closure) { - $this->bind[$abstract] = $instance; - } else { - if (isset($this->bind[$abstract])) { - $abstract = $this->bind[$abstract]; - } - - $this->instances[$abstract] = $instance; - } - - return $this; - } - - /** - * 判断容器中是否存在类及标识 - * @access public - * @param string $abstract 类名或者标识 - * @return bool - */ - public function bound($abstract) - { - return isset($this->bind[$abstract]) || isset($this->instances[$abstract]); - } - - /** - * 判断容器中是否存在对象实例 - * @access public - * @param string $abstract 类名或者标识 - * @return bool - */ - public function exists($abstract) - { - if (isset($this->bind[$abstract])) { - $abstract = $this->bind[$abstract]; - } - - return isset($this->instances[$abstract]); - } - - /** - * 判断容器中是否存在类及标识 - * @access public - * @param string $name 类名或者标识 - * @return bool - */ - public function has($name) - { - return $this->bound($name); - } - - /** - * 创建类的实例 - * @access public - * @param string $abstract 类名或者标识 - * @param array|true $vars 变量 - * @param bool $newInstance 是否每次创建新的实例 - * @return object - */ - public function make($abstract, $vars = [], $newInstance = false) - { - if (true === $vars) { - // 总是创建新的实例化对象 - $newInstance = true; - $vars = []; - } - - $abstract = isset($this->name[$abstract]) ? $this->name[$abstract] : $abstract; - - if (isset($this->instances[$abstract]) && !$newInstance) { - return $this->instances[$abstract]; - } - - if (isset($this->bind[$abstract])) { - $concrete = $this->bind[$abstract]; - - if ($concrete instanceof Closure) { - $object = $this->invokeFunction($concrete, $vars); - } else { - $this->name[$abstract] = $concrete; - return $this->make($concrete, $vars, $newInstance); - } - } else { - $object = $this->invokeClass($abstract, $vars); - } - - if (!$newInstance) { - $this->instances[$abstract] = $object; - } - - return $object; - } - - /** - * 删除容器中的对象实例 - * @access public - * @param string|array $abstract 类名或者标识 - * @return void - */ - public function delete($abstract) - { - foreach ((array) $abstract as $name) { - $name = isset($this->name[$name]) ? $this->name[$name] : $name; - - if (isset($this->instances[$name])) { - unset($this->instances[$name]); - } - } - } - - /** - * 获取容器中的对象实例 - * @access public - * @return array - */ - public function all() - { - return $this->instances; - } - - /** - * 清除容器中的对象实例 - * @access public - * @return void - */ - public function flush() - { - $this->instances = []; - $this->bind = []; - $this->name = []; - } - - /** - * 执行函数或者闭包方法 支持参数调用 - * @access public - * @param mixed $function 函数或者闭包 - * @param array $vars 参数 - * @return mixed - */ - public function invokeFunction($function, $vars = []) - { - try { - $reflect = new ReflectionFunction($function); - - $args = $this->bindParams($reflect, $vars); - - return call_user_func_array($function, $args); - } catch (ReflectionException $e) { - throw new Exception('function not exists: ' . $function . '()'); - } - } - - /** - * 调用反射执行类的方法 支持参数绑定 - * @access public - * @param mixed $method 方法 - * @param array $vars 参数 - * @return mixed - */ - public function invokeMethod($method, $vars = []) - { - try { - if (is_array($method)) { - $class = is_object($method[0]) ? $method[0] : $this->invokeClass($method[0]); - $reflect = new ReflectionMethod($class, $method[1]); - } else { - // 静态方法 - $reflect = new ReflectionMethod($method); - } - - $args = $this->bindParams($reflect, $vars); - - return $reflect->invokeArgs(isset($class) ? $class : null, $args); - } catch (ReflectionException $e) { - if (is_array($method) && is_object($method[0])) { - $method[0] = get_class($method[0]); - } - - throw new Exception('method not exists: ' . (is_array($method) ? $method[0] . '::' . $method[1] : $method) . '()'); - } - } - - /** - * 调用反射执行类的方法 支持参数绑定 - * @access public - * @param object $instance 对象实例 - * @param mixed $reflect 反射类 - * @param array $vars 参数 - * @return mixed - */ - public function invokeReflectMethod($instance, $reflect, $vars = []) - { - $args = $this->bindParams($reflect, $vars); - - return $reflect->invokeArgs($instance, $args); - } - - /** - * 调用反射执行callable 支持参数绑定 - * @access public - * @param mixed $callable - * @param array $vars 参数 - * @return mixed - */ - public function invoke($callable, $vars = []) - { - if ($callable instanceof Closure) { - return $this->invokeFunction($callable, $vars); - } - - return $this->invokeMethod($callable, $vars); - } - - /** - * 调用反射执行类的实例化 支持依赖注入 - * @access public - * @param string $class 类名 - * @param array $vars 参数 - * @return mixed - */ - public function invokeClass($class, $vars = []) - { - try { - $reflect = new ReflectionClass($class); - - if ($reflect->hasMethod('__make')) { - $method = new ReflectionMethod($class, '__make'); - - if ($method->isPublic() && $method->isStatic()) { - $args = $this->bindParams($method, $vars); - return $method->invokeArgs(null, $args); - } - } - - $constructor = $reflect->getConstructor(); - - $args = $constructor ? $this->bindParams($constructor, $vars) : []; - - return $reflect->newInstanceArgs($args); - - } catch (ReflectionException $e) { - throw new ClassNotFoundException('class not exists: ' . $class, $class); - } - } - - /** - * 绑定参数 - * @access protected - * @param \ReflectionMethod|\ReflectionFunction $reflect 反射类 - * @param array $vars 参数 - * @return array - */ - protected function bindParams($reflect, $vars = []) - { - if ($reflect->getNumberOfParameters() == 0) { - return []; - } - - // 判断数组类型 数字数组时按顺序绑定参数 - reset($vars); - $type = key($vars) === 0 ? 1 : 0; - $params = $reflect->getParameters(); - - foreach ($params as $param) { - $name = $param->getName(); - $lowerName = Loader::parseName($name); - $class = $param->getClass(); - - if ($class) { - $args[] = $this->getObjectParam($class->getName(), $vars); - } elseif (1 == $type && !empty($vars)) { - $args[] = array_shift($vars); - } elseif (0 == $type && isset($vars[$name])) { - $args[] = $vars[$name]; - } elseif (0 == $type && isset($vars[$lowerName])) { - $args[] = $vars[$lowerName]; - } elseif ($param->isDefaultValueAvailable()) { - $args[] = $param->getDefaultValue(); - } else { - throw new InvalidArgumentException('method param miss:' . $name); - } - } - - return $args; - } - - /** - * 获取对象类型的参数值 - * @access protected - * @param string $className 类名 - * @param array $vars 参数 - * @return mixed - */ - protected function getObjectParam($className, &$vars) - { - $array = $vars; - $value = array_shift($array); - - if ($value instanceof $className) { - $result = $value; - array_shift($vars); - } else { - $result = $this->make($className); - } - - return $result; - } - - public function __set($name, $value) - { - $this->bindTo($name, $value); - } - - public function __get($name) - { - return $this->make($name); - } - - public function __isset($name) - { - return $this->bound($name); - } - - public function __unset($name) - { - $this->delete($name); - } - - public function offsetExists($key) - { - return $this->__isset($key); - } - - public function offsetGet($key) - { - return $this->__get($key); - } - - public function offsetSet($key, $value) - { - $this->__set($key, $value); - } - - public function offsetUnset($key) - { - $this->__unset($key); - } - - //Countable - public function count() - { - return count($this->instances); - } - - //IteratorAggregate - public function getIterator() - { - return new ArrayIterator($this->instances); - } - - public function __debugInfo() - { - $data = get_object_vars($this); - unset($data['instances'], $data['instance']); - - return $data; - } -} diff --git a/thinkphp/library/think/Controller.php b/thinkphp/library/think/Controller.php deleted file mode 100755 index 7c8d0acf5..000000000 --- a/thinkphp/library/think/Controller.php +++ /dev/null @@ -1,316 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think; - -use think\exception\ValidateException; -use traits\controller\Jump; - -class Controller -{ - use Jump; - - /** - * 视图类实例 - * @var \think\View - */ - protected $view; - - /** - * Request实例 - * @var \think\Request - */ - protected $request; - - /** - * 验证失败是否抛出异常 - * @var bool - */ - protected $failException = false; - - /** - * 是否批量验证 - * @var bool - */ - protected $batchValidate = false; - - /** - * 前置操作方法列表(即将废弃) - * @var array $beforeActionList - */ - protected $beforeActionList = []; - - /** - * 控制器中间件 - * @var array - */ - protected $middleware = []; - - /** - * 构造方法 - * @access public - */ - /*public function __construct(App $app = null) - { - $this->app = $app ?: Container::get('app'); - $this->request = $this->app['request']; - $this->view = $this->app['view']; - - // 控制器初始化 - $this->initialize(); - - $this->registerMiddleware(); - - // 前置操作方法 即将废弃 - foreach ((array) $this->beforeActionList as $method => $options) { - is_numeric($method) ? - $this->beforeAction($options) : - $this->beforeAction($method, $options); - } - }*/ - - /** - * 构造方法 - * @author Devil - * @blog http://gong.gg/ - * @version 1.0.0 - * @date 2020-06-11 - * @desc description - * @param [type] $app [description] - */ - public function __construct($app = null) - { - // 实例化控制器,构造方法参数可传非对象数据 - $this->app = is_object($app) ? $app : Container::get('app'); - $this->request = $this->app['request']; - $this->view = $this->app['view']; - - // 控制器初始化 - $this->initialize(); - - $this->registerMiddleware(); - - // 前置操作方法 即将废弃 - foreach ((array) $this->beforeActionList as $method => $options) { - is_numeric($method) ? - $this->beforeAction($options) : - $this->beforeAction($method, $options); - } - } - - // 初始化 - protected function initialize() - {} - - // 注册控制器中间件 - public function registerMiddleware() - { - foreach ($this->middleware as $key => $val) { - if (!is_int($key)) { - $only = $except = null; - - if (isset($val['only'])) { - $only = array_map(function ($item) { - return strtolower($item); - }, $val['only']); - } elseif (isset($val['except'])) { - $except = array_map(function ($item) { - return strtolower($item); - }, $val['except']); - } - - if (isset($only) && !in_array($this->request->action(), $only)) { - continue; - } elseif (isset($except) && in_array($this->request->action(), $except)) { - continue; - } else { - $val = $key; - } - } - - $this->app['middleware']->controller($val); - } - } - - /** - * 前置操作 - * @access protected - * @param string $method 前置操作方法名 - * @param array $options 调用参数 ['only'=>[...]] 或者['except'=>[...]] - */ - protected function beforeAction($method, $options = []) - { - if (isset($options['only'])) { - if (is_string($options['only'])) { - $options['only'] = explode(',', $options['only']); - } - - $only = array_map(function ($val) { - return strtolower($val); - }, $options['only']); - - if (!in_array($this->request->action(), $only)) { - return; - } - } elseif (isset($options['except'])) { - if (is_string($options['except'])) { - $options['except'] = explode(',', $options['except']); - } - - $except = array_map(function ($val) { - return strtolower($val); - }, $options['except']); - - if (in_array($this->request->action(), $except)) { - return; - } - } - - call_user_func([$this, $method]); - } - - /** - * 加载模板输出 - * @access protected - * @param string $template 模板文件名 - * @param array $vars 模板输出变量 - * @param array $config 模板参数 - * @return mixed - */ - protected function fetch($template = '', $vars = [], $config = []) - { - return $this->view->fetch($template, $vars, $config); - } - - /** - * 渲染内容输出 - * @access protected - * @param string $content 模板内容 - * @param array $vars 模板输出变量 - * @param array $config 模板参数 - * @return mixed - */ - protected function display($content = '', $vars = [], $config = []) - { - return $this->view->display($content, $vars, $config); - } - - /** - * 模板变量赋值 - * @access protected - * @param mixed $name 要显示的模板变量 - * @param mixed $value 变量的值 - * @return $this - */ - protected function assign($name, $value = '') - { - $this->view->assign($name, $value); - - return $this; - } - - /** - * 视图过滤 - * @access protected - * @param Callable $filter 过滤方法或闭包 - * @return $this - */ - protected function filter($filter) - { - $this->view->filter($filter); - - return $this; - } - - /** - * 初始化模板引擎 - * @access protected - * @param array|string $engine 引擎参数 - * @return $this - */ - protected function engine($engine) - { - $this->view->engine($engine); - - return $this; - } - - /** - * 设置验证失败后是否抛出异常 - * @access protected - * @param bool $fail 是否抛出异常 - * @return $this - */ - protected function validateFailException($fail = true) - { - $this->failException = $fail; - - return $this; - } - - /** - * 验证数据 - * @access protected - * @param array $data 数据 - * @param string|array $validate 验证器名或者验证规则数组 - * @param array $message 提示信息 - * @param bool $batch 是否批量验证 - * @param mixed $callback 回调方法(闭包) - * @return array|string|true - * @throws ValidateException - */ - protected function validate($data, $validate, $message = [], $batch = false, $callback = null) - { - if (is_array($validate)) { - $v = $this->app->validate(); - $v->rule($validate); - } else { - if (strpos($validate, '.')) { - // 支持场景 - list($validate, $scene) = explode('.', $validate); - } - $v = $this->app->validate($validate); - if (!empty($scene)) { - $v->scene($scene); - } - } - - // 是否批量验证 - if ($batch || $this->batchValidate) { - $v->batch(true); - } - - if (is_array($message)) { - $v->message($message); - } - - if ($callback && is_callable($callback)) { - call_user_func_array($callback, [$v, &$data]); - } - - if (!$v->check($data)) { - if ($this->failException) { - throw new ValidateException($v->getError()); - } - return $v->getError(); - } - - return true; - } - - public function __debugInfo() - { - $data = get_object_vars($this); - unset($data['app'], $data['request']); - - return $data; - } -} diff --git a/thinkphp/library/think/Cookie.php b/thinkphp/library/think/Cookie.php deleted file mode 100755 index 6a9fb1ee5..000000000 --- a/thinkphp/library/think/Cookie.php +++ /dev/null @@ -1,268 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think; - -class Cookie -{ - /** - * 配置参数 - * @var array - */ - protected $config = [ - // cookie 名称前缀 - 'prefix' => '', - // cookie 保存时间 - 'expire' => 0, - // cookie 保存路径 - 'path' => '/', - // cookie 有效域名 - 'domain' => '', - // cookie 启用安全传输 - 'secure' => false, - // httponly设置 - 'httponly' => false, - // 是否使用 setcookie - 'setcookie' => true, - ]; - - /** - * 构造方法 - * @access public - */ - public function __construct(array $config = []) - { - $this->init($config); - } - - /** - * Cookie初始化 - * @access public - * @param array $config - * @return void - */ - public function init(array $config = []) - { - $this->config = array_merge($this->config, array_change_key_case($config)); - - if (!empty($this->config['httponly']) && PHP_SESSION_ACTIVE != session_status()) { - ini_set('session.cookie_httponly', 1); - } - } - - public static function __make(Config $config) - { - return new static($config->pull('cookie')); - } - - /** - * 设置或者获取cookie作用域(前缀) - * @access public - * @param string $prefix - * @return string|void - */ - public function prefix($prefix = '') - { - if (empty($prefix)) { - return $this->config['prefix']; - } - - $this->config['prefix'] = $prefix; - } - - /** - * Cookie 设置、获取、删除 - * - * @access public - * @param string $name cookie名称 - * @param mixed $value cookie值 - * @param mixed $option 可选参数 可能会是 null|integer|string - * @return void - */ - public function set($name, $value = '', $option = null) - { - // 参数设置(会覆盖黙认设置) - if (!is_null($option)) { - if (is_numeric($option)) { - $option = ['expire' => $option]; - } elseif (is_string($option)) { - parse_str($option, $option); - } - - $config = array_merge($this->config, array_change_key_case($option)); - } else { - $config = $this->config; - } - - $name = $config['prefix'] . $name; - - // 设置cookie - if (is_array($value)) { - array_walk_recursive($value, [$this, 'jsonFormatProtect'], 'encode'); - $value = 'think:' . json_encode($value); - } - - $expire = !empty($config['expire']) ? $_SERVER['REQUEST_TIME'] + intval($config['expire']) : 0; - - if ($config['setcookie']) { - $this->setCookie($name, $value, $expire, $config); - } - - $_COOKIE[$name] = $value; - } - - /** - * Cookie 设置保存 - * - * @access public - * @param string $name cookie名称 - * @param mixed $value cookie值 - * @param array $option 可选参数 - * @return void - */ - protected function setCookie($name, $value, $expire, $option = []) - { - setcookie($name, $value, $expire, $option['path'], $option['domain'], $option['secure'], $option['httponly']); - } - - /** - * 永久保存Cookie数据 - * @access public - * @param string $name cookie名称 - * @param mixed $value cookie值 - * @param mixed $option 可选参数 可能会是 null|integer|string - * @return void - */ - public function forever($name, $value = '', $option = null) - { - if (is_null($option) || is_numeric($option)) { - $option = []; - } - - $option['expire'] = 315360000; - - $this->set($name, $value, $option); - } - - /** - * 判断Cookie数据 - * @access public - * @param string $name cookie名称 - * @param string|null $prefix cookie前缀 - * @return bool - */ - public function has($name, $prefix = null) - { - $prefix = !is_null($prefix) ? $prefix : $this->config['prefix']; - $name = $prefix . $name; - - return isset($_COOKIE[$name]); - } - - /** - * Cookie获取 - * @access public - * @param string $name cookie名称 留空获取全部 - * @param string|null $prefix cookie前缀 - * @return mixed - */ - public function get($name = '', $prefix = null) - { - $prefix = !is_null($prefix) ? $prefix : $this->config['prefix']; - $key = $prefix . $name; - - if ('' == $name) { - if ($prefix) { - $value = []; - foreach ($_COOKIE as $k => $val) { - if (0 === strpos($k, $prefix)) { - $value[$k] = $val; - } - } - } else { - $value = $_COOKIE; - } - } elseif (isset($_COOKIE[$key])) { - $value = $_COOKIE[$key]; - - if (0 === strpos($value, 'think:')) { - $value = substr($value, 6); - $value = json_decode($value, true); - array_walk_recursive($value, [$this, 'jsonFormatProtect'], 'decode'); - } - } else { - $value = null; - } - - return $value; - } - - /** - * Cookie删除 - * @access public - * @param string $name cookie名称 - * @param string|null $prefix cookie前缀 - * @return void - */ - public function delete($name, $prefix = null) - { - $config = $this->config; - $prefix = !is_null($prefix) ? $prefix : $config['prefix']; - $name = $prefix . $name; - - if ($config['setcookie']) { - $this->setcookie($name, '', $_SERVER['REQUEST_TIME'] - 3600, $config); - } - - // 删除指定cookie - unset($_COOKIE[$name]); - } - - /** - * Cookie清空 - * @access public - * @param string|null $prefix cookie前缀 - * @return void - */ - public function clear($prefix = null) - { - // 清除指定前缀的所有cookie - if (empty($_COOKIE)) { - return; - } - - // 要删除的cookie前缀,不指定则删除config设置的指定前缀 - $config = $this->config; - $prefix = !is_null($prefix) ? $prefix : $config['prefix']; - - if ($prefix) { - // 如果前缀为空字符串将不作处理直接返回 - foreach ($_COOKIE as $key => $val) { - if (0 === strpos($key, $prefix)) { - if ($config['setcookie']) { - $this->setcookie($key, '', $_SERVER['REQUEST_TIME'] - 3600, $config); - } - unset($_COOKIE[$key]); - } - } - } - - return; - } - - private function jsonFormatProtect(&$val, $key, $type = 'encode') - { - if (!empty($val) && true !== $val) { - $val = 'decode' == $type ? urldecode($val) : urlencode($val); - } - } - -} diff --git a/thinkphp/library/think/Db.php b/thinkphp/library/think/Db.php deleted file mode 100755 index 9280eac0e..000000000 --- a/thinkphp/library/think/Db.php +++ /dev/null @@ -1,197 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think; - -use think\db\Connection; - -/** - * Class Db - * @package think - * @method \think\db\Query master() static 从主服务器读取数据 - * @method \think\db\Query readMaster(bool $all = false) static 后续从主服务器读取数据 - * @method \think\db\Query table(string $table) static 指定数据表(含前缀) - * @method \think\db\Query name(string $name) static 指定数据表(不含前缀) - * @method \think\db\Expression raw(string $value) static 使用表达式设置数据 - * @method \think\db\Query where(mixed $field, string $op = null, mixed $condition = null) static 查询条件 - * @method \think\db\Query whereRaw(string $where, array $bind = []) static 表达式查询 - * @method \think\db\Query whereExp(string $field, string $condition, array $bind = []) static 字段表达式查询 - * @method \think\db\Query when(mixed $condition, mixed $query, mixed $otherwise = null) static 条件查询 - * @method \think\db\Query join(mixed $join, mixed $condition = null, string $type = 'INNER') static JOIN查询 - * @method \think\db\Query view(mixed $join, mixed $field = null, mixed $on = null, string $type = 'INNER') static 视图查询 - * @method \think\db\Query field(mixed $field, boolean $except = false) static 指定查询字段 - * @method \think\db\Query fieldRaw(string $field, array $bind = []) static 指定查询字段 - * @method \think\db\Query union(mixed $union, boolean $all = false) static UNION查询 - * @method \think\db\Query limit(mixed $offset, integer $length = null) static 查询LIMIT - * @method \think\db\Query order(mixed $field, string $order = null) static 查询ORDER - * @method \think\db\Query orderRaw(string $field, array $bind = []) static 查询ORDER - * @method \think\db\Query cache(mixed $key = null , integer $expire = null) static 设置查询缓存 - * @method \think\db\Query withAttr(string $name,callable $callback = null) static 使用获取器获取数据 - * @method mixed value(string $field) static 获取某个字段的值 - * @method array column(string $field, string $key = '') static 获取某个列的值 - * @method mixed find(mixed $data = null) static 查询单个记录 - * @method mixed select(mixed $data = null) static 查询多个记录 - * @method integer insert(array $data, boolean $replace = false, boolean $getLastInsID = false, string $sequence = null) static 插入一条记录 - * @method integer insertGetId(array $data, boolean $replace = false, string $sequence = null) static 插入一条记录并返回自增ID - * @method integer insertAll(array $dataSet) static 插入多条记录 - * @method integer update(array $data) static 更新记录 - * @method integer delete(mixed $data = null) static 删除记录 - * @method boolean chunk(integer $count, callable $callback, string $column = null) static 分块获取数据 - * @method \Generator cursor(mixed $data = null) static 使用游标查找记录 - * @method mixed query(string $sql, array $bind = [], boolean $master = false, bool $pdo = false) static SQL查询 - * @method integer execute(string $sql, array $bind = [], boolean $fetch = false, boolean $getLastInsID = false, string $sequence = null) static SQL执行 - * @method \think\Paginator paginate(integer $listRows = 15, mixed $simple = null, array $config = []) static 分页查询 - * @method mixed transaction(callable $callback) static 执行数据库事务 - * @method void startTrans() static 启动事务 - * @method void commit() static 用于非自动提交状态下面的查询提交 - * @method void rollback() static 事务回滚 - * @method boolean batchQuery(array $sqlArray) static 批处理执行SQL语句 - * @method string getLastInsID(string $sequence = null) static 获取最近插入的ID - */ -class Db -{ - /** - * 当前数据库连接对象 - * @var Connection - */ - protected static $connection; - - /** - * 数据库配置 - * @var array - */ - protected static $config = []; - - /** - * 查询次数 - * @var integer - */ - public static $queryTimes = 0; - - /** - * 执行次数 - * @var integer - */ - public static $executeTimes = 0; - - /** - * 配置 - * @access public - * @param mixed $config - * @return void - */ - public static function init($config = []) - { - self::$config = $config; - - if (empty($config['query'])) { - self::$config['query'] = '\\think\\db\\Query'; - } - } - - /** - * 获取数据库配置 - * @access public - * @param string $config 配置名称 - * @return mixed - */ - public static function getConfig($name = '') - { - if ('' === $name) { - return self::$config; - } - - return isset(self::$config[$name]) ? self::$config[$name] : null; - } - - /** - * 切换数据库连接 - * @access public - * @param mixed $config 连接配置 - * @param bool|string $name 连接标识 true 强制重新连接 - * @param string $query 查询对象类名 - * @return mixed 返回查询对象实例 - * @throws Exception - */ - public static function connect($config = [], $name = false, $query = '') - { - // 解析配置参数 - $options = self::parseConfig($config ?: self::$config); - - $query = $query ?: $options['query']; - - // 创建数据库连接对象实例 - self::$connection = Connection::instance($options, $name); - - return new $query(self::$connection); - } - - /** - * 数据库连接参数解析 - * @access private - * @param mixed $config - * @return array - */ - private static function parseConfig($config) - { - if (is_string($config) && false === strpos($config, '/')) { - // 支持读取配置参数 - $config = isset(self::$config[$config]) ? self::$config[$config] : self::$config; - } - - $result = is_string($config) ? self::parseDsnConfig($config) : $config; - - if (empty($result['query'])) { - $result['query'] = self::$config['query']; - } - - return $result; - } - - /** - * DSN解析 - * 格式: mysql://username:passwd@localhost:3306/DbName?param1=val1¶m2=val2#utf8 - * @access private - * @param string $dsnStr - * @return array - */ - private static function parseDsnConfig($dsnStr) - { - $info = parse_url($dsnStr); - - if (!$info) { - return []; - } - - $dsn = [ - 'type' => $info['scheme'], - 'username' => isset($info['user']) ? $info['user'] : '', - 'password' => isset($info['pass']) ? $info['pass'] : '', - 'hostname' => isset($info['host']) ? $info['host'] : '', - 'hostport' => isset($info['port']) ? $info['port'] : '', - 'database' => !empty($info['path']) ? ltrim($info['path'], '/') : '', - 'charset' => isset($info['fragment']) ? $info['fragment'] : 'utf8', - ]; - - if (isset($info['query'])) { - parse_str($info['query'], $dsn['params']); - } else { - $dsn['params'] = []; - } - - return $dsn; - } - - public static function __callStatic($method, $args) - { - return call_user_func_array([static::connect(), $method], $args); - } -} diff --git a/thinkphp/library/think/Debug.php b/thinkphp/library/think/Debug.php deleted file mode 100755 index 776e17873..000000000 --- a/thinkphp/library/think/Debug.php +++ /dev/null @@ -1,278 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think; - -use think\model\Collection as ModelCollection; -use think\response\Redirect; - -class Debug -{ - /** - * 配置参数 - * @var array - */ - protected $config = []; - - /** - * 区间时间信息 - * @var array - */ - protected $info = []; - - /** - * 区间内存信息 - * @var array - */ - protected $mem = []; - - /** - * 应用对象 - * @var App - */ - protected $app; - - public function __construct(App $app, array $config = []) - { - $this->app = $app; - $this->config = $config; - } - - public static function __make(App $app, Config $config) - { - return new static($app, $config->pull('trace')); - } - - public function setConfig(array $config) - { - $this->config = array_merge($this->config, $config); - } - - /** - * 记录时间(微秒)和内存使用情况 - * @access public - * @param string $name 标记位置 - * @param mixed $value 标记值 留空则取当前 time 表示仅记录时间 否则同时记录时间和内存 - * @return void - */ - public function remark($name, $value = '') - { - // 记录时间和内存使用 - $this->info[$name] = is_float($value) ? $value : microtime(true); - - if ('time' != $value) { - $this->mem['mem'][$name] = is_float($value) ? $value : memory_get_usage(); - $this->mem['peak'][$name] = memory_get_peak_usage(); - } - } - - /** - * 统计某个区间的时间(微秒)使用情况 - * @access public - * @param string $start 开始标签 - * @param string $end 结束标签 - * @param integer|string $dec 小数位 - * @return integer - */ - public function getRangeTime($start, $end, $dec = 6) - { - if (!isset($this->info[$end])) { - $this->info[$end] = microtime(true); - } - - return number_format(($this->info[$end] - $this->info[$start]), $dec); - } - - /** - * 统计从开始到统计时的时间(微秒)使用情况 - * @access public - * @param integer|string $dec 小数位 - * @return integer - */ - public function getUseTime($dec = 6) - { - return number_format((microtime(true) - $this->app->getBeginTime()), $dec); - } - - /** - * 获取当前访问的吞吐率情况 - * @access public - * @return string - */ - public function getThroughputRate() - { - return number_format(1 / $this->getUseTime(), 2) . 'req/s'; - } - - /** - * 记录区间的内存使用情况 - * @access public - * @param string $start 开始标签 - * @param string $end 结束标签 - * @param integer|string $dec 小数位 - * @return string - */ - public function getRangeMem($start, $end, $dec = 2) - { - if (!isset($this->mem['mem'][$end])) { - $this->mem['mem'][$end] = memory_get_usage(); - } - - $size = $this->mem['mem'][$end] - $this->mem['mem'][$start]; - $a = ['B', 'KB', 'MB', 'GB', 'TB']; - $pos = 0; - - while ($size >= 1024) { - $size /= 1024; - $pos++; - } - - return round($size, $dec) . " " . $a[$pos]; - } - - /** - * 统计从开始到统计时的内存使用情况 - * @access public - * @param integer|string $dec 小数位 - * @return string - */ - public function getUseMem($dec = 2) - { - $size = memory_get_usage() - $this->app->getBeginMem(); - $a = ['B', 'KB', 'MB', 'GB', 'TB']; - $pos = 0; - - while ($size >= 1024) { - $size /= 1024; - $pos++; - } - - return round($size, $dec) . " " . $a[$pos]; - } - - /** - * 统计区间的内存峰值情况 - * @access public - * @param string $start 开始标签 - * @param string $end 结束标签 - * @param integer|string $dec 小数位 - * @return string - */ - public function getMemPeak($start, $end, $dec = 2) - { - if (!isset($this->mem['peak'][$end])) { - $this->mem['peak'][$end] = memory_get_peak_usage(); - } - - $size = $this->mem['peak'][$end] - $this->mem['peak'][$start]; - $a = ['B', 'KB', 'MB', 'GB', 'TB']; - $pos = 0; - - while ($size >= 1024) { - $size /= 1024; - $pos++; - } - - return round($size, $dec) . " " . $a[$pos]; - } - - /** - * 获取文件加载信息 - * @access public - * @param bool $detail 是否显示详细 - * @return integer|array - */ - public function getFile($detail = false) - { - if ($detail) { - $files = get_included_files(); - $info = []; - - foreach ($files as $key => $file) { - $info[] = $file . ' ( ' . number_format(filesize($file) / 1024, 2) . ' KB )'; - } - - return $info; - } - - return count(get_included_files()); - } - - /** - * 浏览器友好的变量输出 - * @access public - * @param mixed $var 变量 - * @param boolean $echo 是否输出 默认为true 如果为false 则返回输出字符串 - * @param string $label 标签 默认为空 - * @param integer $flags htmlspecialchars flags - * @return void|string - */ - public function dump($var, $echo = true, $label = null, $flags = ENT_SUBSTITUTE) - { - $label = (null === $label) ? '' : rtrim($label) . ':'; - if ($var instanceof Model || $var instanceof ModelCollection) { - $var = $var->toArray(); - } - - ob_start(); - var_dump($var); - - $output = ob_get_clean(); - $output = preg_replace('/\]\=\>\n(\s+)/m', '] => ', $output); - - if (PHP_SAPI == 'cli') { - $output = PHP_EOL . $label . $output . PHP_EOL; - } else { - if (!extension_loaded('xdebug')) { - $output = htmlspecialchars($output, $flags); - } - $output = '
' . $label . $output . '
'; - } - if ($echo) { - echo($output); - return; - } - return $output; - } - - public function inject(Response $response, &$content) - { - $config = $this->config; - $type = isset($config['type']) ? $config['type'] : 'Html'; - - unset($config['type']); - - $trace = Loader::factory($type, '\\think\\debug\\', $config); - - if ($response instanceof Redirect) { - //TODO 记录 - } else { - $output = $trace->output($response, $this->app['log']->getLog()); - if (is_string($output)) { - // trace调试信息注入 - $pos = strripos($content, ''); - if (false !== $pos) { - $content = substr($content, 0, $pos) . $output . substr($content, $pos); - } else { - $content = $content . $output; - } - } - } - } - - public function __debugInfo() - { - $data = get_object_vars($this); - unset($data['app']); - - return $data; - } -} diff --git a/thinkphp/library/think/Error.php b/thinkphp/library/think/Error.php deleted file mode 100755 index ea3328eec..000000000 --- a/thinkphp/library/think/Error.php +++ /dev/null @@ -1,147 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think; - -use think\console\Output as ConsoleOutput; -use think\exception\ErrorException; -use think\exception\Handle; -use think\exception\ThrowableError; - -class Error -{ - /** - * 配置参数 - * @var array - */ - protected static $exceptionHandler; - - /** - * 注册异常处理 - * @access public - * @return void - */ - public static function register() - { - error_reporting(E_ALL); - set_error_handler([__CLASS__, 'appError']); - set_exception_handler([__CLASS__, 'appException']); - register_shutdown_function([__CLASS__, 'appShutdown']); - } - - /** - * Exception Handler - * @access public - * @param \Exception|\Throwable $e - */ - public static function appException($e) - { - if (!$e instanceof \Exception) { - $e = new ThrowableError($e); - } - - self::getExceptionHandler()->report($e); - - if (PHP_SAPI == 'cli') { - self::getExceptionHandler()->renderForConsole(new ConsoleOutput, $e); - } else { - self::getExceptionHandler()->render($e)->send(); - } - } - - /** - * Error Handler - * @access public - * @param integer $errno 错误编号 - * @param integer $errstr 详细错误信息 - * @param string $errfile 出错的文件 - * @param integer $errline 出错行号 - * @throws ErrorException - */ - public static function appError($errno, $errstr, $errfile = '', $errline = 0) - { - $exception = new ErrorException($errno, $errstr, $errfile, $errline); - if (error_reporting() & $errno) { - // 将错误信息托管至 think\exception\ErrorException - throw $exception; - } - - self::getExceptionHandler()->report($exception); - } - - /** - * Shutdown Handler - * @access public - */ - public static function appShutdown() - { - if (!is_null($error = error_get_last()) && self::isFatal($error['type'])) { - // 将错误信息托管至think\ErrorException - $exception = new ErrorException($error['type'], $error['message'], $error['file'], $error['line']); - - self::appException($exception); - } - - // 写入日志 - Container::get('log')->save(); - } - - /** - * 确定错误类型是否致命 - * - * @access protected - * @param int $type - * @return bool - */ - protected static function isFatal($type) - { - return in_array($type, [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE]); - } - - /** - * 设置异常处理类 - * - * @access public - * @param mixed $handle - * @return void - */ - public static function setExceptionHandler($handle) - { - self::$exceptionHandler = $handle; - } - - /** - * Get an instance of the exception handler. - * - * @access public - * @return Handle - */ - public static function getExceptionHandler() - { - static $handle; - - if (!$handle) { - // 异常处理handle - $class = self::$exceptionHandler; - - if ($class && is_string($class) && class_exists($class) && is_subclass_of($class, "\\think\\exception\\Handle")) { - $handle = new $class; - } else { - $handle = new Handle; - if ($class instanceof \Closure) { - $handle->setRender($class); - } - } - } - - return $handle; - } -} diff --git a/thinkphp/library/think/File.php b/thinkphp/library/think/File.php deleted file mode 100755 index b29060972..000000000 --- a/thinkphp/library/think/File.php +++ /dev/null @@ -1,496 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think; - -use SplFileObject; - -class File extends SplFileObject -{ - /** - * 错误信息 - * @var string - */ - private $error = ''; - - /** - * 当前完整文件名 - * @var string - */ - protected $filename; - - /** - * 上传文件名 - * @var string - */ - protected $saveName; - - /** - * 上传文件命名规则 - * @var string - */ - protected $rule = 'date'; - - /** - * 上传文件验证规则 - * @var array - */ - protected $validate = []; - - /** - * 是否单元测试 - * @var bool - */ - protected $isTest; - - /** - * 上传文件信息 - * @var array - */ - protected $info = []; - - /** - * 文件hash规则 - * @var array - */ - protected $hash = []; - - public function __construct($filename, $mode = 'r') - { - parent::__construct($filename, $mode); - - $this->filename = $this->getRealPath() ?: $this->getPathname(); - } - - /** - * 是否测试 - * @access public - * @param bool $test 是否测试 - * @return $this - */ - public function isTest($test = false) - { - $this->isTest = $test; - - return $this; - } - - /** - * 设置上传信息 - * @access public - * @param array $info 上传文件信息 - * @return $this - */ - public function setUploadInfo($info) - { - $this->info = $info; - - return $this; - } - - /** - * 获取上传文件的信息 - * @access public - * @param string $name - * @return array|string - */ - public function getInfo($name = '') - { - return isset($this->info[$name]) ? $this->info[$name] : $this->info; - } - - /** - * 获取上传文件的文件名 - * @access public - * @return string - */ - public function getSaveName() - { - return $this->saveName; - } - - /** - * 设置上传文件的保存文件名 - * @access public - * @param string $saveName - * @return $this - */ - public function setSaveName($saveName) - { - $this->saveName = $saveName; - - return $this; - } - - /** - * 获取文件的哈希散列值 - * @access public - * @param string $type - * @return string - */ - public function hash($type = 'sha1') - { - if (!isset($this->hash[$type])) { - $this->hash[$type] = hash_file($type, $this->filename); - } - - return $this->hash[$type]; - } - - /** - * 检查目录是否可写 - * @access protected - * @param string $path 目录 - * @return boolean - */ - protected function checkPath($path) - { - if (is_dir($path)) { - return true; - } - - if (mkdir($path, 0755, true)) { - return true; - } - - $this->error = ['directory {:path} creation failed', ['path' => $path]]; - return false; - } - - /** - * 获取文件类型信息 - * @access public - * @return string - */ - public function getMime() - { - $finfo = finfo_open(FILEINFO_MIME_TYPE); - - return finfo_file($finfo, $this->filename); - } - - /** - * 设置文件的命名规则 - * @access public - * @param string $rule 文件命名规则 - * @return $this - */ - public function rule($rule) - { - $this->rule = $rule; - - return $this; - } - - /** - * 设置上传文件的验证规则 - * @access public - * @param array $rule 验证规则 - * @return $this - */ - public function validate($rule = []) - { - $this->validate = $rule; - - return $this; - } - - /** - * 检测是否合法的上传文件 - * @access public - * @return bool - */ - public function isValid() - { - if ($this->isTest) { - return is_file($this->filename); - } - - return is_uploaded_file($this->filename); - } - - /** - * 检测上传文件 - * @access public - * @param array $rule 验证规则 - * @return bool - */ - public function check($rule = []) - { - $rule = $rule ?: $this->validate; - - if ((isset($rule['size']) && !$this->checkSize($rule['size'])) - || (isset($rule['type']) && !$this->checkMime($rule['type'])) - || (isset($rule['ext']) && !$this->checkExt($rule['ext'])) - || !$this->checkImg()) { - return false; - } - - return true; - } - - /** - * 检测上传文件后缀 - * @access public - * @param array|string $ext 允许后缀 - * @return bool - */ - public function checkExt($ext) - { - if (is_string($ext)) { - $ext = explode(',', $ext); - } - - $extension = strtolower(pathinfo($this->getInfo('name'), PATHINFO_EXTENSION)); - - if (!in_array($extension, $ext)) { - $this->error = 'extensions to upload is not allowed'; - return false; - } - - return true; - } - - /** - * 检测图像文件 - * @access public - * @return bool - */ - public function checkImg() - { - $extension = strtolower(pathinfo($this->getInfo('name'), PATHINFO_EXTENSION)); - - /* 对图像文件进行严格检测 */ - if (in_array($extension, ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'swf']) && !in_array($this->getImageType($this->filename), [1, 2, 3, 4, 6, 13])) { - $this->error = 'illegal image files'; - return false; - } - - return true; - } - - // 判断图像类型 - protected function getImageType($image) - { - if (function_exists('exif_imagetype')) { - return exif_imagetype($image); - } - - try { - $info = getimagesize($image); - return $info ? $info[2] : false; - } catch (\Exception $e) { - return false; - } - } - - /** - * 检测上传文件大小 - * @access public - * @param integer $size 最大大小 - * @return bool - */ - public function checkSize($size) - { - if ($this->getSize() > $size) { - $this->error = 'filesize not match'; - return false; - } - - return true; - } - - /** - * 检测上传文件类型 - * @access public - * @param array|string $mime 允许类型 - * @return bool - */ - public function checkMime($mime) - { - if (is_string($mime)) { - $mime = explode(',', $mime); - } - - if (!in_array(strtolower($this->getMime()), $mime)) { - $this->error = 'mimetype to upload is not allowed'; - return false; - } - - return true; - } - - /** - * 移动文件 - * @access public - * @param string $path 保存路径 - * @param string|bool $savename 保存的文件名 默认自动生成 - * @param boolean $replace 同名文件是否覆盖 - * @param bool $autoAppendExt 自动补充扩展名 - * @return false|File false-失败 否则返回File实例 - */ - public function move($path, $savename = true, $replace = true, $autoAppendExt = true) - { - // 文件上传失败,捕获错误代码 - if (!empty($this->info['error'])) { - $this->error($this->info['error']); - return false; - } - - // 检测合法性 - if (!$this->isValid()) { - $this->error = 'upload illegal files'; - return false; - } - - // 验证上传 - if (!$this->check()) { - return false; - } - - $path = rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; - // 文件保存命名规则 - $saveName = $this->buildSaveName($savename, $autoAppendExt); - $filename = $path . $saveName; - - // 检测目录 - if (false === $this->checkPath(dirname($filename))) { - return false; - } - - /* 不覆盖同名文件 */ - if (!$replace && is_file($filename)) { - $this->error = ['has the same filename: {:filename}', ['filename' => $filename]]; - return false; - } - - /* 移动文件 */ - if ($this->isTest) { - rename($this->filename, $filename); - } elseif (!move_uploaded_file($this->filename, $filename)) { - $this->error = 'upload write error'; - return false; - } - - // 返回 File对象实例 - $file = new self($filename); - $file->setSaveName($saveName); - $file->setUploadInfo($this->info); - - return $file; - } - - /** - * 获取保存文件名 - * @access protected - * @param string|bool $savename 保存的文件名 默认自动生成 - * @param bool $autoAppendExt 自动补充扩展名 - * @return string - */ - protected function buildSaveName($savename, $autoAppendExt = true) - { - if (true === $savename) { - // 自动生成文件名 - $savename = $this->autoBuildName(); - } elseif ('' === $savename || false === $savename) { - // 保留原文件名 - $savename = $this->getInfo('name'); - } - - if ($autoAppendExt && false === strpos($savename, '.')) { - $savename .= '.' . pathinfo($this->getInfo('name'), PATHINFO_EXTENSION); - } - - return $savename; - } - - /** - * 自动生成文件名 - * @access protected - * @return string - */ - protected function autoBuildName() - { - if ($this->rule instanceof \Closure) { - $savename = call_user_func_array($this->rule, [$this]); - } else { - switch ($this->rule) { - case 'date': - $savename = date('Ymd') . DIRECTORY_SEPARATOR . md5(microtime(true)); - break; - default: - if (in_array($this->rule, hash_algos())) { - $hash = $this->hash($this->rule); - $savename = substr($hash, 0, 2) . DIRECTORY_SEPARATOR . substr($hash, 2); - } elseif (is_callable($this->rule)) { - $savename = call_user_func($this->rule); - } else { - $savename = date('Ymd') . DIRECTORY_SEPARATOR . md5(microtime(true)); - } - } - } - - return $savename; - } - - /** - * 获取错误代码信息 - * @access private - * @param int $errorNo 错误号 - */ - private function error($errorNo) - { - switch ($errorNo) { - case 1: - case 2: - $this->error = 'upload File size exceeds the maximum value'; - break; - case 3: - $this->error = 'only the portion of file is uploaded'; - break; - case 4: - $this->error = 'no file to uploaded'; - break; - case 6: - $this->error = 'upload temp dir not found'; - break; - case 7: - $this->error = 'file write error'; - break; - default: - $this->error = 'unknown upload error'; - } - } - - /** - * 获取错误信息(支持多语言) - * @access public - * @return string - */ - public function getError() - { - $lang = Container::get('lang'); - - if (is_array($this->error)) { - list($msg, $vars) = $this->error; - } else { - $msg = $this->error; - $vars = []; - } - - return $lang->has($msg) ? $lang->get($msg, $vars) : $msg; - } - - public function __call($method, $args) - { - return $this->hash($method); - } -} diff --git a/thinkphp/library/think/Hook.php b/thinkphp/library/think/Hook.php deleted file mode 100755 index 1d011410e..000000000 --- a/thinkphp/library/think/Hook.php +++ /dev/null @@ -1,220 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think; - -class Hook -{ - /** - * 钩子行为定义 - * @var array - */ - private $tags = []; - - /** - * 绑定行为列表 - * @var array - */ - protected $bind = []; - - /** - * 入口方法名称 - * @var string - */ - private static $portal = 'run'; - - /** - * 应用对象 - * @var App - */ - protected $app; - - public function __construct(App $app) - { - $this->app = $app; - } - - /** - * 指定入口方法名称 - * @access public - * @param string $name 方法名 - * @return $this - */ - public function portal($name) - { - self::$portal = $name; - return $this; - } - - /** - * 指定行为标识 便于调用 - * @access public - * @param string|array $name 行为标识 - * @param mixed $behavior 行为 - * @return $this - */ - public function alias($name, $behavior = null) - { - if (is_array($name)) { - $this->bind = array_merge($this->bind, $name); - } else { - $this->bind[$name] = $behavior; - } - - return $this; - } - - /** - * 动态添加行为扩展到某个标签 - * @access public - * @param string $tag 标签名称 - * @param mixed $behavior 行为名称 - * @param bool $first 是否放到开头执行 - * @return void - */ - public function add($tag, $behavior, $first = false) - { - isset($this->tags[$tag]) || $this->tags[$tag] = []; - - if (is_array($behavior) && !is_callable($behavior)) { - if (!array_key_exists('_overlay', $behavior)) { - $this->tags[$tag] = array_merge($this->tags[$tag], $behavior); - } else { - unset($behavior['_overlay']); - $this->tags[$tag] = $behavior; - } - } elseif ($first) { - array_unshift($this->tags[$tag], $behavior); - } else { - $this->tags[$tag][] = $behavior; - } - } - - /** - * 批量导入插件 - * @access public - * @param array $tags 插件信息 - * @param bool $recursive 是否递归合并 - * @return void - */ - public function import(array $tags, $recursive = true) - { - if ($recursive) { - foreach ($tags as $tag => $behavior) { - $this->add($tag, $behavior); - } - } else { - $this->tags = $tags + $this->tags; - } - } - - /** - * 获取插件信息 - * @access public - * @param string $tag 插件位置 留空获取全部 - * @return array - */ - public function get($tag = '') - { - if (empty($tag)) { - //获取全部的插件信息 - return $this->tags; - } - - return array_key_exists($tag, $this->tags) ? $this->tags[$tag] : []; - } - - /** - * 监听标签的行为 - * @access public - * @param string $tag 标签名称 - * @param mixed $params 传入参数 - * @param bool $once 只获取一个有效返回值 - * @return mixed - */ - public function listen($tag, $params = null, $once = false) - { - $results = []; - $tags = $this->get($tag); - - foreach ($tags as $key => $name) { - $results[$key] = $this->execTag($name, $tag, $params); - - if (false === $results[$key] || (!is_null($results[$key]) && $once)) { - break; - } - } - - return $once ? end($results) : $results; - } - - /** - * 执行行为 - * @access public - * @param mixed $class 行为 - * @param mixed $params 参数 - * @return mixed - */ - public function exec($class, $params = null) - { - if ($class instanceof \Closure || is_array($class)) { - $method = $class; - } else { - if (isset($this->bind[$class])) { - $class = $this->bind[$class]; - } - $method = [$class, self::$portal]; - } - - return $this->app->invoke($method, [$params]); - } - - /** - * 执行某个标签的行为 - * @access protected - * @param mixed $class 要执行的行为 - * @param string $tag 方法名(标签名) - * @param mixed $params 参数 - * @return mixed - */ - protected function execTag($class, $tag = '', $params = null) - { - $method = Loader::parseName($tag, 1, false); - - if ($class instanceof \Closure) { - $call = $class; - $class = 'Closure'; - } elseif (is_array($class) || strpos($class, '::')) { - $call = $class; - } else { - $obj = Container::get($class); - - if (!is_callable([$obj, $method])) { - $method = self::$portal; - } - - $call = [$class, $method]; - $class = $class . '->' . $method; - } - - $result = $this->app->invoke($call, [$params]); - - return $result; - } - - public function __debugInfo() - { - $data = get_object_vars($this); - unset($data['app']); - - return $data; - } -} diff --git a/thinkphp/library/think/Lang.php b/thinkphp/library/think/Lang.php deleted file mode 100755 index be7979f89..000000000 --- a/thinkphp/library/think/Lang.php +++ /dev/null @@ -1,284 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think; - -class Lang -{ - /** - * 多语言信息 - * @var array - */ - private $lang = []; - - /** - * 当前语言 - * @var string - */ - private $range = 'zh-cn'; - - /** - * 多语言自动侦测变量名 - * @var string - */ - protected $langDetectVar = 'lang'; - - /** - * 多语言cookie变量 - * @var string - */ - protected $langCookieVar = 'think_var'; - - /** - * 允许的多语言列表 - * @var array - */ - protected $allowLangList = []; - - /** - * Accept-Language转义为对应语言包名称 系统默认配置 - * @var string - */ - protected $acceptLanguage = [ - 'zh-hans-cn' => 'zh-cn', - ]; - - /** - * 应用对象 - * @var App - */ - protected $app; - - public function __construct(App $app) - { - $this->app = $app; - } - - // 设定当前的语言 - public function range($range = '') - { - if ('' == $range) { - return $this->range; - } else { - $this->range = $range; - } - } - - /** - * 设置语言定义(不区分大小写) - * @access public - * @param string|array $name 语言变量 - * @param string $value 语言值 - * @param string $range 语言作用域 - * @return mixed - */ - public function set($name, $value = null, $range = '') - { - $range = $range ?: $this->range; - // 批量定义 - if (!isset($this->lang[$range])) { - $this->lang[$range] = []; - } - - if (is_array($name)) { - return $this->lang[$range] = array_change_key_case($name) + $this->lang[$range]; - } - - return $this->lang[$range][strtolower($name)] = $value; - } - - /** - * 加载语言定义(不区分大小写) - * @access public - * @param string|array $file 语言文件 - * @param string $range 语言作用域 - * @return array - */ - public function load($file, $range = '') - { - $range = $range ?: $this->range; - if (!isset($this->lang[$range])) { - $this->lang[$range] = []; - } - - // 批量定义 - if (is_string($file)) { - $file = [$file]; - } - - $lang = []; - - foreach ($file as $_file) { - if (is_file($_file)) { - // 记录加载信息 - $this->app->log('[ LANG ] ' . $_file); - $_lang = include $_file; - if (is_array($_lang)) { - $lang = array_change_key_case($_lang) + $lang; - } - } - } - - if (!empty($lang)) { - $this->lang[$range] = $lang + $this->lang[$range]; - } - - return $this->lang[$range]; - } - - /** - * 获取语言定义(不区分大小写) - * @access public - * @param string|null $name 语言变量 - * @param string $range 语言作用域 - * @return bool - */ - public function has($name, $range = '') - { - $range = $range ?: $this->range; - - return isset($this->lang[$range][strtolower($name)]); - } - - /** - * 获取语言定义(不区分大小写) - * @access public - * @param string|null $name 语言变量 - * @param array $vars 变量替换 - * @param string $range 语言作用域 - * @return mixed - */ - public function get($name = null, $vars = [], $range = '') - { - $range = $range ?: $this->range; - - // 空参数返回所有定义 - if (is_null($name)) { - return $this->lang[$range]; - } - - $key = strtolower($name); - $value = isset($this->lang[$range][$key]) ? $this->lang[$range][$key] : $name; - - // 变量解析 - if (!empty($vars) && is_array($vars)) { - /** - * Notes: - * 为了检测的方便,数字索引的判断仅仅是参数数组的第一个元素的key为数字0 - * 数字索引采用的是系统的 sprintf 函数替换,用法请参考 sprintf 函数 - */ - if (key($vars) === 0) { - // 数字索引解析 - array_unshift($vars, $value); - $value = call_user_func_array('sprintf', $vars); - } else { - // 关联索引解析 - $replace = array_keys($vars); - foreach ($replace as &$v) { - $v = "{:{$v}}"; - } - $value = str_replace($replace, $vars, $value); - } - } - - return $value; - } - - /** - * 自动侦测设置获取语言选择 - * @access public - * @return string - */ - public function detect() - { - // 自动侦测设置获取语言选择 - $langSet = ''; - - if (isset($_GET[$this->langDetectVar])) { - // url中设置了语言变量 - $langSet = strtolower($_GET[$this->langDetectVar]); - } elseif (isset($_COOKIE[$this->langCookieVar])) { - // Cookie中设置了语言变量 - $langSet = strtolower($_COOKIE[$this->langCookieVar]); - } elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { - // 自动侦测浏览器语言 - preg_match('/^([a-z\d\-]+)/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches); - $langSet = strtolower($matches[1]); - if (isset($this->acceptLanguage[$langSet])) { - $langSet = $this->acceptLanguage[$langSet]; - } - } - - if (empty($this->allowLangList) || in_array($langSet, $this->allowLangList)) { - // 合法的语言 - $this->range = $langSet ?: $this->range; - } - - return $this->range; - } - - /** - * 设置当前语言到Cookie - * @access public - * @param string $lang 语言 - * @return void - */ - public function saveToCookie($lang = null) - { - $range = $lang ?: $this->range; - - $_COOKIE[$this->langCookieVar] = $range; - } - - /** - * 设置语言自动侦测的变量 - * @access public - * @param string $var 变量名称 - * @return void - */ - public function setLangDetectVar($var) - { - $this->langDetectVar = $var; - } - - /** - * 设置语言的cookie保存变量 - * @access public - * @param string $var 变量名称 - * @return void - */ - public function setLangCookieVar($var) - { - $this->langCookieVar = $var; - } - - /** - * 设置允许的语言列表 - * @access public - * @param array $list 语言列表 - * @return void - */ - public function setAllowLangList(array $list) - { - $this->allowLangList = $list; - } - - /** - * 设置转义的语言列表 - * @access public - * @param array $list 语言列表 - * @return void - */ - public function setAcceptLanguage(array $list) - { - $this->acceptLanguage = array_merge($this->acceptLanguage, $list); - } -} diff --git a/thinkphp/library/think/Loader.php b/thinkphp/library/think/Loader.php deleted file mode 100755 index d807db640..000000000 --- a/thinkphp/library/think/Loader.php +++ /dev/null @@ -1,417 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think; - -use think\exception\ClassNotFoundException; - -class Loader -{ - /** - * 类名映射信息 - * @var array - */ - protected static $classMap = []; - - /** - * 类库别名 - * @var array - */ - protected static $classAlias = []; - - /** - * PSR-4 - * @var array - */ - private static $prefixLengthsPsr4 = []; - private static $prefixDirsPsr4 = []; - private static $fallbackDirsPsr4 = []; - - /** - * PSR-0 - * @var array - */ - private static $prefixesPsr0 = []; - private static $fallbackDirsPsr0 = []; - - /** - * 需要加载的文件 - * @var array - */ - private static $files = []; - - /** - * Composer安装路径 - * @var string - */ - private static $composerPath; - - // 获取应用根目录 - public static function getRootPath() - { - if ('cli' == PHP_SAPI) { - $scriptName = realpath($_SERVER['argv'][0]); - } else { - $scriptName = $_SERVER['SCRIPT_FILENAME']; - } - - $path = realpath(dirname($scriptName)); - - if (!is_file($path . DIRECTORY_SEPARATOR . 'think')) { - $path = dirname($path); - } - - return $path . DIRECTORY_SEPARATOR; - } - - // 注册自动加载机制 - public static function register($autoload = '') - { - // 注册系统自动加载 - spl_autoload_register($autoload ?: 'think\\Loader::autoload', true, true); - - $rootPath = self::getRootPath(); - - self::$composerPath = $rootPath . 'vendor' . DIRECTORY_SEPARATOR . 'composer' . DIRECTORY_SEPARATOR; - - // Composer自动加载支持 - if (is_dir(self::$composerPath)) { - if (is_file(self::$composerPath . 'autoload_static.php')) { - require self::$composerPath . 'autoload_static.php'; - - $declaredClass = get_declared_classes(); - $composerClass = array_pop($declaredClass); - - foreach (['prefixLengthsPsr4', 'prefixDirsPsr4', 'fallbackDirsPsr4', 'prefixesPsr0', 'fallbackDirsPsr0', 'classMap', 'files'] as $attr) { - if (property_exists($composerClass, $attr)) { - self::${$attr} = $composerClass::${$attr}; - } - } - } else { - self::registerComposerLoader(self::$composerPath); - } - } - - // 注册命名空间定义 - self::addNamespace([ - 'think' => __DIR__, - 'traits' => dirname(__DIR__) . DIRECTORY_SEPARATOR . 'traits', - ]); - - // 加载类库映射文件 - if (is_file($rootPath . 'runtime' . DIRECTORY_SEPARATOR . 'classmap.php')) { - self::addClassMap(__include_file($rootPath . 'runtime' . DIRECTORY_SEPARATOR . 'classmap.php')); - } - - // 自动加载extend目录 - self::addAutoLoadDir($rootPath . 'extend'); - } - - // 自动加载 - public static function autoload($class) - { - if (isset(self::$classAlias[$class])) { - return class_alias(self::$classAlias[$class], $class); - } - - if ($file = self::findFile($class)) { - - // Win环境严格区分大小写 - if (strpos(PHP_OS, 'WIN') !== false && pathinfo($file, PATHINFO_FILENAME) != pathinfo(realpath($file), PATHINFO_FILENAME)) { - return false; - } - - __include_file($file); - return true; - } - } - - /** - * 查找文件 - * @access private - * @param string $class - * @return string|false - */ - private static function findFile($class) - { - if (!empty(self::$classMap[$class])) { - // 类库映射 - return self::$classMap[$class]; - } - - // 查找 PSR-4 - $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . '.php'; - - $first = $class[0]; - if (isset(self::$prefixLengthsPsr4[$first])) { - foreach (self::$prefixLengthsPsr4[$first] as $prefix => $length) { - if (0 === strpos($class, $prefix)) { - foreach (self::$prefixDirsPsr4[$prefix] as $dir) { - if (is_file($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) { - return $file; - } - } - } - } - } - - // 查找 PSR-4 fallback dirs - foreach (self::$fallbackDirsPsr4 as $dir) { - if (is_file($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { - return $file; - } - } - - // 查找 PSR-0 - if (false !== $pos = strrpos($class, '\\')) { - // namespaced class name - $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) - . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); - } else { - // PEAR-like class name - $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . '.php'; - } - - if (isset(self::$prefixesPsr0[$first])) { - foreach (self::$prefixesPsr0[$first] as $prefix => $dirs) { - if (0 === strpos($class, $prefix)) { - foreach ($dirs as $dir) { - if (is_file($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { - return $file; - } - } - } - } - } - - // 查找 PSR-0 fallback dirs - foreach (self::$fallbackDirsPsr0 as $dir) { - if (is_file($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { - return $file; - } - } - - return self::$classMap[$class] = false; - } - - // 注册classmap - public static function addClassMap($class, $map = '') - { - if (is_array($class)) { - self::$classMap = array_merge(self::$classMap, $class); - } else { - self::$classMap[$class] = $map; - } - } - - // 注册命名空间 - public static function addNamespace($namespace, $path = '') - { - if (is_array($namespace)) { - foreach ($namespace as $prefix => $paths) { - self::addPsr4($prefix . '\\', rtrim($paths, DIRECTORY_SEPARATOR), true); - } - } else { - self::addPsr4($namespace . '\\', rtrim($path, DIRECTORY_SEPARATOR), true); - } - } - - // 添加Ps0空间 - private static function addPsr0($prefix, $paths, $prepend = false) - { - if (!$prefix) { - if ($prepend) { - self::$fallbackDirsPsr0 = array_merge( - (array) $paths, - self::$fallbackDirsPsr0 - ); - } else { - self::$fallbackDirsPsr0 = array_merge( - self::$fallbackDirsPsr0, - (array) $paths - ); - } - - return; - } - - $first = $prefix[0]; - if (!isset(self::$prefixesPsr0[$first][$prefix])) { - self::$prefixesPsr0[$first][$prefix] = (array) $paths; - - return; - } - - if ($prepend) { - self::$prefixesPsr0[$first][$prefix] = array_merge( - (array) $paths, - self::$prefixesPsr0[$first][$prefix] - ); - } else { - self::$prefixesPsr0[$first][$prefix] = array_merge( - self::$prefixesPsr0[$first][$prefix], - (array) $paths - ); - } - } - - // 添加Psr4空间 - private static function addPsr4($prefix, $paths, $prepend = false) - { - if (!$prefix) { - // Register directories for the root namespace. - if ($prepend) { - self::$fallbackDirsPsr4 = array_merge( - (array) $paths, - self::$fallbackDirsPsr4 - ); - } else { - self::$fallbackDirsPsr4 = array_merge( - self::$fallbackDirsPsr4, - (array) $paths - ); - } - } elseif (!isset(self::$prefixDirsPsr4[$prefix])) { - // Register directories for a new namespace. - $length = strlen($prefix); - if ('\\' !== $prefix[$length - 1]) { - throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); - } - - self::$prefixLengthsPsr4[$prefix[0]][$prefix] = $length; - self::$prefixDirsPsr4[$prefix] = (array) $paths; - } elseif ($prepend) { - // Prepend directories for an already registered namespace. - self::$prefixDirsPsr4[$prefix] = array_merge( - (array) $paths, - self::$prefixDirsPsr4[$prefix] - ); - } else { - // Append directories for an already registered namespace. - self::$prefixDirsPsr4[$prefix] = array_merge( - self::$prefixDirsPsr4[$prefix], - (array) $paths - ); - } - } - - // 注册自动加载类库目录 - public static function addAutoLoadDir($path) - { - self::$fallbackDirsPsr4[] = $path; - } - - // 注册类别名 - public static function addClassAlias($alias, $class = null) - { - if (is_array($alias)) { - self::$classAlias = array_merge(self::$classAlias, $alias); - } else { - self::$classAlias[$alias] = $class; - } - } - - // 注册composer自动加载 - public static function registerComposerLoader($composerPath) - { - if (is_file($composerPath . 'autoload_namespaces.php')) { - $map = require $composerPath . 'autoload_namespaces.php'; - foreach ($map as $namespace => $path) { - self::addPsr0($namespace, $path); - } - } - - if (is_file($composerPath . 'autoload_psr4.php')) { - $map = require $composerPath . 'autoload_psr4.php'; - foreach ($map as $namespace => $path) { - self::addPsr4($namespace, $path); - } - } - - if (is_file($composerPath . 'autoload_classmap.php')) { - $classMap = require $composerPath . 'autoload_classmap.php'; - if ($classMap) { - self::addClassMap($classMap); - } - } - - if (is_file($composerPath . 'autoload_files.php')) { - self::$files = require $composerPath . 'autoload_files.php'; - } - } - - // 加载composer autofile文件 - public static function loadComposerAutoloadFiles() - { - foreach (self::$files as $fileIdentifier => $file) { - if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { - __require_file($file); - - $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; - } - } - } - - /** - * 字符串命名风格转换 - * type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格 - * @access public - * @param string $name 字符串 - * @param integer $type 转换类型 - * @param bool $ucfirst 首字母是否大写(驼峰规则) - * @return string - */ - public static function parseName($name, $type = 0, $ucfirst = true) - { - if ($type) { - $name = preg_replace_callback('/_([a-zA-Z])/', function ($match) { - return strtoupper($match[1]); - }, $name); - return $ucfirst ? ucfirst($name) : lcfirst($name); - } - - return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_")); - } - - /** - * 创建工厂对象实例 - * @access public - * @param string $name 工厂类名 - * @param string $namespace 默认命名空间 - * @return mixed - */ - public static function factory($name, $namespace = '', ...$args) - { - $class = false !== strpos($name, '\\') ? $name : $namespace . ucwords($name); - - if (class_exists($class)) { - return Container::getInstance()->invokeClass($class, $args); - } else { - throw new ClassNotFoundException('class not exists:' . $class, $class); - } - } -} - -/** - * 作用范围隔离 - * - * @param $file - * @return mixed - */ -function __include_file($file) -{ - return include $file; -} - -function __require_file($file) -{ - return require $file; -} diff --git a/thinkphp/library/think/Log.php b/thinkphp/library/think/Log.php deleted file mode 100755 index 1a3749626..000000000 --- a/thinkphp/library/think/Log.php +++ /dev/null @@ -1,387 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think; - -class Log implements LoggerInterface -{ - const EMERGENCY = 'emergency'; - const ALERT = 'alert'; - const CRITICAL = 'critical'; - const ERROR = 'error'; - const WARNING = 'warning'; - const NOTICE = 'notice'; - const INFO = 'info'; - const DEBUG = 'debug'; - const SQL = 'sql'; - - /** - * 日志信息 - * @var array - */ - protected $log = []; - - /** - * 配置参数 - * @var array - */ - protected $config = []; - - /** - * 日志写入驱动 - * @var object - */ - protected $driver; - - /** - * 日志授权key - * @var string - */ - protected $key; - - /** - * 是否允许日志写入 - * @var bool - */ - protected $allowWrite = true; - - /** - * 应用对象 - * @var App - */ - protected $app; - - public function __construct(App $app) - { - $this->app = $app; - } - - public static function __make(App $app, Config $config) - { - return (new static($app))->init($config->pull('log')); - } - - /** - * 日志初始化 - * @access public - * @param array $config - * @return $this - */ - public function init($config = []) - { - $type = isset($config['type']) ? $config['type'] : 'File'; - - $this->config = $config; - - unset($config['type']); - - if (!empty($config['close'])) { - $this->allowWrite = false; - } - - $this->driver = Loader::factory($type, '\\think\\log\\driver\\', $config); - - return $this; - } - - /** - * 获取日志信息 - * @access public - * @param string $type 信息类型 - * @return array - */ - public function getLog($type = '') - { - return $type ? $this->log[$type] : $this->log; - } - - /** - * 记录日志信息 - * @access public - * @param mixed $msg 日志信息 - * @param string $type 日志级别 - * @param array $context 替换内容 - * @return $this - */ - public function record($msg, $type = 'info', array $context = []) - { - if (!$this->allowWrite) { - return; - } - - if (is_string($msg) && !empty($context)) { - $replace = []; - foreach ($context as $key => $val) { - $replace['{' . $key . '}'] = $val; - } - - $msg = strtr($msg, $replace); - } - - if (PHP_SAPI == 'cli') { - // 命令行日志实时写入 - $this->write($msg, $type, true); - } else { - $this->log[$type][] = $msg; - } - - return $this; - } - - /** - * 清空日志信息 - * @access public - * @return $this - */ - public function clear() - { - $this->log = []; - - return $this; - } - - /** - * 当前日志记录的授权key - * @access public - * @param string $key 授权key - * @return $this - */ - public function key($key) - { - $this->key = $key; - - return $this; - } - - /** - * 检查日志写入权限 - * @access public - * @param array $config 当前日志配置参数 - * @return bool - */ - public function check($config) - { - if ($this->key && !empty($config['allow_key']) && !in_array($this->key, $config['allow_key'])) { - return false; - } - - return true; - } - - /** - * 关闭本次请求日志写入 - * @access public - * @return $this - */ - public function close() - { - $this->allowWrite = false; - $this->log = []; - - return $this; - } - - /** - * 保存调试信息 - * @access public - * @return bool - */ - public function save() - { - if (empty($this->log) || !$this->allowWrite) { - return true; - } - - if (!$this->check($this->config)) { - // 检测日志写入权限 - return false; - } - - $log = []; - - foreach ($this->log as $level => $info) { - if (!$this->app->isDebug() && 'debug' == $level) { - continue; - } - - if (empty($this->config['level']) || in_array($level, $this->config['level'])) { - $log[$level] = $info; - - $this->app['hook']->listen('log_level', [$level, $info]); - } - } - - $result = $this->driver->save($log, true); - - if ($result) { - $this->log = []; - } - - return $result; - } - - /** - * 实时写入日志信息 并支持行为 - * @access public - * @param mixed $msg 调试信息 - * @param string $type 日志级别 - * @param bool $force 是否强制写入 - * @return bool - */ - public function write($msg, $type = 'info', $force = false) - { - // 封装日志信息 - if (empty($this->config['level'])) { - $force = true; - } - - if (true === $force || in_array($type, $this->config['level'])) { - $log[$type][] = $msg; - } else { - return false; - } - - // 监听log_write - $this->app['hook']->listen('log_write', $log); - - // 写入日志 - return $this->driver->save($log, false); - } - - /** - * 记录日志信息 - * @access public - * @param string $level 日志级别 - * @param mixed $message 日志信息 - * @param array $context 替换内容 - * @return void - */ - public function log($level, $message, array $context = []) - { - $this->record($message, $level, $context); - } - - /** - * 记录emergency信息 - * @access public - * @param mixed $message 日志信息 - * @param array $context 替换内容 - * @return void - */ - public function emergency($message, array $context = []) - { - $this->log(__FUNCTION__, $message, $context); - } - - /** - * 记录警报信息 - * @access public - * @param mixed $message 日志信息 - * @param array $context 替换内容 - * @return void - */ - public function alert($message, array $context = []) - { - $this->log(__FUNCTION__, $message, $context); - } - - /** - * 记录紧急情况 - * @access public - * @param mixed $message 日志信息 - * @param array $context 替换内容 - * @return void - */ - public function critical($message, array $context = []) - { - $this->log(__FUNCTION__, $message, $context); - } - - /** - * 记录错误信息 - * @access public - * @param mixed $message 日志信息 - * @param array $context 替换内容 - * @return void - */ - public function error($message, array $context = []) - { - $this->log(__FUNCTION__, $message, $context); - } - - /** - * 记录warning信息 - * @access public - * @param mixed $message 日志信息 - * @param array $context 替换内容 - * @return void - */ - public function warning($message, array $context = []) - { - $this->log(__FUNCTION__, $message, $context); - } - - /** - * 记录notice信息 - * @access public - * @param mixed $message 日志信息 - * @param array $context 替换内容 - * @return void - */ - public function notice($message, array $context = []) - { - $this->log(__FUNCTION__, $message, $context); - } - - /** - * 记录一般信息 - * @access public - * @param mixed $message 日志信息 - * @param array $context 替换内容 - * @return void - */ - public function info($message, array $context = []) - { - $this->log(__FUNCTION__, $message, $context); - } - - /** - * 记录调试信息 - * @access public - * @param mixed $message 日志信息 - * @param array $context 替换内容 - * @return void - */ - public function debug($message, array $context = []) - { - $this->log(__FUNCTION__, $message, $context); - } - - /** - * 记录sql信息 - * @access public - * @param mixed $message 日志信息 - * @param array $context 替换内容 - * @return void - */ - public function sql($message, array $context = []) - { - $this->log(__FUNCTION__, $message, $context); - } - - public function __debugInfo() - { - $data = get_object_vars($this); - unset($data['app']); - - return $data; - } -} diff --git a/thinkphp/library/think/Middleware.php b/thinkphp/library/think/Middleware.php deleted file mode 100755 index d3f43606d..000000000 --- a/thinkphp/library/think/Middleware.php +++ /dev/null @@ -1,205 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think; - -use InvalidArgumentException; -use LogicException; -use think\exception\HttpResponseException; - -class Middleware -{ - protected $queue = []; - protected $app; - protected $config = [ - 'default_namespace' => 'app\\http\\middleware\\', - ]; - - public function __construct(App $app, array $config = []) - { - $this->app = $app; - $this->config = array_merge($this->config, $config); - } - - public static function __make(App $app, Config $config) - { - return new static($app, $config->pull('middleware')); - } - - public function setConfig(array $config) - { - $this->config = array_merge($this->config, $config); - } - - /** - * 导入中间件 - * @access public - * @param array $middlewares - * @param string $type 中间件类型 - */ - public function import(array $middlewares = [], $type = 'route') - { - foreach ($middlewares as $middleware) { - $this->add($middleware, $type); - } - } - - /** - * 注册中间件 - * @access public - * @param mixed $middleware - * @param string $type 中间件类型 - */ - public function add($middleware, $type = 'route') - { - if (is_null($middleware)) { - return; - } - - $middleware = $this->buildMiddleware($middleware, $type); - - if ($middleware) { - $this->queue[$type][] = $middleware; - } - } - - /** - * 注册控制器中间件 - * @access public - * @param mixed $middleware - */ - public function controller($middleware) - { - return $this->add($middleware, 'controller'); - } - - /** - * 移除中间件 - * @access public - * @param mixed $middleware - * @param string $type 中间件类型 - */ - public function unshift($middleware, $type = 'route') - { - if (is_null($middleware)) { - return; - } - - $middleware = $this->buildMiddleware($middleware, $type); - - if ($middleware) { - array_unshift($this->queue[$type], $middleware); - } - } - - /** - * 获取注册的中间件 - * @access public - * @param string $type 中间件类型 - */ - public function all($type = 'route') - { - return $this->queue[$type] ?: []; - } - - /** - * 清除中间件 - * @access public - */ - public function clear() - { - $this->queue = []; - } - - /** - * 中间件调度 - * @access public - * @param Request $request - * @param string $type 中间件类型 - */ - public function dispatch(Request $request, $type = 'route') - { - return call_user_func($this->resolve($type), $request); - } - - /** - * 解析中间件 - * @access protected - * @param mixed $middleware - * @param string $type 中间件类型 - */ - protected function buildMiddleware($middleware, $type = 'route') - { - if (is_array($middleware)) { - list($middleware, $param) = $middleware; - } - - if ($middleware instanceof \Closure) { - return [$middleware, isset($param) ? $param : null]; - } - - if (!is_string($middleware)) { - throw new InvalidArgumentException('The middleware is invalid'); - } - - if (false === strpos($middleware, '\\')) { - if (isset($this->config[$middleware])) { - $middleware = $this->config[$middleware]; - } else { - $middleware = $this->config['default_namespace'] . $middleware; - } - } - - if (is_array($middleware)) { - return $this->import($middleware, $type); - } - - if (strpos($middleware, ':')) { - list($middleware, $param) = explode(':', $middleware, 2); - } - - return [[$this->app->make($middleware), 'handle'], isset($param) ? $param : null]; - } - - protected function resolve($type = 'route') - { - return function (Request $request) use ($type) { - - $middleware = array_shift($this->queue[$type]); - - if (null === $middleware) { - throw new InvalidArgumentException('The queue was exhausted, with no response returned'); - } - - list($call, $param) = $middleware; - - try { - $response = call_user_func_array($call, [$request, $this->resolve($type), $param]); - } catch (HttpResponseException $exception) { - $response = $exception->getResponse(); - } - - if (!$response instanceof Response) { - throw new LogicException('The middleware must return Response instance'); - } - - return $response; - }; - } - - public function __debugInfo() - { - $data = get_object_vars($this); - unset($data['app']); - - return $data; - } -} diff --git a/thinkphp/library/think/Model.php b/thinkphp/library/think/Model.php deleted file mode 100755 index 9896f9ff5..000000000 --- a/thinkphp/library/think/Model.php +++ /dev/null @@ -1,1072 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think; - -use InvalidArgumentException; -use think\db\Query; - -/** - * Class Model - * @package think - * @mixin Query - * @method \think\Model withAttr(array $name,\Closure $closure) 动态定义获取器 - */ -abstract class Model implements \JsonSerializable, \ArrayAccess -{ - use model\concern\Attribute; - use model\concern\RelationShip; - use model\concern\ModelEvent; - use model\concern\TimeStamp; - use model\concern\Conversion; - - /** - * 是否存在数据 - * @var bool - */ - private $exists = false; - - /** - * 是否Replace - * @var bool - */ - private $replace = false; - - /** - * 是否强制更新所有数据 - * @var bool - */ - private $force = false; - - /** - * 更新条件 - * @var array - */ - private $updateWhere; - - /** - * 数据库配置信息 - * @var array|string - */ - protected $connection = []; - - /** - * 数据库查询对象类名 - * @var string - */ - protected $query; - - /** - * 模型名称 - * @var string - */ - protected $name; - - /** - * 数据表名称 - * @var string - */ - protected $table; - - /** - * 写入自动完成定义 - * @var array - */ - protected $auto = []; - - /** - * 新增自动完成定义 - * @var array - */ - protected $insert = []; - - /** - * 更新自动完成定义 - * @var array - */ - protected $update = []; - - /** - * 初始化过的模型. - * @var array - */ - protected static $initialized = []; - - /** - * 是否从主库读取(主从分布式有效) - * @var array - */ - protected static $readMaster; - - /** - * 查询对象实例 - * @var Query - */ - protected $queryInstance; - - /** - * 错误信息 - * @var mixed - */ - protected $error; - - /** - * 软删除字段默认值 - * @var mixed - */ - protected $defaultSoftDelete; - - /** - * 全局查询范围 - * @var array - */ - protected $globalScope = []; - - /** - * 架构函数 - * @access public - * @param array|object $data 数据 - */ - public function __construct($data = []) - { - if (is_object($data)) { - $this->data = get_object_vars($data); - } else { - $this->data = $data; - } - - if ($this->disuse) { - // 废弃字段 - foreach ((array) $this->disuse as $key) { - if (array_key_exists($key, $this->data)) { - unset($this->data[$key]); - } - } - } - - // 记录原始数据 - $this->origin = $this->data; - - $config = Db::getConfig(); - - if (empty($this->name)) { - // 当前模型名 - $name = str_replace('\\', '/', static::class); - $this->name = basename($name); - if (Container::get('config')->get('class_suffix')) { - $suffix = basename(dirname($name)); - $this->name = substr($this->name, 0, -strlen($suffix)); - } - } - - if (is_null($this->autoWriteTimestamp)) { - // 自动写入时间戳 - $this->autoWriteTimestamp = $config['auto_timestamp']; - } - - if (is_null($this->dateFormat)) { - // 设置时间戳格式 - $this->dateFormat = $config['datetime_format']; - } - - if (is_null($this->resultSetType)) { - $this->resultSetType = $config['resultset_type']; - } - - if (!empty($this->connection) && is_array($this->connection)) { - // 设置模型的数据库连接 - $this->connection = array_merge($config, $this->connection); - } - - if ($this->observerClass) { - // 注册模型观察者 - static::observe($this->observerClass); - } - - // 执行初始化操作 - $this->initialize(); - } - - /** - * 获取当前模型名称 - * @access public - * @return string - */ - public function getName() - { - return $this->name; - } - - /** - * 是否从主库读取数据(主从分布有效) - * @access public - * @param bool $all 是否所有模型有效 - * @return $this - */ - public function readMaster($all = false) - { - $model = $all ? '*' : static::class; - - static::$readMaster[$model] = true; - - return $this; - } - - /** - * 创建新的模型实例 - * @access public - * @param array|object $data 数据 - * @param bool $isUpdate 是否为更新 - * @param mixed $where 更新条件 - * @return Model - */ - public function newInstance($data = [], $isUpdate = false, $where = null) - { - return (new static($data))->isUpdate($isUpdate, $where); - } - - /** - * 创建模型的查询对象 - * @access protected - * @return Query - */ - protected function buildQuery() - { - // 设置当前模型 确保查询返回模型对象 - $query = Db::connect($this->connection, false, $this->query); - $query->model($this) - ->name($this->name) - ->json($this->json, $this->jsonAssoc) - ->setJsonFieldType($this->jsonType); - - if (isset(static::$readMaster['*']) || isset(static::$readMaster[static::class])) { - $query->master(true); - } - - // 设置当前数据表和模型名 - if (!empty($this->table)) { - $query->table($this->table); - } - - if (!empty($this->pk)) { - $query->pk($this->pk); - } - - return $query; - } - - /** - * 获取当前模型的数据库查询对象 - * @access public - * @param Query $query 查询对象实例 - * @return $this - */ - public function setQuery($query) - { - $this->queryInstance = $query; - return $this; - } - - /** - * 获取当前模型的数据库查询对象 - * @access public - * @param bool|array $useBaseQuery 是否调用全局查询范围(或者指定查询范围名称) - * @return Query - */ - public function db($useBaseQuery = true) - { - if ($this->queryInstance) { - return $this->queryInstance; - } - - $query = $this->buildQuery(); - - // 软删除 - if (property_exists($this, 'withTrashed') && !$this->withTrashed) { - $this->withNoTrashed($query); - } - - // 全局作用域 - if (true === $useBaseQuery && method_exists($this, 'base')) { - call_user_func_array([$this, 'base'], [ & $query]); - } - - $globalScope = is_array($useBaseQuery) && $useBaseQuery ? $useBaseQuery : $this->globalScope; - - if ($globalScope && false !== $useBaseQuery) { - $query->scope($globalScope); - } - - // 返回当前模型的数据库查询对象 - return $query; - } - - /** - * 初始化模型 - * @access protected - * @return void - */ - protected function initialize() - { - if (!isset(static::$initialized[static::class])) { - static::$initialized[static::class] = true; - static::init(); - } - } - - /** - * 初始化处理 - * @access protected - * @return void - */ - protected static function init() - {} - - /** - * 数据自动完成 - * @access protected - * @param array $auto 要自动更新的字段列表 - * @return void - */ - protected function autoCompleteData($auto = []) - { - foreach ($auto as $field => $value) { - if (is_integer($field)) { - $field = $value; - $value = null; - } - - if (!isset($this->data[$field])) { - $default = null; - } else { - $default = $this->data[$field]; - } - - $this->setAttr($field, !is_null($value) ? $value : $default); - } - } - - /** - * 更新是否强制写入数据 而不做比较 - * @access public - * @param bool $force - * @return $this - */ - public function force($force = true) - { - $this->force = $force; - return $this; - } - - /** - * 判断force - * @access public - * @return bool - */ - public function isForce() - { - return $this->force; - } - - /** - * 新增数据是否使用Replace - * @access public - * @param bool $replace - * @return $this - */ - public function replace($replace = true) - { - $this->replace = $replace; - return $this; - } - - /** - * 设置数据是否存在 - * @access public - * @param bool $exists - * @return $this - */ - public function exists($exists) - { - $this->exists = $exists; - return $this; - } - - /** - * 判断数据是否存在数据库 - * @access public - * @return bool - */ - public function isExists() - { - return $this->exists; - } - - /** - * 保存当前数据对象 - * @access public - * @param array $data 数据 - * @param array $where 更新条件 - * @param string $sequence 自增序列名 - * @return bool - */ - public function save($data = [], $where = [], $sequence = null) - { - if (is_string($data)) { - $sequence = $data; - $data = []; - } - - if (!$this->checkBeforeSave($data, $where)) { - return false; - } - - $result = $this->exists ? $this->updateData($where) : $this->insertData($sequence); - - if (false === $result) { - return false; - } - - // 写入回调 - $this->trigger('after_write'); - - // 重新记录原始数据 - $this->origin = $this->data; - $this->set = []; - - return true; - } - - /** - * 写入之前检查数据 - * @access protected - * @param array $data 数据 - * @param array $where 保存条件 - * @return bool - */ - protected function checkBeforeSave($data, $where) - { - if (!empty($data)) { - // 数据对象赋值 - foreach ($data as $key => $value) { - $this->setAttr($key, $value, $data); - } - - if (!empty($where)) { - $this->exists = true; - $this->updateWhere = $where; - } - } - - // 数据自动完成 - $this->autoCompleteData($this->auto); - - // 事件回调 - if (false === $this->trigger('before_write')) { - return false; - } - - return true; - } - - /** - * 检查数据是否允许写入 - * @access protected - * @param array $append 自动完成的字段列表 - * @return array - */ - protected function checkAllowFields(array $append = []) - { - // 检测字段 - if (empty($this->field) || true === $this->field) { - $query = $this->db(false); - $table = $this->table ?: $query->getTable(); - - $this->field = $query->getConnection()->getTableFields($table); - - $field = $this->field; - } else { - $field = array_merge($this->field, $append); - - if ($this->autoWriteTimestamp) { - array_push($field, $this->createTime, $this->updateTime); - } - } - - if ($this->disuse) { - // 废弃字段 - $field = array_diff($field, (array) $this->disuse); - } - - return $field; - } - - /** - * 更新写入数据 - * @access protected - * @param mixed $where 更新条件 - * @return bool - */ - protected function updateData($where) - { - // 自动更新 - $this->autoCompleteData($this->update); - - // 事件回调 - if (false === $this->trigger('before_update')) { - return false; - } - - // 获取有更新的数据 - $data = $this->getChangedData(); - - if (empty($data)) { - // 关联更新 - if (!empty($this->relationWrite)) { - $this->autoRelationUpdate(); - } - - return false; - } elseif ($this->autoWriteTimestamp && $this->updateTime && !isset($data[$this->updateTime])) { - // 自动写入更新时间 - $data[$this->updateTime] = $this->autoWriteTimestamp($this->updateTime); - - $this->data[$this->updateTime] = $data[$this->updateTime]; - } - - if (empty($where) && !empty($this->updateWhere)) { - $where = $this->updateWhere; - } - - // 检查允许字段 - $allowFields = $this->checkAllowFields(array_merge($this->auto, $this->update)); - - // 保留主键数据 - foreach ($this->data as $key => $val) { - if ($this->isPk($key)) { - $data[$key] = $val; - } - } - - $pk = $this->getPk(); - $array = []; - - foreach ((array) $pk as $key) { - if (isset($data[$key])) { - $array[] = [$key, '=', $data[$key]]; - unset($data[$key]); - } - } - - if (!empty($array)) { - $where = $array; - } - - foreach ((array) $this->relationWrite as $name => $val) { - if (is_array($val)) { - foreach ($val as $key) { - if (isset($data[$key])) { - unset($data[$key]); - } - } - } - } - - // 模型更新 - $db = $this->db(false); - $db->startTrans(); - - try { - $db->where($where) - ->strict(false) - ->field($allowFields) - ->update($data); - - // 关联更新 - if (!empty($this->relationWrite)) { - $this->autoRelationUpdate(); - } - - $db->commit(); - - // 更新回调 - $this->trigger('after_update'); - - return true; - } catch (\Exception $e) { - $db->rollback(); - throw $e; - } - } - - /** - * 新增写入数据 - * @access protected - * @param string $sequence 自增序列名 - * @return bool - */ - protected function insertData($sequence) - { - // 自动写入 - $this->autoCompleteData($this->insert); - - // 时间戳自动写入 - $this->checkTimeStampWrite(); - - if (false === $this->trigger('before_insert')) { - return false; - } - - // 检查允许字段 - $allowFields = $this->checkAllowFields(array_merge($this->auto, $this->insert)); - - $db = $this->db(false); - $db->startTrans(); - - try { - $result = $db->strict(false) - ->field($allowFields) - ->insert($this->data, $this->replace, false, $sequence); - - // 获取自动增长主键 - if ($result && $insertId = $db->getLastInsID($sequence)) { - $pk = $this->getPk(); - - foreach ((array) $pk as $key) { - if (!isset($this->data[$key]) || '' == $this->data[$key]) { - $this->data[$key] = $insertId; - } - } - } - - // 关联写入 - if (!empty($this->relationWrite)) { - $this->autoRelationInsert(); - } - - $db->commit(); - - // 标记为更新 - $this->exists = true; - - // 新增回调 - $this->trigger('after_insert'); - - return true; - } catch (\Exception $e) { - $db->rollback(); - throw $e; - } - } - - /** - * 字段值(延迟)增长 - * @access public - * @param string $field 字段名 - * @param integer $step 增长值 - * @param integer $lazyTime 延时时间(s) - * @return bool - * @throws Exception - */ - public function setInc($field, $step = 1, $lazyTime = 0) - { - // 读取更新条件 - $where = $this->getWhere(); - - // 事件回调 - if (false === $this->trigger('before_update')) { - return false; - } - - $result = $this->db(false) - ->where($where) - ->setInc($field, $step, $lazyTime); - - if (true !== $result) { - $this->data[$field] += $step; - } - - // 更新回调 - $this->trigger('after_update'); - - return true; - } - - /** - * 字段值(延迟)减少 - * @access public - * @param string $field 字段名 - * @param integer $step 减少值 - * @param integer $lazyTime 延时时间(s) - * @return bool - * @throws Exception - */ - public function setDec($field, $step = 1, $lazyTime = 0) - { - // 读取更新条件 - $where = $this->getWhere(); - - // 事件回调 - if (false === $this->trigger('before_update')) { - return false; - } - - $result = $this->db(false) - ->where($where) - ->setDec($field, $step, $lazyTime); - - if (true !== $result) { - $this->data[$field] -= $step; - } - - // 更新回调 - $this->trigger('after_update'); - - return true; - } - - /** - * 获取当前的更新条件 - * @access protected - * @return mixed - */ - protected function getWhere() - { - // 删除条件 - $pk = $this->getPk(); - - if (is_string($pk) && isset($this->data[$pk])) { - $where[] = [$pk, '=', $this->data[$pk]]; - } elseif (!empty($this->updateWhere)) { - $where = $this->updateWhere; - } else { - $where = null; - } - - return $where; - } - - /** - * 保存多个数据到当前数据对象 - * @access public - * @param array $dataSet 数据 - * @param boolean $replace 是否自动识别更新和写入 - * @return Collection - * @throws \Exception - */ - public function saveAll($dataSet, $replace = true) - { - $db = $this->db(false); - $db->startTrans(); - - try { - $pk = $this->getPk(); - - if (is_string($pk) && $replace) { - $auto = true; - } - - $result = []; - - foreach ($dataSet as $key => $data) { - if ($this->exists || (!empty($auto) && isset($data[$pk]))) { - $result[$key] = self::update($data, [], $this->field); - } else { - $result[$key] = self::create($data, $this->field, $this->replace); - } - } - - $db->commit(); - - return $this->toCollection($result); - } catch (\Exception $e) { - $db->rollback(); - throw $e; - } - } - - /** - * 是否为更新数据 - * @access public - * @param mixed $update - * @param mixed $where - * @return $this - */ - public function isUpdate($update = true, $where = null) - { - if (is_bool($update)) { - $this->exists = $update; - - if (!empty($where)) { - $this->updateWhere = $where; - } - } else { - $this->exists = true; - $this->updateWhere = $update; - } - - return $this; - } - - /** - * 删除当前的记录 - * @access public - * @return bool - */ - public function delete() - { - if (!$this->exists || false === $this->trigger('before_delete')) { - return false; - } - - // 读取更新条件 - $where = $this->getWhere(); - - $db = $this->db(false); - $db->startTrans(); - - try { - // 删除当前模型数据 - $db->where($where)->delete(); - - // 关联删除 - if (!empty($this->relationWrite)) { - $this->autoRelationDelete(); - } - - $db->commit(); - - $this->trigger('after_delete'); - - $this->exists = false; - - return true; - } catch (\Exception $e) { - $db->rollback(); - throw $e; - } - } - - /** - * 设置自动完成的字段( 规则通过修改器定义) - * @access public - * @param array $fields 需要自动完成的字段 - * @return $this - */ - public function auto($fields) - { - $this->auto = $fields; - - return $this; - } - - /** - * 写入数据 - * @access public - * @param array $data 数据数组 - * @param array|true $field 允许字段 - * @param bool $replace 使用Replace - * @return static - */ - public static function create($data = [], $field = null, $replace = false) - { - $model = new static(); - - if (!empty($field)) { - $model->allowField($field); - } - - $model->isUpdate(false)->replace($replace)->save($data, []); - - return $model; - } - - /** - * 更新数据 - * @access public - * @param array $data 数据数组 - * @param array $where 更新条件 - * @param array|true $field 允许字段 - * @return static - */ - public static function update($data = [], $where = [], $field = null) - { - $model = new static(); - - if (!empty($field)) { - $model->allowField($field); - } - - $model->isUpdate(true)->save($data, $where); - - return $model; - } - - /** - * 删除记录 - * @access public - * @param mixed $data 主键列表 支持闭包查询条件 - * @return bool - */ - public static function destroy($data) - { - if (empty($data) && 0 !== $data) { - return false; - } - - $model = new static(); - - $query = $model->db(); - - if (is_array($data) && key($data) !== 0) { - $query->where($data); - $data = null; - } elseif ($data instanceof \Closure) { - $data($query); - $data = null; - } - - $resultSet = $query->select($data); - - if ($resultSet) { - foreach ($resultSet as $data) { - $data->delete(); - } - } - - return true; - } - - /** - * 获取错误信息 - * @access public - * @return mixed - */ - public function getError() - { - return $this->error; - } - - /** - * 解序列化后处理 - */ - public function __wakeup() - { - $this->initialize(); - } - - public function __debugInfo() - { - return [ - 'data' => $this->data, - 'relation' => $this->relation, - ]; - } - - /** - * 修改器 设置数据对象的值 - * @access public - * @param string $name 名称 - * @param mixed $value 值 - * @return void - */ - public function __set($name, $value) - { - $this->setAttr($name, $value); - } - - /** - * 获取器 获取数据对象的值 - * @access public - * @param string $name 名称 - * @return mixed - */ - public function __get($name) - { - return $this->getAttr($name); - } - - /** - * 检测数据对象的值 - * @access public - * @param string $name 名称 - * @return boolean - */ - public function __isset($name) - { - try { - return !is_null($this->getAttr($name)); - } catch (InvalidArgumentException $e) { - return false; - } - } - - /** - * 销毁数据对象的值 - * @access public - * @param string $name 名称 - * @return void - */ - public function __unset($name) - { - unset($this->data[$name], $this->relation[$name]); - } - - // ArrayAccess - public function offsetSet($name, $value) - { - $this->setAttr($name, $value); - } - - public function offsetExists($name) - { - return $this->__isset($name); - } - - public function offsetUnset($name) - { - $this->__unset($name); - } - - public function offsetGet($name) - { - return $this->getAttr($name); - } - - /** - * 设置是否使用全局查询范围 - * @access public - * @param bool|array $use 是否启用全局查询范围(或者用数组指定查询范围名称) - * @return Query - */ - public static function useGlobalScope($use) - { - $model = new static(); - - return $model->db($use); - } - - public function __call($method, $args) - { - if ('withattr' == strtolower($method)) { - return call_user_func_array([$this, 'withAttribute'], $args); - } - - return call_user_func_array([$this->db(), $method], $args); - } - - public static function __callStatic($method, $args) - { - $model = new static(); - - return call_user_func_array([$model->db(), $method], $args); - } -} diff --git a/thinkphp/library/think/Process.php b/thinkphp/library/think/Process.php deleted file mode 100755 index 3b574db49..000000000 --- a/thinkphp/library/think/Process.php +++ /dev/null @@ -1,1268 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think; - -use think\process\exception\Failed as ProcessFailedException; -use think\process\exception\Timeout as ProcessTimeoutException; -use think\process\pipes\Pipes; -use think\process\pipes\Unix as UnixPipes; -use think\process\pipes\Windows as WindowsPipes; -use think\process\Utils; - -class Process -{ - - const ERR = 'err'; - const OUT = 'out'; - - const STATUS_READY = 'ready'; - const STATUS_STARTED = 'started'; - const STATUS_TERMINATED = 'terminated'; - - const STDIN = 0; - const STDOUT = 1; - const STDERR = 2; - - const TIMEOUT_PRECISION = 0.2; - - private $callback; - private $commandline; - private $cwd; - private $env; - private $input; - private $starttime; - private $lastOutputTime; - private $timeout; - private $idleTimeout; - private $options; - private $exitcode; - private $fallbackExitcode; - private $processInformation; - private $outputDisabled = false; - private $stdout; - private $stderr; - private $enhanceWindowsCompatibility = true; - private $enhanceSigchildCompatibility; - private $process; - private $status = self::STATUS_READY; - private $incrementalOutputOffset = 0; - private $incrementalErrorOutputOffset = 0; - private $tty; - private $pty; - - private $useFileHandles = false; - - /** @var Pipes */ - private $processPipes; - - private $latestSignal; - - private static $sigchild; - - /** - * @var array - */ - public static $exitCodes = [ - 0 => 'OK', - 1 => 'General error', - 2 => 'Misuse of shell builtins', - 126 => 'Invoked command cannot execute', - 127 => 'Command not found', - 128 => 'Invalid exit argument', - // signals - 129 => 'Hangup', - 130 => 'Interrupt', - 131 => 'Quit and dump core', - 132 => 'Illegal instruction', - 133 => 'Trace/breakpoint trap', - 134 => 'Process aborted', - 135 => 'Bus error: "access to undefined portion of memory object"', - 136 => 'Floating point exception: "erroneous arithmetic operation"', - 137 => 'Kill (terminate immediately)', - 138 => 'User-defined 1', - 139 => 'Segmentation violation', - 140 => 'User-defined 2', - 141 => 'Write to pipe with no one reading', - 142 => 'Signal raised by alarm', - 143 => 'Termination (request to terminate)', - // 144 - not defined - 145 => 'Child process terminated, stopped (or continued*)', - 146 => 'Continue if stopped', - 147 => 'Stop executing temporarily', - 148 => 'Terminal stop signal', - 149 => 'Background process attempting to read from tty ("in")', - 150 => 'Background process attempting to write to tty ("out")', - 151 => 'Urgent data available on socket', - 152 => 'CPU time limit exceeded', - 153 => 'File size limit exceeded', - 154 => 'Signal raised by timer counting virtual time: "virtual timer expired"', - 155 => 'Profiling timer expired', - // 156 - not defined - 157 => 'Pollable event', - // 158 - not defined - 159 => 'Bad syscall', - ]; - - /** - * 构造方法 - * @access public - * @param string $commandline 指令 - * @param string|null $cwd 工作目录 - * @param array|null $env 环境变量 - * @param string|null $input 输入 - * @param int|float|null $timeout 超时时间 - * @param array $options proc_open的选项 - * @throws \RuntimeException - * @api - */ - public function __construct($commandline, $cwd = null, array $env = null, $input = null, $timeout = 60, array $options = []) - { - if (!function_exists('proc_open')) { - throw new \RuntimeException('The Process class relies on proc_open, which is not available on your PHP installation.'); - } - - $this->commandline = $commandline; - $this->cwd = $cwd; - - if (null === $this->cwd && (defined('ZEND_THREAD_SAFE') || '\\' === DIRECTORY_SEPARATOR)) { - $this->cwd = getcwd(); - } - if (null !== $env) { - $this->setEnv($env); - } - - $this->input = $input; - $this->setTimeout($timeout); - $this->useFileHandles = '\\' === DIRECTORY_SEPARATOR; - $this->pty = false; - $this->enhanceWindowsCompatibility = true; - $this->enhanceSigchildCompatibility = '\\' !== DIRECTORY_SEPARATOR && $this->isSigchildEnabled(); - $this->options = array_replace([ - 'suppress_errors' => true, - 'binary_pipes' => true, - ], $options); - } - - public function __destruct() - { - $this->stop(); - } - - public function __clone() - { - $this->resetProcessData(); - } - - /** - * 运行指令 - * @access public - * @param callback|null $callback - * @return int - */ - public function run($callback = null) - { - $this->start($callback); - - return $this->wait(); - } - - /** - * 运行指令 - * @access public - * @param callable|null $callback - * @return self - * @throws \RuntimeException - * @throws ProcessFailedException - */ - public function mustRun($callback = null) - { - if ($this->isSigchildEnabled() && !$this->enhanceSigchildCompatibility) { - throw new \RuntimeException('This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.'); - } - - if (0 !== $this->run($callback)) { - throw new ProcessFailedException($this); - } - - return $this; - } - - /** - * 启动进程并写到 STDIN 输入后返回。 - * @access public - * @param callable|null $callback - * @throws \RuntimeException - * @throws \RuntimeException - * @throws \LogicException - */ - public function start($callback = null) - { - if ($this->isRunning()) { - throw new \RuntimeException('Process is already running'); - } - if ($this->outputDisabled && null !== $callback) { - throw new \LogicException('Output has been disabled, enable it to allow the use of a callback.'); - } - - $this->resetProcessData(); - $this->starttime = $this->lastOutputTime = microtime(true); - $this->callback = $this->buildCallback($callback); - $descriptors = $this->getDescriptors(); - - $commandline = $this->commandline; - - if ('\\' === DIRECTORY_SEPARATOR && $this->enhanceWindowsCompatibility) { - $commandline = 'cmd /V:ON /E:ON /C "(' . $commandline . ')'; - foreach ($this->processPipes->getFiles() as $offset => $filename) { - $commandline .= ' ' . $offset . '>' . Utils::escapeArgument($filename); - } - $commandline .= '"'; - - if (!isset($this->options['bypass_shell'])) { - $this->options['bypass_shell'] = true; - } - } - - $this->process = proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $this->env, $this->options); - - if (!is_resource($this->process)) { - throw new \RuntimeException('Unable to launch a new process.'); - } - $this->status = self::STATUS_STARTED; - - if ($this->tty) { - return; - } - - $this->updateStatus(false); - $this->checkTimeout(); - } - - /** - * 重启进程 - * @access public - * @param callable|null $callback - * @return Process - * @throws \RuntimeException - * @throws \RuntimeException - */ - public function restart($callback = null) - { - if ($this->isRunning()) { - throw new \RuntimeException('Process is already running'); - } - - $process = clone $this; - $process->start($callback); - - return $process; - } - - /** - * 等待要终止的进程 - * @access public - * @param callable|null $callback - * @return int - */ - public function wait($callback = null) - { - $this->requireProcessIsStarted(__FUNCTION__); - - $this->updateStatus(false); - if (null !== $callback) { - $this->callback = $this->buildCallback($callback); - } - - do { - $this->checkTimeout(); - $running = '\\' === DIRECTORY_SEPARATOR ? $this->isRunning() : $this->processPipes->areOpen(); - $close = '\\' !== DIRECTORY_SEPARATOR || !$running; - $this->readPipes(true, $close); - } while ($running); - - while ($this->isRunning()) { - usleep(1000); - } - - if ($this->processInformation['signaled'] && $this->processInformation['termsig'] !== $this->latestSignal) { - throw new \RuntimeException(sprintf('The process has been signaled with signal "%s".', $this->processInformation['termsig'])); - } - - return $this->exitcode; - } - - /** - * 获取PID - * @access public - * @return int|null - * @throws \RuntimeException - */ - public function getPid() - { - if ($this->isSigchildEnabled()) { - throw new \RuntimeException('This PHP has been compiled with --enable-sigchild. The process identifier can not be retrieved.'); - } - - $this->updateStatus(false); - - return $this->isRunning() ? $this->processInformation['pid'] : null; - } - - /** - * 将一个 POSIX 信号发送到进程中 - * @access public - * @param int $signal - * @return Process - */ - public function signal($signal) - { - $this->doSignal($signal, true); - - return $this; - } - - /** - * 禁用从底层过程获取输出和错误输出。 - * @access public - * @return Process - */ - public function disableOutput() - { - if ($this->isRunning()) { - throw new \RuntimeException('Disabling output while the process is running is not possible.'); - } - if (null !== $this->idleTimeout) { - throw new \LogicException('Output can not be disabled while an idle timeout is set.'); - } - - $this->outputDisabled = true; - - return $this; - } - - /** - * 开启从底层过程获取输出和错误输出。 - * @access public - * @return Process - * @throws \RuntimeException - */ - public function enableOutput() - { - if ($this->isRunning()) { - throw new \RuntimeException('Enabling output while the process is running is not possible.'); - } - - $this->outputDisabled = false; - - return $this; - } - - /** - * 输出是否禁用 - * @access public - * @return bool - */ - public function isOutputDisabled() - { - return $this->outputDisabled; - } - - /** - * 获取当前的输出管道 - * @access public - * @return string - * @throws \LogicException - * @api - */ - public function getOutput() - { - if ($this->outputDisabled) { - throw new \LogicException('Output has been disabled.'); - } - - $this->requireProcessIsStarted(__FUNCTION__); - - $this->readPipes(false, '\\' === DIRECTORY_SEPARATOR ? !$this->processInformation['running'] : true); - - return $this->stdout; - } - - /** - * 以增量方式返回的输出结果。 - * @access public - * @return string - */ - public function getIncrementalOutput() - { - $this->requireProcessIsStarted(__FUNCTION__); - - $data = $this->getOutput(); - - $latest = substr($data, $this->incrementalOutputOffset); - - if (false === $latest) { - return ''; - } - - $this->incrementalOutputOffset = strlen($data); - - return $latest; - } - - /** - * 清空输出 - * @access public - * @return Process - */ - public function clearOutput() - { - $this->stdout = ''; - $this->incrementalOutputOffset = 0; - - return $this; - } - - /** - * 返回当前的错误输出的过程 (STDERR)。 - * @access public - * @return string - */ - public function getErrorOutput() - { - if ($this->outputDisabled) { - throw new \LogicException('Output has been disabled.'); - } - - $this->requireProcessIsStarted(__FUNCTION__); - - $this->readPipes(false, '\\' === DIRECTORY_SEPARATOR ? !$this->processInformation['running'] : true); - - return $this->stderr; - } - - /** - * 以增量方式返回 errorOutput - * @access public - * @return string - */ - public function getIncrementalErrorOutput() - { - $this->requireProcessIsStarted(__FUNCTION__); - - $data = $this->getErrorOutput(); - - $latest = substr($data, $this->incrementalErrorOutputOffset); - - if (false === $latest) { - return ''; - } - - $this->incrementalErrorOutputOffset = strlen($data); - - return $latest; - } - - /** - * 清空 errorOutput - * @access public - * @return Process - */ - public function clearErrorOutput() - { - $this->stderr = ''; - $this->incrementalErrorOutputOffset = 0; - - return $this; - } - - /** - * 获取退出码 - * @access public - * @return null|int - */ - public function getExitCode() - { - if ($this->isSigchildEnabled() && !$this->enhanceSigchildCompatibility) { - throw new \RuntimeException('This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.'); - } - - $this->updateStatus(false); - - return $this->exitcode; - } - - /** - * 获取退出文本 - * @access public - * @return null|string - */ - public function getExitCodeText() - { - if (null === $exitcode = $this->getExitCode()) { - return; - } - - return isset(self::$exitCodes[$exitcode]) ? self::$exitCodes[$exitcode] : 'Unknown error'; - } - - /** - * 检查是否成功 - * @access public - * @return bool - */ - public function isSuccessful() - { - return 0 === $this->getExitCode(); - } - - /** - * 是否未捕获的信号已被终止子进程 - * @access public - * @return bool - */ - public function hasBeenSignaled() - { - $this->requireProcessIsTerminated(__FUNCTION__); - - if ($this->isSigchildEnabled()) { - throw new \RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.'); - } - - $this->updateStatus(false); - - return $this->processInformation['signaled']; - } - - /** - * 返回导致子进程终止其执行的数。 - * @access public - * @return int - */ - public function getTermSignal() - { - $this->requireProcessIsTerminated(__FUNCTION__); - - if ($this->isSigchildEnabled()) { - throw new \RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.'); - } - - $this->updateStatus(false); - - return $this->processInformation['termsig']; - } - - /** - * 检查子进程信号是否已停止 - * @access public - * @return bool - */ - public function hasBeenStopped() - { - $this->requireProcessIsTerminated(__FUNCTION__); - - $this->updateStatus(false); - - return $this->processInformation['stopped']; - } - - /** - * 返回导致子进程停止其执行的数。 - * @access public - * @return int - */ - public function getStopSignal() - { - $this->requireProcessIsTerminated(__FUNCTION__); - - $this->updateStatus(false); - - return $this->processInformation['stopsig']; - } - - /** - * 检查是否正在运行 - * @access public - * @return bool - */ - public function isRunning() - { - if (self::STATUS_STARTED !== $this->status) { - return false; - } - - $this->updateStatus(false); - - return $this->processInformation['running']; - } - - /** - * 检查是否已开始 - * @access public - * @return bool - */ - public function isStarted() - { - return self::STATUS_READY != $this->status; - } - - /** - * 检查是否已终止 - * @access public - * @return bool - */ - public function isTerminated() - { - $this->updateStatus(false); - - return self::STATUS_TERMINATED == $this->status; - } - - /** - * 获取当前的状态 - * @access public - * @return string - */ - public function getStatus() - { - $this->updateStatus(false); - - return $this->status; - } - - /** - * 终止进程 - * @access public - */ - public function stop() - { - if ($this->isRunning()) { - if ('\\' === DIRECTORY_SEPARATOR && !$this->isSigchildEnabled()) { - exec(sprintf('taskkill /F /T /PID %d 2>&1', $this->getPid()), $output, $exitCode); - if ($exitCode > 0) { - throw new \RuntimeException('Unable to kill the process'); - } - } else { - $pids = preg_split('/\s+/', `ps -o pid --no-heading --ppid {$this->getPid()}`); - foreach ($pids as $pid) { - if (is_numeric($pid)) { - posix_kill($pid, 9); - } - } - } - } - - $this->updateStatus(false); - if ($this->processInformation['running']) { - $this->close(); - } - - return $this->exitcode; - } - - /** - * 添加一行输出 - * @access public - * @param string $line - */ - public function addOutput($line) -{ - $this->lastOutputTime = microtime(true); - $this->stdout .= $line; - } - - /** - * 添加一行错误输出 - * @access public - * @param string $line - */ - public function addErrorOutput($line) -{ - $this->lastOutputTime = microtime(true); - $this->stderr .= $line; - } - - /** - * 获取被执行的指令 - * @access public - * @return string - */ - public function getCommandLine() -{ - return $this->commandline; - } - - /** - * 设置指令 - * @access public - * @param string $commandline - * @return self - */ - public function setCommandLine($commandline) -{ - $this->commandline = $commandline; - - return $this; - } - - /** - * 获取超时时间 - * @access public - * @return float|null - */ - public function getTimeout() -{ - return $this->timeout; - } - - /** - * 获取idle超时时间 - * @access public - * @return float|null - */ - public function getIdleTimeout() -{ - return $this->idleTimeout; - } - - /** - * 设置超时时间 - * @access public - * @param int|float|null $timeout - * @return self - */ - public function setTimeout($timeout) -{ - $this->timeout = $this->validateTimeout($timeout); - - return $this; - } - - /** - * 设置idle超时时间 - * @access public - * @param int|float|null $timeout - * @return self - */ - public function setIdleTimeout($timeout) -{ - if (null !== $timeout && $this->outputDisabled) { - throw new \LogicException('Idle timeout can not be set while the output is disabled.'); - } - - $this->idleTimeout = $this->validateTimeout($timeout); - - return $this; - } - - /** - * 设置TTY - * @access public - * @param bool $tty - * @return self - */ - public function setTty($tty) -{ - if ('\\' === DIRECTORY_SEPARATOR && $tty) { - throw new \RuntimeException('TTY mode is not supported on Windows platform.'); - } - if ($tty && (!file_exists('/dev/tty') || !is_readable('/dev/tty'))) { - throw new \RuntimeException('TTY mode requires /dev/tty to be readable.'); - } - - $this->tty = (bool) $tty; - - return $this; - } - - /** - * 检查是否是tty模式 - * @access public - * @return bool - */ - public function isTty() -{ - return $this->tty; - } - - /** - * 设置pty模式 - * @access public - * @param bool $bool - * @return self - */ - public function setPty($bool) -{ - $this->pty = (bool) $bool; - - return $this; - } - - /** - * 是否是pty模式 - * @access public - * @return bool - */ - public function isPty() -{ - return $this->pty; - } - - /** - * 获取工作目录 - * @access public - * @return string|null - */ - public function getWorkingDirectory() -{ - if (null === $this->cwd) { - return getcwd() ?: null; - } - - return $this->cwd; - } - - /** - * 设置工作目录 - * @access public - * @param string $cwd - * @return self - */ - public function setWorkingDirectory($cwd) -{ - $this->cwd = $cwd; - - return $this; - } - - /** - * 获取环境变量 - * @access public - * @return array - */ - public function getEnv() -{ - return $this->env; - } - - /** - * 设置环境变量 - * @access public - * @param array $env - * @return self - */ - public function setEnv(array $env) -{ - $env = array_filter($env, function ($value) { - return !is_array($value); - }); - - $this->env = []; - foreach ($env as $key => $value) { - $this->env[(binary) $key] = (binary) $value; - } - - return $this; - } - - /** - * 获取输入 - * @access public - * @return null|string - */ - public function getInput() -{ - return $this->input; - } - - /** - * 设置输入 - * @access public - * @param mixed $input - * @return self - */ - public function setInput($input) -{ - if ($this->isRunning()) { - throw new \LogicException('Input can not be set while the process is running.'); - } - - $this->input = Utils::validateInput(sprintf('%s::%s', __CLASS__, __FUNCTION__), $input); - - return $this; - } - - /** - * 获取proc_open的选项 - * @access public - * @return array - */ - public function getOptions() -{ - return $this->options; - } - - /** - * 设置proc_open的选项 - * @access public - * @param array $options - * @return self - */ - public function setOptions(array $options) -{ - $this->options = $options; - - return $this; - } - - /** - * 是否兼容windows - * @access public - * @return bool - */ - public function getEnhanceWindowsCompatibility() -{ - return $this->enhanceWindowsCompatibility; - } - - /** - * 设置是否兼容windows - * @access public - * @param bool $enhance - * @return self - */ - public function setEnhanceWindowsCompatibility($enhance) -{ - $this->enhanceWindowsCompatibility = (bool) $enhance; - - return $this; - } - - /** - * 返回是否 sigchild 兼容模式激活 - * @access public - * @return bool - */ - public function getEnhanceSigchildCompatibility() -{ - return $this->enhanceSigchildCompatibility; - } - - /** - * 激活 sigchild 兼容性模式。 - * @access public - * @param bool $enhance - * @return self - */ - public function setEnhanceSigchildCompatibility($enhance) -{ - $this->enhanceSigchildCompatibility = (bool) $enhance; - - return $this; - } - - /** - * 是否超时 - */ - public function checkTimeout() -{ - if (self::STATUS_STARTED !== $this->status) { - return; - } - - if (null !== $this->timeout && $this->timeout < microtime(true) - $this->starttime) { - $this->stop(); - - throw new ProcessTimeoutException($this, ProcessTimeoutException::TYPE_GENERAL); - } - - if (null !== $this->idleTimeout && $this->idleTimeout < microtime(true) - $this->lastOutputTime) { - $this->stop(); - - throw new ProcessTimeoutException($this, ProcessTimeoutException::TYPE_IDLE); - } - } - - /** - * 是否支持pty - * @access public - * @return bool - */ - public static function isPtySupported() -{ - static $result; - - if (null !== $result) { - return $result; - } - - if ('\\' === DIRECTORY_SEPARATOR) { - return $result = false; - } - - $proc = @proc_open('echo 1', [['pty'], ['pty'], ['pty']], $pipes); - if (is_resource($proc)) { - proc_close($proc); - - return $result = true; - } - - return $result = false; - } - - /** - * 创建所需的 proc_open 的描述符 - * @access private - * @return array - */ - private function getDescriptors() -{ - if ('\\' === DIRECTORY_SEPARATOR) { - $this->processPipes = WindowsPipes::create($this, $this->input); - } else { - $this->processPipes = UnixPipes::create($this, $this->input); - } - $descriptors = $this->processPipes->getDescriptors($this->outputDisabled); - - if (!$this->useFileHandles && $this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) { - - $descriptors = array_merge($descriptors, [['pipe', 'w']]); - - $this->commandline = '(' . $this->commandline . ') 3>/dev/null; code=$?; echo $code >&3; exit $code'; - } - - return $descriptors; - } - - /** - * 建立 wait () 使用的回调。 - * @access protected - * @param callable|null $callback - * @return callable - */ - protected function buildCallback($callback) -{ - $out = self::OUT; - $callback = function ($type, $data) use ($callback, $out) { - if ($out == $type) { - $this->addOutput($data); - } else { - $this->addErrorOutput($data); - } - - if (null !== $callback) { - call_user_func($callback, $type, $data); - } - }; - - return $callback; - } - - /** - * 更新状态 - * @access protected - * @param bool $blocking - */ - protected function updateStatus($blocking) -{ - if (self::STATUS_STARTED !== $this->status) { - return; - } - - $this->processInformation = proc_get_status($this->process); - $this->captureExitCode(); - - $this->readPipes($blocking, '\\' === DIRECTORY_SEPARATOR ? !$this->processInformation['running'] : true); - - if (!$this->processInformation['running']) { - $this->close(); - } - } - - /** - * 是否开启 '--enable-sigchild' - * @access protected - * @return bool - */ - protected function isSigchildEnabled() -{ - if (null !== self::$sigchild) { - return self::$sigchild; - } - - if (!function_exists('phpinfo')) { - return self::$sigchild = false; - } - - ob_start(); - phpinfo(INFO_GENERAL); - - return self::$sigchild = false !== strpos(ob_get_clean(), '--enable-sigchild'); - } - - /** - * 验证是否超时 - * @access private - * @param int|float|null $timeout - * @return float|null - */ - private function validateTimeout($timeout) -{ - $timeout = (float) $timeout; - - if (0.0 === $timeout) { - $timeout = null; - } elseif ($timeout < 0) { - throw new \InvalidArgumentException('The timeout value must be a valid positive integer or float number.'); - } - - return $timeout; - } - - /** - * 读取pipes - * @access private - * @param bool $blocking - * @param bool $close - */ - private function readPipes($blocking, $close) -{ - $result = $this->processPipes->readAndWrite($blocking, $close); - - $callback = $this->callback; - foreach ($result as $type => $data) { - if (3 == $type) { - $this->fallbackExitcode = (int) $data; - } else { - $callback(self::STDOUT === $type ? self::OUT : self::ERR, $data); - } - } - } - - /** - * 捕获退出码 - */ - private function captureExitCode() -{ - if (isset($this->processInformation['exitcode']) && -1 != $this->processInformation['exitcode']) { - $this->exitcode = $this->processInformation['exitcode']; - } - } - - /** - * 关闭资源 - * @access private - * @return int 退出码 - */ - private function close() -{ - $this->processPipes->close(); - if (is_resource($this->process)) { - $exitcode = proc_close($this->process); - } else { - $exitcode = -1; - } - - $this->exitcode = -1 !== $exitcode ? $exitcode : (null !== $this->exitcode ? $this->exitcode : -1); - $this->status = self::STATUS_TERMINATED; - - if (-1 === $this->exitcode && null !== $this->fallbackExitcode) { - $this->exitcode = $this->fallbackExitcode; - } elseif (-1 === $this->exitcode && $this->processInformation['signaled'] - && 0 < $this->processInformation['termsig'] - ) { - $this->exitcode = 128 + $this->processInformation['termsig']; - } - - return $this->exitcode; - } - - /** - * 重置数据 - */ - private function resetProcessData() -{ - $this->starttime = null; - $this->callback = null; - $this->exitcode = null; - $this->fallbackExitcode = null; - $this->processInformation = null; - $this->stdout = null; - $this->stderr = null; - $this->process = null; - $this->latestSignal = null; - $this->status = self::STATUS_READY; - $this->incrementalOutputOffset = 0; - $this->incrementalErrorOutputOffset = 0; - } - - /** - * 将一个 POSIX 信号发送到进程中。 - * @access private - * @param int $signal - * @param bool $throwException - * @return bool - */ - private function doSignal($signal, $throwException) -{ - if (!$this->isRunning()) { - if ($throwException) { - throw new \LogicException('Can not send signal on a non running process.'); - } - - return false; - } - - if ($this->isSigchildEnabled()) { - if ($throwException) { - throw new \RuntimeException('This PHP has been compiled with --enable-sigchild. The process can not be signaled.'); - } - - return false; - } - - if (true !== @proc_terminate($this->process, $signal)) { - if ($throwException) { - throw new \RuntimeException(sprintf('Error while sending signal `%s`.', $signal)); - } - - return false; - } - - $this->latestSignal = $signal; - - return true; - } - - /** - * 确保进程已经开启 - * @access private - * @param string $functionName - */ - private function requireProcessIsStarted($functionName) -{ - if (!$this->isStarted()) { - throw new \LogicException(sprintf('Process must be started before calling %s.', $functionName)); - } - } - - /** - * 确保进程已经终止 - * @access private - * @param string $functionName - */ - private function requireProcessIsTerminated($functionName) -{ - if (!$this->isTerminated()) { - throw new \LogicException(sprintf('Process must be terminated before calling %s.', $functionName)); - } - } -} diff --git a/thinkphp/library/think/Route.php b/thinkphp/library/think/Route.php deleted file mode 100755 index 7bd468ba6..000000000 --- a/thinkphp/library/think/Route.php +++ /dev/null @@ -1,990 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think; - -use think\exception\RouteNotFoundException; -use think\route\AliasRule; -use think\route\dispatch\Url as UrlDispatch; -use think\route\Domain; -use think\route\Resource; -use think\route\RuleGroup; -use think\route\RuleItem; - -class Route -{ - /** - * REST定义 - * @var array - */ - protected $rest = [ - 'index' => ['get', '', 'index'], - 'create' => ['get', '/create', 'create'], - 'edit' => ['get', '//edit', 'edit'], - 'read' => ['get', '/', 'read'], - 'save' => ['post', '', 'save'], - 'update' => ['put', '/', 'update'], - 'delete' => ['delete', '/', 'delete'], - ]; - - /** - * 请求方法前缀定义 - * @var array - */ - protected $methodPrefix = [ - 'get' => 'get', - 'post' => 'post', - 'put' => 'put', - 'delete' => 'delete', - 'patch' => 'patch', - ]; - - /** - * 应用对象 - * @var App - */ - protected $app; - - /** - * 请求对象 - * @var Request - */ - protected $request; - - /** - * 当前HOST - * @var string - */ - protected $host; - - /** - * 当前域名 - * @var string - */ - protected $domain; - - /** - * 当前分组对象 - * @var RuleGroup - */ - protected $group; - - /** - * 配置参数 - * @var array - */ - protected $config = []; - - /** - * 路由绑定 - * @var array - */ - protected $bind = []; - - /** - * 域名对象 - * @var array - */ - protected $domains = []; - - /** - * 跨域路由规则 - * @var RuleGroup - */ - protected $cross; - - /** - * 路由别名 - * @var array - */ - protected $alias = []; - - /** - * 路由是否延迟解析 - * @var bool - */ - protected $lazy = true; - - /** - * 路由是否测试模式 - * @var bool - */ - protected $isTest; - - /** - * (分组)路由规则是否合并解析 - * @var bool - */ - protected $mergeRuleRegex = true; - - /** - * 路由解析自动搜索多级控制器 - * @var bool - */ - protected $autoSearchController = true; - - public function __construct(App $app, array $config = []) - { - $this->app = $app; - $this->request = $app['request']; - $this->config = $config; - - $this->host = $this->request->host(true) ?: $config['app_host']; - - $this->setDefaultDomain(); - } - - public function config($name = null) - { - if (is_null($name)) { - return $this->config; - } - - return isset($this->config[$name]) ? $this->config[$name] : null; - } - - /** - * 配置 - * @access public - * @param array $config - * @return void - */ - public function setConfig(array $config = []) - { - $this->config = array_merge($this->config, array_change_key_case($config)); - } - - public static function __make(App $app, Config $config) - { - $config = $config->pull('app'); - $route = new static($app, $config); - - $route->lazy($config['url_lazy_route']) - ->autoSearchController($config['controller_auto_search']) - ->mergeRuleRegex($config['route_rule_merge']); - - return $route; - } - - /** - * 设置路由的请求对象实例 - * @access public - * @param Request $request 请求对象实例 - * @return void - */ - public function setRequest($request) - { - $this->request = $request; - } - - /** - * 设置路由域名及分组(包括资源路由)是否延迟解析 - * @access public - * @param bool $lazy 路由是否延迟解析 - * @return $this - */ - public function lazy($lazy = true) - { - $this->lazy = $lazy; - return $this; - } - - /** - * 设置路由为测试模式 - * @access public - * @param bool $test 路由是否测试模式 - * @return void - */ - public function setTestMode($test) - { - $this->isTest = $test; - } - - /** - * 检查路由是否为测试模式 - * @access public - * @return bool - */ - public function isTest() - { - return $this->isTest; - } - - /** - * 设置路由域名及分组(包括资源路由)是否合并解析 - * @access public - * @param bool $merge 路由是否合并解析 - * @return $this - */ - public function mergeRuleRegex($merge = true) - { - $this->mergeRuleRegex = $merge; - $this->group->mergeRuleRegex($merge); - - return $this; - } - - /** - * 设置路由自动解析是否搜索多级控制器 - * @access public - * @param bool $auto 是否自动搜索多级控制器 - * @return $this - */ - public function autoSearchController($auto = true) - { - $this->autoSearchController = $auto; - return $this; - } - - /** - * 初始化默认域名 - * @access protected - * @return void - */ - protected function setDefaultDomain() - { - // 默认域名 - $this->domain = $this->host; - - // 注册默认域名 - $domain = new Domain($this, $this->host); - - $this->domains[$this->host] = $domain; - - // 默认分组 - $this->group = $domain; - } - - /** - * 设置当前域名 - * @access public - * @param RuleGroup $group 域名 - * @return void - */ - public function setGroup(RuleGroup $group) - { - $this->group = $group; - } - - /** - * 获取当前分组 - * @access public - * @return RuleGroup - */ - public function getGroup() - { - return $this->group; - } - - /** - * 注册变量规则 - * @access public - * @param string|array $name 变量名 - * @param string $rule 变量规则 - * @return $this - */ - public function pattern($name, $rule = '') - { - $this->group->pattern($name, $rule); - - return $this; - } - - /** - * 注册路由参数 - * @access public - * @param string|array $name 参数名 - * @param mixed $value 值 - * @return $this - */ - public function option($name, $value = '') - { - $this->group->option($name, $value); - - return $this; - } - - /** - * 注册域名路由 - * @access public - * @param string|array $name 子域名 - * @param mixed $rule 路由规则 - * @param array $option 路由参数 - * @param array $pattern 变量规则 - * @return Domain - */ - public function domain($name, $rule = '', $option = [], $pattern = []) - { - // 支持多个域名使用相同路由规则 - $domainName = is_array($name) ? array_shift($name) : $name; - - if ('*' != $domainName && false === strpos($domainName, '.')) { - $domainName .= '.' . $this->request->rootDomain(); - } - - if (!isset($this->domains[$domainName])) { - $domain = (new Domain($this, $domainName, $rule, $option, $pattern)) - ->lazy($this->lazy) - ->mergeRuleRegex($this->mergeRuleRegex); - - $this->domains[$domainName] = $domain; - } else { - $domain = $this->domains[$domainName]; - $domain->parseGroupRule($rule); - } - - if (is_array($name) && !empty($name)) { - $root = $this->request->rootDomain(); - foreach ($name as $item) { - if (false === strpos($item, '.')) { - $item .= '.' . $root; - } - - $this->domains[$item] = $domainName; - } - } - - // 返回域名对象 - return $domain; - } - - /** - * 获取域名 - * @access public - * @return array - */ - public function getDomains() - { - return $this->domains; - } - - /** - * 设置路由绑定 - * @access public - * @param string $bind 绑定信息 - * @param string $domain 域名 - * @return $this - */ - public function bind($bind, $domain = null) - { - $domain = is_null($domain) ? $this->domain : $domain; - - $this->bind[$domain] = $bind; - - return $this; - } - - /** - * 读取路由绑定 - * @access public - * @param string $domain 域名 - * @return string|null - */ - public function getBind($domain = null) - { - if (is_null($domain)) { - $domain = $this->domain; - } elseif (true === $domain) { - return $this->bind; - } elseif (false === strpos($domain, '.')) { - $domain .= '.' . $this->request->rootDomain(); - } - - $subDomain = $this->request->subDomain(); - - if (strpos($subDomain, '.')) { - $name = '*' . strstr($subDomain, '.'); - } - - if (isset($this->bind[$domain])) { - $result = $this->bind[$domain]; - } elseif (isset($name) && isset($this->bind[$name])) { - $result = $this->bind[$name]; - } elseif (isset($this->bind['*'])) { - $result = $this->bind['*']; - } else { - $result = null; - } - - return $result; - } - - /** - * 读取路由标识 - * @access public - * @param string $name 路由标识 - * @param string $domain 域名 - * @return mixed - */ - public function getName($name = null, $domain = null, $method = '*') - { - return $this->app['rule_name']->get($name, $domain, $method); - } - - /** - * 读取路由 - * @access public - * @param string $rule 路由规则 - * @param string $domain 域名 - * @return array - */ - public function getRule($rule, $domain = null) - { - if (is_null($domain)) { - $domain = $this->domain; - } - - return $this->app['rule_name']->getRule($rule, $domain); - } - - /** - * 读取路由 - * @access public - * @param string $domain 域名 - * @return array - */ - public function getRuleList($domain = null) - { - return $this->app['rule_name']->getRuleList($domain); - } - - /** - * 批量导入路由标识 - * @access public - * @param array $name 路由标识 - * @return $this - */ - public function setName($name) - { - $this->app['rule_name']->import($name); - return $this; - } - - /** - * 导入配置文件的路由规则 - * @access public - * @param array $rules 路由规则 - * @param string $type 请求类型 - * @return void - */ - public function import(array $rules, $type = '*') - { - // 检查域名部署 - if (isset($rules['__domain__'])) { - foreach ($rules['__domain__'] as $key => $rule) { - $this->domain($key, $rule); - } - unset($rules['__domain__']); - } - - // 检查变量规则 - if (isset($rules['__pattern__'])) { - $this->pattern($rules['__pattern__']); - unset($rules['__pattern__']); - } - - // 检查路由别名 - if (isset($rules['__alias__'])) { - foreach ($rules['__alias__'] as $key => $val) { - $this->alias($key, $val); - } - unset($rules['__alias__']); - } - - // 检查资源路由 - if (isset($rules['__rest__'])) { - foreach ($rules['__rest__'] as $key => $rule) { - $this->resource($key, $rule); - } - unset($rules['__rest__']); - } - - // 检查路由规则(包含分组) - foreach ($rules as $key => $val) { - if (is_numeric($key)) { - $key = array_shift($val); - } - - if (empty($val)) { - continue; - } - - if (is_string($key) && 0 === strpos($key, '[')) { - $key = substr($key, 1, -1); - $this->group($key, $val); - } elseif (is_array($val)) { - $this->rule($key, $val[0], $type, $val[1], isset($val[2]) ? $val[2] : []); - } else { - $this->rule($key, $val, $type); - } - } - } - - /** - * 注册路由规则 - * @access public - * @param string $rule 路由规则 - * @param mixed $route 路由地址 - * @param string $method 请求类型 - * @param array $option 路由参数 - * @param array $pattern 变量规则 - * @return RuleItem - */ - public function rule($rule, $route, $method = '*', array $option = [], array $pattern = []) - { - return $this->group->addRule($rule, $route, $method, $option, $pattern); - } - - /** - * 设置跨域有效路由规则 - * @access public - * @param Rule $rule 路由规则 - * @param string $method 请求类型 - * @return $this - */ - public function setCrossDomainRule($rule, $method = '*') - { - if (!isset($this->cross)) { - $this->cross = (new RuleGroup($this))->mergeRuleRegex($this->mergeRuleRegex); - } - - $this->cross->addRuleItem($rule, $method); - - return $this; - } - - /** - * 批量注册路由规则 - * @access public - * @param array $rules 路由规则 - * @param string $method 请求类型 - * @param array $option 路由参数 - * @param array $pattern 变量规则 - * @return void - */ - public function rules($rules, $method = '*', array $option = [], array $pattern = []) - { - $this->group->addRules($rules, $method, $option, $pattern); - } - - /** - * 注册路由分组 - * @access public - * @param string|array $name 分组名称或者参数 - * @param array|\Closure $route 分组路由 - * @param array $option 路由参数 - * @param array $pattern 变量规则 - * @return RuleGroup - */ - public function group($name, $route, array $option = [], array $pattern = []) - { - if (is_array($name)) { - $option = $name; - $name = isset($option['name']) ? $option['name'] : ''; - } - - return (new RuleGroup($this, $this->group, $name, $route, $option, $pattern)) - ->lazy($this->lazy) - ->mergeRuleRegex($this->mergeRuleRegex); - } - - /** - * 注册路由 - * @access public - * @param string $rule 路由规则 - * @param mixed $route 路由地址 - * @param array $option 路由参数 - * @param array $pattern 变量规则 - * @return RuleItem - */ - public function any($rule, $route = '', array $option = [], array $pattern = []) - { - return $this->rule($rule, $route, '*', $option, $pattern); - } - - /** - * 注册GET路由 - * @access public - * @param string $rule 路由规则 - * @param mixed $route 路由地址 - * @param array $option 路由参数 - * @param array $pattern 变量规则 - * @return RuleItem - */ - public function get($rule, $route = '', array $option = [], array $pattern = []) - { - return $this->rule($rule, $route, 'GET', $option, $pattern); - } - - /** - * 注册POST路由 - * @access public - * @param string $rule 路由规则 - * @param mixed $route 路由地址 - * @param array $option 路由参数 - * @param array $pattern 变量规则 - * @return RuleItem - */ - public function post($rule, $route = '', array $option = [], array $pattern = []) - { - return $this->rule($rule, $route, 'POST', $option, $pattern); - } - - /** - * 注册PUT路由 - * @access public - * @param string $rule 路由规则 - * @param mixed $route 路由地址 - * @param array $option 路由参数 - * @param array $pattern 变量规则 - * @return RuleItem - */ - public function put($rule, $route = '', array $option = [], array $pattern = []) - { - return $this->rule($rule, $route, 'PUT', $option, $pattern); - } - - /** - * 注册DELETE路由 - * @access public - * @param string $rule 路由规则 - * @param mixed $route 路由地址 - * @param array $option 路由参数 - * @param array $pattern 变量规则 - * @return RuleItem - */ - public function delete($rule, $route = '', array $option = [], array $pattern = []) - { - return $this->rule($rule, $route, 'DELETE', $option, $pattern); - } - - /** - * 注册PATCH路由 - * @access public - * @param string $rule 路由规则 - * @param mixed $route 路由地址 - * @param array $option 路由参数 - * @param array $pattern 变量规则 - * @return RuleItem - */ - public function patch($rule, $route = '', array $option = [], array $pattern = []) - { - return $this->rule($rule, $route, 'PATCH', $option, $pattern); - } - - /** - * 注册资源路由 - * @access public - * @param string $rule 路由规则 - * @param string $route 路由地址 - * @param array $option 路由参数 - * @param array $pattern 变量规则 - * @return Resource - */ - public function resource($rule, $route = '', array $option = [], array $pattern = []) - { - return (new Resource($this, $this->group, $rule, $route, $option, $pattern, $this->rest)) - ->lazy($this->lazy); - } - - /** - * 注册控制器路由 操作方法对应不同的请求前缀 - * @access public - * @param string $rule 路由规则 - * @param string $route 路由地址 - * @param array $option 路由参数 - * @param array $pattern 变量规则 - * @return RuleGroup - */ - public function controller($rule, $route = '', array $option = [], array $pattern = []) - { - $group = new RuleGroup($this, $this->group, $rule, null, $option, $pattern); - - foreach ($this->methodPrefix as $type => $val) { - $group->addRule('', $val . '', $type); - } - - return $group->prefix($route . '/'); - } - - /** - * 注册视图路由 - * @access public - * @param string|array $rule 路由规则 - * @param string $template 路由模板地址 - * @param array $vars 模板变量 - * @param array $option 路由参数 - * @param array $pattern 变量规则 - * @return RuleItem - */ - public function view($rule, $template = '', array $vars = [], array $option = [], array $pattern = []) - { - return $this->rule($rule, $template, 'GET', $option, $pattern)->view($vars); - } - - /** - * 注册重定向路由 - * @access public - * @param string|array $rule 路由规则 - * @param string $route 路由地址 - * @param array $status 状态码 - * @param array $option 路由参数 - * @param array $pattern 变量规则 - * @return RuleItem - */ - public function redirect($rule, $route = '', $status = 301, array $option = [], array $pattern = []) - { - return $this->rule($rule, $route, '*', $option, $pattern)->redirect()->status($status); - } - - /** - * 注册别名路由 - * @access public - * @param string $rule 路由别名 - * @param string $route 路由地址 - * @param array $option 路由参数 - * @return AliasRule - */ - public function alias($rule, $route, array $option = []) - { - $aliasRule = new AliasRule($this, $this->group, $rule, $route, $option); - - $this->alias[$rule] = $aliasRule; - - return $aliasRule; - } - - /** - * 获取别名路由定义 - * @access public - * @param string $name 路由别名 - * @return string|array|null - */ - public function getAlias($name = null) - { - if (is_null($name)) { - return $this->alias; - } - - return isset($this->alias[$name]) ? $this->alias[$name] : null; - } - - /** - * 设置不同请求类型下面的方法前缀 - * @access public - * @param string|array $method 请求类型 - * @param string $prefix 类型前缀 - * @return $this - */ - public function setMethodPrefix($method, $prefix = '') - { - if (is_array($method)) { - $this->methodPrefix = array_merge($this->methodPrefix, array_change_key_case($method)); - } else { - $this->methodPrefix[strtolower($method)] = $prefix; - } - - return $this; - } - - /** - * 获取请求类型的方法前缀 - * @access public - * @param string $method 请求类型 - * @param string $prefix 类型前缀 - * @return string|null - */ - public function getMethodPrefix($method) - { - $method = strtolower($method); - - return isset($this->methodPrefix[$method]) ? $this->methodPrefix[$method] : null; - } - - /** - * rest方法定义和修改 - * @access public - * @param string $name 方法名称 - * @param array|bool $resource 资源 - * @return $this - */ - public function rest($name, $resource = []) - { - if (is_array($name)) { - $this->rest = $resource ? $name : array_merge($this->rest, $name); - } else { - $this->rest[$name] = $resource; - } - - return $this; - } - - /** - * 获取rest方法定义的参数 - * @access public - * @param string $name 方法名称 - * @return array|null - */ - public function getRest($name = null) - { - if (is_null($name)) { - return $this->rest; - } - - return isset($this->rest[$name]) ? $this->rest[$name] : null; - } - - /** - * 注册未匹配路由规则后的处理 - * @access public - * @param string $route 路由地址 - * @param string $method 请求类型 - * @param array $option 路由参数 - * @return RuleItem - */ - public function miss($route, $method = '*', array $option = []) - { - return $this->group->addMissRule($route, $method, $option); - } - - /** - * 注册一个自动解析的URL路由 - * @access public - * @param string $route 路由地址 - * @return RuleItem - */ - public function auto($route) - { - return $this->group->addAutoRule($route); - } - - /** - * 检测URL路由 - * @access public - * @param string $url URL地址 - * @param bool $must 是否强制路由 - * @return Dispatch - * @throws RouteNotFoundException - */ - public function check($url, $must = false) - { - // 自动检测域名路由 - $domain = $this->checkDomain(); - $url = str_replace($this->config['pathinfo_depr'], '|', $url); - - $completeMatch = $this->config['route_complete_match']; - - $result = $domain->check($this->request, $url, $completeMatch); - - if (false === $result && !empty($this->cross)) { - // 检测跨域路由 - $result = $this->cross->check($this->request, $url, $completeMatch); - } - - if (false !== $result) { - // 路由匹配 - return $result; - } elseif ($must) { - // 强制路由不匹配则抛出异常 - throw new RouteNotFoundException(); - } - - // 默认路由解析 - return new UrlDispatch($this->request, $this->group, $url, [ - 'auto_search' => $this->autoSearchController, - ]); - } - - /** - * 检测域名的路由规则 - * @access protected - * @return Domain - */ - protected function checkDomain() - { - // 获取当前子域名 - $subDomain = $this->request->subDomain(); - - $item = false; - - if ($subDomain && count($this->domains) > 1) { - $domain = explode('.', $subDomain); - $domain2 = array_pop($domain); - - if ($domain) { - // 存在三级域名 - $domain3 = array_pop($domain); - } - - if ($subDomain && isset($this->domains[$subDomain])) { - // 子域名配置 - $item = $this->domains[$subDomain]; - } elseif (isset($this->domains['*.' . $domain2]) && !empty($domain3)) { - // 泛三级域名 - $item = $this->domains['*.' . $domain2]; - $panDomain = $domain3; - } elseif (isset($this->domains['*']) && !empty($domain2)) { - // 泛二级域名 - if ('www' != $domain2) { - $item = $this->domains['*']; - $panDomain = $domain2; - } - } - - if (isset($panDomain)) { - // 保存当前泛域名 - $this->request->setPanDomain($panDomain); - } - } - - if (false === $item) { - // 检测当前完整域名 - $item = $this->domains[$this->host]; - } - - if (is_string($item)) { - $item = $this->domains[$item]; - } - - return $item; - } - - /** - * 清空路由规则 - * @access public - * @return void - */ - public function clear() - { - $this->app['rule_name']->clear(); - $this->group->clear(); - } - - /** - * 设置全局的路由分组参数 - * @access public - * @param string $method 方法名 - * @param array $args 调用参数 - * @return RuleGroup - */ - public function __call($method, $args) - { - return call_user_func_array([$this->group, $method], $args); - } - - public function __debugInfo() - { - $data = get_object_vars($this); - unset($data['app'], $data['request']); - - return $data; - } -} diff --git a/thinkphp/library/think/Session.php b/thinkphp/library/think/Session.php deleted file mode 100755 index 63ee7a03e..000000000 --- a/thinkphp/library/think/Session.php +++ /dev/null @@ -1,579 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think; - -use think\exception\ClassNotFoundException; - -class Session -{ - /** - * 配置参数 - * @var array - */ - protected $config = []; - - /** - * 前缀 - * @var string - */ - protected $prefix = ''; - - /** - * 是否初始化 - * @var bool - */ - protected $init = null; - - /** - * 锁驱动 - * @var object - */ - protected $lockDriver = null; - - /** - * 锁key - * @var string - */ - protected $sessKey = 'PHPSESSID'; - - /** - * 锁超时时间 - * @var integer - */ - protected $lockTimeout = 3; - - /** - * 是否启用锁机制 - * @var bool - */ - protected $lock = false; - - public function __construct(array $config = []) - { - $this->config = $config; - } - - /** - * 设置或者获取session作用域(前缀) - * @access public - * @param string $prefix - * @return string|void - */ - public function prefix($prefix = '') - { - empty($this->init) && $this->boot(); - - if (empty($prefix) && null !== $prefix) { - return $this->prefix; - } else { - $this->prefix = $prefix; - } - } - - public static function __make(Config $config) - { - return new static($config->pull('session')); - } - - /** - * 配置 - * @access public - * @param array $config - * @return void - */ - public function setConfig(array $config = []) - { - $this->config = array_merge($this->config, array_change_key_case($config)); - - if (isset($config['prefix'])) { - $this->prefix = $config['prefix']; - } - - if (isset($config['use_lock'])) { - $this->lock = $config['use_lock']; - } - } - - /** - * 设置已经初始化 - * @access public - * @return void - */ - public function inited() - { - $this->init = true; - } - - /** - * session初始化 - * @access public - * @param array $config - * @return void - * @throws \think\Exception - */ - public function init(array $config = []) - { - $config = $config ?: $this->config; - - $isDoStart = false; - if (isset($config['use_trans_sid'])) { - ini_set('session.use_trans_sid', $config['use_trans_sid'] ? 1 : 0); - } - - // 启动session - if (!empty($config['auto_start']) && PHP_SESSION_ACTIVE != session_status()) { - ini_set('session.auto_start', 0); - $isDoStart = true; - } - - if (isset($config['prefix'])) { - $this->prefix = $config['prefix']; - } - - if (isset($config['use_lock'])) { - $this->lock = $config['use_lock']; - } - - if (isset($config['var_session_id']) && isset($_REQUEST[$config['var_session_id']])) { - session_id($_REQUEST[$config['var_session_id']]); - } elseif (isset($config['id']) && !empty($config['id'])) { - session_id($config['id']); - } - - if (isset($config['name'])) { - session_name($config['name']); - } - - if (isset($config['path'])) { - session_save_path($config['path']); - } - - if (isset($config['domain'])) { - ini_set('session.cookie_domain', $config['domain']); - } - - if (isset($config['expire'])) { - ini_set('session.gc_maxlifetime', $config['expire']); - ini_set('session.cookie_lifetime', $config['expire']); - } - - if (isset($config['secure'])) { - ini_set('session.cookie_secure', $config['secure']); - } - - if (isset($config['httponly'])) { - ini_set('session.cookie_httponly', $config['httponly']); - } - - if (isset($config['use_cookies'])) { - ini_set('session.use_cookies', $config['use_cookies'] ? 1 : 0); - } - - if (isset($config['cache_limiter'])) { - session_cache_limiter($config['cache_limiter']); - } - - if (isset($config['cache_expire'])) { - session_cache_expire($config['cache_expire']); - } - - if (!empty($config['type'])) { - // 读取session驱动 - $class = false !== strpos($config['type'], '\\') ? $config['type'] : '\\think\\session\\driver\\' . ucwords($config['type']); - - // 检查驱动类 - if (!class_exists($class) || !session_set_save_handler(new $class($config))) { - throw new ClassNotFoundException('error session handler:' . $class, $class); - } - } - - if ($isDoStart) { - $this->start(); - } else { - $this->init = false; - } - - return $this; - } - - /** - * session自动启动或者初始化 - * @access public - * @return void - */ - public function boot() - { - if (is_null($this->init)) { - $this->init(); - } - - if (false === $this->init) { - if (PHP_SESSION_ACTIVE != session_status()) { - $this->start(); - } - $this->init = true; - } - } - - /** - * session设置 - * @access public - * @param string $name session名称 - * @param mixed $value session值 - * @param string|null $prefix 作用域(前缀) - * @return void - */ - public function set($name, $value, $prefix = null) - { - $this->lock(); - - empty($this->init) && $this->boot(); - - $prefix = !is_null($prefix) ? $prefix : $this->prefix; - - if (strpos($name, '.')) { - // 二维数组赋值 - list($name1, $name2) = explode('.', $name); - if ($prefix) { - $_SESSION[$prefix][$name1][$name2] = $value; - } else { - $_SESSION[$name1][$name2] = $value; - } - } elseif ($prefix) { - $_SESSION[$prefix][$name] = $value; - } else { - $_SESSION[$name] = $value; - } - - $this->unlock(); - } - - /** - * session获取 - * @access public - * @param string $name session名称 - * @param string|null $prefix 作用域(前缀) - * @return mixed - */ - public function get($name = '', $prefix = null) - { - $this->lock(); - - empty($this->init) && $this->boot(); - - $prefix = !is_null($prefix) ? $prefix : $this->prefix; - - $value = $prefix ? (!empty($_SESSION[$prefix]) ? $_SESSION[$prefix] : []) : $_SESSION; - - if ('' != $name) { - $name = explode('.', $name); - - foreach ($name as $val) { - if (isset($value[$val])) { - $value = $value[$val]; - } else { - $value = null; - break; - } - } - } - - $this->unlock(); - - return $value; - } - - /** - * session 读写锁驱动实例化 - */ - protected function initDriver() - { - $config = $this->config; - - if (!empty($config['type']) && isset($config['use_lock']) && $config['use_lock']) { - // 读取session驱动 - $class = false !== strpos($config['type'], '\\') ? $config['type'] : '\\think\\session\\driver\\' . ucwords($config['type']); - - // 检查驱动类及类中是否存在 lock 和 unlock 函数 - if (class_exists($class) && method_exists($class, 'lock') && method_exists($class, 'unlock')) { - $this->lockDriver = new $class($config); - } - } - - // 通过cookie获得session_id - if (isset($config['name']) && $config['name']) { - $this->sessKey = $config['name']; - } - - if (isset($config['lock_timeout']) && $config['lock_timeout'] > 0) { - $this->lockTimeout = $config['lock_timeout']; - } - } - - /** - * session 读写加锁 - * @access protected - * @return void - */ - protected function lock() - { - if (empty($this->lock)) { - return; - } - - $this->initDriver(); - - if (null !== $this->lockDriver && method_exists($this->lockDriver, 'lock')) { - $t = time(); - // 使用 session_id 作为互斥条件,即只对同一 session_id 的会话互斥。第一次请求没有 session_id - $sessID = isset($_COOKIE[$this->sessKey]) ? $_COOKIE[$this->sessKey] : ''; - - do { - if (time() - $t > $this->lockTimeout) { - $this->unlock(); - } - } while (!$this->lockDriver->lock($sessID, $this->lockTimeout)); - } - } - - /** - * session 读写解锁 - * @access protected - * @return void - */ - protected function unlock() - { - if (empty($this->lock)) { - return; - } - - $this->pause(); - - if ($this->lockDriver && method_exists($this->lockDriver, 'unlock')) { - $sessID = isset($_COOKIE[$this->sessKey]) ? $_COOKIE[$this->sessKey] : ''; - $this->lockDriver->unlock($sessID); - } - } - - /** - * session获取并删除 - * @access public - * @param string $name session名称 - * @param string|null $prefix 作用域(前缀) - * @return mixed - */ - public function pull($name, $prefix = null) - { - $result = $this->get($name, $prefix); - - if ($result) { - $this->delete($name, $prefix); - return $result; - } else { - return; - } - } - - /** - * session设置 下一次请求有效 - * @access public - * @param string $name session名称 - * @param mixed $value session值 - * @param string|null $prefix 作用域(前缀) - * @return void - */ - public function flash($name, $value) - { - $this->set($name, $value); - - if (!$this->has('__flash__.__time__')) { - $this->set('__flash__.__time__', $_SERVER['REQUEST_TIME_FLOAT']); - } - - $this->push('__flash__', $name); - } - - /** - * 清空当前请求的session数据 - * @access public - * @return void - */ - public function flush() - { - if (!$this->init) { - return; - } - - $item = $this->get('__flash__'); - - if (!empty($item)) { - $time = $item['__time__']; - - if ($_SERVER['REQUEST_TIME_FLOAT'] > $time) { - unset($item['__time__']); - $this->delete($item); - $this->set('__flash__', []); - } - } - } - - /** - * 删除session数据 - * @access public - * @param string|array $name session名称 - * @param string|null $prefix 作用域(前缀) - * @return void - */ - public function delete($name, $prefix = null) - { - empty($this->init) && $this->boot(); - - $prefix = !is_null($prefix) ? $prefix : $this->prefix; - - if (is_array($name)) { - foreach ($name as $key) { - $this->delete($key, $prefix); - } - } elseif (strpos($name, '.')) { - list($name1, $name2) = explode('.', $name); - if ($prefix) { - unset($_SESSION[$prefix][$name1][$name2]); - } else { - unset($_SESSION[$name1][$name2]); - } - } else { - if ($prefix) { - unset($_SESSION[$prefix][$name]); - } else { - unset($_SESSION[$name]); - } - } - } - - /** - * 清空session数据 - * @access public - * @param string|null $prefix 作用域(前缀) - * @return void - */ - public function clear($prefix = null) - { - empty($this->init) && $this->boot(); - $prefix = !is_null($prefix) ? $prefix : $this->prefix; - - if ($prefix) { - unset($_SESSION[$prefix]); - } else { - $_SESSION = []; - } - } - - /** - * 判断session数据 - * @access public - * @param string $name session名称 - * @param string|null $prefix - * @return bool - */ - public function has($name, $prefix = null) - { - empty($this->init) && $this->boot(); - - $prefix = !is_null($prefix) ? $prefix : $this->prefix; - $value = $prefix ? (!empty($_SESSION[$prefix]) ? $_SESSION[$prefix] : []) : $_SESSION; - - $name = explode('.', $name); - - foreach ($name as $val) { - if (!isset($value[$val])) { - return false; - } else { - $value = $value[$val]; - } - } - - return true; - } - - /** - * 添加数据到一个session数组 - * @access public - * @param string $key - * @param mixed $value - * @return void - */ - public function push($key, $value) - { - $array = $this->get($key); - - if (is_null($array)) { - $array = []; - } - - $array[] = $value; - - $this->set($key, $array); - } - - /** - * 启动session - * @access public - * @return void - */ - public function start() - { - session_start(); - - $this->init = true; - } - - /** - * 销毁session - * @access public - * @return void - */ - public function destroy() - { - if (!empty($_SESSION)) { - $_SESSION = []; - } - - session_unset(); - session_destroy(); - - $this->init = null; - $this->lockDriver = null; - } - - /** - * 重新生成session_id - * @access public - * @param bool $delete 是否删除关联会话文件 - * @return void - */ - public function regenerate($delete = false) - { - session_regenerate_id($delete); - } - - /** - * 暂停session - * @access public - * @return void - */ - public function pause() - { - // 暂停session - session_write_close(); - $this->init = false; - } -} diff --git a/thinkphp/library/think/Url.php b/thinkphp/library/think/Url.php deleted file mode 100755 index a339f8de2..000000000 --- a/thinkphp/library/think/Url.php +++ /dev/null @@ -1,404 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think; - -class Url -{ - /** - * 配置参数 - * @var array - */ - protected $config = []; - - /** - * ROOT地址 - * @var string - */ - protected $root; - - /** - * 绑定检查 - * @var bool - */ - protected $bindCheck; - - /** - * 应用对象 - * @var App - */ - protected $app; - - public function __construct(App $app, array $config = []) - { - $this->app = $app; - $this->config = $config; - - if (is_file($app->getRuntimePath() . 'route.php')) { - // 读取路由映射文件 - $app['route']->setName(include $app->getRuntimePath() . 'route.php'); - } - } - - /** - * 初始化 - * @access public - * @param array $config - * @return void - */ - public function init(array $config = []) - { - $this->config = array_merge($this->config, array_change_key_case($config)); - } - - public static function __make(App $app, Config $config) - { - return new static($app, $config->pull('app')); - } - - /** - * URL生成 支持路由反射 - * @access public - * @param string $url 路由地址 - * @param string|array $vars 参数(支持数组和字符串)a=val&b=val2... ['a'=>'val1', 'b'=>'val2'] - * @param string|bool $suffix 伪静态后缀,默认为true表示获取配置值 - * @param boolean|string $domain 是否显示域名 或者直接传入域名 - * @return string - */ - public function build($url = '', $vars = '', $suffix = true, $domain = false) - { - // 解析URL - if (0 === strpos($url, '[') && $pos = strpos($url, ']')) { - // [name] 表示使用路由命名标识生成URL - $name = substr($url, 1, $pos - 1); - $url = 'name' . substr($url, $pos + 1); - } - - if (false === strpos($url, '://') && 0 !== strpos($url, '/')) { - $info = parse_url($url); - $url = !empty($info['path']) ? $info['path'] : ''; - - if (isset($info['fragment'])) { - // 解析锚点 - $anchor = $info['fragment']; - - if (false !== strpos($anchor, '?')) { - // 解析参数 - list($anchor, $info['query']) = explode('?', $anchor, 2); - } - - if (false !== strpos($anchor, '@')) { - // 解析域名 - list($anchor, $domain) = explode('@', $anchor, 2); - } - } elseif (strpos($url, '@') && false === strpos($url, '\\')) { - // 解析域名 - list($url, $domain) = explode('@', $url, 2); - } - } - - // 解析参数 - if (is_string($vars)) { - // aaa=1&bbb=2 转换成数组 - parse_str($vars, $vars); - } - - if ($url) { - $checkName = isset($name) ? $name : $url . (isset($info['query']) ? '?' . $info['query'] : ''); - $checkDomain = $domain && is_string($domain) ? $domain : null; - - $rule = $this->app['route']->getName($checkName, $checkDomain); - - if (is_null($rule) && isset($info['query'])) { - $rule = $this->app['route']->getName($url); - // 解析地址里面参数 合并到vars - parse_str($info['query'], $params); - $vars = array_merge($params, $vars); - unset($info['query']); - } - } - - if (!empty($rule) && $match = $this->getRuleUrl($rule, $vars, $domain)) { - // 匹配路由命名标识 - $url = $match[0]; - - $domain = $match[1]; - - if (!is_null($match[2])) { - $suffix = $match[2]; - } - } elseif (!empty($rule) && isset($name)) { - throw new \InvalidArgumentException('route name not exists:' . $name); - } else { - // 检查别名路由 - $alias = $this->app['route']->getAlias(); - $matchAlias = false; - - if ($alias) { - // 别名路由解析 - foreach ($alias as $key => $item) { - $val = $item->getRoute(); - - if (0 === strpos($url, $val)) { - $url = $key . substr($url, strlen($val)); - $matchAlias = true; - break; - } - } - } - - if (!$matchAlias) { - // 路由标识不存在 直接解析 - $url = $this->parseUrl($url); - } - - // 检测URL绑定 - if (!$this->bindCheck) { - $bind = $this->app['route']->getBind($domain && is_string($domain) ? $domain : null); - - if ($bind && 0 === strpos($url, $bind)) { - $url = substr($url, strlen($bind) + 1); - } else { - $binds = $this->app['route']->getBind(true); - - foreach ($binds as $key => $val) { - if (is_string($val) && 0 === strpos($url, $val) && substr_count($val, '/') > 1) { - $url = substr($url, strlen($val) + 1); - $domain = $key; - break; - } - } - } - } - - if (isset($info['query'])) { - // 解析地址里面参数 合并到vars - parse_str($info['query'], $params); - $vars = array_merge($params, $vars); - } - } - - // 还原URL分隔符 - $depr = $this->config['pathinfo_depr']; - $url = str_replace('/', $depr, $url); - - // URL后缀 - if ('/' == substr($url, -1) || '' == $url) { - $suffix = ''; - } else { - $suffix = $this->parseSuffix($suffix); - } - - // 锚点 - $anchor = !empty($anchor) ? '#' . $anchor : ''; - - // 参数组装 - if (!empty($vars)) { - // 添加参数 - if ($this->config['url_common_param']) { - $vars = http_build_query($vars); - $url .= $suffix . '?' . $vars . $anchor; - } else { - $paramType = $this->config['url_param_type']; - - foreach ($vars as $var => $val) { - if ('' !== trim($val)) { - if ($paramType) { - $url .= $depr . urlencode($val); - } else { - $url .= $depr . $var . $depr . urlencode($val); - } - } - } - - $url .= $suffix . $anchor; - } - } else { - $url .= $suffix . $anchor; - } - - // 检测域名 - $domain = $this->parseDomain($url, $domain); - - // URL组装 - $url = $domain . rtrim($this->root ?: $this->app['request']->root(), '/') . '/' . ltrim($url, '/'); - - $this->bindCheck = false; - - return $url; - } - - // 直接解析URL地址 - protected function parseUrl($url) - { - $request = $this->app['request']; - - if (0 === strpos($url, '/')) { - // 直接作为路由地址解析 - $url = substr($url, 1); - } elseif (false !== strpos($url, '\\')) { - // 解析到类 - $url = ltrim(str_replace('\\', '/', $url), '/'); - } elseif (0 === strpos($url, '@')) { - // 解析到控制器 - $url = substr($url, 1); - } else { - // 解析到 模块/控制器/操作 - $module = $request->module(); - $module = $module ? $module . '/' : ''; - $controller = $request->controller(); - - if ('' == $url) { - $action = $request->action(); - } else { - $path = explode('/', $url); - $action = array_pop($path); - $controller = empty($path) ? $controller : array_pop($path); - $module = empty($path) ? $module : array_pop($path) . '/'; - } - - if ($this->config['url_convert']) { - $action = strtolower($action); - $controller = Loader::parseName($controller); - } - - $url = $module . $controller . '/' . $action; - } - - return $url; - } - - // 检测域名 - protected function parseDomain(&$url, $domain) - { - if (!$domain) { - return ''; - } - - $rootDomain = $this->app['request']->rootDomain(); - if (true === $domain) { - // 自动判断域名 - $domain = $this->config['app_host'] ?: $this->app['request']->host(); - - $domains = $this->app['route']->getDomains(); - - if ($domains) { - $route_domain = array_keys($domains); - foreach ($route_domain as $domain_prefix) { - if (0 === strpos($domain_prefix, '*.') && strpos($domain, ltrim($domain_prefix, '*.')) !== false) { - foreach ($domains as $key => $rule) { - $rule = is_array($rule) ? $rule[0] : $rule; - if (is_string($rule) && false === strpos($key, '*') && 0 === strpos($url, $rule)) { - $url = ltrim($url, $rule); - $domain = $key; - - // 生成对应子域名 - if (!empty($rootDomain)) { - $domain .= $rootDomain; - } - break; - } elseif (false !== strpos($key, '*')) { - if (!empty($rootDomain)) { - $domain .= $rootDomain; - } - - break; - } - } - } - } - } - } elseif (0 !== strpos($domain, $rootDomain) && false === strpos($domain, '.')) { - $domain .= '.' . $rootDomain; - } - - if (false !== strpos($domain, '://')) { - $scheme = ''; - } else { - $scheme = $this->app['request']->isSsl() || $this->config['is_https'] ? 'https://' : 'http://'; - - } - - return $scheme . $domain; - } - - // 解析URL后缀 - protected function parseSuffix($suffix) - { - if ($suffix) { - $suffix = true === $suffix ? $this->config['url_html_suffix'] : $suffix; - - if ($pos = strpos($suffix, '|')) { - $suffix = substr($suffix, 0, $pos); - } - } - - return (empty($suffix) || 0 === strpos($suffix, '.')) ? $suffix : '.' . $suffix; - } - - // 匹配路由地址 - public function getRuleUrl($rule, &$vars = [], $allowDomain = '') - { - foreach ($rule as $item) { - list($url, $pattern, $domain, $suffix, $method) = $item; - - if (is_string($allowDomain) && $domain != $allowDomain) { - continue; - } - - if (!in_array($this->app['request']->port(), [80, 443])) { - $domain .= ':' . $this->app['request']->port(); - } - - if (empty($pattern)) { - return [rtrim($url, '?/-'), $domain, $suffix]; - } - - $type = $this->config['url_common_param']; - - foreach ($pattern as $key => $val) { - if (isset($vars[$key])) { - $url = str_replace(['[:' . $key . ']', '<' . $key . '?>', ':' . $key, '<' . $key . '>'], $type ? $vars[$key] : urlencode($vars[$key]), $url); - unset($vars[$key]); - $url = str_replace(['/?', '-?'], ['/', '-'], $url); - $result = [rtrim($url, '?/-'), $domain, $suffix]; - } elseif (2 == $val) { - $url = str_replace(['/[:' . $key . ']', '[:' . $key . ']', '<' . $key . '?>'], '', $url); - $url = str_replace(['/?', '-?'], ['/', '-'], $url); - $result = [rtrim($url, '?/-'), $domain, $suffix]; - } else { - break; - } - } - - if (isset($result)) { - return $result; - } - } - - return false; - } - - // 指定当前生成URL地址的root - public function root($root) - { - $this->root = $root; - $this->app['request']->setRoot($root); - } - - public function __debugInfo() - { - $data = get_object_vars($this); - unset($data['app']); - - return $data; - } -} diff --git a/thinkphp/library/think/View.php b/thinkphp/library/think/View.php deleted file mode 100755 index 17860a6ba..000000000 --- a/thinkphp/library/think/View.php +++ /dev/null @@ -1,250 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think; - -class View -{ - /** - * 模板引擎实例 - * @var object - */ - public $engine; - - /** - * 模板变量 - * @var array - */ - protected $data = []; - - /** - * 内容过滤 - * @var mixed - */ - protected $filter; - - /** - * 全局模板变量 - * @var array - */ - protected static $var = []; - - /** - * 初始化 - * @access public - * @param mixed $engine 模板引擎参数 - * @return $this - */ - public function init($engine = []) - { - // 初始化模板引擎 - $this->engine($engine); - - return $this; - } - - public static function __make(Config $config) - { - return (new static())->init($config->pull('template')); - } - - /** - * 模板变量静态赋值 - * @access public - * @param mixed $name 变量名 - * @param mixed $value 变量值 - * @return $this - */ - public function share($name, $value = '') - { - if (is_array($name)) { - self::$var = array_merge(self::$var, $name); - } else { - self::$var[$name] = $value; - } - - return $this; - } - - /** - * 清理模板变量 - * @access public - * @return void - */ - public function clear() - { - self::$var = []; - $this->data = []; - } - - /** - * 模板变量赋值 - * @access public - * @param mixed $name 变量名 - * @param mixed $value 变量值 - * @return $this - */ - public function assign($name, $value = '') - { - if (is_array($name)) { - $this->data = array_merge($this->data, $name); - } else { - $this->data[$name] = $value; - } - - return $this; - } - - /** - * 设置当前模板解析的引擎 - * @access public - * @param array|string $options 引擎参数 - * @return $this - */ - public function engine($options = []) - { - if (is_string($options)) { - $type = $options; - $options = []; - } else { - $type = !empty($options['type']) ? $options['type'] : 'Think'; - } - - if (isset($options['type'])) { - unset($options['type']); - } - - $this->engine = Loader::factory($type, '\\think\\view\\driver\\', $options); - - return $this; - } - - /** - * 配置模板引擎 - * @access public - * @param string|array $name 参数名 - * @param mixed $value 参数值 - * @return $this - */ - public function config($name, $value = null) - { - $this->engine->config($name, $value); - - return $this; - } - - /** - * 检查模板是否存在 - * @access public - * @param string|array $name 参数名 - * @return bool - */ - public function exists($name) - { - return $this->engine->exists($name); - } - - /** - * 视图过滤 - * @access public - * @param Callable $filter 过滤方法或闭包 - * @return $this - */ - public function filter($filter) - { - $this->filter = $filter; - return $this; - } - - /** - * 解析和获取模板内容 用于输出 - * @access public - * @param string $template 模板文件名或者内容 - * @param array $vars 模板输出变量 - * @param array $config 模板参数 - * @param bool $renderContent 是否渲染内容 - * @return string - * @throws \Exception - */ - public function fetch($template = '', $vars = [], $config = [], $renderContent = false) - { - // 模板变量 - $vars = array_merge(self::$var, $this->data, $vars); - - // 页面缓存 - ob_start(); - ob_implicit_flush(0); - - // 渲染输出 - try { - $method = $renderContent ? 'display' : 'fetch'; - $this->engine->$method($template, $vars, $config); - } catch (\Exception $e) { - ob_end_clean(); - throw $e; - } - - // 获取并清空缓存 - $content = ob_get_clean(); - - if ($this->filter) { - $content = call_user_func_array($this->filter, [$content]); - } - - return $content; - } - - /** - * 渲染内容输出 - * @access public - * @param string $content 内容 - * @param array $vars 模板输出变量 - * @param array $config 模板参数 - * @return mixed - */ - public function display($content, $vars = [], $config = []) - { - return $this->fetch($content, $vars, $config, true); - } - - /** - * 模板变量赋值 - * @access public - * @param string $name 变量名 - * @param mixed $value 变量值 - */ - public function __set($name, $value) - { - $this->data[$name] = $value; - } - - /** - * 取得模板显示变量的值 - * @access protected - * @param string $name 模板变量 - * @return mixed - */ - public function __get($name) - { - return $this->data[$name]; - } - - /** - * 检测模板变量是否设置 - * @access public - * @param string $name 模板变量名 - * @return bool - */ - public function __isset($name) - { - return isset($this->data[$name]); - } -} diff --git a/thinkphp/library/think/cache/Driver.php b/thinkphp/library/think/cache/Driver.php deleted file mode 100755 index f4c5dcbf7..000000000 --- a/thinkphp/library/think/cache/Driver.php +++ /dev/null @@ -1,363 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\cache; - -use think\Container; - -/** - * 缓存基础类 - */ -abstract class Driver -{ - /** - * 驱动句柄 - * @var object - */ - protected $handler = null; - - /** - * 缓存读取次数 - * @var integer - */ - protected $readTimes = 0; - - /** - * 缓存写入次数 - * @var integer - */ - protected $writeTimes = 0; - - /** - * 缓存参数 - * @var array - */ - protected $options = []; - - /** - * 缓存标签 - * @var string - */ - protected $tag; - - /** - * 序列化方法 - * @var array - */ - protected static $serialize = ['serialize', 'unserialize', 'think_serialize:', 16]; - - /** - * 判断缓存是否存在 - * @access public - * @param string $name 缓存变量名 - * @return bool - */ - abstract public function has($name); - - /** - * 读取缓存 - * @access public - * @param string $name 缓存变量名 - * @param mixed $default 默认值 - * @return mixed - */ - abstract public function get($name, $default = false); - - /** - * 写入缓存 - * @access public - * @param string $name 缓存变量名 - * @param mixed $value 存储数据 - * @param int $expire 有效时间 0为永久 - * @return boolean - */ - abstract public function set($name, $value, $expire = null); - - /** - * 自增缓存(针对数值缓存) - * @access public - * @param string $name 缓存变量名 - * @param int $step 步长 - * @return false|int - */ - abstract public function inc($name, $step = 1); - - /** - * 自减缓存(针对数值缓存) - * @access public - * @param string $name 缓存变量名 - * @param int $step 步长 - * @return false|int - */ - abstract public function dec($name, $step = 1); - - /** - * 删除缓存 - * @access public - * @param string $name 缓存变量名 - * @return boolean - */ - abstract public function rm($name); - - /** - * 清除缓存 - * @access public - * @param string $tag 标签名 - * @return boolean - */ - abstract public function clear($tag = null); - - /** - * 获取有效期 - * @access protected - * @param integer|\DateTime $expire 有效期 - * @return integer - */ - protected function getExpireTime($expire) - { - if ($expire instanceof \DateTime) { - $expire = $expire->getTimestamp() - time(); - } - - return $expire; - } - - /** - * 获取实际的缓存标识 - * @access protected - * @param string $name 缓存名 - * @return string - */ - protected function getCacheKey($name) - { - return $this->options['prefix'] . $name; - } - - /** - * 读取缓存并删除 - * @access public - * @param string $name 缓存变量名 - * @return mixed - */ - public function pull($name) - { - $result = $this->get($name, false); - - if ($result) { - $this->rm($name); - return $result; - } else { - return; - } - } - - /** - * 如果不存在则写入缓存 - * @access public - * @param string $name 缓存变量名 - * @param mixed $value 存储数据 - * @param int $expire 有效时间 0为永久 - * @return mixed - */ - public function remember($name, $value, $expire = null) - { - if (!$this->has($name)) { - $time = time(); - while ($time + 5 > time() && $this->has($name . '_lock')) { - // 存在锁定则等待 - usleep(200000); - } - - try { - // 锁定 - $this->set($name . '_lock', true); - - if ($value instanceof \Closure) { - // 获取缓存数据 - $value = Container::getInstance()->invokeFunction($value); - } - - // 缓存数据 - $this->set($name, $value, $expire); - - // 解锁 - $this->rm($name . '_lock'); - } catch (\Exception $e) { - $this->rm($name . '_lock'); - throw $e; - } catch (\throwable $e) { - $this->rm($name . '_lock'); - throw $e; - } - } else { - $value = $this->get($name); - } - - return $value; - } - - /** - * 缓存标签 - * @access public - * @param string $name 标签名 - * @param string|array $keys 缓存标识 - * @param bool $overlay 是否覆盖 - * @return $this - */ - public function tag($name, $keys = null, $overlay = false) - { - if (is_null($name)) { - - } elseif (is_null($keys)) { - $this->tag = $name; - } else { - $key = $this->getTagkey($name); - - if (is_string($keys)) { - $keys = explode(',', $keys); - } - - $keys = array_map([$this, 'getCacheKey'], $keys); - - if ($overlay) { - $value = $keys; - } else { - $value = array_unique(array_merge($this->getTagItem($name), $keys)); - } - - $this->set($key, implode(',', $value), 0); - } - - return $this; - } - - /** - * 更新标签 - * @access protected - * @param string $name 缓存标识 - * @return void - */ - protected function setTagItem($name) - { - if ($this->tag) { - $key = $this->getTagkey($this->tag); - $prev = $this->tag; - $this->tag = null; - - if ($this->has($key)) { - $value = explode(',', $this->get($key)); - $value[] = $name; - - if (count($value) > 1000) { - array_shift($value); - } - - $value = implode(',', array_unique($value)); - } else { - $value = $name; - } - - $this->set($key, $value, 0); - $this->tag = $prev; - } - } - - /** - * 获取标签包含的缓存标识 - * @access protected - * @param string $tag 缓存标签 - * @return array - */ - protected function getTagItem($tag) - { - $key = $this->getTagkey($tag); - $value = $this->get($key); - - if ($value) { - return array_filter(explode(',', $value)); - } else { - return []; - } - } - - protected function getTagKey($tag) - { - return 'tag_' . md5($tag); - } - - /** - * 序列化数据 - * @access protected - * @param mixed $data - * @return string - */ - protected function serialize($data) - { - if (is_scalar($data) || !$this->options['serialize']) { - return $data; - } - - $serialize = self::$serialize[0]; - - return self::$serialize[2] . $serialize($data); - } - - /** - * 反序列化数据 - * @access protected - * @param string $data - * @return mixed - */ - protected function unserialize($data) - { - if ($this->options['serialize'] && 0 === strpos($data, self::$serialize[2])) { - $unserialize = self::$serialize[1]; - - return $unserialize(substr($data, self::$serialize[3])); - } else { - return $data; - } - } - - /** - * 注册序列化机制 - * @access public - * @param callable $serialize 序列化方法 - * @param callable $unserialize 反序列化方法 - * @param string $prefix 序列化前缀标识 - * @return $this - */ - public static function registerSerialize($serialize, $unserialize, $prefix = 'think_serialize:') - { - self::$serialize = [$serialize, $unserialize, $prefix, strlen($prefix)]; - } - - /** - * 返回句柄对象,可执行其它高级方法 - * - * @access public - * @return object - */ - public function handler() - { - return $this->handler; - } - - public function getReadTimes() - { - return $this->readTimes; - } - - public function getWriteTimes() - { - return $this->writeTimes; - } -} diff --git a/thinkphp/library/think/cache/driver/File.php b/thinkphp/library/think/cache/driver/File.php deleted file mode 100755 index 93d321f23..000000000 --- a/thinkphp/library/think/cache/driver/File.php +++ /dev/null @@ -1,305 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\cache\driver; - -use think\cache\Driver; -use think\Container; - -/** - * 文件类型缓存类 - * @author liu21st - */ -class File extends Driver -{ - protected $options = [ - 'expire' => 0, - 'cache_subdir' => true, - 'prefix' => '', - 'path' => '', - 'hash_type' => 'md5', - 'data_compress' => false, - 'serialize' => true, - ]; - - protected $expire; - - /** - * 架构函数 - * @param array $options - */ - public function __construct($options = []) - { - if (!empty($options)) { - $this->options = array_merge($this->options, $options); - } - - if (empty($this->options['path'])) { - $this->options['path'] = Container::get('app')->getRuntimePath() . 'cache' . DIRECTORY_SEPARATOR; - } elseif (substr($this->options['path'], -1) != DIRECTORY_SEPARATOR) { - $this->options['path'] .= DIRECTORY_SEPARATOR; - } - - $this->init(); - } - - /** - * 初始化检查 - * @access private - * @return boolean - */ - private function init() - { - // 创建项目缓存目录 - try { - if (!is_dir($this->options['path']) && mkdir($this->options['path'], 0755, true)) { - return true; - } - } catch (\Exception $e) { - } - - return false; - } - - /** - * 取得变量的存储文件名 - * @access protected - * @param string $name 缓存变量名 - * @param bool $auto 是否自动创建目录 - * @return string - */ - protected function getCacheKey($name, $auto = false) - { - $name = hash($this->options['hash_type'], $name); - - if ($this->options['cache_subdir']) { - // 使用子目录 - $name = substr($name, 0, 2) . DIRECTORY_SEPARATOR . substr($name, 2); - } - - if ($this->options['prefix']) { - $name = $this->options['prefix'] . DIRECTORY_SEPARATOR . $name; - } - - $filename = $this->options['path'] . $name . '.php'; - $dir = dirname($filename); - - if ($auto && !is_dir($dir)) { - try { - mkdir($dir, 0755, true); - } catch (\Exception $e) { - } - } - - return $filename; - } - - /** - * 判断缓存是否存在 - * @access public - * @param string $name 缓存变量名 - * @return bool - */ - public function has($name) - { - return false !== $this->get($name) ? true : false; - } - - /** - * 读取缓存 - * @access public - * @param string $name 缓存变量名 - * @param mixed $default 默认值 - * @return mixed - */ - public function get($name, $default = false) - { - $this->readTimes++; - - $filename = $this->getCacheKey($name); - - if (!is_file($filename)) { - return $default; - } - - $content = file_get_contents($filename); - $this->expire = null; - - if (false !== $content) { - $expire = (int) substr($content, 8, 12); - if (0 != $expire && time() > filemtime($filename) + $expire) { - //缓存过期删除缓存文件 - $this->unlink($filename); - return $default; - } - - $this->expire = $expire; - $content = substr($content, 32); - - if ($this->options['data_compress'] && function_exists('gzcompress')) { - //启用数据压缩 - $content = gzuncompress($content); - } - return $this->unserialize($content); - } else { - return $default; - } - } - - /** - * 写入缓存 - * @access public - * @param string $name 缓存变量名 - * @param mixed $value 存储数据 - * @param int|\DateTime $expire 有效时间 0为永久 - * @return boolean - */ - public function set($name, $value, $expire = null) - { - $this->writeTimes++; - - if (is_null($expire)) { - $expire = $this->options['expire']; - } - - $expire = $this->getExpireTime($expire); - $filename = $this->getCacheKey($name, true); - - if ($this->tag && !is_file($filename)) { - $first = true; - } - - $data = $this->serialize($value); - - if ($this->options['data_compress'] && function_exists('gzcompress')) { - //数据压缩 - $data = gzcompress($data, 3); - } - - $data = "\n" . $data; - $result = file_put_contents($filename, $data); - - if ($result) { - isset($first) && $this->setTagItem($filename); - clearstatcache(); - return true; - } else { - return false; - } - } - - /** - * 自增缓存(针对数值缓存) - * @access public - * @param string $name 缓存变量名 - * @param int $step 步长 - * @return false|int - */ - public function inc($name, $step = 1) - { - if ($this->has($name)) { - $value = $this->get($name) + $step; - $expire = $this->expire; - } else { - $value = $step; - $expire = 0; - } - - return $this->set($name, $value, $expire) ? $value : false; - } - - /** - * 自减缓存(针对数值缓存) - * @access public - * @param string $name 缓存变量名 - * @param int $step 步长 - * @return false|int - */ - public function dec($name, $step = 1) - { - if ($this->has($name)) { - $value = $this->get($name) - $step; - $expire = $this->expire; - } else { - $value = -$step; - $expire = 0; - } - - return $this->set($name, $value, $expire) ? $value : false; - } - - /** - * 删除缓存 - * @access public - * @param string $name 缓存变量名 - * @return boolean - */ - public function rm($name) - { - $this->writeTimes++; - - try { - return $this->unlink($this->getCacheKey($name)); - } catch (\Exception $e) { - } - } - - /** - * 清除缓存 - * @access public - * @param string $tag 标签名 - * @return boolean - */ - public function clear($tag = null) - { - if ($tag) { - // 指定标签清除 - $keys = $this->getTagItem($tag); - foreach ($keys as $key) { - $this->unlink($key); - } - $this->rm($this->getTagKey($tag)); - return true; - } - - $this->writeTimes++; - - $files = (array) glob($this->options['path'] . ($this->options['prefix'] ? $this->options['prefix'] . DIRECTORY_SEPARATOR : '') . '*'); - - foreach ($files as $path) { - if (is_dir($path)) { - $matches = glob($path . DIRECTORY_SEPARATOR . '*.php'); - if (is_array($matches)) { - array_map('unlink', $matches); - } - rmdir($path); - } else { - unlink($path); - } - } - - return true; - } - - /** - * 判断文件是否存在后,删除 - * @access private - * @param string $path - * @return bool - * @author byron sampson - * @return boolean - */ - private function unlink($path) - { - return is_file($path) && unlink($path); - } - -} diff --git a/thinkphp/library/think/cache/driver/Lite.php b/thinkphp/library/think/cache/driver/Lite.php deleted file mode 100755 index 0cfe39079..000000000 --- a/thinkphp/library/think/cache/driver/Lite.php +++ /dev/null @@ -1,209 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\cache\driver; - -use think\cache\Driver; - -/** - * 文件类型缓存类 - * @author liu21st - */ -class Lite extends Driver -{ - protected $options = [ - 'prefix' => '', - 'path' => '', - 'expire' => 0, // 等于 10*365*24*3600(10年) - ]; - - /** - * 架构函数 - * @access public - * - * @param array $options - */ - public function __construct($options = []) - { - if (!empty($options)) { - $this->options = array_merge($this->options, $options); - } - - if (substr($this->options['path'], -1) != DIRECTORY_SEPARATOR) { - $this->options['path'] .= DIRECTORY_SEPARATOR; - } - - } - - /** - * 取得变量的存储文件名 - * @access protected - * @param string $name 缓存变量名 - * @return string - */ - protected function getCacheKey($name) - { - return $this->options['path'] . $this->options['prefix'] . md5($name) . '.php'; - } - - /** - * 判断缓存是否存在 - * @access public - * @param string $name 缓存变量名 - * @return mixed - */ - public function has($name) - { - return $this->get($name) ? true : false; - } - - /** - * 读取缓存 - * @access public - * @param string $name 缓存变量名 - * @param mixed $default 默认值 - * @return mixed - */ - public function get($name, $default = false) - { - $this->readTimes++; - - $filename = $this->getCacheKey($name); - - if (is_file($filename)) { - // 判断是否过期 - $mtime = filemtime($filename); - - if ($mtime < time()) { - // 清除已经过期的文件 - unlink($filename); - return $default; - } - - return include $filename; - } else { - return $default; - } - } - - /** - * 写入缓存 - * @access public - * @param string $name 缓存变量名 - * @param mixed $value 存储数据 - * @param int|\DateTime $expire 有效时间 0为永久 - * @return bool - */ - public function set($name, $value, $expire = null) - { - $this->writeTimes++; - - if (is_null($expire)) { - $expire = $this->options['expire']; - } - - if ($expire instanceof \DateTime) { - $expire = $expire->getTimestamp(); - } else { - $expire = 0 === $expire ? 10 * 365 * 24 * 3600 : $expire; - $expire = time() + $expire; - } - - $filename = $this->getCacheKey($name); - - if ($this->tag && !is_file($filename)) { - $first = true; - } - - $ret = file_put_contents($filename, ("setTagItem($filename); - touch($filename, $expire); - } - - return $ret; - } - - /** - * 自增缓存(针对数值缓存) - * @access public - * @param string $name 缓存变量名 - * @param int $step 步长 - * @return false|int - */ - public function inc($name, $step = 1) - { - if ($this->has($name)) { - $value = $this->get($name) + $step; - } else { - $value = $step; - } - - return $this->set($name, $value, 0) ? $value : false; - } - - /** - * 自减缓存(针对数值缓存) - * @access public - * @param string $name 缓存变量名 - * @param int $step 步长 - * @return false|int - */ - public function dec($name, $step = 1) - { - if ($this->has($name)) { - $value = $this->get($name) - $step; - } else { - $value = -$step; - } - - return $this->set($name, $value, 0) ? $value : false; - } - - /** - * 删除缓存 - * @access public - * @param string $name 缓存变量名 - * @return boolean - */ - public function rm($name) - { - $this->writeTimes++; - - return unlink($this->getCacheKey($name)); - } - - /** - * 清除缓存 - * @access public - * @param string $tag 标签名 - * @return bool - */ - public function clear($tag = null) - { - if ($tag) { - // 指定标签清除 - $keys = $this->getTagItem($tag); - foreach ($keys as $key) { - unlink($key); - } - - $this->rm($this->getTagKey($tag)); - return true; - } - - $this->writeTimes++; - - array_map("unlink", glob($this->options['path'] . ($this->options['prefix'] ? $this->options['prefix'] . DIRECTORY_SEPARATOR : '') . '*.php')); - } -} diff --git a/thinkphp/library/think/cache/driver/Sqlite.php b/thinkphp/library/think/cache/driver/Sqlite.php deleted file mode 100755 index f57361e3c..000000000 --- a/thinkphp/library/think/cache/driver/Sqlite.php +++ /dev/null @@ -1,233 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\cache\driver; - -use think\cache\Driver; - -/** - * Sqlite缓存驱动 - * @author liu21st - */ -class Sqlite extends Driver -{ - protected $options = [ - 'db' => ':memory:', - 'table' => 'sharedmemory', - 'prefix' => '', - 'expire' => 0, - 'persistent' => false, - 'serialize' => true, - ]; - - /** - * 架构函数 - * @access public - * @param array $options 缓存参数 - * @throws \BadFunctionCallException - */ - public function __construct($options = []) - { - if (!extension_loaded('sqlite')) { - throw new \BadFunctionCallException('not support: sqlite'); - } - - if (!empty($options)) { - $this->options = array_merge($this->options, $options); - } - - $func = $this->options['persistent'] ? 'sqlite_popen' : 'sqlite_open'; - - $this->handler = $func($this->options['db']); - } - - /** - * 获取实际的缓存标识 - * @access public - * @param string $name 缓存名 - * @return string - */ - protected function getCacheKey($name) - { - return $this->options['prefix'] . sqlite_escape_string($name); - } - - /** - * 判断缓存 - * @access public - * @param string $name 缓存变量名 - * @return bool - */ - public function has($name) - { - $name = $this->getCacheKey($name); - - $sql = 'SELECT value FROM ' . $this->options['table'] . ' WHERE var=\'' . $name . '\' AND (expire=0 OR expire >' . time() . ') LIMIT 1'; - $result = sqlite_query($this->handler, $sql); - - return sqlite_num_rows($result); - } - - /** - * 读取缓存 - * @access public - * @param string $name 缓存变量名 - * @param mixed $default 默认值 - * @return mixed - */ - public function get($name, $default = false) - { - $this->readTimes++; - - $name = $this->getCacheKey($name); - - $sql = 'SELECT value FROM ' . $this->options['table'] . ' WHERE var=\'' . $name . '\' AND (expire=0 OR expire >' . time() . ') LIMIT 1'; - - $result = sqlite_query($this->handler, $sql); - - if (sqlite_num_rows($result)) { - $content = sqlite_fetch_single($result); - if (function_exists('gzcompress')) { - //启用数据压缩 - $content = gzuncompress($content); - } - - return $this->unserialize($content); - } - - return $default; - } - - /** - * 写入缓存 - * @access public - * @param string $name 缓存变量名 - * @param mixed $value 存储数据 - * @param integer|\DateTime $expire 有效时间(秒) - * @return boolean - */ - public function set($name, $value, $expire = null) - { - $this->writeTimes++; - - $name = $this->getCacheKey($name); - - $value = sqlite_escape_string($this->serialize($value)); - - if (is_null($expire)) { - $expire = $this->options['expire']; - } - - if ($expire instanceof \DateTime) { - $expire = $expire->getTimestamp(); - } else { - $expire = (0 == $expire) ? 0 : (time() + $expire); //缓存有效期为0表示永久缓存 - } - - if (function_exists('gzcompress')) { - //数据压缩 - $value = gzcompress($value, 3); - } - - if ($this->tag) { - $tag = $this->tag; - $this->tag = null; - } else { - $tag = ''; - } - - $sql = 'REPLACE INTO ' . $this->options['table'] . ' (var, value, expire, tag) VALUES (\'' . $name . '\', \'' . $value . '\', \'' . $expire . '\', \'' . $tag . '\')'; - - if (sqlite_query($this->handler, $sql)) { - return true; - } - - return false; - } - - /** - * 自增缓存(针对数值缓存) - * @access public - * @param string $name 缓存变量名 - * @param int $step 步长 - * @return false|int - */ - public function inc($name, $step = 1) - { - if ($this->has($name)) { - $value = $this->get($name) + $step; - } else { - $value = $step; - } - - return $this->set($name, $value, 0) ? $value : false; - } - - /** - * 自减缓存(针对数值缓存) - * @access public - * @param string $name 缓存变量名 - * @param int $step 步长 - * @return false|int - */ - public function dec($name, $step = 1) - { - if ($this->has($name)) { - $value = $this->get($name) - $step; - } else { - $value = -$step; - } - - return $this->set($name, $value, 0) ? $value : false; - } - - /** - * 删除缓存 - * @access public - * @param string $name 缓存变量名 - * @return boolean - */ - public function rm($name) - { - $this->writeTimes++; - - $name = $this->getCacheKey($name); - - $sql = 'DELETE FROM ' . $this->options['table'] . ' WHERE var=\'' . $name . '\''; - sqlite_query($this->handler, $sql); - - return true; - } - - /** - * 清除缓存 - * @access public - * @param string $tag 标签名 - * @return boolean - */ - public function clear($tag = null) - { - if ($tag) { - $name = sqlite_escape_string($this->getTagKey($tag)); - $sql = 'DELETE FROM ' . $this->options['table'] . ' WHERE tag=\'' . $name . '\''; - sqlite_query($this->handler, $sql); - return true; - } - - $this->writeTimes++; - - $sql = 'DELETE FROM ' . $this->options['table']; - - sqlite_query($this->handler, $sql); - - return true; - } -} diff --git a/thinkphp/library/think/cache/driver/Xcache.php b/thinkphp/library/think/cache/driver/Xcache.php deleted file mode 100755 index 4e698597a..000000000 --- a/thinkphp/library/think/cache/driver/Xcache.php +++ /dev/null @@ -1,179 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\cache\driver; - -use think\cache\Driver; - -/** - * Xcache缓存驱动 - * @author liu21st - */ -class Xcache extends Driver -{ - protected $options = [ - 'prefix' => '', - 'expire' => 0, - 'serialize' => true, - ]; - - /** - * 架构函数 - * @access public - * @param array $options 缓存参数 - * @throws \BadFunctionCallException - */ - public function __construct($options = []) - { - if (!function_exists('xcache_info')) { - throw new \BadFunctionCallException('not support: Xcache'); - } - - if (!empty($options)) { - $this->options = array_merge($this->options, $options); - } - } - - /** - * 判断缓存 - * @access public - * @param string $name 缓存变量名 - * @return bool - */ - public function has($name) - { - $key = $this->getCacheKey($name); - - return xcache_isset($key); - } - - /** - * 读取缓存 - * @access public - * @param string $name 缓存变量名 - * @param mixed $default 默认值 - * @return mixed - */ - public function get($name, $default = false) - { - $this->readTimes++; - - $key = $this->getCacheKey($name); - - return xcache_isset($key) ? $this->unserialize(xcache_get($key)) : $default; - } - - /** - * 写入缓存 - * @access public - * @param string $name 缓存变量名 - * @param mixed $value 存储数据 - * @param integer|\DateTime $expire 有效时间(秒) - * @return boolean - */ - public function set($name, $value, $expire = null) - { - $this->writeTimes++; - - if (is_null($expire)) { - $expire = $this->options['expire']; - } - - if ($this->tag && !$this->has($name)) { - $first = true; - } - - $key = $this->getCacheKey($name); - $expire = $this->getExpireTime($expire); - $value = $this->serialize($value); - - if (xcache_set($key, $value, $expire)) { - isset($first) && $this->setTagItem($key); - return true; - } - - return false; - } - - /** - * 自增缓存(针对数值缓存) - * @access public - * @param string $name 缓存变量名 - * @param int $step 步长 - * @return false|int - */ - public function inc($name, $step = 1) - { - $this->writeTimes++; - - $key = $this->getCacheKey($name); - - return xcache_inc($key, $step); - } - - /** - * 自减缓存(针对数值缓存) - * @access public - * @param string $name 缓存变量名 - * @param int $step 步长 - * @return false|int - */ - public function dec($name, $step = 1) - { - $this->writeTimes++; - - $key = $this->getCacheKey($name); - - return xcache_dec($key, $step); - } - - /** - * 删除缓存 - * @access public - * @param string $name 缓存变量名 - * @return boolean - */ - public function rm($name) - { - $this->writeTimes++; - - return xcache_unset($this->getCacheKey($name)); - } - - /** - * 清除缓存 - * @access public - * @param string $tag 标签名 - * @return boolean - */ - public function clear($tag = null) - { - if ($tag) { - // 指定标签清除 - $keys = $this->getTagItem($tag); - - foreach ($keys as $key) { - xcache_unset($key); - } - - $this->rm($this->getTagKey($tag)); - return true; - } - - $this->writeTimes++; - - if (function_exists('xcache_unset_by_prefix')) { - return xcache_unset_by_prefix($this->options['prefix']); - } else { - return false; - } - } -} diff --git a/thinkphp/library/think/config/driver/Ini.php b/thinkphp/library/think/config/driver/Ini.php deleted file mode 100755 index b2a647d11..000000000 --- a/thinkphp/library/think/config/driver/Ini.php +++ /dev/null @@ -1,31 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\config\driver; - -class Ini -{ - protected $config; - - public function __construct($config) - { - $this->config = $config; - } - - public function parse() - { - if (is_file($this->config)) { - return parse_ini_file($this->config, true); - } else { - return parse_ini_string($this->config, true); - } - } -} diff --git a/thinkphp/library/think/config/driver/Xml.php b/thinkphp/library/think/config/driver/Xml.php deleted file mode 100755 index 9d6963384..000000000 --- a/thinkphp/library/think/config/driver/Xml.php +++ /dev/null @@ -1,40 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\config\driver; - -class Xml -{ - protected $config; - - public function __construct($config) - { - $this->config = $config; - } - - public function parse() - { - if (is_file($this->config)) { - $content = simplexml_load_file($this->config); - } else { - $content = simplexml_load_string($this->config); - } - - $result = (array) $content; - foreach ($result as $key => $val) { - if (is_object($val)) { - $result[$key] = (array) $val; - } - } - - return $result; - } -} diff --git a/thinkphp/library/think/console/command/Build.php b/thinkphp/library/think/console/command/Build.php deleted file mode 100755 index 88a5bf820..000000000 --- a/thinkphp/library/think/console/command/Build.php +++ /dev/null @@ -1,59 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\console\command; - -use think\console\Command; -use think\console\Input; -use think\console\input\Option; -use think\console\Output; -use think\facade\App; -use think\facade\Build as AppBuild; - -class Build extends Command -{ - /** - * {@inheritdoc} - */ - protected function configure() - { - $this->setName('build') - ->setDefinition([ - new Option('config', null, Option::VALUE_OPTIONAL, "build.php path"), - new Option('module', null, Option::VALUE_OPTIONAL, "module name"), - ]) - ->setDescription('Build Application Dirs'); - } - - protected function execute(Input $input, Output $output) - { - if ($input->hasOption('module')) { - AppBuild::module($input->getOption('module')); - $output->writeln("Successed"); - return; - } - - if ($input->hasOption('config')) { - $build = include $input->getOption('config'); - } else { - $build = include App::getAppPath() . 'build.php'; - } - - if (empty($build)) { - $output->writeln("Build Config Is Empty"); - return; - } - - AppBuild::run($build); - $output->writeln("Successed"); - - } -} diff --git a/thinkphp/library/think/console/command/make/stubs/controller.plain.stub b/thinkphp/library/think/console/command/make/stubs/controller.plain.stub deleted file mode 100755 index b7539dcf6..000000000 --- a/thinkphp/library/think/console/command/make/stubs/controller.plain.stub +++ /dev/null @@ -1,10 +0,0 @@ - -// +---------------------------------------------------------------------- -namespace think\console\command\optimize; - -use think\console\Command; -use think\console\Input; -use think\console\Output; -use think\Container; - -class Autoload extends Command -{ - protected function configure() - { - $this->setName('optimize:autoload') - ->setDescription('Optimizes PSR0 and PSR4 packages to be loaded with classmaps too, good for production.'); - } - - protected function execute(Input $input, Output $output) - { - - $classmapFile = <<getNamespace() . '\\' => realpath(rtrim($app->getAppPath())), - 'think\\' => $app->getThinkPath() . 'library/think', - 'traits\\' => $app->getThinkPath() . 'library/traits', - '' => realpath(rtrim($app->getRootPath() . 'extend')), - ]; - - krsort($namespacesToScan); - $classMap = []; - foreach ($namespacesToScan as $namespace => $dir) { - - if (!is_dir($dir)) { - continue; - } - - $namespaceFilter = '' === $namespace ? null : $namespace; - $classMap = $this->addClassMapCode($dir, $namespaceFilter, $classMap); - } - - ksort($classMap); - foreach ($classMap as $class => $code) { - $classmapFile .= ' ' . var_export($class, true) . ' => ' . $code; - } - $classmapFile .= "];\n"; - $runtimePath = $app->getRuntimePath(); - if (!is_dir($runtimePath)) { - @mkdir($runtimePath, 0755, true); - } - - file_put_contents($runtimePath . 'classmap.php', $classmapFile); - - $output->writeln('Succeed!'); - } - - protected function addClassMapCode($dir, $namespace, $classMap) - { - foreach ($this->createMap($dir, $namespace) as $class => $path) { - - $pathCode = $this->getPathCode($path) . ",\n"; - - if (!isset($classMap[$class])) { - $classMap[$class] = $pathCode; - } elseif ($classMap[$class] !== $pathCode && !preg_match('{/(test|fixture|example|stub)s?/}i', strtr($classMap[$class] . ' ' . $path, '\\', '/'))) { - $this->output->writeln( - 'Warning: Ambiguous class resolution, "' . $class . '"' . - ' was found in both "' . str_replace(["',\n"], [ - '', - ], $classMap[$class]) . '" and "' . $path . '", the first will be used.' - ); - } - } - return $classMap; - } - - protected function getPathCode($path) - { - $baseDir = ''; - $app = Container::get('app'); - $appPath = $this->normalizePath(realpath($app->getAppPath())); - $libPath = $this->normalizePath(realpath($app->getThinkPath() . 'library')); - $extendPath = $this->normalizePath(realpath($app->getRootPath() . 'extend')); - $path = $this->normalizePath($path); - - if (strpos($path, $libPath . '/') === 0) { - $path = substr($path, strlen($app->getThinkPath() . 'library')); - $baseDir = "'" . $libPath . "/'"; - } elseif (strpos($path, $appPath . '/') === 0) { - $path = substr($path, strlen($appPath) + 1); - $baseDir = "'" . $appPath . "/'"; - } elseif (strpos($path, $extendPath . '/') === 0) { - $path = substr($path, strlen($extendPath) + 1); - $baseDir = "'" . $extendPath . "/'"; - } - - if (false !== $path) { - $baseDir .= " . "; - } - - return $baseDir . ((false !== $path) ? var_export($path, true) : ""); - } - - protected function normalizePath($path) - { - $parts = []; - $path = strtr($path, '\\', '/'); - $prefix = ''; - $absolute = false; - - if (preg_match('{^([0-9a-z]+:(?://(?:[a-z]:)?)?)}i', $path, $match)) { - $prefix = $match[1]; - $path = substr($path, strlen($prefix)); - } - - if (substr($path, 0, 1) === '/') { - $absolute = true; - $path = substr($path, 1); - } - - $up = false; - foreach (explode('/', $path) as $chunk) { - if ('..' === $chunk && ($absolute || $up)) { - array_pop($parts); - $up = !(empty($parts) || '..' === end($parts)); - } elseif ('.' !== $chunk && '' !== $chunk) { - $parts[] = $chunk; - $up = '..' !== $chunk; - } - } - - return $prefix . ($absolute ? '/' : '') . implode('/', $parts); - } - - protected function createMap($path, $namespace = null) - { - if (is_string($path)) { - if (is_file($path)) { - $path = [new \SplFileInfo($path)]; - } elseif (is_dir($path)) { - - $objects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path), \RecursiveIteratorIterator::SELF_FIRST); - - $path = []; - - /** @var \SplFileInfo $object */ - foreach ($objects as $object) { - if ($object->isFile() && $object->getExtension() == 'php') { - $path[] = $object; - } - } - } else { - throw new \RuntimeException( - 'Could not scan for classes inside "' . $path . - '" which does not appear to be a file nor a folder' - ); - } - } - - $map = []; - - /** @var \SplFileInfo $file */ - foreach ($path as $file) { - $filePath = $file->getRealPath(); - - if (pathinfo($filePath, PATHINFO_EXTENSION) != 'php') { - continue; - } - - $classes = $this->findClasses($filePath); - - foreach ($classes as $class) { - if (null !== $namespace && 0 !== strpos($class, $namespace)) { - continue; - } - - if (!isset($map[$class])) { - $map[$class] = $filePath; - } elseif ($map[$class] !== $filePath && !preg_match('{/(test|fixture|example|stub)s?/}i', strtr($map[$class] . ' ' . $filePath, '\\', '/'))) { - $this->output->writeln( - 'Warning: Ambiguous class resolution, "' . $class . '"' . - ' was found in both "' . $map[$class] . '" and "' . $filePath . '", the first will be used.' - ); - } - } - } - - return $map; - } - - protected function findClasses($path) - { - $extraTypes = '|trait'; - - $contents = @php_strip_whitespace($path); - if (!$contents) { - if (!file_exists($path)) { - $message = 'File at "%s" does not exist, check your classmap definitions'; - } elseif (!is_readable($path)) { - $message = 'File at "%s" is not readable, check its permissions'; - } elseif ('' === trim(file_get_contents($path))) { - return []; - } else { - $message = 'File at "%s" could not be parsed as PHP, it may be binary or corrupted'; - } - $error = error_get_last(); - if (isset($error['message'])) { - $message .= PHP_EOL . 'The following message may be helpful:' . PHP_EOL . $error['message']; - } - throw new \RuntimeException(sprintf($message, $path)); - } - - if (!preg_match('{\b(?:class|interface' . $extraTypes . ')\s}i', $contents)) { - return []; - } - - // strip heredocs/nowdocs - $contents = preg_replace('{<<<\s*(\'?)(\w+)\\1(?:\r\n|\n|\r)(?:.*?)(?:\r\n|\n|\r)\\2(?=\r\n|\n|\r|;)}s', 'null', $contents); - // strip strings - $contents = preg_replace('{"[^"\\\\]*+(\\\\.[^"\\\\]*+)*+"|\'[^\'\\\\]*+(\\\\.[^\'\\\\]*+)*+\'}s', 'null', $contents); - // strip leading non-php code if needed - if (substr($contents, 0, 2) !== '.+<\?}s', '?>'); - if (false !== $pos && false === strpos(substr($contents, $pos), '])(?Pclass|interface' . $extraTypes . ') \s++ (?P[a-zA-Z_\x7f-\xff:][a-zA-Z0-9_\x7f-\xff:\-]*+) - | \b(?])(?Pnamespace) (?P\s++[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\s*+\\\\\s*+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)*+)? \s*+ [\{;] - ) - }ix', $contents, $matches); - - $classes = []; - $namespace = ''; - - for ($i = 0, $len = count($matches['type']); $i < $len; $i++) { - if (!empty($matches['ns'][$i])) { - $namespace = str_replace([' ', "\t", "\r", "\n"], '', $matches['nsname'][$i]) . '\\'; - } else { - $name = $matches['name'][$i]; - if (':' === $name[0]) { - $name = 'xhp' . substr(str_replace(['-', ':'], ['_', '__'], $name), 1); - } elseif ('enum' === $matches['type'][$i]) { - $name = rtrim($name, ':'); - } - $classes[] = ltrim($namespace . $name, '\\'); - } - } - - return $classes; - } - -} diff --git a/thinkphp/library/think/console/command/optimize/Config.php b/thinkphp/library/think/console/command/optimize/Config.php deleted file mode 100755 index da9555683..000000000 --- a/thinkphp/library/think/console/command/optimize/Config.php +++ /dev/null @@ -1,107 +0,0 @@ - -// +---------------------------------------------------------------------- -namespace think\console\command\optimize; - -use think\console\Command; -use think\console\Input; -use think\console\input\Argument; -use think\console\Output; -use think\Container; -use think\facade\App; - -class Config extends Command -{ - protected function configure() - { - $this->setName('optimize:config') - ->addArgument('module', Argument::OPTIONAL, 'Build module config cache .') - ->setDescription('Build config and common file cache.'); - } - - protected function execute(Input $input, Output $output) - { - if ($input->getArgument('module')) { - $module = $input->getArgument('module') . DIRECTORY_SEPARATOR; - } else { - $module = ''; - } - - $content = 'buildCacheContent($module); - $runtimePath = App::getRuntimePath(); - if (!is_dir($runtimePath . $module)) { - @mkdir($runtimePath . $module, 0755, true); - } - - file_put_contents($runtimePath . $module . 'init.php', $content); - - $output->writeln('Succeed!'); - } - - protected function buildCacheContent($module) - { - $content = '// This cache file is automatically generated at:' . date('Y-m-d H:i:s') . PHP_EOL; - $path = realpath(App::getAppPath() . $module) . DIRECTORY_SEPARATOR; - if ($module) { - $configPath = is_dir($path . 'config') ? $path . 'config' : App::getConfigPath() . $module; - } else { - $configPath = App::getConfigPath(); - } - $ext = App::getConfigExt(); - $config = Container::get('config'); - - $files = is_dir($configPath) ? scandir($configPath) : []; - - foreach ($files as $file) { - if ('.' . pathinfo($file, PATHINFO_EXTENSION) === $ext) { - $filename = $configPath . DIRECTORY_SEPARATOR . $file; - $config->load($filename, pathinfo($file, PATHINFO_FILENAME)); - } - } - - // 加载行为扩展文件 - if (is_file($path . 'tags.php')) { - $tags = include $path . 'tags.php'; - if (is_array($tags)) { - $content .= PHP_EOL . '\think\facade\Hook::import(' . (var_export($tags, true)) . ');' . PHP_EOL; - } - } - - // 加载公共文件 - if (is_file($path . 'common.php')) { - $common = substr(php_strip_whitespace($path . 'common.php'), 6); - if ($common) { - $content .= PHP_EOL . $common . PHP_EOL; - } - } - - if ('' == $module) { - $content .= PHP_EOL . substr(php_strip_whitespace(App::getThinkPath() . 'helper.php'), 6) . PHP_EOL; - - if (is_file($path . 'middleware.php')) { - $middleware = include $path . 'middleware.php'; - if (is_array($middleware)) { - $content .= PHP_EOL . '\think\Container::get("middleware")->import(' . var_export($middleware, true) . ');' . PHP_EOL; - } - } - } - - if (is_file($path . 'provider.php')) { - $provider = include $path . 'provider.php'; - if (is_array($provider)) { - $content .= PHP_EOL . '\think\Container::getInstance()->bindTo(' . var_export($provider, true) . ');' . PHP_EOL; - } - } - - $content .= PHP_EOL . '\think\facade\Config::set(' . var_export($config->get(), true) . ');' . PHP_EOL; - - return $content; - } -} diff --git a/thinkphp/library/think/console/command/optimize/Schema.php b/thinkphp/library/think/console/command/optimize/Schema.php deleted file mode 100755 index 16ac83d5d..000000000 --- a/thinkphp/library/think/console/command/optimize/Schema.php +++ /dev/null @@ -1,118 +0,0 @@ - -// +---------------------------------------------------------------------- -namespace think\console\command\optimize; - -use think\console\Command; -use think\console\Input; -use think\console\input\Option; -use think\console\Output; -use think\Db; -use think\facade\App; - -class Schema extends Command -{ - protected function configure() - { - $this->setName('optimize:schema') - ->addOption('db', null, Option::VALUE_REQUIRED, 'db name .') - ->addOption('table', null, Option::VALUE_REQUIRED, 'table name .') - ->addOption('module', null, Option::VALUE_REQUIRED, 'module name .') - ->setDescription('Build database schema cache.'); - } - - protected function execute(Input $input, Output $output) - { - if (!is_dir(App::getRuntimePath() . 'schema')) { - @mkdir(App::getRuntimePath() . 'schema', 0755, true); - } - - if ($input->hasOption('module')) { - $module = $input->getOption('module'); - // 读取模型 - $path = App::getAppPath() . $module . DIRECTORY_SEPARATOR . 'model'; - $list = is_dir($path) ? scandir($path) : []; - $namespace = App::getNamespace(); - - foreach ($list as $file) { - if (0 === strpos($file, '.')) { - continue; - } - $class = '\\' . $namespace . '\\' . $module . '\\model\\' . pathinfo($file, PATHINFO_FILENAME); - $this->buildModelSchema($class); - } - - $output->writeln('Succeed!'); - return; - } elseif ($input->hasOption('table')) { - $table = $input->getOption('table'); - if (false === strpos($table, '.')) { - $dbName = Db::getConfig('database'); - } - - $tables[] = $table; - } elseif ($input->hasOption('db')) { - $dbName = $input->getOption('db'); - $tables = Db::getConnection()->getTables($dbName); - } elseif (!\think\facade\Config::get('app_multi_module')) { - $namespace = App::getNamespace(); - $path = App::getAppPath() . 'model'; - $list = is_dir($path) ? scandir($path) : []; - - foreach ($list as $file) { - if (0 === strpos($file, '.')) { - continue; - } - $class = '\\' . $namespace . '\\model\\' . pathinfo($file, PATHINFO_FILENAME); - $this->buildModelSchema($class); - } - - $output->writeln('Succeed!'); - return; - } else { - $tables = Db::getConnection()->getTables(); - } - - $db = isset($dbName) ? $dbName . '.' : ''; - $this->buildDataBaseSchema($tables, $db); - - $output->writeln('Succeed!'); - } - - protected function buildModelSchema($class) - { - $reflect = new \ReflectionClass($class); - if (!$reflect->isAbstract() && $reflect->isSubclassOf('\think\Model')) { - $table = $class::getTable(); - $dbName = $class::getConfig('database'); - $content = 'getFields($table); - $content .= var_export($info, true) . ';'; - - file_put_contents(App::getRuntimePath() . 'schema' . DIRECTORY_SEPARATOR . $dbName . '.' . $table . '.php', $content); - } - } - - protected function buildDataBaseSchema($tables, $db) - { - if ('' == $db) { - $dbName = Db::getConfig('database') . '.'; - } else { - $dbName = $db; - } - - foreach ($tables as $table) { - $content = 'getFields($db . $table); - $content .= var_export($info, true) . ';'; - file_put_contents(App::getRuntimePath() . 'schema' . DIRECTORY_SEPARATOR . $dbName . $table . '.php', $content); - } - } -} diff --git a/thinkphp/library/think/db/Builder.php b/thinkphp/library/think/db/Builder.php deleted file mode 100755 index 3dbbf7683..000000000 --- a/thinkphp/library/think/db/Builder.php +++ /dev/null @@ -1,1164 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\db; - -use PDO; -use think\Exception; - -abstract class Builder -{ - // connection对象实例 - protected $connection; - - // 查询表达式映射 - protected $exp = ['EQ' => '=', 'NEQ' => '<>', 'GT' => '>', 'EGT' => '>=', 'LT' => '<', 'ELT' => '<=', 'NOTLIKE' => 'NOT LIKE', 'NOTIN' => 'NOT IN', 'NOTBETWEEN' => 'NOT BETWEEN', 'NOTEXISTS' => 'NOT EXISTS', 'NOTNULL' => 'NOT NULL', 'NOTBETWEEN TIME' => 'NOT BETWEEN TIME']; - - // 查询表达式解析 - protected $parser = [ - 'parseCompare' => ['=', '<>', '>', '>=', '<', '<='], - 'parseLike' => ['LIKE', 'NOT LIKE'], - 'parseBetween' => ['NOT BETWEEN', 'BETWEEN'], - 'parseIn' => ['NOT IN', 'IN'], - 'parseExp' => ['EXP'], - 'parseNull' => ['NOT NULL', 'NULL'], - 'parseBetweenTime' => ['BETWEEN TIME', 'NOT BETWEEN TIME'], - 'parseTime' => ['< TIME', '> TIME', '<= TIME', '>= TIME'], - 'parseExists' => ['NOT EXISTS', 'EXISTS'], - 'parseColumn' => ['COLUMN'], - ]; - - // SQL表达式 - protected $selectSql = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%FORCE%%JOIN%%WHERE%%GROUP%%HAVING%%UNION%%ORDER%%LIMIT% %LOCK%%COMMENT%'; - - protected $insertSql = '%INSERT% INTO %TABLE% (%FIELD%) VALUES (%DATA%) %COMMENT%'; - - protected $insertAllSql = '%INSERT% INTO %TABLE% (%FIELD%) %DATA% %COMMENT%'; - - protected $updateSql = 'UPDATE %TABLE% SET %SET%%JOIN%%WHERE%%ORDER%%LIMIT% %LOCK%%COMMENT%'; - - protected $deleteSql = 'DELETE FROM %TABLE%%USING%%JOIN%%WHERE%%ORDER%%LIMIT% %LOCK%%COMMENT%'; - - /** - * 架构函数 - * @access public - * @param Connection $connection 数据库连接对象实例 - */ - public function __construct(Connection $connection) - { - $this->connection = $connection; - } - - /** - * 获取当前的连接对象实例 - * @access public - * @return Connection - */ - public function getConnection() - { - return $this->connection; - } - - /** - * 注册查询表达式解析 - * @access public - * @param string $name 解析方法 - * @param array $parser 匹配表达式数据 - * @return $this - */ - public function bindParser($name, $parser) - { - $this->parser[$name] = $parser; - return $this; - } - - /** - * 数据分析 - * @access protected - * @param Query $query 查询对象 - * @param array $data 数据 - * @param array $fields 字段信息 - * @param array $bind 参数绑定 - * @return array - */ - protected function parseData(Query $query, $data = [], $fields = [], $bind = []) - { - if (empty($data)) { - return []; - } - - $options = $query->getOptions(); - - // 获取绑定信息 - if (empty($bind)) { - $bind = $this->connection->getFieldsBind($options['table']); - } - - if (empty($fields)) { - if ('*' == $options['field']) { - $fields = array_keys($bind); - } else { - $fields = $options['field']; - } - } - - $result = []; - - foreach ($data as $key => $val) { - if ('*' != $options['field'] && !in_array($key, $fields, true)) { - continue; - } - - $item = $this->parseKey($query, $key, true); - - if ($val instanceof Expression) { - $result[$item] = $val->getValue(); - continue; - } elseif (!is_scalar($val) && (in_array($key, (array) $query->getOptions('json')) || 'json' == $this->connection->getFieldsType($options['table'], $key))) { - $val = json_encode($val, JSON_UNESCAPED_UNICODE); - } elseif (is_object($val) && method_exists($val, '__toString')) { - // 对象数据写入 - $val = $val->__toString(); - } - - if (false !== strpos($key, '->')) { - list($key, $name) = explode('->', $key); - $item = $this->parseKey($query, $key); - $result[$item] = 'json_set(' . $item . ', \'$.' . $name . '\', ' . $this->parseDataBind($query, $key, $val, $bind) . ')'; - } elseif ('*' == $options['field'] && false === strpos($key, '.') && !in_array($key, $fields, true)) { - if ($options['strict']) { - throw new Exception('fields not exists:[' . $key . ']'); - } - } elseif (is_null($val)) { - $result[$item] = 'NULL'; - } elseif (is_array($val) && !empty($val)) { - switch (strtoupper($val[0])) { - case 'INC': - $result[$item] = $item . ' + ' . floatval($val[1]); - break; - case 'DEC': - $result[$item] = $item . ' - ' . floatval($val[1]); - break; - case 'EXP': - throw new Exception('not support data:[' . $val[0] . ']'); - } - } elseif (is_scalar($val)) { - // 过滤非标量数据 - $result[$item] = $this->parseDataBind($query, $key, $val, $bind); - } - } - - return $result; - } - - /** - * 数据绑定处理 - * @access protected - * @param Query $query 查询对象 - * @param string $key 字段名 - * @param mixed $data 数据 - * @param array $bind 绑定数据 - * @return string - */ - protected function parseDataBind(Query $query, $key, $data, $bind = []) - { - if ($data instanceof Expression) { - return $data->getValue(); - } - - $name = $query->bind($data, isset($bind[$key]) ? $bind[$key] : PDO::PARAM_STR); - - return ':' . $name; - } - - /** - * 字段名分析 - * @access public - * @param Query $query 查询对象 - * @param mixed $key 字段名 - * @param bool $strict 严格检测 - * @return string - */ - public function parseKey(Query $query, $key, $strict = false) - { - return $key instanceof Expression ? $key->getValue() : $key; - } - - /** - * field分析 - * @access protected - * @param Query $query 查询对象 - * @param mixed $fields 字段名 - * @return string - */ - protected function parseField(Query $query, $fields) - { - if ('*' == $fields || empty($fields)) { - $fieldsStr = '*'; - } elseif (is_array($fields)) { - // 支持 'field1'=>'field2' 这样的字段别名定义 - $array = []; - - foreach ($fields as $key => $field) { - if (!is_numeric($key)) { - $array[] = $this->parseKey($query, $key) . ' AS ' . $this->parseKey($query, $field, true); - } else { - $array[] = $this->parseKey($query, $field); - } - } - - $fieldsStr = implode(',', $array); - } - - return $fieldsStr; - } - - /** - * table分析 - * @access protected - * @param Query $query 查询对象 - * @param mixed $tables 表名 - * @return string - */ - protected function parseTable(Query $query, $tables) - { - $item = []; - $options = $query->getOptions(); - - foreach ((array) $tables as $key => $table) { - if (!is_numeric($key)) { - $key = $this->connection->parseSqlTable($key); - $item[] = $this->parseKey($query, $key) . ' ' . $this->parseKey($query, $table); - } else { - $table = $this->connection->parseSqlTable($table); - - if (isset($options['alias'][$table])) { - $item[] = $this->parseKey($query, $table) . ' ' . $this->parseKey($query, $options['alias'][$table]); - } else { - $item[] = $this->parseKey($query, $table); - } - } - } - - return implode(',', $item); - } - - /** - * where分析 - * @access protected - * @param Query $query 查询对象 - * @param mixed $where 查询条件 - * @return string - */ - protected function parseWhere(Query $query, $where) - { - $options = $query->getOptions(); - $whereStr = $this->buildWhere($query, $where); - - if (!empty($options['soft_delete'])) { - // 附加软删除条件 - list($field, $condition) = $options['soft_delete']; - - $binds = $this->connection->getFieldsBind($options['table']); - $whereStr = $whereStr ? '( ' . $whereStr . ' ) AND ' : ''; - $whereStr = $whereStr . $this->parseWhereItem($query, $field, $condition, '', $binds); - } - - return empty($whereStr) ? '' : ' WHERE ' . $whereStr; - } - - /** - * 生成查询条件SQL - * @access public - * @param Query $query 查询对象 - * @param mixed $where 查询条件 - * @return string - */ - public function buildWhere(Query $query, $where) - { - if (empty($where)) { - $where = []; - } - - $whereStr = ''; - $binds = $this->connection->getFieldsBind($query->getOptions('table')); - - foreach ($where as $logic => $val) { - $str = []; - - foreach ($val as $value) { - if ($value instanceof Expression) { - $str[] = ' ' . $logic . ' ( ' . $value->getValue() . ' )'; - continue; - } - - if (is_array($value)) { - if (key($value) !== 0) { - throw new Exception('where express error:' . var_export($value, true)); - } - $field = array_shift($value); - } elseif (!($value instanceof \Closure)) { - throw new Exception('where express error:' . var_export($value, true)); - } - - if ($value instanceof \Closure) { - // 使用闭包查询 - $newQuery = $query->newQuery()->setConnection($this->connection); - $value($newQuery); - $whereClause = $this->buildWhere($query, $newQuery->getOptions('where')); - - if (!empty($whereClause)) { - $str[] = ' ' . $logic . ' ( ' . $whereClause . ' )'; - } - } elseif (is_array($field)) { - array_unshift($value, $field); - $str2 = []; - foreach ($value as $item) { - $str2[] = $this->parseWhereItem($query, array_shift($item), $item, $logic, $binds); - } - - $str[] = ' ' . $logic . ' ( ' . implode(' AND ', $str2) . ' )'; - } elseif (strpos($field, '|')) { - // 不同字段使用相同查询条件(OR) - $array = explode('|', $field); - $item = []; - - foreach ($array as $k) { - $item[] = $this->parseWhereItem($query, $k, $value, '', $binds); - } - - $str[] = ' ' . $logic . ' ( ' . implode(' OR ', $item) . ' )'; - } elseif (strpos($field, '&')) { - // 不同字段使用相同查询条件(AND) - $array = explode('&', $field); - $item = []; - - foreach ($array as $k) { - $item[] = $this->parseWhereItem($query, $k, $value, '', $binds); - } - - $str[] = ' ' . $logic . ' ( ' . implode(' AND ', $item) . ' )'; - } else { - // 对字段使用表达式查询 - $field = is_string($field) ? $field : ''; - $str[] = ' ' . $logic . ' ' . $this->parseWhereItem($query, $field, $value, $logic, $binds); - } - } - - $whereStr .= empty($whereStr) ? substr(implode(' ', $str), strlen($logic) + 1) : implode(' ', $str); - } - - return $whereStr; - } - - // where子单元分析 - protected function parseWhereItem(Query $query, $field, $val, $rule = '', $binds = []) - { - // 字段分析 - $key = $field ? $this->parseKey($query, $field, true) : ''; - - // 查询规则和条件 - if (!is_array($val)) { - $val = is_null($val) ? ['NULL', ''] : ['=', $val]; - } - - list($exp, $value) = $val; - - // 对一个字段使用多个查询条件 - if (is_array($exp)) { - $item = array_pop($val); - - // 传入 or 或者 and - if (is_string($item) && in_array($item, ['AND', 'and', 'OR', 'or'])) { - $rule = $item; - } else { - array_push($val, $item); - } - - foreach ($val as $k => $item) { - $str[] = $this->parseWhereItem($query, $field, $item, $rule, $binds); - } - - return '( ' . implode(' ' . $rule . ' ', $str) . ' )'; - } - - // 检测操作符 - $exp = strtoupper($exp); - if (isset($this->exp[$exp])) { - $exp = $this->exp[$exp]; - } - - if ($value instanceof Expression) { - - } elseif (is_object($value) && method_exists($value, '__toString')) { - // 对象数据写入 - $value = $value->__toString(); - } - - if (strpos($field, '->')) { - $jsonType = $query->getJsonFieldType($field); - $bindType = $this->connection->getFieldBindType($jsonType); - } else { - $bindType = isset($binds[$field]) ? $binds[$field] : PDO::PARAM_STR; - } - - if (is_scalar($value) && !in_array($exp, ['EXP', 'NOT NULL', 'NULL', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN']) && strpos($exp, 'TIME') === false) { - if (0 === strpos($value, ':') && $query->isBind(substr($value, 1))) { - } else { - $name = $query->bind($value, $bindType); - $value = ':' . $name; - } - } - - // 解析查询表达式 - foreach ($this->parser as $fun => $parse) { - if (in_array($exp, $parse)) { - $whereStr = $this->$fun($query, $key, $exp, $value, $field, $bindType, isset($val[2]) ? $val[2] : 'AND'); - break; - } - } - - if (!isset($whereStr)) { - throw new Exception('where express error:' . $exp); - } - - return $whereStr; - } - - /** - * 模糊查询 - * @access protected - * @param Query $query 查询对象 - * @param string $key - * @param string $exp - * @param mixed $value - * @param string $field - * @param integer $bindType - * @param string $logic - * @return string - */ - protected function parseLike(Query $query, $key, $exp, $value, $field, $bindType, $logic) - { - // 模糊匹配 - if (is_array($value)) { - foreach ($value as $item) { - $name = $query->bind($item, $bindType); - $array[] = $key . ' ' . $exp . ' :' . $name; - } - - $whereStr = '(' . implode($array, ' ' . strtoupper($logic) . ' ') . ')'; - } else { - $whereStr = $key . ' ' . $exp . ' ' . $value; - } - - return $whereStr; - } - - /** - * 表达式查询 - * @access protected - * @param Query $query 查询对象 - * @param string $key - * @param string $exp - * @param array $value - * @param string $field - * @param integer $bindType - * @return string - */ - protected function parseColumn(Query $query, $key, $exp, array $value, $field, $bindType) - { - // 字段比较查询 - list($op, $field2) = $value; - - if (!in_array($op, ['=', '<>', '>', '>=', '<', '<='])) { - throw new Exception('where express error:' . var_export($value, true)); - } - - return '( ' . $key . ' ' . $op . ' ' . $this->parseKey($query, $field2, true) . ' )'; - } - - /** - * 表达式查询 - * @access protected - * @param Query $query 查询对象 - * @param string $key - * @param string $exp - * @param Expression $value - * @param string $field - * @param integer $bindType - * @return string - */ - protected function parseExp(Query $query, $key, $exp, Expression $value, $field, $bindType) - { - // 表达式查询 - return '( ' . $key . ' ' . $value->getValue() . ' )'; - } - - /** - * Null查询 - * @access protected - * @param Query $query 查询对象 - * @param string $key - * @param string $exp - * @param mixed $value - * @param string $field - * @param integer $bindType - * @return string - */ - protected function parseNull(Query $query, $key, $exp, $value, $field, $bindType) - { - // NULL 查询 - return $key . ' IS ' . $exp; - } - - /** - * 范围查询 - * @access protected - * @param Query $query 查询对象 - * @param string $key - * @param string $exp - * @param mixed $value - * @param string $field - * @param integer $bindType - * @return string - */ - protected function parseBetween(Query $query, $key, $exp, $value, $field, $bindType) - { - // BETWEEN 查询 - $data = is_array($value) ? $value : explode(',', $value); - - $min = $query->bind($data[0], $bindType); - $max = $query->bind($data[1], $bindType); - - return $key . ' ' . $exp . ' :' . $min . ' AND :' . $max . ' '; - } - - /** - * Exists查询 - * @access protected - * @param Query $query 查询对象 - * @param string $key - * @param string $exp - * @param mixed $value - * @param string $field - * @param integer $bindType - * @return string - */ - protected function parseExists(Query $query, $key, $exp, $value, $field, $bindType) - { - // EXISTS 查询 - if ($value instanceof \Closure) { - $value = $this->parseClosure($query, $value, false); - } elseif ($value instanceof Expression) { - $value = $value->getValue(); - } else { - throw new Exception('where express error:' . $value); - } - - return $exp . ' (' . $value . ')'; - } - - /** - * 时间比较查询 - * @access protected - * @param Query $query 查询对象 - * @param string $key - * @param string $exp - * @param mixed $value - * @param string $field - * @param integer $bindType - * @return string - */ - protected function parseTime(Query $query, $key, $exp, $value, $field, $bindType) - { - return $key . ' ' . substr($exp, 0, 2) . ' ' . $this->parseDateTime($query, $value, $field, $bindType); - } - - /** - * 大小比较查询 - * @access protected - * @param Query $query 查询对象 - * @param string $key - * @param string $exp - * @param mixed $value - * @param string $field - * @param integer $bindType - * @return string - */ - protected function parseCompare(Query $query, $key, $exp, $value, $field, $bindType) - { - if (is_array($value)) { - throw new Exception('where express error:' . $exp . var_export($value, true)); - } - - // 比较运算 - if ($value instanceof \Closure) { - $value = $this->parseClosure($query, $value); - } - - return $key . ' ' . $exp . ' ' . $value; - } - - /** - * 时间范围查询 - * @access protected - * @param Query $query 查询对象 - * @param string $key - * @param string $exp - * @param mixed $value - * @param string $field - * @param integer $bindType - * @return string - */ - protected function parseBetweenTime(Query $query, $key, $exp, $value, $field, $bindType) - { - if (is_string($value)) { - $value = explode(',', $value); - } - - return $key . ' ' . substr($exp, 0, -4) - . $this->parseDateTime($query, $value[0], $field, $bindType) - . ' AND ' - . $this->parseDateTime($query, $value[1], $field, $bindType); - - } - - /** - * IN查询 - * @access protected - * @param Query $query 查询对象 - * @param string $key - * @param string $exp - * @param mixed $value - * @param string $field - * @param integer $bindType - * @return string - */ - protected function parseIn(Query $query, $key, $exp, $value, $field, $bindType) - { - // IN 查询 - if ($value instanceof \Closure) { - $value = $this->parseClosure($query, $value, false); - } else { - $value = array_unique(is_array($value) ? $value : explode(',', $value)); - - $array = []; - - foreach ($value as $k => $v) { - $name = $query->bind($v, $bindType); - $array[] = ':' . $name; - } - - $zone = implode(',', $array); - - $value = empty($zone) ? "''" : $zone; - } - - return $key . ' ' . $exp . ' (' . $value . ')'; - } - - /** - * 闭包子查询 - * @access protected - * @param Query $query 查询对象 - * @param \Closure $call - * @param bool $show - * @return string - */ - protected function parseClosure(Query $query, $call, $show = true) - { - $newQuery = $query->newQuery()->setConnection($this->connection); - $call($newQuery); - - return $newQuery->buildSql($show); - } - - /** - * 日期时间条件解析 - * @access protected - * @param Query $query 查询对象 - * @param string $value - * @param string $key - * @param integer $bindType - * @return string - */ - protected function parseDateTime(Query $query, $value, $key, $bindType = null) - { - $options = $query->getOptions(); - - // 获取时间字段类型 - if (strpos($key, '.')) { - list($table, $key) = explode('.', $key); - - if (isset($options['alias']) && $pos = array_search($table, $options['alias'])) { - $table = $pos; - } - } else { - $table = $options['table']; - } - - $type = $this->connection->getTableInfo($table, 'type'); - - if (isset($type[$key])) { - $info = $type[$key]; - } - - if (isset($info)) { - if (is_string($value)) { - $value = strtotime($value) ?: $value; - } - - if (preg_match('/(datetime|timestamp)/is', $info)) { - // 日期及时间戳类型 - $value = date('Y-m-d H:i:s', $value); - } elseif (preg_match('/(date)/is', $info)) { - // 日期及时间戳类型 - $value = date('Y-m-d', $value); - } - } - - $name = $query->bind($value, $bindType); - - return ':' . $name; - } - - /** - * limit分析 - * @access protected - * @param Query $query 查询对象 - * @param mixed $limit - * @return string - */ - protected function parseLimit(Query $query, $limit) - { - return (!empty($limit) && false === strpos($limit, '(')) ? ' LIMIT ' . $limit . ' ' : ''; - } - - /** - * join分析 - * @access protected - * @param Query $query 查询对象 - * @param array $join - * @return string - */ - protected function parseJoin(Query $query, $join) - { - $joinStr = ''; - - if (!empty($join)) { - foreach ($join as $item) { - list($table, $type, $on) = $item; - - $condition = []; - - foreach ((array) $on as $val) { - if ($val instanceof Expression) { - $condition[] = $val->getValue(); - } elseif (strpos($val, '=')) { - list($val1, $val2) = explode('=', $val, 2); - - $condition[] = $this->parseKey($query, $val1) . '=' . $this->parseKey($query, $val2); - } else { - $condition[] = $val; - } - } - - $table = $this->parseTable($query, $table); - - $joinStr .= ' ' . $type . ' JOIN ' . $table . ' ON ' . implode(' AND ', $condition); - } - } - - return $joinStr; - } - - /** - * order分析 - * @access protected - * @param Query $query 查询对象 - * @param mixed $order - * @return string - */ - protected function parseOrder(Query $query, $order) - { - foreach ($order as $key => $val) { - if ($val instanceof Expression) { - $array[] = $val->getValue(); - } elseif (is_array($val) && preg_match('/^[\w\.]+$/', $key)) { - $array[] = $this->parseOrderField($query, $key, $val); - } elseif ('[rand]' == $val) { - $array[] = $this->parseRand($query); - } elseif (is_string($val)) { - if (is_numeric($key)) { - list($key, $sort) = explode(' ', strpos($val, ' ') ? $val : $val . ' '); - } else { - $sort = $val; - } - - if (preg_match('/^[\w\.]+$/', $key)) { - $sort = strtoupper($sort); - $sort = in_array($sort, ['ASC', 'DESC'], true) ? ' ' . $sort : ''; - $array[] = $this->parseKey($query, $key, true) . $sort; - } else { - throw new Exception('order express error:' . $key); - } - } - } - - return empty($array) ? '' : ' ORDER BY ' . implode(',', $array); - } - - /** - * orderField分析 - * @access protected - * @param Query $query 查询对象 - * @param mixed $key - * @param array $val - * @return string - */ - protected function parseOrderField($query, $key, $val) - { - if (isset($val['sort'])) { - $sort = $val['sort']; - unset($val['sort']); - } else { - $sort = ''; - } - - $sort = strtoupper($sort); - $sort = in_array($sort, ['ASC', 'DESC'], true) ? ' ' . $sort : ''; - - $options = $query->getOptions(); - $bind = $this->connection->getFieldsBind($options['table']); - - foreach ($val as $k => $item) { - $val[$k] = $this->parseDataBind($query, $key, $item, $bind); - } - - return 'field(' . $this->parseKey($query, $key, true) . ',' . implode(',', $val) . ')' . $sort; - } - - /** - * group分析 - * @access protected - * @param Query $query 查询对象 - * @param mixed $group - * @return string - */ - protected function parseGroup(Query $query, $group) - { - if (empty($group)) { - return ''; - } - - if (is_string($group)) { - $group = explode(',', $group); - } - - foreach ($group as $key) { - $val[] = $this->parseKey($query, $key); - } - - return ' GROUP BY ' . implode(',', $val); - } - - /** - * having分析 - * @access protected - * @param Query $query 查询对象 - * @param string $having - * @return string - */ - protected function parseHaving(Query $query, $having) - { - return !empty($having) ? ' HAVING ' . $having : ''; - } - - /** - * comment分析 - * @access protected - * @param Query $query 查询对象 - * @param string $comment - * @return string - */ - protected function parseComment(Query $query, $comment) - { - if (false !== strpos($comment, '*/')) { - $comment = strstr($comment, '*/', true); - } - - return !empty($comment) ? ' /* ' . $comment . ' */' : ''; - } - - /** - * distinct分析 - * @access protected - * @param Query $query 查询对象 - * @param mixed $distinct - * @return string - */ - protected function parseDistinct(Query $query, $distinct) - { - return !empty($distinct) ? ' DISTINCT ' : ''; - } - - /** - * union分析 - * @access protected - * @param Query $query 查询对象 - * @param mixed $union - * @return string - */ - protected function parseUnion(Query $query, $union) - { - if (empty($union)) { - return ''; - } - - $type = $union['type']; - unset($union['type']); - - foreach ($union as $u) { - if ($u instanceof \Closure) { - $sql[] = $type . ' ' . $this->parseClosure($query, $u); - } elseif (is_string($u)) { - $sql[] = $type . ' ( ' . $this->connection->parseSqlTable($u) . ' )'; - } - } - - return ' ' . implode(' ', $sql); - } - - /** - * index分析,可在操作链中指定需要强制使用的索引 - * @access protected - * @param Query $query 查询对象 - * @param mixed $index - * @return string - */ - protected function parseForce(Query $query, $index) - { - if (empty($index)) { - return ''; - } - - return sprintf(" FORCE INDEX ( %s ) ", is_array($index) ? implode(',', $index) : $index); - } - - /** - * 设置锁机制 - * @access protected - * @param Query $query 查询对象 - * @param bool|string $lock - * @return string - */ - protected function parseLock(Query $query, $lock = false) - { - if (is_bool($lock)) { - return $lock ? ' FOR UPDATE ' : ''; - } elseif (is_string($lock) && !empty($lock)) { - return ' ' . trim($lock) . ' '; - } - } - - /** - * 生成查询SQL - * @access public - * @param Query $query 查询对象 - * @return string - */ - public function select(Query $query) - { - $options = $query->getOptions(); - - return str_replace( - ['%TABLE%', '%DISTINCT%', '%FIELD%', '%JOIN%', '%WHERE%', '%GROUP%', '%HAVING%', '%ORDER%', '%LIMIT%', '%UNION%', '%LOCK%', '%COMMENT%', '%FORCE%'], - [ - $this->parseTable($query, $options['table']), - $this->parseDistinct($query, $options['distinct']), - $this->parseField($query, $options['field']), - $this->parseJoin($query, $options['join']), - $this->parseWhere($query, $options['where']), - $this->parseGroup($query, $options['group']), - $this->parseHaving($query, $options['having']), - $this->parseOrder($query, $options['order']), - $this->parseLimit($query, $options['limit']), - $this->parseUnion($query, $options['union']), - $this->parseLock($query, $options['lock']), - $this->parseComment($query, $options['comment']), - $this->parseForce($query, $options['force']), - ], - $this->selectSql); - } - - /** - * 生成Insert SQL - * @access public - * @param Query $query 查询对象 - * @param bool $replace 是否replace - * @return string - */ - public function insert(Query $query, $replace = false) - { - $options = $query->getOptions(); - - // 分析并处理数据 - $data = $this->parseData($query, $options['data']); - if (empty($data)) { - return ''; - } - - $fields = array_keys($data); - $values = array_values($data); - - return str_replace( - ['%INSERT%', '%TABLE%', '%FIELD%', '%DATA%', '%COMMENT%'], - [ - $replace ? 'REPLACE' : 'INSERT', - $this->parseTable($query, $options['table']), - implode(' , ', $fields), - implode(' , ', $values), - $this->parseComment($query, $options['comment']), - ], - $this->insertSql); - } - - /** - * 生成insertall SQL - * @access public - * @param Query $query 查询对象 - * @param array $dataSet 数据集 - * @param bool $replace 是否replace - * @return string - */ - public function insertAll(Query $query, $dataSet, $replace = false) - { - $options = $query->getOptions(); - - // 获取合法的字段 - if ('*' == $options['field']) { - $allowFields = $this->connection->getTableFields($options['table']); - } else { - $allowFields = $options['field']; - } - - // 获取绑定信息 - $bind = $this->connection->getFieldsBind($options['table']); - - foreach ($dataSet as $data) { - $data = $this->parseData($query, $data, $allowFields, $bind); - - $values[] = 'SELECT ' . implode(',', array_values($data)); - - if (!isset($insertFields)) { - $insertFields = array_keys($data); - } - } - - $fields = []; - - foreach ($insertFields as $field) { - $fields[] = $this->parseKey($query, $field); - } - - return str_replace( - ['%INSERT%', '%TABLE%', '%FIELD%', '%DATA%', '%COMMENT%'], - [ - $replace ? 'REPLACE' : 'INSERT', - $this->parseTable($query, $options['table']), - implode(' , ', $fields), - implode(' UNION ALL ', $values), - $this->parseComment($query, $options['comment']), - ], - $this->insertAllSql); - } - - /** - * 生成slect insert SQL - * @access public - * @param Query $query 查询对象 - * @param array $fields 数据 - * @param string $table 数据表 - * @return string - */ - public function selectInsert(Query $query, $fields, $table) - { - if (is_string($fields)) { - $fields = explode(',', $fields); - } - - foreach ($fields as &$field) { - $field = $this->parseKey($query, $field, true); - } - - return 'INSERT INTO ' . $this->parseTable($query, $table) . ' (' . implode(',', $fields) . ') ' . $this->select($query); - } - - /** - * 生成update SQL - * @access public - * @param Query $query 查询对象 - * @return string - */ - public function update(Query $query) - { - $options = $query->getOptions(); - - $data = $this->parseData($query, $options['data']); - - if (empty($data)) { - return ''; - } - - foreach ($data as $key => $val) { - $set[] = $key . ' = ' . $val; - } - - return str_replace( - ['%TABLE%', '%SET%', '%JOIN%', '%WHERE%', '%ORDER%', '%LIMIT%', '%LOCK%', '%COMMENT%'], - [ - $this->parseTable($query, $options['table']), - implode(' , ', $set), - $this->parseJoin($query, $options['join']), - $this->parseWhere($query, $options['where']), - $this->parseOrder($query, $options['order']), - $this->parseLimit($query, $options['limit']), - $this->parseLock($query, $options['lock']), - $this->parseComment($query, $options['comment']), - ], - $this->updateSql); - } - - /** - * 生成delete SQL - * @access public - * @param Query $query 查询对象 - * @return string - */ - public function delete(Query $query) - { - $options = $query->getOptions(); - - return str_replace( - ['%TABLE%', '%USING%', '%JOIN%', '%WHERE%', '%ORDER%', '%LIMIT%', '%LOCK%', '%COMMENT%'], - [ - $this->parseTable($query, $options['table']), - !empty($options['using']) ? ' USING ' . $this->parseTable($query, $options['using']) . ' ' : '', - $this->parseJoin($query, $options['join']), - $this->parseWhere($query, $options['where']), - $this->parseOrder($query, $options['order']), - $this->parseLimit($query, $options['limit']), - $this->parseLock($query, $options['lock']), - $this->parseComment($query, $options['comment']), - ], - $this->deleteSql); - } -} diff --git a/thinkphp/library/think/db/Connection.php b/thinkphp/library/think/db/Connection.php deleted file mode 100755 index af27fd629..000000000 --- a/thinkphp/library/think/db/Connection.php +++ /dev/null @@ -1,2150 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\db; - -use InvalidArgumentException; -use PDO; -use PDOStatement; -use think\Container; -use think\Db; -use think\db\exception\BindParamException; -use think\Debug; -use think\Exception; -use think\exception\PDOException; -use think\Loader; - -abstract class Connection -{ - const PARAM_FLOAT = 21; - protected static $instance = []; - /** @var PDOStatement PDO操作实例 */ - protected $PDOStatement; - - /** @var string 当前SQL指令 */ - protected $queryStr = ''; - // 返回或者影响记录数 - protected $numRows = 0; - // 事务指令数 - protected $transTimes = 0; - // 错误信息 - protected $error = ''; - - /** @var PDO[] 数据库连接ID 支持多个连接 */ - protected $links = []; - - /** @var PDO 当前连接ID */ - protected $linkID; - protected $linkRead; - protected $linkWrite; - - // 查询结果类型 - protected $fetchType = PDO::FETCH_ASSOC; - // 字段属性大小写 - protected $attrCase = PDO::CASE_LOWER; - // 监听回调 - protected static $event = []; - - // 数据表信息 - protected static $info = []; - - // 使用Builder类 - protected $builderClassName; - // Builder对象 - protected $builder; - // 数据库连接参数配置 - protected $config = [ - // 数据库类型 - 'type' => '', - // 服务器地址 - 'hostname' => '', - // 数据库名 - 'database' => '', - // 用户名 - 'username' => '', - // 密码 - 'password' => '', - // 端口 - 'hostport' => '', - // 连接dsn - 'dsn' => '', - // 数据库连接参数 - 'params' => [], - // 数据库编码默认采用utf8 - 'charset' => 'utf8', - // 数据库表前缀 - 'prefix' => '', - // 数据库调试模式 - 'debug' => false, - // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) - 'deploy' => 0, - // 数据库读写是否分离 主从式有效 - 'rw_separate' => false, - // 读写分离后 主服务器数量 - 'master_num' => 1, - // 指定从服务器序号 - 'slave_no' => '', - // 模型写入后自动读取主服务器 - 'read_master' => false, - // 是否严格检查字段是否存在 - 'fields_strict' => true, - // 数据集返回类型 - 'resultset_type' => '', - // 自动写入时间戳字段 - 'auto_timestamp' => false, - // 时间字段取出后的默认时间格式 - 'datetime_format' => 'Y-m-d H:i:s', - // 是否需要进行SQL性能分析 - 'sql_explain' => false, - // Builder类 - 'builder' => '', - // Query类 - 'query' => '\\think\\db\\Query', - // 是否需要断线重连 - 'break_reconnect' => false, - // 断线标识字符串 - 'break_match_str' => [], - ]; - - // PDO连接参数 - protected $params = [ - PDO::ATTR_CASE => PDO::CASE_NATURAL, - PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, - PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL, - PDO::ATTR_STRINGIFY_FETCHES => false, - PDO::ATTR_EMULATE_PREPARES => false, - ]; - - // 服务器断线标识字符 - protected $breakMatchStr = [ - 'server has gone away', - 'no connection to the server', - 'Lost connection', - 'is dead or not enabled', - 'Error while sending', - 'decryption failed or bad record mac', - 'server closed the connection unexpectedly', - 'SSL connection has been closed unexpectedly', - 'Error writing data to the connection', - 'Resource deadlock avoided', - 'failed with errno', - ]; - - // 绑定参数 - protected $bind = []; - - /** - * 架构函数 读取数据库配置信息 - * @access public - * @param array $config 数据库配置数组 - */ - public function __construct(array $config = []) - { - if (!empty($config)) { - $this->config = array_merge($this->config, $config); - } - - // 创建Builder对象 - $class = $this->getBuilderClass(); - - $this->builder = new $class($this); - - // 执行初始化操作 - $this->initialize(); - } - - /** - * 初始化 - * @access protected - * @return void - */ - protected function initialize() - {} - - /** - * 取得数据库连接类实例 - * @access public - * @param mixed $config 连接配置 - * @param bool|string $name 连接标识 true 强制重新连接 - * @return Connection - * @throws Exception - */ - public static function instance($config = [], $name = false) - { - if (false === $name) { - $name = md5(serialize($config)); - } - - if (true === $name || !isset(self::$instance[$name])) { - if (empty($config['type'])) { - throw new InvalidArgumentException('Undefined db type'); - } - - // 记录初始化信息 - Container::get('app')->log('[ DB ] INIT ' . $config['type']); - - if (true === $name) { - $name = md5(serialize($config)); - } - - self::$instance[$name] = Loader::factory($config['type'], '\\think\\db\\connector\\', $config); - } - - return self::$instance[$name]; - } - - /** - * 获取当前连接器类对应的Builder类 - * @access public - * @return string - */ - public function getBuilderClass() - { - if (!empty($this->builderClassName)) { - return $this->builderClassName; - } - - return $this->getConfig('builder') ?: '\\think\\db\\builder\\' . ucfirst($this->getConfig('type')); - } - - /** - * 设置当前的数据库Builder对象 - * @access protected - * @param Builder $builder - * @return void - */ - protected function setBuilder(Builder $builder) - { - $this->builder = $builder; - - return $this; - } - - /** - * 获取当前的builder实例对象 - * @access public - * @return Builder - */ - public function getBuilder() - { - return $this->builder; - } - - /** - * 解析pdo连接的dsn信息 - * @access protected - * @param array $config 连接信息 - * @return string - */ - abstract protected function parseDsn($config); - - /** - * 取得数据表的字段信息 - * @access public - * @param string $tableName - * @return array - */ - abstract public function getFields($tableName); - - /** - * 取得数据库的表信息 - * @access public - * @param string $dbName - * @return array - */ - abstract public function getTables($dbName); - - /** - * SQL性能分析 - * @access protected - * @param string $sql - * @return array - */ - abstract protected function getExplain($sql); - - /** - * 对返数据表字段信息进行大小写转换出来 - * @access public - * @param array $info 字段信息 - * @return array - */ - public function fieldCase($info) - { - // 字段大小写转换 - switch ($this->attrCase) { - case PDO::CASE_LOWER: - $info = array_change_key_case($info); - break; - case PDO::CASE_UPPER: - $info = array_change_key_case($info, CASE_UPPER); - break; - case PDO::CASE_NATURAL: - default: - // 不做转换 - } - - return $info; - } - - /** - * 获取字段绑定类型 - * @access public - * @param string $type 字段类型 - * @return integer - */ - public function getFieldBindType($type) - { - if (0 === strpos($type, 'set') || 0 === strpos($type, 'enum')) { - $bind = PDO::PARAM_STR; - } elseif (preg_match('/(double|float|decimal|real|numeric)/is', $type)) { - $bind = self::PARAM_FLOAT; - } elseif (preg_match('/(int|serial|bit)/is', $type)) { - $bind = PDO::PARAM_INT; - } elseif (preg_match('/bool/is', $type)) { - $bind = PDO::PARAM_BOOL; - } else { - $bind = PDO::PARAM_STR; - } - - return $bind; - } - - /** - * 将SQL语句中的__TABLE_NAME__字符串替换成带前缀的表名(小写) - * @access public - * @param string $sql sql语句 - * @return string - */ - public function parseSqlTable($sql) - { - if (false !== strpos($sql, '__')) { - $sql = preg_replace_callback("/__([A-Z0-9_-]+)__/sU", function ($match) { - return $this->getConfig('prefix') . strtolower($match[1]); - }, $sql); - } - - return $sql; - } - - /** - * 获取数据表信息 - * @access public - * @param mixed $tableName 数据表名 留空自动获取 - * @param string $fetch 获取信息类型 包括 fields type bind pk - * @return mixed - */ - public function getTableInfo($tableName, $fetch = '') - { - if (is_array($tableName)) { - $tableName = key($tableName) ?: current($tableName); - } - - if (strpos($tableName, ',')) { - // 多表不获取字段信息 - return false; - } else { - $tableName = $this->parseSqlTable($tableName); - } - - // 修正子查询作为表名的问题 - if (strpos($tableName, ')')) { - return []; - } - - list($tableName) = explode(' ', $tableName); - - if (false === strpos($tableName, '.')) { - $schema = $this->getConfig('database') . '.' . $tableName; - } else { - $schema = $tableName; - } - - if (!isset(self::$info[$schema])) { - // 读取缓存 - $cacheFile = Container::get('app')->getRuntimePath() . 'schema' . DIRECTORY_SEPARATOR . $schema . '.php'; - - if (!$this->config['debug'] && is_file($cacheFile)) { - $info = include $cacheFile; - } else { - $info = $this->getFields($tableName); - } - - $fields = array_keys($info); - $bind = $type = []; - - foreach ($info as $key => $val) { - // 记录字段类型 - $type[$key] = $val['type']; - $bind[$key] = $this->getFieldBindType($val['type']); - - if (!empty($val['primary'])) { - $pk[] = $key; - } - } - - if (isset($pk)) { - // 设置主键 - $pk = count($pk) > 1 ? $pk : $pk[0]; - } else { - $pk = null; - } - - self::$info[$schema] = ['fields' => $fields, 'type' => $type, 'bind' => $bind, 'pk' => $pk]; - } - - return $fetch ? self::$info[$schema][$fetch] : self::$info[$schema]; - } - - /** - * 获取数据表的主键 - * @access public - * @param string $tableName 数据表名 - * @return string|array - */ - public function getPk($tableName) - { - return $this->getTableInfo($tableName, 'pk'); - } - - /** - * 获取数据表字段信息 - * @access public - * @param string $tableName 数据表名 - * @return array - */ - public function getTableFields($tableName) - { - return $this->getTableInfo($tableName, 'fields'); - } - - /** - * 获取数据表字段类型 - * @access public - * @param string $tableName 数据表名 - * @param string $field 字段名 - * @return array|string - */ - public function getFieldsType($tableName, $field = null) - { - $result = $this->getTableInfo($tableName, 'type'); - - if ($field && isset($result[$field])) { - return $result[$field]; - } - - return $result; - } - - /** - * 获取数据表绑定信息 - * @access public - * @param string $tableName 数据表名 - * @return array - */ - public function getFieldsBind($tableName) - { - return $this->getTableInfo($tableName, 'bind'); - } - - /** - * 获取数据库的配置参数 - * @access public - * @param string $config 配置名称 - * @return mixed - */ - public function getConfig($config = '') - { - return $config ? $this->config[$config] : $this->config; - } - - /** - * 设置数据库的配置参数 - * @access public - * @param string|array $config 配置名称 - * @param mixed $value 配置值 - * @return void - */ - public function setConfig($config, $value = '') - { - if (is_array($config)) { - $this->config = array_merge($this->config, $config); - } else { - $this->config[$config] = $value; - } - } - - /** - * 连接数据库方法 - * @access public - * @param array $config 连接参数 - * @param integer $linkNum 连接序号 - * @param array|bool $autoConnection 是否自动连接主数据库(用于分布式) - * @return PDO - * @throws Exception - */ - public function connect(array $config = [], $linkNum = 0, $autoConnection = false) - { - if (isset($this->links[$linkNum])) { - return $this->links[$linkNum]; - } - - if (!$config) { - $config = $this->config; - } else { - $config = array_merge($this->config, $config); - } - - // 连接参数 - if (isset($config['params']) && is_array($config['params'])) { - $params = $config['params'] + $this->params; - } else { - $params = $this->params; - } - - // 记录当前字段属性大小写设置 - $this->attrCase = $params[PDO::ATTR_CASE]; - - if (!empty($config['break_match_str'])) { - $this->breakMatchStr = array_merge($this->breakMatchStr, (array) $config['break_match_str']); - } - - try { - if (empty($config['dsn'])) { - $config['dsn'] = $this->parseDsn($config); - } - - if ($config['debug']) { - $startTime = microtime(true); - } - - $this->links[$linkNum] = new PDO($config['dsn'], $config['username'], $config['password'], $params); - - if ($config['debug']) { - // 记录数据库连接信息 - $this->log('[ DB ] CONNECT:[ UseTime:' . number_format(microtime(true) - $startTime, 6) . 's ] ' . $config['dsn']); - } - - return $this->links[$linkNum]; - } catch (\PDOException $e) { - if ($autoConnection) { - $this->log($e->getMessage(), 'error'); - return $this->connect($autoConnection, $linkNum); - } else { - throw $e; - } - } - } - - /** - * 释放查询结果 - * @access public - */ - public function free() - { - $this->PDOStatement = null; - } - - /** - * 获取PDO对象 - * @access public - * @return \PDO|false - */ - public function getPdo() - { - if (!$this->linkID) { - return false; - } - - return $this->linkID; - } - - /** - * 执行查询 使用生成器返回数据 - * @access public - * @param string $sql sql指令 - * @param array $bind 参数绑定 - * @param bool $master 是否在主服务器读操作 - * @param Model $model 模型对象实例 - * @param array $condition 查询条件 - * @param mixed $relation 关联查询 - * @return \Generator - */ - public function getCursor($sql, $bind = [], $master = false, $model = null, $condition = null, $relation = null) - { - $this->initConnect($master); - - // 记录SQL语句 - $this->queryStr = $sql; - - $this->bind = $bind; - - Db::$queryTimes++; - - // 调试开始 - $this->debug(true); - - // 预处理 - $this->PDOStatement = $this->linkID->prepare($sql); - - // 是否为存储过程调用 - $procedure = in_array(strtolower(substr(trim($sql), 0, 4)), ['call', 'exec']); - - // 参数绑定 - if ($procedure) { - $this->bindParam($bind); - } else { - $this->bindValue($bind); - } - - // 执行查询 - $this->PDOStatement->execute(); - - // 调试结束 - $this->debug(false, '', $master); - - // 返回结果集 - while ($result = $this->PDOStatement->fetch($this->fetchType)) { - if ($model) { - $instance = $model->newInstance($result, $condition); - - if ($relation) { - $instance->relationQuery($relation); - } - - yield $instance; - } else { - yield $result; - } - } - } - - /** - * 执行查询 返回数据集 - * @access public - * @param string $sql sql指令 - * @param array $bind 参数绑定 - * @param bool $master 是否在主服务器读操作 - * @param bool $pdo 是否返回PDO对象 - * @return array - * @throws BindParamException - * @throws \PDOException - * @throws \Exception - * @throws \Throwable - */ - public function query($sql, $bind = [], $master = false, $pdo = false) - { - $this->initConnect($master); - - if (!$this->linkID) { - return false; - } - - // 记录SQL语句 - $this->queryStr = $sql; - - $this->bind = $bind; - - Db::$queryTimes++; - - try { - // 调试开始 - $this->debug(true); - - // 预处理 - $this->PDOStatement = $this->linkID->prepare($sql); - - // 是否为存储过程调用 - $procedure = in_array(strtolower(substr(trim($sql), 0, 4)), ['call', 'exec']); - - // 参数绑定 - if ($procedure) { - $this->bindParam($bind); - } else { - $this->bindValue($bind); - } - - // 执行查询 - $this->PDOStatement->execute(); - - // 调试结束 - $this->debug(false, '', $master); - - // 返回结果集 - return $this->getResult($pdo, $procedure); - } catch (\PDOException $e) { - if ($this->isBreak($e)) { - return $this->close()->query($sql, $bind, $master, $pdo); - } - - throw new PDOException($e, $this->config, $this->getLastsql()); - } catch (\Throwable $e) { - if ($this->isBreak($e)) { - return $this->close()->query($sql, $bind, $master, $pdo); - } - - throw $e; - } catch (\Exception $e) { - if ($this->isBreak($e)) { - return $this->close()->query($sql, $bind, $master, $pdo); - } - - throw $e; - } - } - - /** - * 执行语句 - * @access public - * @param string $sql sql指令 - * @param array $bind 参数绑定 - * @param Query $query 查询对象 - * @return int - * @throws BindParamException - * @throws \PDOException - * @throws \Exception - * @throws \Throwable - */ - public function execute($sql, $bind = [], Query $query = null) - { - $this->initConnect(true); - - if (!$this->linkID) { - return false; - } - - // 记录SQL语句 - $this->queryStr = $sql; - - $this->bind = $bind; - - Db::$executeTimes++; - try { - // 调试开始 - $this->debug(true); - - // 预处理 - $this->PDOStatement = $this->linkID->prepare($sql); - - // 是否为存储过程调用 - $procedure = in_array(strtolower(substr(trim($sql), 0, 4)), ['call', 'exec']); - - // 参数绑定 - if ($procedure) { - $this->bindParam($bind); - } else { - $this->bindValue($bind); - } - - // 执行语句 - $this->PDOStatement->execute(); - - // 调试结束 - $this->debug(false, '', true); - - if ($query && !empty($this->config['deploy']) && !empty($this->config['read_master'])) { - $query->readMaster(); - } - - $this->numRows = $this->PDOStatement->rowCount(); - - return $this->numRows; - } catch (\PDOException $e) { - if ($this->isBreak($e)) { - return $this->close()->execute($sql, $bind, $query); - } - - throw new PDOException($e, $this->config, $this->getLastsql()); - } catch (\Throwable $e) { - if ($this->isBreak($e)) { - return $this->close()->execute($sql, $bind, $query); - } - - throw $e; - } catch (\Exception $e) { - if ($this->isBreak($e)) { - return $this->close()->execute($sql, $bind, $query); - } - - throw $e; - } - } - - /** - * 查找单条记录 - * @access public - * @param Query $query 查询对象 - * @return array|null|\PDOStatement|string - * @throws DbException - * @throws ModelNotFoundException - * @throws DataNotFoundException - */ - public function find(Query $query) - { - // 分析查询表达式 - $options = $query->getOptions(); - $pk = $query->getPk($options); - - $data = $options['data']; - $query->setOption('limit', 1); - - if (empty($options['fetch_sql']) && !empty($options['cache'])) { - // 判断查询缓存 - $cache = $options['cache']; - - if (is_string($cache['key'])) { - $key = $cache['key']; - } else { - $key = $this->getCacheKey($query, $data); - } - - $result = Container::get('cache')->get($key); - - if (false !== $result) { - return $result; - } - } - - if (is_string($pk) && !is_array($data)) { - if (isset($key) && strpos($key, '|')) { - list($a, $val) = explode('|', $key); - $item[$pk] = $val; - } else { - $item[$pk] = $data; - } - $data = $item; - } - - $query->setOption('data', $data); - - // 生成查询SQL - $sql = $this->builder->select($query); - - $query->removeOption('limit'); - - $bind = $query->getBind(); - - if (!empty($options['fetch_sql'])) { - // 获取实际执行的SQL语句 - return $this->getRealSql($sql, $bind); - } - - // 事件回调 - $result = $query->trigger('before_find'); - - if (!$result) { - // 执行查询 - $resultSet = $this->query($sql, $bind, $options['master'], $options['fetch_pdo']); - - if ($resultSet instanceof \PDOStatement) { - // 返回PDOStatement对象 - return $resultSet; - } - - $result = isset($resultSet[0]) ? $resultSet[0] : null; - } - - if (isset($cache) && $result) { - // 缓存数据 - $this->cacheData($key, $result, $cache); - } - - return $result; - } - - /** - * 使用游标查询记录 - * @access public - * @param Query $query 查询对象 - * @return \Generator - */ - public function cursor(Query $query) - { - // 分析查询表达式 - $options = $query->getOptions(); - - // 生成查询SQL - $sql = $this->builder->select($query); - - $bind = $query->getBind(); - - $condition = isset($options['where']['AND']) ? $options['where']['AND'] : null; - $relation = isset($options['relaltion']) ? $options['relation'] : null; - - // 执行查询操作 - return $this->getCursor($sql, $bind, $options['master'], $query->getModel(), $condition, $relation); - } - - /** - * 查找记录 - * @access public - * @param Query $query 查询对象 - * @return array|\PDOStatement|string - * @throws DbException - * @throws ModelNotFoundException - * @throws DataNotFoundException - */ - public function select(Query $query) - { - // 分析查询表达式 - $options = $query->getOptions(); - - if (empty($options['fetch_sql']) && !empty($options['cache'])) { - $resultSet = $this->getCacheData($query, $options['cache'], null, $key); - - if (false !== $resultSet) { - return $resultSet; - } - } - - // 生成查询SQL - $sql = $this->builder->select($query); - - $query->removeOption('limit'); - - $bind = $query->getBind(); - - if (!empty($options['fetch_sql'])) { - // 获取实际执行的SQL语句 - return $this->getRealSql($sql, $bind); - } - - $resultSet = $query->trigger('before_select'); - - if (!$resultSet) { - // 执行查询操作 - $resultSet = $this->query($sql, $bind, $options['master'], $options['fetch_pdo']); - - if ($resultSet instanceof \PDOStatement) { - // 返回PDOStatement对象 - return $resultSet; - } - } - - if (!empty($options['cache']) && false !== $resultSet) { - // 缓存数据集 - $this->cacheData($key, $resultSet, $options['cache']); - } - - return $resultSet; - } - - /** - * 插入记录 - * @access public - * @param Query $query 查询对象 - * @param boolean $replace 是否replace - * @param boolean $getLastInsID 返回自增主键 - * @param string $sequence 自增序列名 - * @return integer|string - */ - public function insert(Query $query, $replace = false, $getLastInsID = false, $sequence = null) - { - // 分析查询表达式 - $options = $query->getOptions(); - - // 生成SQL语句 - $sql = $this->builder->insert($query, $replace); - - $bind = $query->getBind(); - - if (!empty($options['fetch_sql'])) { - // 获取实际执行的SQL语句 - return $this->getRealSql($sql, $bind); - } - - // 执行操作 - $result = '' == $sql ? 0 : $this->execute($sql, $bind, $query); - - if ($result) { - $sequence = $sequence ?: (isset($options['sequence']) ? $options['sequence'] : null); - $lastInsId = $this->getLastInsID($sequence); - - $data = $options['data']; - - if ($lastInsId) { - $pk = $query->getPk($options); - if (is_string($pk)) { - $data[$pk] = $lastInsId; - } - } - - $query->setOption('data', $data); - - $query->trigger('after_insert'); - - if ($getLastInsID) { - return $lastInsId; - } - } - - return $result; - } - - /** - * 批量插入记录 - * @access public - * @param Query $query 查询对象 - * @param mixed $dataSet 数据集 - * @param bool $replace 是否replace - * @param integer $limit 每次写入数据限制 - * @return integer|string - * @throws \Exception - * @throws \Throwable - */ - public function insertAll(Query $query, $dataSet = [], $replace = false, $limit = null) - { - if (!is_array(reset($dataSet))) { - return false; - } - - $options = $query->getOptions(); - - if ($limit) { - // 分批写入 自动启动事务支持 - $this->startTrans(); - - try { - $array = array_chunk($dataSet, $limit, true); - $count = 0; - - foreach ($array as $item) { - $sql = $this->builder->insertAll($query, $item, $replace); - $bind = $query->getBind(); - - if (!empty($options['fetch_sql'])) { - $fetchSql[] = $this->getRealSql($sql, $bind); - } else { - $count += $this->execute($sql, $bind, $query); - } - } - - // 提交事务 - $this->commit(); - } catch (\Exception $e) { - $this->rollback(); - throw $e; - } catch (\Throwable $e) { - $this->rollback(); - throw $e; - } - - return isset($fetchSql) ? implode(';', $fetchSql) : $count; - } - - $sql = $this->builder->insertAll($query, $dataSet, $replace); - $bind = $query->getBind(); - - if (!empty($options['fetch_sql'])) { - return $this->getRealSql($sql, $bind); - } - - return $this->execute($sql, $bind, $query); - } - - /** - * 通过Select方式插入记录 - * @access public - * @param Query $query 查询对象 - * @param string $fields 要插入的数据表字段名 - * @param string $table 要插入的数据表名 - * @return integer|string - * @throws PDOException - */ - public function selectInsert(Query $query, $fields, $table) - { - // 分析查询表达式 - $options = $query->getOptions(); - - $table = $this->parseSqlTable($table); - - $sql = $this->builder->selectInsert($query, $fields, $table); - - $bind = $query->getBind(); - - if (!empty($options['fetch_sql'])) { - return $this->getRealSql($sql, $bind); - } - - return $this->execute($sql, $bind, $query); - } - - /** - * 更新记录 - * @access public - * @param Query $query 查询对象 - * @return integer|string - * @throws Exception - * @throws PDOException - */ - public function update(Query $query) - { - $options = $query->getOptions(); - - if (isset($options['cache']) && is_string($options['cache']['key'])) { - $key = $options['cache']['key']; - } - - $pk = $query->getPk($options); - $data = $options['data']; - - if (empty($options['where'])) { - // 如果存在主键数据 则自动作为更新条件 - if (is_string($pk) && isset($data[$pk])) { - $where[$pk] = [$pk, '=', $data[$pk]]; - if (!isset($key)) { - $key = $this->getCacheKey($query, $data[$pk]); - } - unset($data[$pk]); - } elseif (is_array($pk)) { - // 增加复合主键支持 - foreach ($pk as $field) { - if (isset($data[$field])) { - $where[$field] = [$field, '=', $data[$field]]; - } else { - // 如果缺少复合主键数据则不执行 - throw new Exception('miss complex primary data'); - } - unset($data[$field]); - } - } - - if (!isset($where)) { - // 如果没有任何更新条件则不执行 - throw new Exception('miss update condition'); - } else { - $options['where']['AND'] = $where; - $query->setOption('where', ['AND' => $where]); - } - } elseif (!isset($key) && is_string($pk) && isset($options['where']['AND'])) { - foreach ($options['where']['AND'] as $val) { - if (is_array($val) && $val[0] == $pk) { - $key = $this->getCacheKey($query, $val); - } - } - } - - // 更新数据 - $query->setOption('data', $data); - - // 生成UPDATE SQL语句 - $sql = $this->builder->update($query); - $bind = $query->getBind(); - - if (!empty($options['fetch_sql'])) { - // 获取实际执行的SQL语句 - return $this->getRealSql($sql, $bind); - } - - // 检测缓存 - $cache = Container::get('cache'); - - if (isset($key) && $cache->get($key)) { - // 删除缓存 - $cache->rm($key); - } elseif (!empty($options['cache']['tag'])) { - $cache->clear($options['cache']['tag']); - } - - // 执行操作 - $result = '' == $sql ? 0 : $this->execute($sql, $bind, $query); - - if ($result) { - if (is_string($pk) && isset($where[$pk])) { - $data[$pk] = $where[$pk]; - } elseif (is_string($pk) && isset($key) && strpos($key, '|')) { - list($a, $val) = explode('|', $key); - $data[$pk] = $val; - } - - $query->setOption('data', $data); - $query->trigger('after_update'); - } - - return $result; - } - - /** - * 删除记录 - * @access public - * @param Query $query 查询对象 - * @return int - * @throws Exception - * @throws PDOException - */ - public function delete(Query $query) - { - // 分析查询表达式 - $options = $query->getOptions(); - $pk = $query->getPk($options); - $data = $options['data']; - - if (isset($options['cache']) && is_string($options['cache']['key'])) { - $key = $options['cache']['key']; - } elseif (!is_null($data) && true !== $data && !is_array($data)) { - $key = $this->getCacheKey($query, $data); - } elseif (is_string($pk) && isset($options['where']['AND'])) { - foreach ($options['where']['AND'] as $val) { - if (is_array($val) && $val[0] == $pk) { - $key = $this->getCacheKey($query, $val); - } - } - } - - if (true !== $data && empty($options['where'])) { - // 如果条件为空 不进行删除操作 除非设置 1=1 - throw new Exception('delete without condition'); - } - - // 生成删除SQL语句 - $sql = $this->builder->delete($query); - - $bind = $query->getBind(); - - if (!empty($options['fetch_sql'])) { - // 获取实际执行的SQL语句 - return $this->getRealSql($sql, $bind); - } - - // 检测缓存 - $cache = Container::get('cache'); - - if (isset($key) && $cache->get($key)) { - // 删除缓存 - $cache->rm($key); - } elseif (!empty($options['cache']['tag'])) { - $cache->clear($options['cache']['tag']); - } - - // 执行操作 - $result = $this->execute($sql, $bind, $query); - - if ($result) { - if (!is_array($data) && is_string($pk) && isset($key) && strpos($key, '|')) { - list($a, $val) = explode('|', $key); - $item[$pk] = $val; - $data = $item; - } - - $options['data'] = $data; - - $query->trigger('after_delete'); - } - - return $result; - } - - /** - * 得到某个字段的值 - * @access public - * @param Query $query 查询对象 - * @param string $field 字段名 - * @param bool $default 默认值 - * @return mixed - */ - public function value(Query $query, $field, $default = null) - { - $options = $query->getOptions(); - - if (empty($options['fetch_sql']) && !empty($options['cache'])) { - $cache = $options['cache']; - $result = $this->getCacheData($query, $cache, null, $key); - - if (false !== $result) { - return $result; - } - } - - if (isset($options['field'])) { - $query->removeOption('field'); - } - - if (is_string($field)) { - $field = array_map('trim', explode(',', $field)); - } - - $query->setOption('field', $field); - $query->setOption('limit', 1); - - // 生成查询SQL - $sql = $this->builder->select($query); - - if (isset($options['field'])) { - $query->setOption('field', $options['field']); - } else { - $query->removeOption('field'); - } - - $query->removeOption('limit'); - - $bind = $query->getBind(); - - if (!empty($options['fetch_sql'])) { - // 获取实际执行的SQL语句 - return $this->getRealSql($sql, $bind); - } - - // 执行查询操作 - $pdo = $this->query($sql, $bind, $options['master'], true); - - $result = $pdo->fetchColumn(); - - if (isset($cache) && false !== $result) { - // 缓存数据 - $this->cacheData($key, $result, $cache); - } - - return false !== $result ? $result : $default; - } - - /** - * 得到某个字段的值 - * @access public - * @param Query $query 查询对象 - * @param string $aggregate 聚合方法 - * @param mixed $field 字段名 - * @return mixed - */ - public function aggregate(Query $query, $aggregate, $field) - { - if (is_string($field) && 0 === stripos($field, 'DISTINCT ')) { - list($distinct, $field) = explode(' ', $field); - } - - $field = $aggregate . '(' . (!empty($distinct) ? 'DISTINCT ' : '') . $this->builder->parseKey($query, $field, true) . ') AS tp_' . strtolower($aggregate); - - return $this->value($query, $field, 0); - } - - /** - * 得到某个列的数组 - * @access public - * @param Query $query 查询对象 - * @param string $field 字段名 多个字段用逗号分隔 - * @param string $key 索引 - * @return array - */ - public function column(Query $query, $field, $key = '') - { - $options = $query->getOptions(); - - if (empty($options['fetch_sql']) && !empty($options['cache'])) { - // 判断查询缓存 - $cache = $options['cache']; - $result = $this->getCacheData($query, $cache, null, $guid); - - if (false !== $result) { - return $result; - } - } - - if (isset($options['field'])) { - $query->removeOption('field'); - } - - if (is_null($field)) { - $field = ['*']; - } elseif (is_string($field)) { - $field = array_map('trim', explode(',', $field)); - } - - if ($key && ['*'] != $field) { - array_unshift($field, $key); - $field = array_unique($field); - } - - $query->setOption('field', $field); - - // 生成查询SQL - $sql = $this->builder->select($query); - - // 还原field参数 - if (isset($options['field'])) { - $query->setOption('field', $options['field']); - } else { - $query->removeOption('field'); - } - - $bind = $query->getBind(); - - if (!empty($options['fetch_sql'])) { - // 获取实际执行的SQL语句 - return $this->getRealSql($sql, $bind); - } - - // 执行查询操作 - $pdo = $this->query($sql, $bind, $options['master'], true); - - if (1 == $pdo->columnCount()) { - $result = $pdo->fetchAll(PDO::FETCH_COLUMN); - } else { - $resultSet = $pdo->fetchAll(PDO::FETCH_ASSOC); - - if (['*'] == $field && $key) { - $result = array_column($resultSet, null, $key); - } elseif ($resultSet) { - $fields = array_keys($resultSet[0]); - $count = count($fields); - $key1 = array_shift($fields); - $key2 = $fields ? array_shift($fields) : ''; - $key = $key ?: $key1; - - if (strpos($key, '.')) { - list($alias, $key) = explode('.', $key); - } - - if (2 == $count) { - $column = $key2; - } elseif (1 == $count) { - $column = $key1; - } else { - $column = null; - } - - $result = array_column($resultSet, $column, $key); - } else { - $result = []; - } - } - - if (isset($cache) && isset($guid)) { - // 缓存数据 - $this->cacheData($guid, $result, $cache); - } - - return $result; - } - - /** - * 执行查询但只返回PDOStatement对象 - * @access public - * @return \PDOStatement|string - */ - public function pdo(Query $query) - { - // 分析查询表达式 - $options = $query->getOptions(); - - // 生成查询SQL - $sql = $this->builder->select($query); - - $bind = $query->getBind(); - - if (!empty($options['fetch_sql'])) { - // 获取实际执行的SQL语句 - return $this->getRealSql($sql, $bind); - } - - // 执行查询操作 - return $this->query($sql, $bind, $options['master'], true); - } - - /** - * 根据参数绑定组装最终的SQL语句 便于调试 - * @access public - * @param string $sql 带参数绑定的sql语句 - * @param array $bind 参数绑定列表 - * @return string - */ - public function getRealSql($sql, array $bind = []) - { - if (is_array($sql)) { - $sql = implode(';', $sql); - } - - foreach ($bind as $key => $val) { - $value = is_array($val) ? $val[0] : $val; - $type = is_array($val) ? $val[1] : PDO::PARAM_STR; - - if (self::PARAM_FLOAT == $type) { - $value = (float) $value; - } elseif (PDO::PARAM_STR == $type) { - $value = '\'' . addslashes($value) . '\''; - } elseif (PDO::PARAM_INT == $type && '' === $value) { - $value = 0; - } - - // 判断占位符 - $sql = is_numeric($key) ? - substr_replace($sql, $value, strpos($sql, '?'), 1) : - substr_replace($sql, $value, strpos($sql, ':' . $key), strlen(':' . $key)); - } - - return rtrim($sql); - } - - /** - * 参数绑定 - * 支持 ['name'=>'value','id'=>123] 对应命名占位符 - * 或者 ['value',123] 对应问号占位符 - * @access public - * @param array $bind 要绑定的参数列表 - * @return void - * @throws BindParamException - */ - protected function bindValue(array $bind = []) - { - foreach ($bind as $key => $val) { - // 占位符 - $param = is_int($key) ? $key + 1 : ':' . $key; - - if (is_array($val)) { - if (PDO::PARAM_INT == $val[1] && '' === $val[0]) { - $val[0] = 0; - } elseif (self::PARAM_FLOAT == $val[1]) { - $val[0] = (float) $val[0]; - $val[1] = PDO::PARAM_STR; - } - - $result = $this->PDOStatement->bindValue($param, $val[0], $val[1]); - } else { - $result = $this->PDOStatement->bindValue($param, $val); - } - - if (!$result) { - throw new BindParamException( - "Error occurred when binding parameters '{$param}'", - $this->config, - $this->getLastsql(), - $bind - ); - } - } - } - - /** - * 存储过程的输入输出参数绑定 - * @access public - * @param array $bind 要绑定的参数列表 - * @return void - * @throws BindParamException - */ - protected function bindParam($bind) - { - foreach ($bind as $key => $val) { - $param = is_int($key) ? $key + 1 : ':' . $key; - - if (is_array($val)) { - array_unshift($val, $param); - $result = call_user_func_array([$this->PDOStatement, 'bindParam'], $val); - } else { - $result = $this->PDOStatement->bindValue($param, $val); - } - - if (!$result) { - $param = array_shift($val); - - throw new BindParamException( - "Error occurred when binding parameters '{$param}'", - $this->config, - $this->getLastsql(), - $bind - ); - } - } - } - - /** - * 获得数据集数组 - * @access protected - * @param bool $pdo 是否返回PDOStatement - * @param bool $procedure 是否存储过程 - * @return array - */ - protected function getResult($pdo = false, $procedure = false) - { - if ($pdo) { - // 返回PDOStatement对象处理 - return $this->PDOStatement; - } - - if ($procedure) { - // 存储过程返回结果 - return $this->procedure(); - } - - $result = $this->PDOStatement->fetchAll($this->fetchType); - - $this->numRows = count($result); - - return $result; - } - - /** - * 获得存储过程数据集 - * @access protected - * @return array - */ - protected function procedure() - { - $item = []; - - do { - $result = $this->getResult(); - if ($result) { - $item[] = $result; - } - } while ($this->PDOStatement->nextRowset()); - - $this->numRows = count($item); - - return $item; - } - - /** - * 执行数据库事务 - * @access public - * @param callable $callback 数据操作方法回调 - * @return mixed - * @throws PDOException - * @throws \Exception - * @throws \Throwable - */ - public function transaction($callback) - { - $this->startTrans(); - - try { - $result = null; - if (is_callable($callback)) { - $result = call_user_func_array($callback, [$this]); - } - - $this->commit(); - return $result; - } catch (\Exception $e) { - $this->rollback(); - throw $e; - } catch (\Throwable $e) { - $this->rollback(); - throw $e; - } - } - - /** - * 启动XA事务 - * @access public - * @param string $xid XA事务id - * @return void - */ - public function startTransXa($xid) - {} - - /** - * 预编译XA事务 - * @access public - * @param string $xid XA事务id - * @return void - */ - public function prepareXa($xid) - {} - - /** - * 提交XA事务 - * @access public - * @param string $xid XA事务id - * @return void - */ - public function commitXa($xid) - {} - - /** - * 回滚XA事务 - * @access public - * @param string $xid XA事务id - * @return void - */ - public function rollbackXa($xid) - {} - - /** - * 启动事务 - * @access public - * @return void - * @throws \PDOException - * @throws \Exception - */ - public function startTrans() - { - $this->initConnect(true); - if (!$this->linkID) { - return false; - } - - ++$this->transTimes; - - try { - if (1 == $this->transTimes) { - $this->linkID->beginTransaction(); - } elseif ($this->transTimes > 1 && $this->supportSavepoint()) { - $this->linkID->exec( - $this->parseSavepoint('trans' . $this->transTimes) - ); - } - } catch (\Exception $e) { - if ($this->isBreak($e)) { - --$this->transTimes; - return $this->close()->startTrans(); - } - throw $e; - } - } - - /** - * 用于非自动提交状态下面的查询提交 - * @access public - * @return void - * @throws PDOException - */ - public function commit() - { - $this->initConnect(true); - - if (1 == $this->transTimes) { - $this->linkID->commit(); - } - - --$this->transTimes; - } - - /** - * 事务回滚 - * @access public - * @return void - * @throws PDOException - */ - public function rollback() - { - $this->initConnect(true); - - if (1 == $this->transTimes) { - $this->linkID->rollBack(); - } elseif ($this->transTimes > 1 && $this->supportSavepoint()) { - $this->linkID->exec( - $this->parseSavepointRollBack('trans' . $this->transTimes) - ); - } - - $this->transTimes = max(0, $this->transTimes - 1); - } - - /** - * 是否支持事务嵌套 - * @return bool - */ - protected function supportSavepoint() - { - return false; - } - - /** - * 生成定义保存点的SQL - * @access protected - * @param $name - * @return string - */ - protected function parseSavepoint($name) - { - return 'SAVEPOINT ' . $name; - } - - /** - * 生成回滚到保存点的SQL - * @access protected - * @param $name - * @return string - */ - protected function parseSavepointRollBack($name) - { - return 'ROLLBACK TO SAVEPOINT ' . $name; - } - - /** - * 批处理执行SQL语句 - * 批处理的指令都认为是execute操作 - * @access public - * @param array $sqlArray SQL批处理指令 - * @param array $bind 参数绑定 - * @return boolean - */ - public function batchQuery($sqlArray = [], $bind = []) - { - if (!is_array($sqlArray)) { - return false; - } - - // 自动启动事务支持 - $this->startTrans(); - - try { - foreach ($sqlArray as $sql) { - $this->execute($sql, $bind); - } - // 提交事务 - $this->commit(); - } catch (\Exception $e) { - $this->rollback(); - throw $e; - } - - return true; - } - - /** - * 获得查询次数 - * @access public - * @param boolean $execute 是否包含所有查询 - * @return integer - */ - public function getQueryTimes($execute = false) - { - return $execute ? Db::$queryTimes + Db::$executeTimes : Db::$queryTimes; - } - - /** - * 获得执行次数 - * @access public - * @return integer - */ - public function getExecuteTimes() - { - return Db::$executeTimes; - } - - /** - * 关闭数据库(或者重新连接) - * @access public - * @return $this - */ - public function close() - { - $this->linkID = null; - $this->linkWrite = null; - $this->linkRead = null; - $this->links = []; - - // 释放查询 - $this->free(); - - return $this; - } - - /** - * 是否断线 - * @access protected - * @param \PDOException|\Exception $e 异常对象 - * @return bool - */ - protected function isBreak($e) - { - if (!$this->config['break_reconnect']) { - return false; - } - - $error = $e->getMessage(); - - foreach ($this->breakMatchStr as $msg) { - if (false !== stripos($error, $msg)) { - return true; - } - } - return false; - } - - /** - * 获取最近一次查询的sql语句 - * @access public - * @return string - */ - public function getLastSql() - { - return $this->getRealSql($this->queryStr, $this->bind); - } - - /** - * 获取最近插入的ID - * @access public - * @param string $sequence 自增序列名 - * @return string - */ - public function getLastInsID($sequence = null) - { - return $this->linkID->lastInsertId($sequence); - } - - /** - * 获取返回或者影响的记录数 - * @access public - * @return integer - */ - public function getNumRows() - { - return $this->numRows; - } - - /** - * 获取最近的错误信息 - * @access public - * @return string - */ - public function getError() - { - if ($this->PDOStatement) { - $error = $this->PDOStatement->errorInfo(); - $error = $error[1] . ':' . $error[2]; - } else { - $error = ''; - } - - if ('' != $this->queryStr) { - $error .= "\n [ SQL语句 ] : " . $this->getLastsql(); - } - - return $error; - } - - /** - * 数据库调试 记录当前SQL及分析性能 - * @access protected - * @param boolean $start 调试开始标记 true 开始 false 结束 - * @param string $sql 执行的SQL语句 留空自动获取 - * @param bool $master 主从标记 - * @return void - */ - protected function debug($start, $sql = '', $master = false) - { - if (!empty($this->config['debug'])) { - // 开启数据库调试模式 - $debug = Container::get('debug'); - - if ($start) { - $debug->remark('queryStartTime', 'time'); - } else { - // 记录操作结束时间 - $debug->remark('queryEndTime', 'time'); - $runtime = $debug->getRangeTime('queryStartTime', 'queryEndTime'); - $sql = $sql ?: $this->getLastsql(); - $result = []; - - // SQL性能分析 - if ($this->config['sql_explain'] && 0 === stripos(trim($sql), 'select')) { - $result = $this->getExplain($sql); - } - - // SQL监听 - $this->triggerSql($sql, $runtime, $result, $master); - } - } - } - - /** - * 监听SQL执行 - * @access public - * @param callable $callback 回调方法 - * @return void - */ - public function listen($callback) - { - self::$event[] = $callback; - } - - /** - * 触发SQL事件 - * @access protected - * @param string $sql SQL语句 - * @param float $runtime SQL运行时间 - * @param mixed $explain SQL分析 - * @param bool $master 主从标记 - * @return void - */ - protected function triggerSql($sql, $runtime, $explain = [], $master = false) - { - if (!empty(self::$event)) { - foreach (self::$event as $callback) { - if (is_callable($callback)) { - call_user_func_array($callback, [$sql, $runtime, $explain, $master]); - } - } - } else { - if ($this->config['deploy']) { - // 分布式记录当前操作的主从 - $master = $master ? 'master|' : 'slave|'; - } else { - $master = ''; - } - - // 未注册监听则记录到日志中 - $this->log('[ SQL ] ' . $sql . ' [ ' . $master . 'RunTime:' . $runtime . 's ]'); - - if (!empty($explain)) { - $this->log('[ EXPLAIN : ' . var_export($explain, true) . ' ]'); - } - } - } - - public function log($log, $type = 'sql') - { - $this->config['debug'] && Container::get('log')->record($log, $type); - } - - /** - * 初始化数据库连接 - * @access protected - * @param boolean $master 是否主服务器 - * @return void - */ - protected function initConnect($master = true) - { - if (!empty($this->config['deploy'])) { - // 采用分布式数据库 - if ($master || $this->transTimes) { - if (!$this->linkWrite) { - $this->linkWrite = $this->multiConnect(true); - } - - $this->linkID = $this->linkWrite; - } else { - if (!$this->linkRead) { - $this->linkRead = $this->multiConnect(false); - } - - $this->linkID = $this->linkRead; - } - } elseif (!$this->linkID) { - // 默认单数据库 - $this->linkID = $this->connect(); - } - } - - /** - * 连接分布式服务器 - * @access protected - * @param boolean $master 主服务器 - * @return PDO - */ - protected function multiConnect($master = false) - { - $_config = []; - - // 分布式数据库配置解析 - foreach (['username', 'password', 'hostname', 'hostport', 'database', 'dsn', 'charset'] as $name) { - $_config[$name] = is_string($this->config[$name]) ? explode(',', $this->config[$name]) : $this->config[$name]; - } - - // 主服务器序号 - $m = floor(mt_rand(0, $this->config['master_num'] - 1)); - - if ($this->config['rw_separate']) { - // 主从式采用读写分离 - if ($master) // 主服务器写入 - { - $r = $m; - } elseif (is_numeric($this->config['slave_no'])) { - // 指定服务器读 - $r = $this->config['slave_no']; - } else { - // 读操作连接从服务器 每次随机连接的数据库 - $r = floor(mt_rand($this->config['master_num'], count($_config['hostname']) - 1)); - } - } else { - // 读写操作不区分服务器 每次随机连接的数据库 - $r = floor(mt_rand(0, count($_config['hostname']) - 1)); - } - $dbMaster = false; - - if ($m != $r) { - $dbMaster = []; - foreach (['username', 'password', 'hostname', 'hostport', 'database', 'dsn', 'charset'] as $name) { - $dbMaster[$name] = isset($_config[$name][$m]) ? $_config[$name][$m] : $_config[$name][0]; - } - } - - $dbConfig = []; - - foreach (['username', 'password', 'hostname', 'hostport', 'database', 'dsn', 'charset'] as $name) { - $dbConfig[$name] = isset($_config[$name][$r]) ? $_config[$name][$r] : $_config[$name][0]; - } - - return $this->connect($dbConfig, $r, $r == $m ? false : $dbMaster); - } - - /** - * 析构方法 - * @access public - */ - public function __destruct() - { - // 关闭连接 - $this->close(); - } - - /** - * 缓存数据 - * @access protected - * @param string $key 缓存标识 - * @param mixed $data 缓存数据 - * @param array $config 缓存参数 - */ - protected function cacheData($key, $data, $config = []) - { - $cache = Container::get('cache'); - - if (isset($config['tag'])) { - $cache->tag($config['tag'])->set($key, $data, $config['expire']); - } else { - $cache->set($key, $data, $config['expire']); - } - } - - /** - * 获取缓存数据 - * @access protected - * @param Query $query 查询对象 - * @param mixed $cache 缓存设置 - * @param array $options 缓存 - * @return mixed - */ - protected function getCacheData(Query $query, $cache, $data, &$key = null) - { - // 判断查询缓存 - $key = is_string($cache['key']) ? $cache['key'] : $this->getCacheKey($query, $data); - - return Container::get('cache')->get($key); - } - - /** - * 生成缓存标识 - * @access protected - * @param Query $query 查询对象 - * @param mixed $value 缓存数据 - * @return string - */ - protected function getCacheKey(Query $query, $value) - { - if (is_scalar($value)) { - $data = $value; - } elseif (is_array($value) && isset($value[1], $value[2]) && in_array($value[1], ['=', 'eq'], true) && is_scalar($value[2])) { - $data = $value[2]; - } - - $prefix = 'think:' . $this->getConfig('database') . '.'; - - if (isset($data)) { - return $prefix . $query->getTable() . '|' . $data; - } - - try { - return md5($prefix . serialize($query->getOptions()) . serialize($query->getBind(false))); - } catch (\Exception $e) { - throw new Exception('closure not support cache(true)'); - } - } - -} diff --git a/thinkphp/library/think/db/Query.php b/thinkphp/library/think/db/Query.php deleted file mode 100755 index 5c9cfa9b9..000000000 --- a/thinkphp/library/think/db/Query.php +++ /dev/null @@ -1,3734 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\db; - -use PDO; -use think\Collection; -use think\Container; -use think\Db; -use think\db\exception\BindParamException; -use think\db\exception\DataNotFoundException; -use think\db\exception\ModelNotFoundException; -use think\Exception; -use think\exception\DbException; -use think\exception\PDOException; -use think\Loader; -use think\Model; -use think\model\Collection as ModelCollection; -use think\model\Relation; -use think\model\relation\OneToOne; -use think\Paginator; - -class Query -{ - /** - * 当前数据库连接对象 - * @var Connection - */ - protected $connection; - - /** - * 当前模型对象 - * @var Model - */ - protected $model; - - /** - * 当前数据表名称(不含前缀) - * @var string - */ - protected $name = ''; - - /** - * 当前数据表主键 - * @var string|array - */ - protected $pk; - - /** - * 当前数据表前缀 - * @var string - */ - protected $prefix = ''; - - /** - * 当前查询参数 - * @var array - */ - protected $options = []; - - /** - * 当前参数绑定 - * @var array - */ - protected $bind = []; - - /** - * 事件回调 - * @var array - */ - private static $event = []; - - /** - * 扩展查询方法 - * @var array - */ - private static $extend = []; - - /** - * 读取主库的表 - * @var array - */ - protected static $readMaster = []; - - /** - * 日期查询表达式 - * @var array - */ - protected $timeRule = [ - 'today' => ['today', 'tomorrow'], - 'yesterday' => ['yesterday', 'today'], - 'week' => ['this week 00:00:00', 'next week 00:00:00'], - 'last week' => ['last week 00:00:00', 'this week 00:00:00'], - 'month' => ['first Day of this month 00:00:00', 'first Day of next month 00:00:00'], - 'last month' => ['first Day of last month 00:00:00', 'first Day of this month 00:00:00'], - 'year' => ['this year 1/1', 'next year 1/1'], - 'last year' => ['last year 1/1', 'this year 1/1'], - ]; - - /** - * 日期查询快捷定义 - * @var array - */ - protected $timeExp = ['d' => 'today', 'w' => 'week', 'm' => 'month', 'y' => 'year']; - - /** - * 架构函数 - * @access public - */ - public function __construct(Connection $connection = null) - { - if (is_null($connection)) { - $this->connection = Db::connect(); - } else { - $this->connection = $connection; - } - - $this->prefix = $this->connection->getConfig('prefix'); - } - - /** - * 创建一个新的查询对象 - * @access public - * @return Query - */ - public function newQuery() - { - return new static($this->connection); - } - - /** - * 利用__call方法实现一些特殊的Model方法 - * @access public - * @param string $method 方法名称 - * @param array $args 调用参数 - * @return mixed - * @throws DbException - * @throws Exception - */ - public function __call($method, $args) - { - if (isset(self::$extend[strtolower($method)])) { - // 调用扩展查询方法 - array_unshift($args, $this); - - return Container::getInstance() - ->invoke(self::$extend[strtolower($method)], $args); - } elseif (strtolower(substr($method, 0, 5)) == 'getby') { - // 根据某个字段获取记录 - $field = Loader::parseName(substr($method, 5)); - return $this->where($field, '=', $args[0])->find(); - } elseif (strtolower(substr($method, 0, 10)) == 'getfieldby') { - // 根据某个字段获取记录的某个值 - $name = Loader::parseName(substr($method, 10)); - return $this->where($name, '=', $args[0])->value($args[1]); - } elseif (strtolower(substr($method, 0, 7)) == 'whereor') { - $name = Loader::parseName(substr($method, 7)); - array_unshift($args, $name); - return call_user_func_array([$this, 'whereOr'], $args); - } elseif (strtolower(substr($method, 0, 5)) == 'where') { - $name = Loader::parseName(substr($method, 5)); - array_unshift($args, $name); - return call_user_func_array([$this, 'where'], $args); - } elseif ($this->model && method_exists($this->model, 'scope' . $method)) { - // 动态调用命名范围 - $method = 'scope' . $method; - array_unshift($args, $this); - - call_user_func_array([$this->model, $method], $args); - return $this; - } else { - throw new Exception('method not exist:' . ($this->model ? get_class($this->model) : static::class) . '->' . $method); - } - } - - /** - * 扩展查询方法 - * @access public - * @param string|array $method 查询方法名 - * @param callable $callback - * @return void - */ - public static function extend($method, $callback = null) - { - if (is_array($method)) { - foreach ($method as $key => $val) { - self::$extend[strtolower($key)] = $val; - } - } else { - self::$extend[strtolower($method)] = $callback; - } - } - - /** - * 设置当前的数据库Connection对象 - * @access public - * @param Connection $connection - * @return $this - */ - public function setConnection(Connection $connection) - { - $this->connection = $connection; - $this->prefix = $this->connection->getConfig('prefix'); - - return $this; - } - - /** - * 获取当前的数据库Connection对象 - * @access public - * @return Connection - */ - public function getConnection() - { - return $this->connection; - } - - /** - * 指定模型 - * @access public - * @param Model $model 模型对象实例 - * @return $this - */ - public function model(Model $model) - { - $this->model = $model; - return $this; - } - - /** - * 获取当前的模型对象 - * @access public - * @return Model|null - */ - public function getModel() - { - return $this->model ? $this->model->setQuery($this) : null; - } - - /** - * 设置从主库读取数据 - * @access public - * @param bool $all 是否所有表有效 - * @return $this - */ - public function readMaster($all = false) - { - $table = $all ? '*' : $this->getTable(); - - static::$readMaster[$table] = true; - - return $this; - } - - /** - * 指定当前数据表名(不含前缀) - * @access public - * @param string $name - * @return $this - */ - public function name($name) - { - $this->name = $name; - return $this; - } - - /** - * 获取当前的数据表名称 - * @access public - * @return string - */ - public function getName() - { - return $this->name ?: $this->model->getName(); - } - - /** - * 得到当前或者指定名称的数据表 - * @access public - * @param string $name - * @return string - */ - public function getTable($name = '') - { - if (empty($name) && isset($this->options['table'])) { - return $this->options['table']; - } - - $name = $name ?: $this->name; - - return $this->prefix . Loader::parseName($name); - } - - /** - * 执行查询 返回数据集 - * @access public - * @param string $sql sql指令 - * @param array $bind 参数绑定 - * @param boolean $master 是否在主服务器读操作 - * @param bool $pdo 是否返回PDO对象 - * @return mixed - * @throws BindParamException - * @throws PDOException - */ - public function query($sql, $bind = [], $master = false, $pdo = false) - { - return $this->connection->query($sql, $bind, $master, $pdo); - } - - /** - * 执行语句 - * @access public - * @param string $sql sql指令 - * @param array $bind 参数绑定 - * @return int - * @throws BindParamException - * @throws PDOException - */ - public function execute($sql, $bind = []) - { - return $this->connection->execute($sql, $bind, $this); - } - - /** - * 监听SQL执行 - * @access public - * @param callable $callback 回调方法 - * @return void - */ - public function listen($callback) - { - $this->connection->listen($callback); - } - - /** - * 获取最近插入的ID - * @access public - * @param string $sequence 自增序列名 - * @return string - */ - public function getLastInsID($sequence = null) - { - return $this->connection->getLastInsID($sequence); - } - - /** - * 获取返回或者影响的记录数 - * @access public - * @return integer - */ - public function getNumRows() - { - return $this->connection->getNumRows(); - } - - /** - * 获取最近一次查询的sql语句 - * @access public - * @return string - */ - public function getLastSql() - { - return $this->connection->getLastSql(); - } - - /** - * 执行数据库Xa事务 - * @access public - * @param callable $callback 数据操作方法回调 - * @param array $dbs 多个查询对象或者连接对象 - * @return mixed - * @throws PDOException - * @throws \Exception - * @throws \Throwable - */ - public function transactionXa($callback, array $dbs = []) - { - $xid = uniqid('xa'); - - if (empty($dbs)) { - $dbs[] = $this->getConnection(); - } - - foreach ($dbs as $key => $db) { - if ($db instanceof Query) { - $db = $db->getConnection(); - - $dbs[$key] = $db; - } - - $db->startTransXa($xid); - } - - try { - $result = null; - if (is_callable($callback)) { - $result = call_user_func_array($callback, [$this]); - } - - foreach ($dbs as $db) { - $db->prepareXa($xid); - } - - foreach ($dbs as $db) { - $db->commitXa($xid); - } - - return $result; - } catch (\Exception $e) { - foreach ($dbs as $db) { - $db->rollbackXa($xid); - } - throw $e; - } catch (\Throwable $e) { - foreach ($dbs as $db) { - $db->rollbackXa($xid); - } - throw $e; - } - } - - /** - * 执行数据库事务 - * @access public - * @param callable $callback 数据操作方法回调 - * @return mixed - */ - public function transaction($callback) - { - return $this->connection->transaction($callback); - } - - /** - * 启动事务 - * @access public - * @return void - */ - public function startTrans() - { - $this->connection->startTrans(); - } - - /** - * 用于非自动提交状态下面的查询提交 - * @access public - * @return void - * @throws PDOException - */ - public function commit() - { - $this->connection->commit(); - } - - /** - * 事务回滚 - * @access public - * @return void - * @throws PDOException - */ - public function rollback() - { - $this->connection->rollback(); - } - - /** - * 批处理执行SQL语句 - * 批处理的指令都认为是execute操作 - * @access public - * @param array $sql SQL批处理指令 - * @return boolean - */ - public function batchQuery($sql = []) - { - return $this->connection->batchQuery($sql); - } - - /** - * 获取数据库的配置参数 - * @access public - * @param string $name 参数名称 - * @return mixed - */ - public function getConfig($name = '') - { - return $this->connection->getConfig($name); - } - - /** - * 获取数据表字段信息 - * @access public - * @param string $tableName 数据表名 - * @return array - */ - public function getTableFields($tableName = '') - { - if ('' == $tableName) { - $tableName = isset($this->options['table']) ? $this->options['table'] : $this->getTable(); - } - - return $this->connection->getTableFields($tableName); - } - - /** - * 获取数据表字段类型 - * @access public - * @param string $tableName 数据表名 - * @param string $field 字段名 - * @return array|string - */ - public function getFieldsType($tableName = '', $field = null) - { - if ('' == $tableName) { - $tableName = isset($this->options['table']) ? $this->options['table'] : $this->getTable(); - } - - return $this->connection->getFieldsType($tableName, $field); - } - - /** - * 得到分表的的数据表名 - * @access public - * @param array $data 操作的数据 - * @param string $field 分表依据的字段 - * @param array $rule 分表规则 - * @return array - */ - public function getPartitionTableName($data, $field, $rule = []) - { - // 对数据表进行分区 - if ($field && isset($data[$field])) { - $value = $data[$field]; - $type = $rule['type']; - switch ($type) { - case 'id': - // 按照id范围分表 - $step = $rule['expr']; - $seq = floor($value / $step) + 1; - break; - case 'year': - // 按照年份分表 - if (!is_numeric($value)) { - $value = strtotime($value); - } - $seq = date('Y', $value) - $rule['expr'] + 1; - break; - case 'mod': - // 按照id的模数分表 - $seq = ($value % $rule['num']) + 1; - break; - case 'md5': - // 按照md5的序列分表 - $seq = (ord(substr(md5($value), 0, 1)) % $rule['num']) + 1; - break; - default: - if (function_exists($type)) { - // 支持指定函数哈希 - $seq = (ord(substr($type($value), 0, 1)) % $rule['num']) + 1; - } else { - // 按照字段的首字母的值分表 - $seq = (ord($value[0]) % $rule['num']) + 1; - } - } - return $this->getTable() . '_' . $seq; - } - // 当设置的分表字段不在查询条件或者数据中 - // 进行联合查询,必须设定 partition['num'] - $tableName = []; - for ($i = 0; $i < $rule['num']; $i++) { - $tableName[] = 'SELECT * FROM ' . $this->getTable() . '_' . ($i + 1); - } - - return ['( ' . implode(" UNION ", $tableName) . ' )' => $this->name]; - } - - /** - * 得到某个字段的值 - * @access public - * @param string $field 字段名 - * @param mixed $default 默认值 - * @return mixed - */ - public function value($field, $default = null) - { - $this->parseOptions(); - - return $this->connection->value($this, $field, $default); - } - - /** - * 得到某个列的数组 - * @access public - * @param string $field 字段名 多个字段用逗号分隔 - * @param string $key 索引 - * @return array - */ - public function column($field, $key = '') - { - $this->parseOptions(); - - return $this->connection->column($this, $field, $key); - } - - /** - * 聚合查询 - * @access public - * @param string $aggregate 聚合方法 - * @param string $field 字段名 - * @param bool $force 强制转为数字类型 - * @return mixed - */ - public function aggregate($aggregate, $field, $force = false) - { - $this->parseOptions(); - - $result = $this->connection->aggregate($this, $aggregate, $field); - - if (!empty($this->options['fetch_sql'])) { - return $result; - } elseif ($force) { - $result = (float) $result; - } - - return $result; - } - - /** - * COUNT查询 - * @access public - * @param string $field 字段名 - * @return float|string - */ - public function count($field = '*') - { - if (!empty($this->options['group'])) { - // 支持GROUP - $options = $this->getOptions(); - $subSql = $this->options($options) - ->field('count(' . $field . ') AS think_count') - ->bind($this->bind) - ->buildSql(); - - $query = $this->newQuery()->table([$subSql => '_group_count_']); - - if (!empty($options['fetch_sql'])) { - $query->fetchSql(true); - } - - $count = $query->aggregate('COUNT', '*', true); - } else { - $count = $this->aggregate('COUNT', $field, true); - } - - return is_string($count) ? $count : (int) $count; - } - - /** - * SUM查询 - * @access public - * @param string $field 字段名 - * @return float - */ - public function sum($field) - { - return $this->aggregate('SUM', $field, true); - } - - /** - * MIN查询 - * @access public - * @param string $field 字段名 - * @param bool $force 强制转为数字类型 - * @return mixed - */ - public function min($field, $force = true) - { - return $this->aggregate('MIN', $field, $force); - } - - /** - * MAX查询 - * @access public - * @param string $field 字段名 - * @param bool $force 强制转为数字类型 - * @return mixed - */ - public function max($field, $force = true) - { - return $this->aggregate('MAX', $field, $force); - } - - /** - * AVG查询 - * @access public - * @param string $field 字段名 - * @return float - */ - public function avg($field) - { - return $this->aggregate('AVG', $field, true); - } - - /** - * 设置记录的某个字段值 - * 支持使用数据库字段和方法 - * @access public - * @param string|array $field 字段名 - * @param mixed $value 字段值 - * @return integer - */ - public function setField($field, $value = '') - { - if (is_array($field)) { - $data = $field; - } else { - $data[$field] = $value; - } - - return $this->update($data); - } - - /** - * 字段值(延迟)增长 - * @access public - * @param string $field 字段名 - * @param integer $step 增长值 - * @param integer $lazyTime 延时时间(s) - * @return integer|true - * @throws Exception - */ - public function setInc($field, $step = 1, $lazyTime = 0) - { - $condition = !empty($this->options['where']) ? $this->options['where'] : []; - - if (empty($condition)) { - // 没有条件不做任何更新 - throw new Exception('no data to update'); - } - - if ($lazyTime > 0) { - // 延迟写入 - $guid = md5($this->getTable() . '_' . $field . '_' . serialize($condition)); - $step = $this->lazyWrite('inc', $guid, $step, $lazyTime); - - if (false === $step) { - // 清空查询条件 - $this->options = []; - return true; - } - } - - return $this->setField($field, ['INC', $step]); - } - - /** - * 字段值(延迟)减少 - * @access public - * @param string $field 字段名 - * @param integer $step 减少值 - * @param integer $lazyTime 延时时间(s) - * @return integer|true - * @throws Exception - */ - public function setDec($field, $step = 1, $lazyTime = 0) - { - $condition = !empty($this->options['where']) ? $this->options['where'] : []; - - if (empty($condition)) { - // 没有条件不做任何更新 - throw new Exception('no data to update'); - } - - if ($lazyTime > 0) { - // 延迟写入 - $guid = md5($this->getTable() . '_' . $field . '_' . serialize($condition)); - $step = $this->lazyWrite('dec', $guid, $step, $lazyTime); - - if (false === $step) { - // 清空查询条件 - $this->options = []; - return true; - } - - $value = ['INC', $step]; - } else { - $value = ['DEC', $step]; - } - - return $this->setField($field, $value); - } - - /** - * 延时更新检查 返回false表示需要延时 - * 否则返回实际写入的数值 - * @access protected - * @param string $type 自增或者自减 - * @param string $guid 写入标识 - * @param integer $step 写入步进值 - * @param integer $lazyTime 延时时间(s) - * @return false|integer - */ - protected function lazyWrite($type, $guid, $step, $lazyTime) - { - $cache = Container::get('cache'); - - if (!$cache->has($guid . '_time')) { - // 计时开始 - $cache->set($guid . '_time', time(), 0); - $cache->$type($guid, $step); - } elseif (time() > $cache->get($guid . '_time') + $lazyTime) { - // 删除缓存 - $value = $cache->$type($guid, $step); - $cache->rm($guid); - $cache->rm($guid . '_time'); - return 0 === $value ? false : $value; - } else { - // 更新缓存 - $cache->$type($guid, $step); - } - - return false; - } - - /** - * 查询SQL组装 join - * @access public - * @param mixed $join 关联的表名 - * @param mixed $condition 条件 - * @param string $type JOIN类型 - * @return $this - */ - public function join($join, $condition = null, $type = 'INNER') - { - if (empty($condition)) { - // 如果为组数,则循环调用join - foreach ($join as $key => $value) { - if (is_array($value) && 2 <= count($value)) { - $this->join($value[0], $value[1], isset($value[2]) ? $value[2] : $type); - } - } - } else { - $table = $this->getJoinTable($join); - - $this->options['join'][] = [$table, strtoupper($type), $condition]; - } - - return $this; - } - - /** - * LEFT JOIN - * @access public - * @param mixed $join 关联的表名 - * @param mixed $condition 条件 - * @return $this - */ - public function leftJoin($join, $condition = null) - { - return $this->join($join, $condition, 'LEFT'); - } - - /** - * RIGHT JOIN - * @access public - * @param mixed $join 关联的表名 - * @param mixed $condition 条件 - * @return $this - */ - public function rightJoin($join, $condition = null) - { - return $this->join($join, $condition, 'RIGHT'); - } - - /** - * FULL JOIN - * @access public - * @param mixed $join 关联的表名 - * @param mixed $condition 条件 - * @return $this - */ - public function fullJoin($join, $condition = null) - { - return $this->join($join, $condition, 'FULL'); - } - - /** - * 获取Join表名及别名 支持 - * ['prefix_table或者子查询'=>'alias'] 'table alias' - * @access protected - * @param array|string $join - * @param string $alias - * @return string - */ - protected function getJoinTable($join, &$alias = null) - { - if (is_array($join)) { - $table = $join; - $alias = array_shift($join); - } else { - $join = trim($join); - - if (false !== strpos($join, '(')) { - // 使用子查询 - $table = $join; - } else { - $prefix = $this->prefix; - if (strpos($join, ' ')) { - // 使用别名 - list($table, $alias) = explode(' ', $join); - } else { - $table = $join; - if (false === strpos($join, '.') && 0 !== strpos($join, '__')) { - $alias = $join; - } - } - - if ($prefix && false === strpos($table, '.') && 0 !== strpos($table, $prefix) && 0 !== strpos($table, '__')) { - $table = $this->getTable($table); - } - } - - if (isset($alias) && $table != $alias) { - $table = [$table => $alias]; - } - } - - return $table; - } - - /** - * 查询SQL组装 union - * @access public - * @param mixed $union - * @param boolean $all - * @return $this - */ - public function union($union, $all = false) - { - $this->options['union']['type'] = $all ? 'UNION ALL' : 'UNION'; - - if (is_array($union)) { - $this->options['union'] = array_merge($this->options['union'], $union); - } else { - $this->options['union'][] = $union; - } - - return $this; - } - - /** - * 查询SQL组装 union all - * @access public - * @param mixed $union - * @return $this - */ - public function unionAll($union) - { - return $this->union($union, true); - } - - /** - * 指定查询字段 支持字段排除和指定数据表 - * @access public - * @param mixed $field - * @param boolean $except 是否排除 - * @param string $tableName 数据表名 - * @param string $prefix 字段前缀 - * @param string $alias 别名前缀 - * @return $this - */ - public function field($field, $except = false, $tableName = '', $prefix = '', $alias = '') - { - if (empty($field)) { - return $this; - } elseif ($field instanceof Expression) { - $this->options['field'][] = $field; - return $this; - } - - if (is_string($field)) { - if (preg_match('/[\<\'\"\(]/', $field)) { - return $this->fieldRaw($field); - } - - $field = array_map('trim', explode(',', $field)); - } - - if (true === $field) { - // 获取全部字段 - $fields = $this->getTableFields($tableName); - $field = $fields ?: ['*']; - } elseif ($except) { - // 字段排除 - $fields = $this->getTableFields($tableName); - $field = $fields ? array_diff($fields, $field) : $field; - } - - if ($tableName) { - // 添加统一的前缀 - $prefix = $prefix ?: $tableName; - foreach ($field as $key => &$val) { - if (is_numeric($key) && $alias) { - $field[$prefix . '.' . $val] = $alias . $val; - unset($field[$key]); - } elseif (is_numeric($key)) { - $val = $prefix . '.' . $val; - } - } - } - - if (isset($this->options['field'])) { - $field = array_merge((array) $this->options['field'], $field); - } - - $this->options['field'] = array_unique($field); - - return $this; - } - - /** - * 表达式方式指定查询字段 - * @access public - * @param string $field 字段名 - * @return $this - */ - public function fieldRaw($field) - { - $this->options['field'][] = $this->raw($field); - - return $this; - } - - /** - * 设置数据 - * @access public - * @param mixed $field 字段名或者数据 - * @param mixed $value 字段值 - * @return $this - */ - public function data($field, $value = null) - { - if (is_array($field)) { - $this->options['data'] = isset($this->options['data']) ? array_merge($this->options['data'], $field) : $field; - } else { - $this->options['data'][$field] = $value; - } - - return $this; - } - - /** - * 字段值增长 - * @access public - * @param string|array $field 字段名 - * @param integer $step 增长值 - * @return $this - */ - public function inc($field, $step = 1, $op = 'INC') - { - $fields = is_string($field) ? explode(',', $field) : $field; - - foreach ($fields as $field => $val) { - if (is_numeric($field)) { - $field = $val; - } else { - $step = $val; - } - - $this->data($field, [$op, $step]); - } - - return $this; - } - - /** - * 字段值减少 - * @access public - * @param string|array $field 字段名 - * @param integer $step 增长值 - * @return $this - */ - public function dec($field, $step = 1) - { - return $this->inc($field, $step, 'DEC'); - } - - /** - * 使用表达式设置数据 - * @access public - * @param string $field 字段名 - * @param string $value 字段值 - * @return $this - */ - public function exp($field, $value) - { - $this->data($field, $this->raw($value)); - return $this; - } - - /** - * 使用表达式设置数据 - * @access public - * @param mixed $value 表达式 - * @return Expression - */ - public function raw($value) - { - return new Expression($value); - } - - /** - * 指定JOIN查询字段 - * @access public - * @param string|array $table 数据表 - * @param string|array $field 查询字段 - * @param mixed $on JOIN条件 - * @param string $type JOIN类型 - * @return $this - */ - public function view($join, $field = true, $on = null, $type = 'INNER') - { - $this->options['view'] = true; - - if (is_array($join) && key($join) === 0) { - foreach ($join as $key => $val) { - $this->view($val[0], $val[1], isset($val[2]) ? $val[2] : null, isset($val[3]) ? $val[3] : 'INNER'); - } - } else { - $fields = []; - $table = $this->getJoinTable($join, $alias); - - if (true === $field) { - $fields = $alias . '.*'; - } else { - if (is_string($field)) { - $field = explode(',', $field); - } - - foreach ($field as $key => $val) { - if (is_numeric($key)) { - $fields[] = $alias . '.' . $val; - - $this->options['map'][$val] = $alias . '.' . $val; - } else { - if (preg_match('/[,=\.\'\"\(\s]/', $key)) { - $name = $key; - } else { - $name = $alias . '.' . $key; - } - - $fields[] = $name . ' AS ' . $val; - - $this->options['map'][$val] = $name; - } - } - } - - $this->field($fields); - - if ($on) { - $this->join($table, $on, $type); - } else { - $this->table($table); - } - } - - return $this; - } - - /** - * 设置分表规则 - * @access public - * @param array $data 操作的数据 - * @param string $field 分表依据的字段 - * @param array $rule 分表规则 - * @return $this - */ - public function partition($data, $field, $rule = []) - { - $this->options['table'] = $this->getPartitionTableName($data, $field, $rule); - - return $this; - } - - /** - * 指定AND查询条件 - * @access public - * @param mixed $field 查询字段 - * @param mixed $op 查询表达式 - * @param mixed $condition 查询条件 - * @return $this - */ - public function where($field, $op = null, $condition = null) - { - $param = func_get_args(); - array_shift($param); - return $this->parseWhereExp('AND', $field, $op, $condition, $param); - } - - /** - * 指定OR查询条件 - * @access public - * @param mixed $field 查询字段 - * @param mixed $op 查询表达式 - * @param mixed $condition 查询条件 - * @return $this - */ - public function whereOr($field, $op = null, $condition = null) - { - $param = func_get_args(); - array_shift($param); - return $this->parseWhereExp('OR', $field, $op, $condition, $param); - } - - /** - * 指定XOR查询条件 - * @access public - * @param mixed $field 查询字段 - * @param mixed $op 查询表达式 - * @param mixed $condition 查询条件 - * @return $this - */ - public function whereXor($field, $op = null, $condition = null) - { - $param = func_get_args(); - array_shift($param); - return $this->parseWhereExp('XOR', $field, $op, $condition, $param); - } - - /** - * 指定Null查询条件 - * @access public - * @param mixed $field 查询字段 - * @param string $logic 查询逻辑 and or xor - * @return $this - */ - public function whereNull($field, $logic = 'AND') - { - return $this->parseWhereExp($logic, $field, 'NULL', null, [], true); - } - - /** - * 指定NotNull查询条件 - * @access public - * @param mixed $field 查询字段 - * @param string $logic 查询逻辑 and or xor - * @return $this - */ - public function whereNotNull($field, $logic = 'AND') - { - return $this->parseWhereExp($logic, $field, 'NOTNULL', null, [], true); - } - - /** - * 指定Exists查询条件 - * @access public - * @param mixed $condition 查询条件 - * @param string $logic 查询逻辑 and or xor - * @return $this - */ - public function whereExists($condition, $logic = 'AND') - { - if (is_string($condition)) { - $condition = $this->raw($condition); - } - - $this->options['where'][strtoupper($logic)][] = ['', 'EXISTS', $condition]; - return $this; - } - - /** - * 指定NotExists查询条件 - * @access public - * @param mixed $condition 查询条件 - * @param string $logic 查询逻辑 and or xor - * @return $this - */ - public function whereNotExists($condition, $logic = 'AND') - { - if (is_string($condition)) { - $condition = $this->raw($condition); - } - - $this->options['where'][strtoupper($logic)][] = ['', 'NOT EXISTS', $condition]; - return $this; - } - - /** - * 指定In查询条件 - * @access public - * @param mixed $field 查询字段 - * @param mixed $condition 查询条件 - * @param string $logic 查询逻辑 and or xor - * @return $this - */ - public function whereIn($field, $condition, $logic = 'AND') - { - return $this->parseWhereExp($logic, $field, 'IN', $condition, [], true); - } - - /** - * 指定NotIn查询条件 - * @access public - * @param mixed $field 查询字段 - * @param mixed $condition 查询条件 - * @param string $logic 查询逻辑 and or xor - * @return $this - */ - public function whereNotIn($field, $condition, $logic = 'AND') - { - return $this->parseWhereExp($logic, $field, 'NOT IN', $condition, [], true); - } - - /** - * 指定Like查询条件 - * @access public - * @param mixed $field 查询字段 - * @param mixed $condition 查询条件 - * @param string $logic 查询逻辑 and or xor - * @return $this - */ - public function whereLike($field, $condition, $logic = 'AND') - { - return $this->parseWhereExp($logic, $field, 'LIKE', $condition, [], true); - } - - /** - * 指定NotLike查询条件 - * @access public - * @param mixed $field 查询字段 - * @param mixed $condition 查询条件 - * @param string $logic 查询逻辑 and or xor - * @return $this - */ - public function whereNotLike($field, $condition, $logic = 'AND') - { - return $this->parseWhereExp($logic, $field, 'NOT LIKE', $condition, [], true); - } - - /** - * 指定Between查询条件 - * @access public - * @param mixed $field 查询字段 - * @param mixed $condition 查询条件 - * @param string $logic 查询逻辑 and or xor - * @return $this - */ - public function whereBetween($field, $condition, $logic = 'AND') - { - return $this->parseWhereExp($logic, $field, 'BETWEEN', $condition, [], true); - } - - /** - * 指定NotBetween查询条件 - * @access public - * @param mixed $field 查询字段 - * @param mixed $condition 查询条件 - * @param string $logic 查询逻辑 and or xor - * @return $this - */ - public function whereNotBetween($field, $condition, $logic = 'AND') - { - return $this->parseWhereExp($logic, $field, 'NOT BETWEEN', $condition, [], true); - } - - /** - * 比较两个字段 - * @access public - * @param string|array $field1 查询字段 - * @param string $operator 比较操作符 - * @param string $field2 比较字段 - * @param string $logic 查询逻辑 and or xor - * @return $this - */ - public function whereColumn($field1, $operator = null, $field2 = null, $logic = 'AND') - { - if (is_array($field1)) { - foreach ($field1 as $item) { - $this->whereColumn($item[0], $item[1], isset($item[2]) ? $item[2] : null); - } - return $this; - } - - if (is_null($field2)) { - $field2 = $operator; - $operator = '='; - } - - return $this->parseWhereExp($logic, $field1, 'COLUMN', [$operator, $field2], [], true); - } - - /** - * 设置软删除字段及条件 - * @access public - * @param false|string $field 查询字段 - * @param mixed $condition 查询条件 - * @return $this - */ - public function useSoftDelete($field, $condition = null) - { - if ($field) { - $this->options['soft_delete'] = [$field, $condition]; - } - - return $this; - } - - /** - * 指定Exp查询条件 - * @access public - * @param mixed $field 查询字段 - * @param string $where 查询条件 - * @param array $bind 参数绑定 - * @param string $logic 查询逻辑 and or xor - * @return $this - */ - public function whereExp($field, $where, $bind = [], $logic = 'AND') - { - if ($bind) { - $this->bindParams($where, $bind); - } - - $this->options['where'][$logic][] = [$field, 'EXP', $this->raw($where)]; - - return $this; - } - - /** - * 指定表达式查询条件 - * @access public - * @param string $where 查询条件 - * @param array $bind 参数绑定 - * @param string $logic 查询逻辑 and or xor - * @return $this - */ - public function whereRaw($where, $bind = [], $logic = 'AND') - { - if ($bind) { - $this->bindParams($where, $bind); - } - - $this->options['where'][$logic][] = $this->raw($where); - - return $this; - } - - /** - * 参数绑定 - * @access public - * @param string $sql 绑定的sql表达式 - * @param array $bind 参数绑定 - * @return void - */ - protected function bindParams(&$sql, array $bind = []) - { - foreach ($bind as $key => $value) { - if (is_array($value)) { - $name = $this->bind($value[0], $value[1], isset($value[2]) ? $value[2] : null); - } else { - $name = $this->bind($value); - } - - if (is_numeric($key)) { - $sql = substr_replace($sql, ':' . $name, strpos($sql, '?'), 1); - } else { - $sql = str_replace(':' . $key, ':' . $name, $sql); - } - } - } - - /** - * 指定表达式查询条件 OR - * @access public - * @param string $where 查询条件 - * @param array $bind 参数绑定 - * @return $this - */ - public function whereOrRaw($where, $bind = []) - { - return $this->whereRaw($where, $bind, 'OR'); - } - - /** - * 分析查询表达式 - * @access protected - * @param string $logic 查询逻辑 and or xor - * @param mixed $field 查询字段 - * @param mixed $op 查询表达式 - * @param mixed $condition 查询条件 - * @param array $param 查询参数 - * @param bool $strict 严格模式 - * @return $this - */ - protected function parseWhereExp($logic, $field, $op, $condition, array $param = [], $strict = false) - { - if ($field instanceof $this) { - $this->options['where'] = $field->getOptions('where'); - return $this; - } - - $logic = strtoupper($logic); - - if ($field instanceof Where) { - $this->options['where'][$logic] = $field->parse(); - return $this; - } - - if (is_string($field) && !empty($this->options['via']) && false === strpos($field, '.')) { - $field = $this->options['via'] . '.' . $field; - } - - if ($field instanceof Expression) { - return $this->whereRaw($field, is_array($op) ? $op : []); - } elseif ($strict) { - // 使用严格模式查询 - $where = [$field, $op, $condition]; - } elseif (is_array($field)) { - // 解析数组批量查询 - return $this->parseArrayWhereItems($field, $logic); - } elseif ($field instanceof \Closure) { - $where = $field; - } elseif (is_string($field)) { - if (preg_match('/[,=\<\'\"\(\s]/', $field)) { - return $this->whereRaw($field, $op); - } elseif (is_string($op) && strtolower($op) == 'exp') { - $bind = isset($param[2]) && is_array($param[2]) ? $param[2] : null; - return $this->whereExp($field, $condition, $bind, $logic); - } - - $where = $this->parseWhereItem($logic, $field, $op, $condition, $param); - } - - if (!empty($where)) { - $this->options['where'][$logic][] = $where; - } - - return $this; - } - - /** - * 分析查询表达式 - * @access protected - * @param string $logic 查询逻辑 and or xor - * @param mixed $field 查询字段 - * @param mixed $op 查询表达式 - * @param mixed $condition 查询条件 - * @param array $param 查询参数 - * @return mixed - */ - protected function parseWhereItem($logic, $field, $op, $condition, $param = []) - { - if (is_array($op)) { - // 同一字段多条件查询 - array_unshift($param, $field); - $where = $param; - } elseif ($field && is_null($condition)) { - if (in_array(strtoupper($op), ['NULL', 'NOTNULL', 'NOT NULL'], true)) { - // null查询 - $where = [$field, $op, '']; - } elseif (in_array($op, ['=', 'eq', 'EQ', null], true)) { - $where = [$field, 'NULL', '']; - } elseif (in_array($op, ['<>', 'neq', 'NEQ'], true)) { - $where = [$field, 'NOTNULL', '']; - } else { - // 字段相等查询 - $where = [$field, '=', $op]; - } - } elseif (in_array(strtoupper($op), ['REGEXP', 'NOT REGEXP', 'EXISTS', 'NOT EXISTS', 'NOTEXISTS'], true)) { - $where = [$field, $op, is_string($condition) ? $this->raw($condition) : $condition]; - } else { - $where = $field ? [$field, $op, $condition, isset($param[2]) ? $param[2] : null] : null; - } - - return $where; - } - - /** - * 数组批量查询 - * @access protected - * @param array $field 批量查询 - * @param string $logic 查询逻辑 and or xor - * @return $this - */ - protected function parseArrayWhereItems($field, $logic) - { - if (key($field) !== 0) { - $where = []; - foreach ($field as $key => $val) { - if ($val instanceof Expression) { - $where[] = [$key, 'exp', $val]; - } elseif (is_null($val)) { - $where[] = [$key, 'NULL', '']; - } else { - $where[] = [$key, is_array($val) ? 'IN' : '=', $val]; - } - } - } else { - // 数组批量查询 - $where = $field; - } - - if (!empty($where)) { - $this->options['where'][$logic] = isset($this->options['where'][$logic]) ? array_merge($this->options['where'][$logic], $where) : $where; - } - - return $this; - } - - /** - * 去除某个查询条件 - * @access public - * @param string $field 查询字段 - * @param string $logic 查询逻辑 and or xor - * @return $this - */ - public function removeWhereField($field, $logic = 'AND') - { - $logic = strtoupper($logic); - - if (isset($this->options['where'][$logic])) { - foreach ($this->options['where'][$logic] as $key => $val) { - if (is_array($val) && $val[0] == $field) { - unset($this->options['where'][$logic][$key]); - } - } - } - - return $this; - } - - /** - * 去除查询参数 - * @access public - * @param string|bool $option 参数名 true 表示去除所有参数 - * @return $this - */ - public function removeOption($option = true) - { - if (true === $option) { - $this->options = []; - } elseif (is_string($option) && isset($this->options[$option])) { - unset($this->options[$option]); - } - - return $this; - } - - /** - * 条件查询 - * @access public - * @param mixed $condition 满足条件(支持闭包) - * @param \Closure|array $query 满足条件后执行的查询表达式(闭包或数组) - * @param \Closure|array $otherwise 不满足条件后执行 - * @return $this - */ - public function when($condition, $query, $otherwise = null) - { - if ($condition instanceof \Closure) { - $condition = $condition($this); - } - - if ($condition) { - if ($query instanceof \Closure) { - $query($this, $condition); - } elseif (is_array($query)) { - $this->where($query); - } - } elseif ($otherwise) { - if ($otherwise instanceof \Closure) { - $otherwise($this, $condition); - } elseif (is_array($otherwise)) { - $this->where($otherwise); - } - } - - return $this; - } - - /** - * 指定查询数量 - * @access public - * @param mixed $offset 起始位置 - * @param mixed $length 查询数量 - * @return $this - */ - public function limit($offset, $length = null) - { - if (is_null($length) && strpos($offset, ',')) { - list($offset, $length) = explode(',', $offset); - } - - $this->options['limit'] = intval($offset) . ($length ? ',' . intval($length) : ''); - - return $this; - } - - /** - * 指定分页 - * @access public - * @param mixed $page 页数 - * @param mixed $listRows 每页数量 - * @return $this - */ - public function page($page, $listRows = null) - { - if (is_null($listRows) && strpos($page, ',')) { - list($page, $listRows) = explode(',', $page); - } - - $this->options['page'] = [intval($page), intval($listRows)]; - - return $this; - } - - /** - * 分页查询 - * @access public - * @param int|array $listRows 每页数量 数组表示配置参数 - * @param int|bool $simple 是否简洁模式或者总记录数 - * @param array $config 配置参数 - * page:当前页, - * path:url路径, - * query:url额外参数, - * fragment:url锚点, - * var_page:分页变量, - * list_rows:每页数量 - * type:分页类名 - * @return \think\Paginator - * @throws DbException - */ - public function paginate($listRows = null, $simple = false, $config = []) - { - if (is_int($simple)) { - $total = $simple; - $simple = false; - } - - $paginate = Container::get('config')->pull('paginate'); - - if (is_array($listRows)) { - $config = array_merge($paginate, $listRows); - $listRows = $config['list_rows']; - } else { - $config = array_merge($paginate, $config); - $listRows = $listRows ?: $config['list_rows']; - } - - /** @var Paginator $class */ - $class = false !== strpos($config['type'], '\\') ? $config['type'] : '\\think\\paginator\\driver\\' . ucwords($config['type']); - $page = isset($config['page']) ? (int) $config['page'] : call_user_func([ - $class, - 'getCurrentPage', - ], $config['var_page']); - - $page = $page < 1 ? 1 : $page; - - $config['path'] = isset($config['path']) ? $config['path'] : call_user_func([$class, 'getCurrentPath']); - - if (!isset($total) && !$simple) { - $options = $this->getOptions(); - - unset($this->options['order'], $this->options['limit'], $this->options['page'], $this->options['field']); - - $bind = $this->bind; - $total = $this->count(); - $results = $this->options($options)->bind($bind)->page($page, $listRows)->select(); - } elseif ($simple) { - $results = $this->limit(($page - 1) * $listRows, $listRows + 1)->select(); - $total = null; - } else { - $results = $this->page($page, $listRows)->select(); - } - - $this->removeOption('limit'); - $this->removeOption('page'); - - return $class::make($results, $listRows, $page, $total, $simple, $config); - } - - /** - * 指定当前操作的数据表 - * @access public - * @param mixed $table 表名 - * @return $this - */ - public function table($table) - { - if (is_string($table)) { - if (strpos($table, ')')) { - // 子查询 - } elseif (strpos($table, ',')) { - $tables = explode(',', $table); - $table = []; - - foreach ($tables as $item) { - list($item, $alias) = explode(' ', trim($item)); - if ($alias) { - $this->alias([$item => $alias]); - $table[$item] = $alias; - } else { - $table[] = $item; - } - } - } elseif (strpos($table, ' ')) { - list($table, $alias) = explode(' ', $table); - - $table = [$table => $alias]; - $this->alias($table); - } - } else { - $tables = $table; - $table = []; - - foreach ($tables as $key => $val) { - if (is_numeric($key)) { - $table[] = $val; - } else { - $this->alias([$key => $val]); - $table[$key] = $val; - } - } - } - - $this->options['table'] = $table; - - return $this; - } - - /** - * USING支持 用于多表删除 - * @access public - * @param mixed $using - * @return $this - */ - public function using($using) - { - $this->options['using'] = $using; - return $this; - } - - /** - * 指定排序 order('id','desc') 或者 order(['id'=>'desc','create_time'=>'desc']) - * @access public - * @param string|array $field 排序字段 - * @param string $order 排序 - * @return $this - */ - public function order($field, $order = null) - { - if (empty($field)) { - return $this; - } elseif ($field instanceof Expression) { - $this->options['order'][] = $field; - return $this; - } - - if (is_string($field)) { - if (!empty($this->options['via'])) { - $field = $this->options['via'] . '.' . $field; - } - - if (strpos($field, ',')) { - $field = array_map('trim', explode(',', $field)); - } else { - $field = empty($order) ? $field : [$field => $order]; - } - } elseif (!empty($this->options['via'])) { - foreach ($field as $key => $val) { - if (is_numeric($key)) { - $field[$key] = $this->options['via'] . '.' . $val; - } else { - $field[$this->options['via'] . '.' . $key] = $val; - unset($field[$key]); - } - } - } - - if (!isset($this->options['order'])) { - $this->options['order'] = []; - } - - if (is_array($field)) { - $this->options['order'] = array_merge($this->options['order'], $field); - } else { - $this->options['order'][] = $field; - } - - return $this; - } - - /** - * 表达式方式指定Field排序 - * @access public - * @param string $field 排序字段 - * @param array $bind 参数绑定 - * @return $this - */ - public function orderRaw($field, $bind = []) - { - if ($bind) { - $this->bindParams($field, $bind); - } - - $this->options['order'][] = $this->raw($field); - - return $this; - } - - /** - * 指定Field排序 order('id',[1,2,3],'desc') - * @access public - * @param string|array $field 排序字段 - * @param array $values 排序值 - * @param string $order - * @return $this - */ - public function orderField($field, array $values, $order = '') - { - if (!empty($values)) { - $values['sort'] = $order; - - $this->options['order'][$field] = $values; - } - - return $this; - } - - /** - * 随机排序 - * @access public - * @return $this - */ - public function orderRand() - { - $this->options['order'][] = '[rand]'; - return $this; - } - - /** - * 查询缓存 - * @access public - * @param mixed $key 缓存key - * @param integer|\DateTime $expire 缓存有效期 - * @param string $tag 缓存标签 - * @return $this - */ - public function cache($key = true, $expire = null, $tag = null) - { - // 增加快捷调用方式 cache(10) 等同于 cache(true, 10) - if ($key instanceof \DateTime || (is_numeric($key) && is_null($expire))) { - $expire = $key; - $key = true; - } - - if (false !== $key) { - $this->options['cache'] = ['key' => $key, 'expire' => $expire, 'tag' => $tag]; - } - - return $this; - } - - /** - * 指定group查询 - * @access public - * @param string|array $group GROUP - * @return $this - */ - public function group($group) - { - $this->options['group'] = $group; - return $this; - } - - /** - * 指定having查询 - * @access public - * @param string $having having - * @return $this - */ - public function having($having) - { - $this->options['having'] = $having; - return $this; - } - - /** - * 指定查询lock - * @access public - * @param bool|string $lock 是否lock - * @return $this - */ - public function lock($lock = false) - { - $this->options['lock'] = $lock; - $this->options['master'] = true; - - return $this; - } - - /** - * 指定distinct查询 - * @access public - * @param string $distinct 是否唯一 - * @return $this - */ - public function distinct($distinct) - { - $this->options['distinct'] = $distinct; - return $this; - } - - /** - * 指定数据表别名 - * @access public - * @param array|string $alias 数据表别名 - * @return $this - */ - public function alias($alias) - { - if (is_array($alias)) { - foreach ($alias as $key => $val) { - if (false !== strpos($key, '__')) { - $table = $this->connection->parseSqlTable($key); - } else { - $table = $key; - } - $this->options['alias'][$table] = $val; - } - } else { - if (isset($this->options['table'])) { - $table = is_array($this->options['table']) ? key($this->options['table']) : $this->options['table']; - if (false !== strpos($table, '__')) { - $table = $this->connection->parseSqlTable($table); - } - } else { - $table = $this->getTable(); - } - - $this->options['alias'][$table] = $alias; - } - - return $this; - } - - /** - * 指定强制索引 - * @access public - * @param string $force 索引名称 - * @return $this - */ - public function force($force) - { - $this->options['force'] = $force; - return $this; - } - - /** - * 查询注释 - * @access public - * @param string $comment 注释 - * @return $this - */ - public function comment($comment) - { - $this->options['comment'] = $comment; - return $this; - } - - /** - * 获取执行的SQL语句 - * @access public - * @param boolean $fetch 是否返回sql - * @return $this - */ - public function fetchSql($fetch = true) - { - $this->options['fetch_sql'] = $fetch; - return $this; - } - - /** - * 不主动获取数据集 - * @access public - * @param bool $pdo 是否返回 PDOStatement 对象 - * @return $this - */ - public function fetchPdo($pdo = true) - { - $this->options['fetch_pdo'] = $pdo; - return $this; - } - - /** - * 设置是否返回数据集对象(支持设置数据集对象类名) - * @access public - * @param bool|string $collection 是否返回数据集对象 - * @return $this - */ - public function fetchCollection($collection = true) - { - $this->options['collection'] = $collection; - - return $this; - } - - /** - * 设置从主服务器读取数据 - * @access public - * @return $this - */ - public function master() - { - $this->options['master'] = true; - return $this; - } - - /** - * 设置是否严格检查字段名 - * @access public - * @param bool $strict 是否严格检查字段 - * @return $this - */ - public function strict($strict = true) - { - $this->options['strict'] = $strict; - return $this; - } - - /** - * 设置查询数据不存在是否抛出异常 - * @access public - * @param bool $fail 数据不存在是否抛出异常 - * @return $this - */ - public function failException($fail = true) - { - $this->options['fail'] = $fail; - return $this; - } - - /** - * 设置自增序列名 - * @access public - * @param string $sequence 自增序列名 - * @return $this - */ - public function sequence($sequence = null) - { - $this->options['sequence'] = $sequence; - return $this; - } - - /** - * 设置需要隐藏的输出属性 - * @access public - * @param mixed $hidden 需要隐藏的字段名 - * @return $this - */ - public function hidden($hidden) - { - if ($this->model) { - $this->options['hidden'] = $hidden; - return $this; - } - - return $this->field($hidden, true); - } - - /** - * 设置需要输出的属性 - * @access public - * @param array $visible 需要输出的属性 - * @return $this - */ - public function visible(array $visible) - { - $this->options['visible'] = $visible; - return $this; - } - - /** - * 设置需要追加输出的属性 - * @access public - * @param array $append 需要追加的属性 - * @return $this - */ - public function append(array $append) - { - $this->options['append'] = $append; - return $this; - } - - /** - * 设置数据字段获取器 - * @access public - * @param string|array $name 字段名 - * @param callable $callback 闭包获取器 - * @return $this - */ - public function withAttr($name, $callback = null) - { - if (is_array($name)) { - $this->options['with_attr'] = $name; - } else { - $this->options['with_attr'][$name] = $callback; - } - - return $this; - } - - /** - * 设置JSON字段信息 - * @access public - * @param array $json JSON字段 - * @param bool $assoc 是否取出数组 - * @return $this - */ - public function json(array $json = [], $assoc = false) - { - $this->options['json'] = $json; - $this->options['json_assoc'] = $assoc; - return $this; - } - - /** - * 设置字段类型信息 - * @access public - * @param array $type 字段类型信息 - * @return $this - */ - public function setJsonFieldType(array $type) - { - $this->options['field_type'] = $type; - return $this; - } - - /** - * 获取字段类型信息 - * @access public - * @param string $field 字段名 - * @return string|null - */ - public function getJsonFieldType($field) - { - return isset($this->options['field_type'][$field]) ? $this->options['field_type'][$field] : null; - } - - /** - * 是否允许返回空数据(或空模型) - * @access public - * @param bool $allowEmpty 是否允许为空 - * @return $this - */ - public function allowEmpty($allowEmpty = true) - { - $this->options['allow_empty'] = $allowEmpty; - return $this; - } - - /** - * 添加查询范围 - * @access public - * @param array|string|\Closure $scope 查询范围定义 - * @param array $args 参数 - * @return $this - */ - public function scope($scope, ...$args) - { - // 查询范围的第一个参数始终是当前查询对象 - array_unshift($args, $this); - - if ($scope instanceof \Closure) { - call_user_func_array($scope, $args); - return $this; - } - - if (is_string($scope)) { - $scope = explode(',', $scope); - } - - if ($this->model) { - // 检查模型类的查询范围方法 - foreach ($scope as $name) { - $method = 'scope' . trim($name); - - if (method_exists($this->model, $method)) { - call_user_func_array([$this->model, $method], $args); - } - } - } - - return $this; - } - - /** - * 使用搜索器条件搜索字段 - * @access public - * @param array $fields 搜索字段 - * @param array $data 搜索数据 - * @param string $prefix 字段前缀标识 - * @return $this - */ - public function withSearch(array $fields, array $data = [], $prefix = '') - { - foreach ($fields as $key => $field) { - if ($field instanceof \Closure) { - $field($this, isset($data[$key]) ? $data[$key] : null, $data, $prefix); - } elseif ($this->model) { - // 检测搜索器 - $fieldName = is_numeric($key) ? $field : $key; - $method = 'search' . Loader::parseName($fieldName, 1) . 'Attr'; - - if (method_exists($this->model, $method)) { - $this->model->$method($this, isset($data[$field]) ? $data[$field] : null, $data, $prefix); - } - } - } - - return $this; - } - - /** - * 指定数据表主键 - * @access public - * @param string $pk 主键 - * @return $this - */ - public function pk($pk) - { - $this->pk = $pk; - return $this; - } - - /** - * 查询日期或者时间 - * @access public - * @param string $name 时间表达式 - * @param string|array $rule 时间范围 - * @return $this - */ - public function timeRule($name, $rule) - { - $this->timeRule[$name] = $rule; - return $this; - } - - /** - * 查询日期或者时间 - * @access public - * @param string $field 日期字段名 - * @param string|array $op 比较运算符或者表达式 - * @param string|array $range 比较范围 - * @param string $logic AND OR - * @return $this - */ - public function whereTime($field, $op, $range = null, $logic = 'AND') - { - if (is_null($range)) { - if (is_array($op)) { - $range = $op; - } else { - if (isset($this->timeExp[strtolower($op)])) { - $op = $this->timeExp[strtolower($op)]; - } - - if (isset($this->timeRule[strtolower($op)])) { - $range = $this->timeRule[strtolower($op)]; - } else { - $range = $op; - } - } - - $op = is_array($range) ? 'between' : '>='; - } - - return $this->parseWhereExp($logic, $field, strtolower($op) . ' time', $range, [], true); - } - - /** - * 查询当前时间在两个时间字段范围 - * @access public - * @param string $startField 开始时间字段 - * @param string $endField 结束时间字段 - * @return $this - */ - public function whereBetweenTimeField($startField, $endField) - { - return $this->whereTime($startField, '<=', time()) - ->whereTime($endField, '>=', time()); - } - - /** - * 查询当前时间不在两个时间字段范围 - * @access public - * @param string $startField 开始时间字段 - * @param string $endField 结束时间字段 - * @return $this - */ - public function whereNotBetweenTimeField($startField, $endField) - { - return $this->whereTime($startField, '>', time()) - ->whereTime($endField, '<', time(), 'OR'); - } - - /** - * 查询日期或者时间范围 - * @access public - * @param string $field 日期字段名 - * @param string $startTime 开始时间 - * @param string $endTime 结束时间 - * @param string $logic AND OR - * @return $this - */ - public function whereBetweenTime($field, $startTime, $endTime = null, $logic = 'AND') - { - if (is_null($endTime)) { - $time = is_string($startTime) ? strtotime($startTime) : $startTime; - $endTime = strtotime('+1 day', $time); - } - - return $this->parseWhereExp($logic, $field, 'between time', [$startTime, $endTime], [], true); - } - - /** - * 获取当前数据表的主键 - * @access public - * @param string|array $options 数据表名或者查询参数 - * @return string|array - */ - public function getPk($options = '') - { - if (!empty($this->pk)) { - $pk = $this->pk; - } else { - $pk = $this->connection->getPk(is_array($options) && isset($options['table']) ? $options['table'] : $this->getTable()); - } - - return $pk; - } - - /** - * 参数绑定 - * @access public - * @param mixed $value 绑定变量值 - * @param integer $type 绑定类型 - * @param string $name 绑定名称 - * @return $this|string - */ - public function bind($value, $type = PDO::PARAM_STR, $name = null) - { - if (is_array($value)) { - $this->bind = array_merge($this->bind, $value); - } else { - $name = $name ?: 'ThinkBind_' . (count($this->bind) + 1) . '_'; - - $this->bind[$name] = [$value, $type]; - return $name; - } - - return $this; - } - - /** - * 检测参数是否已经绑定 - * @access public - * @param string $key 参数名 - * @return bool - */ - public function isBind($key) - { - return isset($this->bind[$key]); - } - - /** - * 查询参数赋值 - * @access public - * @param string $name 参数名 - * @param mixed $value 值 - * @return $this - */ - public function option($name, $value) - { - $this->options[$name] = $value; - return $this; - } - - /** - * 查询参数赋值 - * @access protected - * @param array $options 表达式参数 - * @return $this - */ - protected function options(array $options) - { - $this->options = $options; - return $this; - } - - /** - * 获取当前的查询参数 - * @access public - * @param string $name 参数名 - * @return mixed - */ - public function getOptions($name = '') - { - if ('' === $name) { - return $this->options; - } - return isset($this->options[$name]) ? $this->options[$name] : null; - } - - /** - * 设置当前的查询参数 - * @access public - * @param string $option 参数名 - * @param mixed $value 参数值 - * @return $this - */ - public function setOption($option, $value) - { - $this->options[$option] = $value; - return $this; - } - - /** - * 设置关联查询JOIN预查询 - * @access public - * @param string|array $with 关联方法名称 - * @return $this - */ - public function with($with) - { - if (empty($with)) { - return $this; - } - - if (is_string($with)) { - $with = explode(',', $with); - } - - $first = true; - - /** @var Model $class */ - $class = $this->model; - foreach ($with as $key => $relation) { - $closure = null; - - if ($relation instanceof \Closure) { - // 支持闭包查询过滤关联条件 - $closure = $relation; - $relation = $key; - } elseif (is_array($relation)) { - $relation = $key; - } elseif (is_string($relation) && strpos($relation, '.')) { - list($relation, $subRelation) = explode('.', $relation, 2); - } - - /** @var Relation $model */ - $relation = Loader::parseName($relation, 1, false); - $model = $class->$relation(); - - if ($model instanceof OneToOne && 0 == $model->getEagerlyType()) { - $table = $model->getTable(); - $model->removeOption() - ->table($table) - ->eagerly($this, $relation, true, '', $closure, $first); - $first = false; - } - } - - $this->via(); - - $this->options['with'] = $with; - - return $this; - } - - /** - * 关联预载入 JOIN方式(不支持嵌套) - * @access protected - * @param string|array $with 关联方法名 - * @param string $joinType JOIN方式 - * @return $this - */ - public function withJoin($with, $joinType = '') - { - if (empty($with)) { - return $this; - } - - if (is_string($with)) { - $with = explode(',', $with); - } - - $first = true; - - /** @var Model $class */ - $class = $this->model; - foreach ($with as $key => $relation) { - $closure = null; - $field = true; - - if ($relation instanceof \Closure) { - // 支持闭包查询过滤关联条件 - $closure = $relation; - $relation = $key; - } elseif (is_array($relation)) { - $field = $relation; - $relation = $key; - } elseif (is_string($relation) && strpos($relation, '.')) { - list($relation, $subRelation) = explode('.', $relation, 2); - } - - /** @var Relation $model */ - $relation = Loader::parseName($relation, 1, false); - $model = $class->$relation(); - - if ($model instanceof OneToOne) { - $model->eagerly($this, $relation, $field, $joinType, $closure, $first); - $first = false; - } else { - // 不支持其它关联 - unset($with[$key]); - } - } - - $this->via(); - - $this->options['with_join'] = $with; - - return $this; - } - - /** - * 关联统计 - * @access protected - * @param string|array $relation 关联方法名 - * @param string $aggregate 聚合查询方法 - * @param string $field 字段 - * @param bool $subQuery 是否使用子查询 - * @return $this - */ - protected function withAggregate($relation, $aggregate = 'count', $field = '*', $subQuery = true) - { - $relations = is_string($relation) ? explode(',', $relation) : $relation; - - if (!$subQuery) { - $this->options['with_count'][] = [$relations, $aggregate, $field]; - } else { - if (!isset($this->options['field'])) { - $this->field('*'); - } - - foreach ($relations as $key => $relation) { - $closure = $aggregateField = null; - - if ($relation instanceof \Closure) { - $closure = $relation; - $relation = $key; - } elseif (!is_int($key)) { - $aggregateField = $relation; - $relation = $key; - } - - $relation = Loader::parseName($relation, 1, false); - - $count = $this->model->$relation()->getRelationCountQuery($closure, $aggregate, $field, $aggregateField); - - if (empty($aggregateField)) { - $aggregateField = Loader::parseName($relation) . '_' . $aggregate; - } - - $this->field(['(' . $count . ')' => $aggregateField]); - } - } - - return $this; - } - - /** - * 关联统计 - * @access public - * @param string|array $relation 关联方法名 - * @param bool $subQuery 是否使用子查询 - * @return $this - */ - public function withCount($relation, $subQuery = true) - { - return $this->withAggregate($relation, 'count', '*', $subQuery); - } - - /** - * 关联统计Sum - * @access public - * @param string|array $relation 关联方法名 - * @param string $field 字段 - * @param bool $subQuery 是否使用子查询 - * @return $this - */ - public function withSum($relation, $field, $subQuery = true) - { - return $this->withAggregate($relation, 'sum', $field, $subQuery); - } - - /** - * 关联统计Max - * @access public - * @param string|array $relation 关联方法名 - * @param string $field 字段 - * @param bool $subQuery 是否使用子查询 - * @return $this - */ - public function withMax($relation, $field, $subQuery = true) - { - return $this->withAggregate($relation, 'max', $field, $subQuery); - } - - /** - * 关联统计Min - * @access public - * @param string|array $relation 关联方法名 - * @param string $field 字段 - * @param bool $subQuery 是否使用子查询 - * @return $this - */ - public function withMin($relation, $field, $subQuery = true) - { - return $this->withAggregate($relation, 'min', $field, $subQuery); - } - - /** - * 关联统计Avg - * @access public - * @param string|array $relation 关联方法名 - * @param string $field 字段 - * @param bool $subQuery 是否使用子查询 - * @return $this - */ - public function withAvg($relation, $field, $subQuery = true) - { - return $this->withAggregate($relation, 'avg', $field, $subQuery); - } - - /** - * 关联预加载中 获取关联指定字段值 - * example: - * Model::with(['relation' => function($query){ - * $query->withField("id,name"); - * }]) - * - * @access public - * @param string | array $field 指定获取的字段 - * @return $this - */ - public function withField($field) - { - $this->options['with_field'] = $field; - - return $this; - } - - /** - * 设置当前字段添加的表别名 - * @access public - * @param string $via - * @return $this - */ - public function via($via = '') - { - $this->options['via'] = $via; - - return $this; - } - - /** - * 设置关联查询 - * @access public - * @param string|array $relation 关联名称 - * @return $this - */ - public function relation($relation) - { - if (empty($relation)) { - return $this; - } - - if (is_string($relation)) { - $relation = explode(',', $relation); - } - - if (isset($this->options['relation'])) { - $this->options['relation'] = array_merge($this->options['relation'], $relation); - } else { - $this->options['relation'] = $relation; - } - - return $this; - } - - /** - * 插入记录 - * @access public - * @param array $data 数据 - * @param boolean $replace 是否replace - * @param boolean $getLastInsID 返回自增主键 - * @param string $sequence 自增序列名 - * @return integer|string - */ - public function insert(array $data = [], $replace = false, $getLastInsID = false, $sequence = null) - { - $this->parseOptions(); - - $this->options['data'] = array_merge($this->options['data'], $data); - - return $this->connection->insert($this, $replace, $getLastInsID, $sequence); - } - - /** - * 插入记录并获取自增ID - * @access public - * @param array $data 数据 - * @param boolean $replace 是否replace - * @param string $sequence 自增序列名 - * @return integer|string - */ - public function insertGetId(array $data, $replace = false, $sequence = null) - { - return $this->insert($data, $replace, true, $sequence); - } - - /** - * 批量插入记录 - * @access public - * @param array $dataSet 数据集 - * @param boolean $replace 是否replace - * @param integer $limit 每次写入数据限制 - * @return integer|string - */ - public function insertAll(array $dataSet = [], $replace = false, $limit = null) - { - $this->parseOptions(); - - if (empty($dataSet)) { - $dataSet = $this->options['data']; - } - - if (empty($limit) && !empty($this->options['limit'])) { - $limit = $this->options['limit']; - } - - return $this->connection->insertAll($this, $dataSet, $replace, $limit); - } - - /** - * 通过Select方式插入记录 - * @access public - * @param string $fields 要插入的数据表字段名 - * @param string $table 要插入的数据表名 - * @return integer|string - * @throws PDOException - */ - public function selectInsert($fields, $table) - { - $this->parseOptions(); - - return $this->connection->selectInsert($this, $fields, $table); - } - - /** - * 更新记录 - * @access public - * @param mixed $data 数据 - * @return integer|string - * @throws Exception - * @throws PDOException - */ - public function update(array $data = []) - { - $this->parseOptions(); - - $this->options['data'] = array_merge($this->options['data'], $data); - - return $this->connection->update($this); - } - - /** - * 删除记录 - * @access public - * @param mixed $data 表达式 true 表示强制删除 - * @return int - * @throws Exception - * @throws PDOException - */ - public function delete($data = null) - { - $this->parseOptions(); - - if (!is_null($data) && true !== $data) { - // AR模式分析主键条件 - $this->parsePkWhere($data); - } - - if (!empty($this->options['soft_delete'])) { - // 软删除 - list($field, $condition) = $this->options['soft_delete']; - if ($condition) { - unset($this->options['soft_delete']); - $this->options['data'] = [$field => $condition]; - - return $this->connection->update($this); - } - } - - $this->options['data'] = $data; - - return $this->connection->delete($this); - } - - /** - * 执行查询但只返回PDOStatement对象 - * @access public - * @return \PDOStatement|string - */ - public function getPdo() - { - $this->parseOptions(); - - return $this->connection->pdo($this); - } - - /** - * 使用游标查找记录 - * @access public - * @param array|string|Query|\Closure $data - * @return \Generator - */ - public function cursor($data = null) - { - if ($data instanceof \Closure) { - $data($this); - $data = null; - } - - $this->parseOptions(); - - if (!is_null($data)) { - // 主键条件分析 - $this->parsePkWhere($data); - } - - $this->options['data'] = $data; - - $connection = clone $this->connection; - - return $connection->cursor($this); - } - - /** - * 查找记录 - * @access public - * @param array|string|Query|\Closure $data - * @return Collection|array|\PDOStatement|string - * @throws DbException - * @throws ModelNotFoundException - * @throws DataNotFoundException - */ - public function select($data = null) - { - if ($data instanceof Query) { - return $data->select(); - } elseif ($data instanceof \Closure) { - $data($this); - $data = null; - } - - $this->parseOptions(); - - if (false === $data) { - // 用于子查询 不查询只返回SQL - $this->options['fetch_sql'] = true; - } elseif (!is_null($data)) { - // 主键条件分析 - $this->parsePkWhere($data); - } - - $this->options['data'] = $data; - - $resultSet = $this->connection->select($this); - - if ($this->options['fetch_sql']) { - return $resultSet; - } - - // 返回结果处理 - if (!empty($this->options['fail']) && count($resultSet) == 0) { - $this->throwNotFound($this->options); - } - - // 数据列表读取后的处理 - if (!empty($this->model)) { - // 生成模型对象 - $resultSet = $this->resultSetToModelCollection($resultSet); - } else { - $this->resultSet($resultSet); - } - - return $resultSet; - } - - /** - * 查询数据转换为模型数据集对象 - * @access protected - * @param array $resultSet 数据集 - * @return ModelCollection - */ - protected function resultSetToModelCollection(array $resultSet) - { - if (!empty($this->options['collection']) && is_string($this->options['collection'])) { - $collection = $this->options['collection']; - } - - if (empty($resultSet)) { - return $this->model->toCollection([], isset($collection) ? $collection : null); - } - - // 检查动态获取器 - if (!empty($this->options['with_attr'])) { - foreach ($this->options['with_attr'] as $name => $val) { - if (strpos($name, '.')) { - list($relation, $field) = explode('.', $name); - - $withRelationAttr[$relation][$field] = $val; - unset($this->options['with_attr'][$name]); - } - } - } - - $withRelationAttr = isset($withRelationAttr) ? $withRelationAttr : []; - - foreach ($resultSet as $key => &$result) { - // 数据转换为模型对象 - $this->resultToModel($result, $this->options, true, $withRelationAttr); - } - - if (!empty($this->options['with'])) { - // 预载入 - $result->eagerlyResultSet($resultSet, $this->options['with'], $withRelationAttr); - } - - if (!empty($this->options['with_join'])) { - // JOIN预载入 - $result->eagerlyResultSet($resultSet, $this->options['with_join'], $withRelationAttr, true); - } - - // 模型数据集转换 - return $result->toCollection($resultSet, isset($collection) ? $collection : null); - } - - /** - * 处理数据集 - * @access public - * @param array $resultSet - * @return void - */ - protected function resultSet(&$resultSet) - { - if (!empty($this->options['json'])) { - foreach ($resultSet as &$result) { - $this->jsonResult($result, $this->options['json'], true); - } - } - - if (!empty($this->options['with_attr'])) { - foreach ($resultSet as &$result) { - $this->getResultAttr($result, $this->options['with_attr']); - } - } - - if (!empty($this->options['collection']) || 'collection' == $this->connection->getConfig('resultset_type')) { - // 返回Collection对象 - $resultSet = new Collection($resultSet); - } - } - - /** - * 查找单条记录 - * @access public - * @param array|string|Query|\Closure $data - * @return array|null|\PDOStatement|string|Model - * @throws DbException - * @throws ModelNotFoundException - * @throws DataNotFoundException - */ - public function find($data = null) - { - if ($data instanceof Query) { - return $data->find(); - } elseif ($data instanceof \Closure) { - $data($this); - $data = null; - } - - $this->parseOptions(); - - if (!is_null($data)) { - // AR模式分析主键条件 - $this->parsePkWhere($data); - } - - $this->options['data'] = $data; - - $result = $this->connection->find($this); - - if ($this->options['fetch_sql']) { - return $result; - } - - // 数据处理 - if (empty($result)) { - return $this->resultToEmpty(); - } - - if (!empty($this->model)) { - // 返回模型对象 - $this->resultToModel($result, $this->options); - } else { - $this->result($result); - } - - return $result; - } - - /** - * 处理空数据 - * @access protected - * @return array|Model|null - * @throws DbException - * @throws ModelNotFoundException - * @throws DataNotFoundException - */ - protected function resultToEmpty() - { - if (!empty($this->options['allow_empty'])) { - return !empty($this->model) ? $this->model->newInstance([], $this->getModelUpdateCondition($this->options)) : []; - } elseif (!empty($this->options['fail'])) { - $this->throwNotFound($this->options); - } - } - - /** - * 查找单条记录 - * @access public - * @param mixed $data 主键值或者查询条件(闭包) - * @param mixed $with 关联预查询 - * @param bool $cache 是否缓存 - * @param bool $failException 是否抛出异常 - * @return static|null - * @throws exception\DbException - */ - public function get($data, $with = [], $cache = false, $failException = false) - { - if (is_null($data)) { - return; - } - - if (true === $with || is_int($with)) { - $cache = $with; - $with = []; - } - - return $this->parseQuery($data, $with, $cache) - ->failException($failException) - ->find($data); - } - - /** - * 查找单条记录 如果不存在直接抛出异常 - * @access public - * @param mixed $data 主键值或者查询条件(闭包) - * @param mixed $with 关联预查询 - * @param bool $cache 是否缓存 - * @return static|null - * @throws exception\DbException - */ - public function getOrFail($data, $with = [], $cache = false) - { - return $this->get($data, $with, $cache, true); - } - - /** - * 查找所有记录 - * @access public - * @param mixed $data 主键列表或者查询条件(闭包) - * @param array|string $with 关联预查询 - * @param bool $cache 是否缓存 - * @return static[]|false - * @throws exception\DbException - */ - public function all($data = null, $with = [], $cache = false) - { - if (true === $with || is_int($with)) { - $cache = $with; - $with = []; - } - - return $this->parseQuery($data, $with, $cache)->select($data); - } - - /** - * 分析查询表达式 - * @access public - * @param mixed $data 主键列表或者查询条件(闭包) - * @param string $with 关联预查询 - * @param bool $cache 是否缓存 - * @return Query - */ - protected function parseQuery(&$data, $with, $cache) - { - $result = $this->with($with)->cache($cache); - - if ((is_array($data) && key($data) !== 0) || $data instanceof Where) { - $result = $result->where($data); - $data = null; - } elseif ($data instanceof \Closure) { - $data($result); - $data = null; - } elseif ($data instanceof Query) { - $result = $data->with($with)->cache($cache); - $data = null; - } - - return $result; - } - - /** - * 处理数据 - * @access protected - * @param array $result 查询数据 - * @return void - */ - protected function result(&$result) - { - if (!empty($this->options['json'])) { - $this->jsonResult($result, $this->options['json'], true); - } - - if (!empty($this->options['with_attr'])) { - $this->getResultAttr($result, $this->options['with_attr']); - } - } - - /** - * 使用获取器处理数据 - * @access protected - * @param array $result 查询数据 - * @param array $withAttr 字段获取器 - * @return void - */ - protected function getResultAttr(&$result, $withAttr = []) - { - foreach ($withAttr as $name => $closure) { - $name = Loader::parseName($name); - - if (strpos($name, '.')) { - // 支持JSON字段 获取器定义 - list($key, $field) = explode('.', $name); - - if (isset($result[$key])) { - $result[$key][$field] = $closure(isset($result[$key][$field]) ? $result[$key][$field] : null, $result[$key]); - } - } else { - $result[$name] = $closure(isset($result[$name]) ? $result[$name] : null, $result); - } - } - } - - /** - * JSON字段数据转换 - * @access protected - * @param array $result 查询数据 - * @param array $json JSON字段 - * @param bool $assoc 是否转换为数组 - * @param array $withRelationAttr 关联获取器 - * @return void - */ - protected function jsonResult(&$result, $json = [], $assoc = false, $withRelationAttr = []) - { - foreach ($json as $name) { - if (isset($result[$name])) { - $result[$name] = json_decode($result[$name], $assoc); - - if (isset($withRelationAttr[$name])) { - foreach ($withRelationAttr[$name] as $key => $closure) { - $data = get_object_vars($result[$name]); - $result[$name]->$key = $closure(isset($result[$name]->$key) ? $result[$name]->$key : null, $data); - } - } - } - } - } - - /** - * 查询数据转换为模型对象 - * @access protected - * @param array $result 查询数据 - * @param array $options 查询参数 - * @param bool $resultSet 是否为数据集查询 - * @param array $withRelationAttr 关联字段获取器 - * @return void - */ - protected function resultToModel(&$result, $options = [], $resultSet = false, $withRelationAttr = []) - { - // 动态获取器 - if (!empty($options['with_attr']) && empty($withRelationAttr)) { - foreach ($options['with_attr'] as $name => $val) { - if (strpos($name, '.')) { - list($relation, $field) = explode('.', $name); - - $withRelationAttr[$relation][$field] = $val; - unset($options['with_attr'][$name]); - } - } - } - - // JSON 数据处理 - if (!empty($options['json'])) { - $this->jsonResult($result, $options['json'], $options['json_assoc'], $withRelationAttr); - } - - $result = $this->model->newInstance($result, $resultSet ? null : $this->getModelUpdateCondition($options)); - - // 动态获取器 - if (!empty($options['with_attr'])) { - $result->withAttribute($options['with_attr']); - } - - // 输出属性控制 - if (!empty($options['visible'])) { - $result->visible($options['visible']); - } elseif (!empty($options['hidden'])) { - $result->hidden($options['hidden']); - } - - if (!empty($options['append'])) { - $result->append($options['append']); - } - - // 关联查询 - if (!empty($options['relation'])) { - $result->relationQuery($options['relation'], $withRelationAttr); - } - - // 预载入查询 - if (!$resultSet && !empty($options['with'])) { - $result->eagerlyResult($result, $options['with'], $withRelationAttr); - } - - // JOIN预载入查询 - if (!$resultSet && !empty($options['with_join'])) { - $result->eagerlyResult($result, $options['with_join'], $withRelationAttr, true); - } - - // 关联统计 - if (!empty($options['with_count'])) { - foreach ($options['with_count'] as $val) { - $result->relationCount($result, $val[0], $val[1], $val[2]); - } - } - } - - /** - * 获取模型的更新条件 - * @access protected - * @param array $options 查询参数 - */ - protected function getModelUpdateCondition(array $options) - { - return isset($options['where']['AND']) ? $options['where']['AND'] : null; - } - - /** - * 查询失败 抛出异常 - * @access protected - * @param array $options 查询参数 - * @throws ModelNotFoundException - * @throws DataNotFoundException - */ - protected function throwNotFound($options = []) - { - if (!empty($this->model)) { - $class = get_class($this->model); - throw new ModelNotFoundException('model data Not Found:' . $class, $class, $options); - } - $table = is_array($options['table']) ? key($options['table']) : $options['table']; - throw new DataNotFoundException('table data not Found:' . $table, $table, $options); - } - - /** - * 查找多条记录 如果不存在则抛出异常 - * @access public - * @param array|string|Query|\Closure $data - * @return array|\PDOStatement|string|Model - * @throws DbException - * @throws ModelNotFoundException - * @throws DataNotFoundException - */ - public function selectOrFail($data = null) - { - return $this->failException(true)->select($data); - } - - /** - * 查找单条记录 如果不存在则抛出异常 - * @access public - * @param array|string|Query|\Closure $data - * @return array|\PDOStatement|string|Model - * @throws DbException - * @throws ModelNotFoundException - * @throws DataNotFoundException - */ - public function findOrFail($data = null) - { - return $this->failException(true)->find($data); - } - - /** - * 查找单条记录 如果不存在则抛出异常 - * @access public - * @param array|string|Query|\Closure $data - * @return array|\PDOStatement|string|Model - * @throws DbException - * @throws ModelNotFoundException - * @throws DataNotFoundException - */ - public function findOrEmpty($data = null) - { - return $this->allowEmpty(true)->find($data); - } - - /** - * 分批数据返回处理 - * @access public - * @param integer $count 每次处理的数据数量 - * @param callable $callback 处理回调方法 - * @param string|array $column 分批处理的字段名 - * @param string $order 字段排序 - * @return boolean - * @throws DbException - */ - public function chunk($count, $callback, $column = null, $order = 'asc') - { - $options = $this->getOptions(); - $column = $column ?: $this->getPk($options); - - if (isset($options['order'])) { - if (Container::get('app')->isDebug()) { - throw new DbException('chunk not support call order'); - } - unset($options['order']); - } - - $bind = $this->bind; - - if (is_array($column)) { - $times = 1; - $query = $this->options($options)->page($times, $count); - } else { - $query = $this->options($options)->limit($count); - - if (strpos($column, '.')) { - list($alias, $key) = explode('.', $column); - } else { - $key = $column; - } - } - - $resultSet = $query->order($column, $order)->select(); - - while (count($resultSet) > 0) { - if ($resultSet instanceof Collection) { - $resultSet = $resultSet->all(); - } - - if (false === call_user_func($callback, $resultSet)) { - return false; - } - - if (isset($times)) { - $times++; - $query = $this->options($options)->page($times, $count); - } else { - $end = end($resultSet); - $lastId = is_array($end) ? $end[$key] : $end->getData($key); - - $query = $this->options($options) - ->limit($count) - ->where($column, 'asc' == strtolower($order) ? '>' : '<', $lastId); - } - - $resultSet = $query->bind($bind)->order($column, $order)->select(); - } - - return true; - } - - /** - * 获取绑定的参数 并清空 - * @access public - * @param bool $clear - * @return array - */ - public function getBind($clear = true) - { - $bind = $this->bind; - if ($clear) { - $this->bind = []; - } - - return $bind; - } - - /** - * 创建子查询SQL - * @access public - * @param bool $sub - * @return string - * @throws DbException - */ - public function buildSql($sub = true) - { - return $sub ? '( ' . $this->select(false) . ' )' : $this->select(false); - } - - /** - * 视图查询处理 - * @access protected - * @param array $options 查询参数 - * @return void - */ - protected function parseView(&$options) - { - if (!isset($options['map'])) { - return; - } - - foreach (['AND', 'OR'] as $logic) { - if (isset($options['where'][$logic])) { - foreach ($options['where'][$logic] as $key => $val) { - if (array_key_exists($key, $options['map'])) { - array_shift($val); - array_unshift($val, $options['map'][$key]); - $options['where'][$logic][$options['map'][$key]] = $val; - unset($options['where'][$logic][$key]); - } - } - } - } - - if (isset($options['order'])) { - // 视图查询排序处理 - if (is_string($options['order'])) { - $options['order'] = explode(',', $options['order']); - } - foreach ($options['order'] as $key => $val) { - if (is_numeric($key) && is_string($val)) { - if (strpos($val, ' ')) { - list($field, $sort) = explode(' ', $val); - if (array_key_exists($field, $options['map'])) { - $options['order'][$options['map'][$field]] = $sort; - unset($options['order'][$key]); - } - } elseif (array_key_exists($val, $options['map'])) { - $options['order'][$options['map'][$val]] = 'asc'; - unset($options['order'][$key]); - } - } elseif (array_key_exists($key, $options['map'])) { - $options['order'][$options['map'][$key]] = $val; - unset($options['order'][$key]); - } - } - } - } - - /** - * 把主键值转换为查询条件 支持复合主键 - * @access public - * @param array|string $data 主键数据 - * @return void - * @throws Exception - */ - public function parsePkWhere($data) - { - $pk = $this->getPk($this->options); - // 获取当前数据表 - $table = is_array($this->options['table']) ? key($this->options['table']) : $this->options['table']; - - if (!empty($this->options['alias'][$table])) { - $alias = $this->options['alias'][$table]; - } - - if (is_string($pk)) { - $key = isset($alias) ? $alias . '.' . $pk : $pk; - // 根据主键查询 - if (is_array($data)) { - $where[$pk] = isset($data[$pk]) ? [$key, '=', $data[$pk]] : [$key, 'in', $data]; - } else { - $where[$pk] = strpos($data, ',') ? [$key, 'IN', $data] : [$key, '=', $data]; - } - } elseif (is_array($pk) && is_array($data) && !empty($data)) { - // 根据复合主键查询 - foreach ($pk as $key) { - if (isset($data[$key])) { - $attr = isset($alias) ? $alias . '.' . $key : $key; - $where[$key] = [$attr, '=', $data[$key]]; - } else { - throw new Exception('miss complex primary data'); - } - } - } - - if (!empty($where)) { - if (isset($this->options['where']['AND'])) { - $this->options['where']['AND'] = array_merge($this->options['where']['AND'], $where); - } else { - $this->options['where']['AND'] = $where; - } - } - - return; - } - - /** - * 分析表达式(可用于查询或者写入操作) - * @access protected - * @return array - */ - protected function parseOptions() - { - $options = $this->getOptions(); - - // 获取数据表 - if (empty($options['table'])) { - $options['table'] = $this->getTable(); - } - - if (!isset($options['where'])) { - $options['where'] = []; - } elseif (isset($options['view'])) { - // 视图查询条件处理 - $this->parseView($options); - } - - if (!isset($options['field'])) { - $options['field'] = '*'; - } - - foreach (['data', 'order', 'join', 'union'] as $name) { - if (!isset($options[$name])) { - $options[$name] = []; - } - } - - if (!isset($options['strict'])) { - $options['strict'] = $this->getConfig('fields_strict'); - } - - foreach (['master', 'lock', 'fetch_pdo', 'fetch_sql', 'distinct'] as $name) { - if (!isset($options[$name])) { - $options[$name] = false; - } - } - - if (isset(static::$readMaster['*']) || (is_string($options['table']) && isset(static::$readMaster[$options['table']]))) { - $options['master'] = true; - } - - foreach (['group', 'having', 'limit', 'force', 'comment'] as $name) { - if (!isset($options[$name])) { - $options[$name] = ''; - } - } - - if (isset($options['page'])) { - // 根据页数计算limit - list($page, $listRows) = $options['page']; - $page = $page > 0 ? $page : 1; - $listRows = $listRows > 0 ? $listRows : (is_numeric($options['limit']) ? $options['limit'] : 20); - $offset = $listRows * ($page - 1); - $options['limit'] = $offset . ',' . $listRows; - } - - $this->options = $options; - - return $options; - } - - /** - * 注册回调方法 - * @access public - * @param string $event 事件名 - * @param callable $callback 回调方法 - * @return void - */ - public static function event($event, $callback) - { - self::$event[$event] = $callback; - } - - /** - * 触发事件 - * @access public - * @param string $event 事件名 - * @return bool - */ - public function trigger($event) - { - $result = false; - - if (isset(self::$event[$event])) { - $result = Container::getInstance()->invoke(self::$event[$event], [$this]); - } - - return $result; - } - -} diff --git a/thinkphp/library/think/db/builder/Mysql.php b/thinkphp/library/think/db/builder/Mysql.php deleted file mode 100755 index 7ec3bf850..000000000 --- a/thinkphp/library/think/db/builder/Mysql.php +++ /dev/null @@ -1,174 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\db\builder; - -use think\db\Builder; -use think\db\Expression; -use think\db\Query; -use think\Exception; - -/** - * mysql数据库驱动 - */ -class Mysql extends Builder -{ - // 查询表达式解析 - protected $parser = [ - 'parseCompare' => ['=', '<>', '>', '>=', '<', '<='], - 'parseLike' => ['LIKE', 'NOT LIKE'], - 'parseBetween' => ['NOT BETWEEN', 'BETWEEN'], - 'parseIn' => ['NOT IN', 'IN'], - 'parseExp' => ['EXP'], - 'parseRegexp' => ['REGEXP', 'NOT REGEXP'], - 'parseNull' => ['NOT NULL', 'NULL'], - 'parseBetweenTime' => ['BETWEEN TIME', 'NOT BETWEEN TIME'], - 'parseTime' => ['< TIME', '> TIME', '<= TIME', '>= TIME'], - 'parseExists' => ['NOT EXISTS', 'EXISTS'], - 'parseColumn' => ['COLUMN'], - ]; - - protected $insertAllSql = '%INSERT% INTO %TABLE% (%FIELD%) VALUES %DATA% %COMMENT%'; - protected $updateSql = 'UPDATE %TABLE% %JOIN% SET %SET% %WHERE% %ORDER%%LIMIT% %LOCK%%COMMENT%'; - - /** - * 生成insertall SQL - * @access public - * @param Query $query 查询对象 - * @param array $dataSet 数据集 - * @param bool $replace 是否replace - * @return string - */ - public function insertAll(Query $query, $dataSet, $replace = false) - { - $options = $query->getOptions(); - - // 获取合法的字段 - if ('*' == $options['field']) { - $allowFields = $this->connection->getTableFields($options['table']); - } else { - $allowFields = $options['field']; - } - - // 获取绑定信息 - $bind = $this->connection->getFieldsBind($options['table']); - - foreach ($dataSet as $k => $data) { - $data = $this->parseData($query, $data, $allowFields, $bind, '_' . $k); - - $values[] = '( ' . implode(',', array_values($data)) . ' )'; - - if (!isset($insertFields)) { - $insertFields = array_keys($data); - } - } - - $fields = []; - foreach ($insertFields as $field) { - $fields[] = $this->parseKey($query, $field); - } - - return str_replace( - ['%INSERT%', '%TABLE%', '%FIELD%', '%DATA%', '%COMMENT%'], - [ - $replace ? 'REPLACE' : 'INSERT', - $this->parseTable($query, $options['table']), - implode(' , ', $fields), - implode(' , ', $values), - $this->parseComment($query, $options['comment']), - ], - $this->insertAllSql); - } - - /** - * 正则查询 - * @access protected - * @param Query $query 查询对象 - * @param string $key - * @param string $exp - * @param Expression $value - * @param string $field - * @return string - */ - protected function parseRegexp(Query $query, $key, $exp, Expression $value, $field) - { - return $key . ' ' . $exp . ' ' . $value->getValue(); - } - - /** - * 字段和表名处理 - * @access public - * @param Query $query 查询对象 - * @param mixed $key 字段名 - * @param bool $strict 严格检测 - * @return string - */ - public function parseKey(Query $query, $key, $strict = false) - { - if (is_numeric($key)) { - return $key; - } elseif ($key instanceof Expression) { - return $key->getValue(); - } - - $key = trim($key); - - if (strpos($key, '->') && false === strpos($key, '(')) { - // JSON字段支持 - list($field, $name) = explode('->', $key, 2); - - return 'json_extract(' . $this->parseKey($query, $field, true) . ', \'$.' . str_replace('->', '.', $name) . '\')'; - } elseif (strpos($key, '.') && !preg_match('/[,\'\"\(\)`\s]/', $key)) { - list($table, $key) = explode('.', $key, 2); - - $alias = $query->getOptions('alias'); - - if ('__TABLE__' == $table) { - $table = $query->getOptions('table'); - $table = is_array($table) ? array_shift($table) : $table; - } - - if (isset($alias[$table])) { - $table = $alias[$table]; - } - } - - if ($strict && !preg_match('/^[\w\.\*]+$/', $key)) { - throw new Exception('not support data:' . $key); - } - - if ('*' != $key && ($strict || !preg_match('/[,\'\"\*\(\)`.\s]/', $key))) { - $key = '`' . $key . '`'; - } - - if (isset($table)) { - if (strpos($table, '.')) { - $table = str_replace('.', '`.`', $table); - } - - $key = '`' . $table . '`.' . $key; - } - - return $key; - } - - /** - * 随机排序 - * @access protected - * @param Query $query 查询对象 - * @return string - */ - protected function parseRand(Query $query) - { - return 'rand()'; - } - -} diff --git a/thinkphp/library/think/db/connector/Sqlsrv.php b/thinkphp/library/think/db/connector/Sqlsrv.php deleted file mode 100755 index 123affb87..000000000 --- a/thinkphp/library/think/db/connector/Sqlsrv.php +++ /dev/null @@ -1,235 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\db\connector; - -use PDO; -use think\db\Connection; -use think\db\Query; - -/** - * Sqlsrv数据库驱动 - */ -class Sqlsrv extends Connection -{ - // PDO连接参数 - protected $params = [ - PDO::ATTR_CASE => PDO::CASE_NATURAL, - PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, - PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL, - PDO::ATTR_STRINGIFY_FETCHES => false, - ]; - - protected $builder = '\\think\\db\\builder\\Sqlsrv'; - - /** - * 解析pdo连接的dsn信息 - * @access protected - * @param array $config 连接信息 - * @return string - */ - protected function parseDsn($config) - { - $dsn = 'sqlsrv:Database=' . $config['database'] . ';Server=' . $config['hostname']; - - if (!empty($config['hostport'])) { - $dsn .= ',' . $config['hostport']; - } - - return $dsn; - } - - /** - * 取得数据表的字段信息 - * @access public - * @param string $tableName - * @return array - */ - public function getFields($tableName) - { - list($tableName) = explode(' ', $tableName); - $tableNames = explode('.', $tableName); - $tableName = isset($tableNames[1]) ? $tableNames[1] : $tableNames[0]; - - $sql = "SELECT column_name, data_type, column_default, is_nullable - FROM information_schema.tables AS t - JOIN information_schema.columns AS c - ON t.table_catalog = c.table_catalog - AND t.table_schema = c.table_schema - AND t.table_name = c.table_name - WHERE t.table_name = '$tableName'"; - - $pdo = $this->query($sql, [], false, true); - $result = $pdo->fetchAll(PDO::FETCH_ASSOC); - $info = []; - - if ($result) { - foreach ($result as $key => $val) { - $val = array_change_key_case($val); - $info[$val['column_name']] = [ - 'name' => $val['column_name'], - 'type' => $val['data_type'], - 'notnull' => (bool) ('' === $val['is_nullable']), // not null is empty, null is yes - 'default' => $val['column_default'], - 'primary' => false, - 'autoinc' => false, - ]; - } - } - - $sql = "SELECT column_name FROM information_schema.key_column_usage WHERE table_name='$tableName'"; - - // 调试开始 - $this->debug(true); - - $pdo = $this->linkID->query($sql); - - // 调试结束 - $this->debug(false, $sql); - - $result = $pdo->fetch(PDO::FETCH_ASSOC); - - if ($result) { - $info[$result['column_name']]['primary'] = true; - } - - return $this->fieldCase($info); - } - - /** - * 取得数据表的字段信息 - * @access public - * @param string $dbName - * @return array - */ - public function getTables($dbName = '') - { - $sql = "SELECT TABLE_NAME - FROM INFORMATION_SCHEMA.TABLES - WHERE TABLE_TYPE = 'BASE TABLE' - "; - - $pdo = $this->query($sql, [], false, true); - $result = $pdo->fetchAll(PDO::FETCH_ASSOC); - $info = []; - - foreach ($result as $key => $val) { - $info[$key] = current($val); - } - - return $info; - } - - /** - * 得到某个列的数组 - * @access public - * @param Query $query 查询对象 - * @param string $field 字段名 多个字段用逗号分隔 - * @param string $key 索引 - * @return array - */ - public function column(Query $query, $field, $key = '') - { - $options = $query->getOptions(); - - if (empty($options['fetch_sql']) && !empty($options['cache'])) { - // 判断查询缓存 - $cache = $options['cache']; - - $guid = is_string($cache['key']) ? $cache['key'] : $this->getCacheKey($query, $field); - - $result = Container::get('cache')->get($guid); - - if (false !== $result) { - return $result; - } - } - - if (isset($options['field'])) { - $query->removeOption('field'); - } - - if (is_null($field)) { - $field = '*'; - } elseif ($key && '*' != $field) { - $field = $key . ',' . $field; - } - - if (is_string($field)) { - $field = array_map('trim', explode(',', $field)); - } - - $query->setOption('field', $field); - - // 生成查询SQL - $sql = $this->builder->select($query); - - $bind = $query->getBind(); - - if (!empty($options['fetch_sql'])) { - // 获取实际执行的SQL语句 - return $this->getRealSql($sql, $bind); - } - - // 执行查询操作 - $pdo = $this->query($sql, $bind, $options['master'], true); - - if (1 == $pdo->columnCount()) { - $result = $pdo->fetchAll(PDO::FETCH_COLUMN); - } else { - $resultSet = $pdo->fetchAll(PDO::FETCH_ASSOC); - - if ('*' == $field && $key) { - $result = array_column($resultSet, null, $key); - } elseif ($resultSet) { - $fields = array_keys($resultSet[0]); - $count = count($fields); - $key1 = array_shift($fields); - $key2 = $fields ? array_shift($fields) : ''; - $key = $key ?: $key1; - - if (strpos($key, '.')) { - list($alias, $key) = explode('.', $key); - } - - if (3 == $count) { - $column = $key2; - } elseif ($count < 3) { - $column = $key1; - } else { - $column = null; - } - - $result = array_column($resultSet, $column, $key); - } else { - $result = []; - } - } - - if (isset($cache) && isset($guid)) { - // 缓存数据 - $this->cacheData($guid, $result, $cache); - } - - return $result; - } - - /** - * SQL性能分析 - * @access protected - * @param string $sql - * @return array - */ - protected function getExplain($sql) - { - return []; - } -} diff --git a/thinkphp/library/think/exception/ThrowableError.php b/thinkphp/library/think/exception/ThrowableError.php deleted file mode 100755 index 87b6b9d74..000000000 --- a/thinkphp/library/think/exception/ThrowableError.php +++ /dev/null @@ -1,47 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\exception; - -class ThrowableError extends \ErrorException -{ - public function __construct(\Throwable $e) - { - - if ($e instanceof \ParseError) { - $message = 'Parse error: ' . $e->getMessage(); - $severity = E_PARSE; - } elseif ($e instanceof \TypeError) { - $message = 'Type error: ' . $e->getMessage(); - $severity = E_RECOVERABLE_ERROR; - } else { - $message = 'Fatal error: ' . $e->getMessage(); - $severity = E_ERROR; - } - - parent::__construct( - $message, - $e->getCode(), - $severity, - $e->getFile(), - $e->getLine() - ); - - $this->setTrace($e->getTrace()); - } - - protected function setTrace($trace) - { - $traceReflector = new \ReflectionProperty('Exception', 'trace'); - $traceReflector->setAccessible(true); - $traceReflector->setValue($this, $trace); - } -} diff --git a/thinkphp/library/think/facade/App.php b/thinkphp/library/think/facade/App.php deleted file mode 100755 index b375aa09f..000000000 --- a/thinkphp/library/think/facade/App.php +++ /dev/null @@ -1,63 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\facade; - -use think\Facade; - -/** - * @see \think\App - * @mixin \think\App - * @method \think\App bind(string $bind) static 绑定模块或者控制器 - * @method void initialize() static 初始化应用 - * @method void init(string $module='') static 初始化模块 - * @method \think\Response run() static 执行应用 - * @method \think\App dispatch(\think\route\Dispatch $dispatch) static 设置当前请求的调度信息 - * @method void log(mixed $log, string $type = 'info') static 记录调试信息 - * @method mixed config(string $name='') static 获取配置参数 - * @method \think\route\Dispatch routeCheck() static URL路由检测(根据PATH_INFO) - * @method \think\App routeMust(bool $must = false) static 设置应用的路由检测机制 - * @method \think\Model model(string $name = '', string $layer = 'model', bool $appendSuffix = false, string $common = 'common') static 实例化模型 - * @method object controller(string $name, string $layer = 'controller', bool $appendSuffix = false, string $empty = '') static 实例化控制器 - * @method \think\Validate validate(string $name = '', string $layer = 'validate', bool $appendSuffix = false, string $common = 'common') static 实例化验证器类 - * @method \think\db\Query db(mixed $config = [], mixed $name = false) static 数据库初始化 - * @method mixed action(string $url, $vars = [], $layer = 'controller', $appendSuffix = false) static 调用模块的操作方法 - * @method string parseClass(string $module, string $layer, string $name, bool $appendSuffix = false) static 解析应用类的类名 - * @method string version() static 获取框架版本 - * @method bool isDebug() static 是否为调试模式 - * @method string getModulePath() static 获取当前模块路径 - * @method void setModulePath(string $path) static 设置当前模块路径 - * @method string getRootPath() static 获取应用根目录 - * @method string getAppPath() static 获取应用类库目录 - * @method string getRuntimePath() static 获取应用运行时目录 - * @method string getThinkPath() static 获取核心框架目录 - * @method string getRoutePath() static 获取路由目录 - * @method string getConfigPath() static 获取应用配置目录 - * @method string getConfigExt() static 获取配置后缀 - * @method string setNamespace(string $namespace) static 设置应用类库命名空间 - * @method string getNamespace() static 获取应用类库命名空间 - * @method string getSuffix() static 是否启用类库后缀 - * @method float getBeginTime() static 获取应用开启时间 - * @method integer getBeginMem() static 获取应用初始内存占用 - * @method \think\Container container() static 获取容器实例 - */ -class App extends Facade -{ - /** - * 获取当前Facade对应类名(或者已经绑定的容器对象标识) - * @access protected - * @return string - */ - protected static function getFacadeClass() - { - return 'app'; - } -} diff --git a/thinkphp/library/think/facade/Build.php b/thinkphp/library/think/facade/Build.php deleted file mode 100755 index c051bea11..000000000 --- a/thinkphp/library/think/facade/Build.php +++ /dev/null @@ -1,33 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\facade; - -use think\Facade; - -/** - * @see \think\Build - * @mixin \think\Build - * @method void run(array $build = [], string $namespace = 'app', bool $suffix = false) static 根据传入的build资料创建目录和文件 - * @method void module(string $module = '', array $list = [], string $namespace = 'app', bool $suffix = false) static 创建模块 - */ -class Build extends Facade -{ - /** - * 获取当前Facade对应类名(或者已经绑定的容器对象标识) - * @access protected - * @return string - */ - protected static function getFacadeClass() - { - return 'build'; - } -} diff --git a/thinkphp/library/think/facade/Cache.php b/thinkphp/library/think/facade/Cache.php deleted file mode 100755 index 9743486eb..000000000 --- a/thinkphp/library/think/facade/Cache.php +++ /dev/null @@ -1,45 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\facade; - -use think\Facade; - -/** - * @see \think\Cache - * @mixin \think\Cache - * @method \think\cache\Driver connect(array $options = [], mixed $name = false) static 连接缓存 - * @method \think\cache\Driver init(array $options = []) static 初始化缓存 - * @method \think\cache\Driver store(string $name = '') static 切换缓存类型 - * @method bool has(string $name) static 判断缓存是否存在 - * @method mixed get(string $name, mixed $default = false) static 读取缓存 - * @method mixed pull(string $name) static 读取缓存并删除 - * @method mixed set(string $name, mixed $value, int $expire = null) static 设置缓存 - * @method mixed remember(string $name, mixed $value, int $expire = null) static 如果不存在则写入缓存 - * @method mixed inc(string $name, int $step = 1) static 自增缓存(针对数值缓存) - * @method mixed dec(string $name, int $step = 1) static 自减缓存(针对数值缓存) - * @method bool rm(string $name) static 删除缓存 - * @method bool clear(string $tag = null) static 清除缓存 - * @method mixed tag(string $name, mixed $keys = null, bool $overlay = false) static 缓存标签 - * @method object handler() static 返回句柄对象,可执行其它高级方法 - */ -class Cache extends Facade -{ - /** - * 获取当前Facade对应类名(或者已经绑定的容器对象标识) - * @access protected - * @return string - */ - protected static function getFacadeClass() - { - return 'cache'; - } -} diff --git a/thinkphp/library/think/facade/Debug.php b/thinkphp/library/think/facade/Debug.php deleted file mode 100755 index df20086d1..000000000 --- a/thinkphp/library/think/facade/Debug.php +++ /dev/null @@ -1,40 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\facade; - -use think\Facade; - -/** - * @see \think\Debug - * @mixin \think\Debug - * @method void remark(string $name, mixed $value = '') static 记录时间(微秒)和内存使用情况 - * @method int getRangeTime(string $start, string $end, mixed $dec = 6) static 统计某个区间的时间(微秒)使用情况 - * @method int getUseTime(int $dec = 6) static 统计从开始到统计时的时间(微秒)使用情况 - * @method string getThroughputRate(string $start, string $end, mixed $dec = 6) static 获取当前访问的吞吐率情况 - * @method string getRangeMem(string $start, string $end, mixed $dec = 2) static 记录区间的内存使用情况 - * @method int getUseMem(int $dec = 2) static 统计从开始到统计时的内存使用情况 - * @method string getMemPeak(string $start, string $end, mixed $dec = 2) static 统计区间的内存峰值情况 - * @method mixed getFile(bool $detail = false) static 获取文件加载信息 - * @method mixed dump(mixed $var, bool $echo = true, string $label = null, int $flags = ENT_SUBSTITUTE) static 浏览器友好的变量输出 - */ -class Debug extends Facade -{ - /** - * 获取当前Facade对应类名(或者已经绑定的容器对象标识) - * @access protected - * @return string - */ - protected static function getFacadeClass() - { - return 'debug'; - } -} diff --git a/thinkphp/library/think/facade/Hook.php b/thinkphp/library/think/facade/Hook.php deleted file mode 100755 index e9e120838..000000000 --- a/thinkphp/library/think/facade/Hook.php +++ /dev/null @@ -1,37 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\facade; - -use think\Facade; - -/** - * @see \think\Hook - * @mixin \think\Hook - * @method \think\Hook alias(mixed $name, mixed $behavior = null) static 指定行为标识 - * @method void add(string $tag, mixed $behavior, bool $first = false) static 动态添加行为扩展到某个标签 - * @method void import(array $tags, bool $recursive = true) static 批量导入插件 - * @method array get(string $tag = '') static 获取插件信息 - * @method mixed listen(string $tag, mixed $params = null, bool $once = false) static 监听标签的行为 - * @method mixed exec(mixed $class, mixed $params = null) static 执行行为 - */ -class Hook extends Facade -{ - /** - * 获取当前Facade对应类名(或者已经绑定的容器对象标识) - * @access protected - * @return string - */ - protected static function getFacadeClass() - { - return 'hook'; - } -} diff --git a/thinkphp/library/think/facade/Lang.php b/thinkphp/library/think/facade/Lang.php deleted file mode 100755 index 56c4777db..000000000 --- a/thinkphp/library/think/facade/Lang.php +++ /dev/null @@ -1,41 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\facade; - -use think\Facade; - -/** - * @see \think\Lang - * @mixin \think\Lang - * @method mixed range($range = '') static 设定当前的语言 - * @method mixed set(mixed $name, string $value = null, string $range = '') static 设置语言定义 - * @method array load(mixed $file, string $range = '') static 加载语言定义 - * @method mixed get(string $name = null, array $vars = [], string $range = '') static 获取语言定义 - * @method mixed has(string $name, string $range = '') static 获取语言定义 - * @method string detect() static 自动侦测设置获取语言选择 - * @method void saveToCookie(string $lang = null) static 设置当前语言到Cookie - * @method void setLangDetectVar(string $var) static 设置语言自动侦测的变量 - * @method void setLangCookieVar(string $var) static 设置语言的cookie保存变量 - * @method void setAllowLangList(array $list) static 设置允许的语言列表 - */ -class Lang extends Facade -{ - /** - * 获取当前Facade对应类名(或者已经绑定的容器对象标识) - * @access protected - * @return string - */ - protected static function getFacadeClass() - { - return 'lang'; - } -} diff --git a/thinkphp/library/think/facade/Log.php b/thinkphp/library/think/facade/Log.php deleted file mode 100755 index ddf851ea4..000000000 --- a/thinkphp/library/think/facade/Log.php +++ /dev/null @@ -1,49 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\facade; - -use think\Facade; - -/** - * @see \think\Log - * @mixin \think\Log - * @method \think\Log init(array $config = []) static 日志初始化 - * @method mixed getLog(string $type = '') static 获取日志信息 - * @method \think\Log record(mixed $msg, string $type = 'info', array $context = []) static 记录日志信息 - * @method \think\Log clear() static 清空日志信息 - * @method \think\Log key(string $key) static 当前日志记录的授权key - * @method bool check(array $config) static 检查日志写入权限 - * @method bool save() static 保存调试信息 - * @method void write(mixed $msg, string $type = 'info', bool $force = false) static 实时写入日志信息 - * @method void log(string $level,mixed $message, array $context = []) static 记录日志信息 - * @method void emergency(mixed $message, array $context = []) static 记录emergency信息 - * @method void alert(mixed $message, array $context = []) static 记录alert信息 - * @method void critical(mixed $message, array $context = []) static 记录critical信息 - * @method void error(mixed $message, array $context = []) static 记录error信息 - * @method void warning(mixed $message, array $context = []) static 记录warning信息 - * @method void notice(mixed $message, array $context = []) static 记录notice信息 - * @method void info(mixed $message, array $context = []) static 记录info信息 - * @method void debug(mixed $message, array $context = []) static 记录debug信息 - * @method void sql(mixed $message, array $context = []) static 记录sql信息 - */ -class Log extends Facade -{ - /** - * 获取当前Facade对应类名(或者已经绑定的容器对象标识) - * @access protected - * @return string - */ - protected static function getFacadeClass() - { - return 'log'; - } -} diff --git a/thinkphp/library/think/facade/Request.php b/thinkphp/library/think/facade/Request.php deleted file mode 100755 index 0989253f9..000000000 --- a/thinkphp/library/think/facade/Request.php +++ /dev/null @@ -1,97 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\facade; - -use think\Facade; - -/** - * @see \think\Request - * @mixin \think\Request - * @method void hook(mixed $method, mixed $callback = null) static Hook 方法注入 - * @method \think\Request create(string $uri, string $method = 'GET', array $params = [], array $cookie = [], array $files = [], array $server = [], string $content = null) static 创建一个URL请求 - * @method mixed domain(bool $port = false) static 获取当前包含协议、端口的域名 - * @method mixed url(bool $domain = false) static 获取当前完整URL - * @method mixed baseUrl(bool $domain = false) static 获取当前URL - * @method mixed baseFile(bool $domain = false) static 获取当前执行的文件 - * @method mixed root(bool $domain = false) static 获取URL访问根地址 - * @method string rootUrl() static 获取URL访问根目录 - * @method string pathinfo() static 获取当前请求URL的pathinfo信息(含URL后缀) - * @method string path() static 获取当前请求URL的pathinfo信息(不含URL后缀) - * @method string ext() static 当前URL的访问后缀 - * @method float time(bool $float = false) static 获取当前请求的时间 - * @method mixed type() static 当前请求的资源类型 - * @method void mimeType(mixed $type, string $val = '') static 设置资源类型 - * @method string method(bool $method = false) static 当前的请求类型 - * @method bool isGet() static 是否为GET请求 - * @method bool isPost() static 是否为POST请求 - * @method bool isPut() static 是否为PUT请求 - * @method bool isDelete() static 是否为DELTE请求 - * @method bool isHead() static 是否为HEAD请求 - * @method bool isPatch() static 是否为PATCH请求 - * @method bool isOptions() static 是否为OPTIONS请求 - * @method bool isCli() static 是否为cli - * @method bool isCgi() static 是否为cgi - * @method mixed param(string $name = '', mixed $default = null, mixed $filter = '') static 获取当前请求的参数 - * @method mixed route(string $name = '', mixed $default = null, mixed $filter = '') static 设置获取路由参数 - * @method mixed get(string $name = '', mixed $default = null, mixed $filter = '') static 设置获取GET参数 - * @method mixed post(string $name = '', mixed $default = null, mixed $filter = '') static 设置获取POST参数 - * @method mixed put(string $name = '', mixed $default = null, mixed $filter = '') static 设置获取PUT参数 - * @method mixed delete(string $name = '', mixed $default = null, mixed $filter = '') static 设置获取DELETE参数 - * @method mixed patch(string $name = '', mixed $default = null, mixed $filter = '') static 设置获取PATCH参数 - * @method mixed request(string $name = '', mixed $default = null, mixed $filter = '') static 获取request变量 - * @method mixed session(string $name = '', mixed $default = null, mixed $filter = '') static 获取session数据 - * @method mixed cookie(string $name = '', mixed $default = null, mixed $filter = '') static 获取cookie参数 - * @method mixed server(string $name = '', mixed $default = null, mixed $filter = '') static 获取server参数 - * @method mixed env(string $name = '', mixed $default = null, mixed $filter = '') static 获取环境变量 - * @method mixed file(string $name = '') static 获取上传的文件信息 - * @method mixed header(string $name = '', mixed $default = null) static 设置或者获取当前的Header - * @method mixed input(array $data,mixed $name = '', mixed $default = null, mixed $filter = '') static 获取变量 支持过滤和默认值 - * @method mixed filter(mixed $filter = null) static 设置或获取当前的过滤规则 - * @method mixed has(string $name, string $type = 'param', bool $checkEmpty = false) static 是否存在某个请求参数 - * @method mixed only(mixed $name, string $type = 'param') static 获取指定的参数 - * @method mixed except(mixed $name, string $type = 'param') static 排除指定参数获取 - * @method bool isSsl() static 当前是否ssl - * @method bool isAjax(bool $ajax = false) static 当前是否Ajax请求 - * @method bool isPjax(bool $pjax = false) static 当前是否Pjax请求 - * @method mixed ip(int $type = 0, bool $adv = true) static 获取客户端IP地址 - * @method bool isMobile() static 检测是否使用手机访问 - * @method string scheme() static 当前URL地址中的scheme参数 - * @method string query() static 当前请求URL地址中的query参数 - * @method string host(bool $stric = false) static 当前请求的host - * @method string port() static 当前请求URL地址中的port参数 - * @method string protocol() static 当前请求 SERVER_PROTOCOL - * @method string remotePort() static 当前请求 REMOTE_PORT - * @method string contentType() static 当前请求 HTTP_CONTENT_TYPE - * @method array routeInfo() static 获取当前请求的路由信息 - * @method array dispatch() static 获取当前请求的调度信息 - * @method string module() static 获取当前的模块名 - * @method string controller(bool $convert = false) static 获取当前的控制器名 - * @method string action(bool $convert = false) static 获取当前的操作名 - * @method string langset() static 获取当前的语言 - * @method string getContent() static 设置或者获取当前请求的content - * @method string getInput() static 获取当前请求的php://input - * @method string token(string $name = '__token__', mixed $type = 'md5') static 生成请求令牌 - * @method string cache(string $key, mixed $expire = null, array $except = [], string $tag = null) static 设置当前地址的请求缓存 - * @method string getCache() static 读取请求缓存设置 - */ -class Request extends Facade -{ - /** - * 获取当前Facade对应类名(或者已经绑定的容器对象标识) - * @access protected - * @return string - */ - protected static function getFacadeClass() - { - return 'request'; - } -} diff --git a/thinkphp/library/think/facade/Response.php b/thinkphp/library/think/facade/Response.php deleted file mode 100755 index d7de142f0..000000000 --- a/thinkphp/library/think/facade/Response.php +++ /dev/null @@ -1,47 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\facade; - -use think\Facade; - -/** - * @see \think\Response - * @mixin \think\Response - * @method \think\response create(mixed $data = '', string $type = '', int $code = 200, array $header = [], array $options = []) static 创建Response对象 - * @method void send() static 发送数据到客户端 - * @method \think\Response options(mixed $options = []) static 输出的参数 - * @method \think\Response data(mixed $data) static 输出数据设置 - * @method \think\Response header(mixed $name, string $value = null) static 设置响应头 - * @method \think\Response content(mixed $content) static 设置页面输出内容 - * @method \think\Response code(int $code) static 发送HTTP状态 - * @method \think\Response lastModified(string $time) static LastModified - * @method \think\Response expires(string $time) static expires - * @method \think\Response eTag(string $eTag) static eTag - * @method \think\Response cacheControl(string $cache) static 页面缓存控制 - * @method \think\Response contentType(string $contentType, string $charset = 'utf-8') static 页面输出类型 - * @method mixed getHeader(string $name) static 获取头部信息 - * @method mixed getData() static 获取原始数据 - * @method mixed getContent() static 获取输出数据 - * @method int getCode() static 获取状态码 - */ -class Response extends Facade -{ - /** - * 获取当前Facade对应类名(或者已经绑定的容器对象标识) - * @access protected - * @return string - */ - protected static function getFacadeClass() - { - return 'response'; - } -} diff --git a/thinkphp/library/think/facade/Route.php b/thinkphp/library/think/facade/Route.php deleted file mode 100755 index 77196dfe4..000000000 --- a/thinkphp/library/think/facade/Route.php +++ /dev/null @@ -1,57 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\facade; - -use think\Facade; - -/** - * @see \think\Route - * @mixin \think\Route - * @method \think\route\Domain domain(mixed $name, mixed $rule = '', array $option = [], array $pattern = []) static 注册域名路由 - * @method \think\Route pattern(mixed $name, string $rule = '') static 注册变量规则 - * @method \think\Route option(mixed $name, mixed $value = '') static 注册路由参数 - * @method \think\Route bind(string $bind) static 设置路由绑定 - * @method mixed getBind(string $bind) static 读取路由绑定 - * @method \think\Route name(string $name) static 设置当前路由标识 - * @method mixed getName(string $name) static 读取路由标识 - * @method void setName(string $name) static 批量导入路由标识 - * @method void import(array $rules, string $type = '*') static 导入配置文件的路由规则 - * @method \think\route\RuleItem rule(string $rule, mixed $route, string $method = '*', array $option = [], array $pattern = []) static 注册路由规则 - * @method void rules(array $rules, string $method = '*', array $option = [], array $pattern = []) static 批量注册路由规则 - * @method \think\route\RuleGroup group(string|array $name, mixed $route, string $method = '*', array $option = [], array $pattern = []) static 注册路由分组 - * @method \think\route\RuleItem any(string $rule, mixed $route, array $option = [], array $pattern = []) static 注册路由 - * @method \think\route\RuleItem get(string $rule, mixed $route, array $option = [], array $pattern = []) static 注册路由 - * @method \think\route\RuleItem post(string $rule, mixed $route, array $option = [], array $pattern = []) static 注册路由 - * @method \think\route\RuleItem put(string $rule, mixed $route, array $option = [], array $pattern = []) static 注册路由 - * @method \think\route\RuleItem delete(string $rule, mixed $route, array $option = [], array $pattern = []) static 注册路由 - * @method \think\route\RuleItem patch(string $rule, mixed $route, array $option = [], array $pattern = []) static 注册路由 - * @method \think\route\Resource resource(string $rule, mixed $route, array $option = [], array $pattern = []) static 注册资源路由 - * @method \think\Route controller(string $rule, mixed $route, array $option = [], array $pattern = []) static 注册控制器路由 - * @method \think\Route alias(string $rule, mixed $route, array $option = [], array $pattern = []) static 注册别名路由 - * @method \think\Route setMethodPrefix(mixed $method, string $prefix = '') static 设置不同请求类型下面的方法前缀 - * @method \think\Route rest(string $name, array $resource = []) static rest方法定义和修改 - * @method \think\Route\RuleItem miss(string $route, string $method = '*', array $option = []) static 注册未匹配路由规则后的处理 - * @method \think\Route\RuleItem auto(string $route) static 注册一个自动解析的URL路由 - * @method \think\Route\Dispatch check(string $url, string $depr = '/', bool $must = false, bool $completeMatch = false) static 检测URL路由 - */ -class Route extends Facade -{ - /** - * 获取当前Facade对应类名(或者已经绑定的容器对象标识) - * @access protected - * @return string - */ - protected static function getFacadeClass() - { - return 'route'; - } -} diff --git a/thinkphp/library/think/facade/Session.php b/thinkphp/library/think/facade/Session.php deleted file mode 100755 index fb9206afa..000000000 --- a/thinkphp/library/think/facade/Session.php +++ /dev/null @@ -1,46 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\facade; - -use think\Facade; - -/** - * @see \think\Session - * @mixin \think\Session - * @method void init(array $config = []) static session初始化 - * @method bool has(string $name,string $prefix = null) static 判断session数据 - * @method mixed prefix(string $prefix = '') static 设置或者获取session作用域(前缀) - * @method mixed get(string $name = '',string $prefix = null) static session获取 - * @method mixed pull(string $name,string $prefix = null) static session获取并删除 - * @method void push(string $key, mixed $value) static 添加数据到一个session数组 - * @method void set(string $name, mixed $value , string $prefix = null) static 设置session数据 - * @method void flash(string $name, mixed $value = null) static session设置 下一次请求有效 - * @method void flush() static 清空当前请求的session数据 - * @method void delete(string $name, string $prefix = null) static 删除session数据 - * @method void clear($prefix = null) static 清空session数据 - * @method void start() static 启动session - * @method void destroy() static 销毁session - * @method void pause() static 暂停session - * @method void regenerate(bool $delete = false) static 重新生成session_id - */ -class Session extends Facade -{ - /** - * 获取当前Facade对应类名(或者已经绑定的容器对象标识) - * @access protected - * @return string - */ - protected static function getFacadeClass() - { - return 'session'; - } -} diff --git a/thinkphp/library/think/facade/Template.php b/thinkphp/library/think/facade/Template.php deleted file mode 100755 index f91b11821..000000000 --- a/thinkphp/library/think/facade/Template.php +++ /dev/null @@ -1,36 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\facade; - -use think\Facade; - -/** - * @see \think\Template - * @mixin \think\Template - * @method void assign(mixed $name, mixed $value = '') static 模板变量赋值 - * @method mixed get(string $name = '') static 获取模板变量 - * @method void fetch(string $template, array $vars = [], array $config = []) static 渲染模板文件 - * @method void display(string $content, array $vars = [], array $config = []) static 渲染模板内容 - * @method mixed layout(string $name, string $replace = '') static 设置模板布局 - */ -class Template extends Facade -{ - /** - * 获取当前Facade对应类名(或者已经绑定的容器对象标识) - * @access protected - * @return string - */ - protected static function getFacadeClass() - { - return 'template'; - } -} diff --git a/thinkphp/library/think/facade/Validate.php b/thinkphp/library/think/facade/Validate.php deleted file mode 100755 index a6eec23e4..000000000 --- a/thinkphp/library/think/facade/Validate.php +++ /dev/null @@ -1,75 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\facade; - -use think\Facade; - -/** - * @see \think\Validate - * @mixin \think\Validate - * @method \think\Validate make(array $rules = [], array $message = [], array $field = []) static 创建一个验证器类 - * @method \think\Validate rule(mixed $name, mixed $rule = '') static 添加字段验证规则 - * @method void extend(string $type, mixed $callback = null) static 注册扩展验证(类型)规则 - * @method void setTypeMsg(mixed $type, string $msg = null) static 设置验证规则的默认提示信息 - * @method \think\Validate message(mixed $name, string $message = '') static 设置提示信息 - * @method \think\Validate scene(string $name) static 设置验证场景 - * @method bool hasScene(string $name) static 判断是否存在某个验证场景 - * @method \think\Validate batch(bool $batch = true) static 设置批量验证 - * @method \think\Validate only(array $fields) static 指定需要验证的字段列表 - * @method \think\Validate remove(mixed $field, mixed $rule = true) static 移除某个字段的验证规则 - * @method \think\Validate append(mixed $field, mixed $rule = null) static 追加某个字段的验证规则 - * @method bool confirm(mixed $value, mixed $rule, array $data = [], string $field = '') static 验证是否和某个字段的值一致 - * @method bool different(mixed $value, mixed $rule, array $data = []) static 验证是否和某个字段的值是否不同 - * @method bool egt(mixed $value, mixed $rule, array $data = []) static 验证是否大于等于某个值 - * @method bool gt(mixed $value, mixed $rule, array $data = []) static 验证是否大于某个值 - * @method bool elt(mixed $value, mixed $rule, array $data = []) static 验证是否小于等于某个值 - * @method bool lt(mixed $value, mixed $rule, array $data = []) static 验证是否小于某个值 - * @method bool eq(mixed $value, mixed $rule) static 验证是否等于某个值 - * @method bool must(mixed $value, mixed $rule) static 必须验证 - * @method bool is(mixed $value, mixed $rule, array $data = []) static 验证字段值是否为有效格式 - * @method bool ip(mixed $value, mixed $rule) static 验证是否有效IP - * @method bool requireIf(mixed $value, mixed $rule) static 验证某个字段等于某个值的时候必须 - * @method bool requireCallback(mixed $value, mixed $rule,array $data) static 通过回调方法验证某个字段是否必须 - * @method bool requireWith(mixed $value, mixed $rule, array $data) static 验证某个字段有值的情况下必须 - * @method bool filter(mixed $value, mixed $rule) static 使用filter_var方式验证 - * @method bool in(mixed $value, mixed $rule) static 验证是否在范围内 - * @method bool notIn(mixed $value, mixed $rule) static 验证是否不在范围内 - * @method bool between(mixed $value, mixed $rule) static between验证数据 - * @method bool notBetween(mixed $value, mixed $rule) static 使用notbetween验证数据 - * @method bool length(mixed $value, mixed $rule) static 验证数据长度 - * @method bool max(mixed $value, mixed $rule) static 验证数据最大长度 - * @method bool min(mixed $value, mixed $rule) static 验证数据最小长度 - * @method bool after(mixed $value, mixed $rule) static 验证日期 - * @method bool before(mixed $value, mixed $rule) static 验证日期 - * @method bool expire(mixed $value, mixed $rule) static 验证有效期 - * @method bool allowIp(mixed $value, mixed $rule) static 验证IP许可 - * @method bool denyIp(mixed $value, mixed $rule) static 验证IP禁用 - * @method bool regex(mixed $value, mixed $rule) static 使用正则验证数据 - * @method bool token(mixed $value, mixed $rule) static 验证表单令牌 - * @method bool dateFormat(mixed $value, mixed $rule) static 验证时间和日期是否符合指定格式 - * @method bool unique(mixed $value, mixed $rule, array $data = [], string $field = '') static 验证是否唯一 - * @method bool check(array $data, mixed $rules = [], string $scene = '') static 数据自动验证 - * @method mixed getError(mixed $value, mixed $rule) static 获取错误信息 - */ -class Validate extends Facade -{ - /** - * 获取当前Facade对应类名(或者已经绑定的容器对象标识) - * @access protected - * @return string - */ - protected static function getFacadeClass() - { - return 'validate'; - } - -} diff --git a/thinkphp/library/think/facade/View.php b/thinkphp/library/think/facade/View.php deleted file mode 100755 index 084339178..000000000 --- a/thinkphp/library/think/facade/View.php +++ /dev/null @@ -1,40 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\facade; - -use think\Facade; - -/** - * @see \think\View - * @mixin \think\View - * @method \think\View init(mixed $engine = [], array $replace = []) static 初始化 - * @method \think\View share(mixed $name, mixed $value = '') static 模板变量静态赋值 - * @method \think\View assign(mixed $name, mixed $value = '') static 模板变量赋值 - * @method \think\View config(mixed $name, mixed $value = '') static 配置模板引擎 - * @method \think\View exists(mixed $name) static 检查模板是否存在 - * @method \think\View filter(Callable $filter) static 视图内容过滤 - * @method \think\View engine(mixed $engine = []) static 设置当前模板解析的引擎 - * @method string fetch(string $template = '', array $vars = [], array $config = [], bool $renderContent = false) static 解析和获取模板内容 - * @method string display(string $content = '', array $vars = [], array $config = []) static 渲染内容输出 - */ -class View extends Facade -{ - /** - * 获取当前Facade对应类名(或者已经绑定的容器对象标识) - * @access protected - * @return string - */ - protected static function getFacadeClass() - { - return 'view'; - } -} diff --git a/thinkphp/library/think/log/driver/File.php b/thinkphp/library/think/log/driver/File.php deleted file mode 100755 index 10f745d26..000000000 --- a/thinkphp/library/think/log/driver/File.php +++ /dev/null @@ -1,283 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\log\driver; - -use think\App; - -/** - * 本地化调试输出到文件 - */ -class File -{ - protected $config = [ - 'time_format' => ' c ', - 'single' => false, - 'file_size' => 2097152, - 'path' => '', - 'apart_level' => [], - 'max_files' => 0, - 'json' => false, - ]; - - protected $app; - - // 实例化并传入参数 - public function __construct(App $app, $config = []) - { - $this->app = $app; - - if (is_array($config)) { - $this->config = array_merge($this->config, $config); - } - - if (empty($this->config['path'])) { - $this->config['path'] = $this->app->getRuntimePath() . 'log' . DIRECTORY_SEPARATOR; - } elseif (substr($this->config['path'], -1) != DIRECTORY_SEPARATOR) { - $this->config['path'] .= DIRECTORY_SEPARATOR; - } - } - - /** - * 日志写入接口 - * @access public - * @param array $log 日志信息 - * @param bool $append 是否追加请求信息 - * @return bool - */ - public function save(array $log = [], $append = false) - { - $destination = $this->getMasterLogFile(); - - $path = dirname($destination); - !is_dir($path) && mkdir($path, 0755, true); - - $info = []; - - foreach ($log as $type => $val) { - - foreach ($val as $msg) { - if (!is_string($msg)) { - $msg = var_export($msg, true); - } - - $info[$type][] = $this->config['json'] ? $msg : '[ ' . $type . ' ] ' . $msg; - } - - if (!$this->config['json'] && (true === $this->config['apart_level'] || in_array($type, $this->config['apart_level']))) { - // 独立记录的日志级别 - $filename = $this->getApartLevelFile($path, $type); - - $this->write($info[$type], $filename, true, $append); - - unset($info[$type]); - } - } - - if ($info) { - return $this->write($info, $destination, false, $append); - } - - return true; - } - - /** - * 日志写入 - * @access protected - * @param array $message 日志信息 - * @param string $destination 日志文件 - * @param bool $apart 是否独立文件写入 - * @param bool $append 是否追加请求信息 - * @return bool - */ - protected function write($message, $destination, $apart = false, $append = false) - { - // 检测日志文件大小,超过配置大小则备份日志文件重新生成 - $this->checkLogSize($destination); - - // 日志信息封装 - $info['timestamp'] = date($this->config['time_format']); - - foreach ($message as $type => $msg) { - $info[$type] = is_array($msg) ? implode("\r\n", $msg) : $msg; - } - - if (PHP_SAPI == 'cli') { - $message = $this->parseCliLog($info); - } else { - // 添加调试日志 - $this->getDebugLog($info, $append, $apart); - - $message = $this->parseLog($info); - } - - return error_log($message, 3, $destination); - } - - /** - * 获取主日志文件名 - * @access public - * @return string - */ - protected function getMasterLogFile() - { - if ($this->config['max_files']) { - $files = glob($this->config['path'] . '*.log'); - - try { - if (count($files) > $this->config['max_files']) { - unlink($files[0]); - } - } catch (\Exception $e) { - } - } - - if ($this->config['single']) { - $name = is_string($this->config['single']) ? $this->config['single'] : 'single'; - - $destination = $this->config['path'] . $name . '.log'; - } else { - $cli = PHP_SAPI == 'cli' ? '_cli' : ''; - - if ($this->config['max_files']) { - $filename = date('Ymd') . $cli . '.log'; - } else { - $filename = date('Ym') . DIRECTORY_SEPARATOR . date('d') . $cli . '.log'; - } - - $destination = $this->config['path'] . $filename; - } - - return $destination; - } - - /** - * 获取独立日志文件名 - * @access public - * @param string $path 日志目录 - * @param string $type 日志类型 - * @return string - */ - protected function getApartLevelFile($path, $type) - { - $cli = PHP_SAPI == 'cli' ? '_cli' : ''; - - if ($this->config['single']) { - $name = is_string($this->config['single']) ? $this->config['single'] : 'single'; - - $name .= '_' . $type; - } elseif ($this->config['max_files']) { - $name = date('Ymd') . '_' . $type . $cli; - } else { - $name = date('d') . '_' . $type . $cli; - } - - return $path . DIRECTORY_SEPARATOR . $name . '.log'; - } - - /** - * 检查日志文件大小并自动生成备份文件 - * @access protected - * @param string $destination 日志文件 - * @return void - */ - protected function checkLogSize($destination) - { - if (is_file($destination) && floor($this->config['file_size']) <= filesize($destination)) { - try { - rename($destination, dirname($destination) . DIRECTORY_SEPARATOR . time() . '-' . basename($destination)); - } catch (\Exception $e) { - } - } - } - - /** - * CLI日志解析 - * @access protected - * @param array $info 日志信息 - * @return string - */ - protected function parseCliLog($info) - { - if ($this->config['json']) { - $message = json_encode($info, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\r\n"; - } else { - $now = $info['timestamp']; - unset($info['timestamp']); - - $message = implode("\r\n", $info); - - $message = "[{$now}]" . $message . "\r\n"; - } - - return $message; - } - - /** - * 解析日志 - * @access protected - * @param array $info 日志信息 - * @return string - */ - protected function parseLog($info) - { - $requestInfo = [ - 'ip' => $this->app['request']->ip(), - 'method' => $this->app['request']->method(), - 'host' => $this->app['request']->host(), - 'uri' => $this->app['request']->url(), - ]; - - if ($this->config['json']) { - $info = $requestInfo + $info; - return json_encode($info, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\r\n"; - } - - array_unshift($info, "---------------------------------------------------------------\r\n[{$info['timestamp']}] {$requestInfo['ip']} {$requestInfo['method']} {$requestInfo['host']}{$requestInfo['uri']}"); - unset($info['timestamp']); - - return implode("\r\n", $info) . "\r\n"; - } - - protected function getDebugLog(&$info, $append, $apart) - { - if ($this->app->isDebug() && $append) { - - if ($this->config['json']) { - // 获取基本信息 - $runtime = round(microtime(true) - $this->app->getBeginTime(), 10); - $reqs = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞'; - - $memory_use = number_format((memory_get_usage() - $this->app->getBeginMem()) / 1024, 2); - - $info = [ - 'runtime' => number_format($runtime, 6) . 's', - 'reqs' => $reqs . 'req/s', - 'memory' => $memory_use . 'kb', - 'file' => count(get_included_files()), - ] + $info; - - } elseif (!$apart) { - // 增加额外的调试信息 - $runtime = round(microtime(true) - $this->app->getBeginTime(), 10); - $reqs = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞'; - - $memory_use = number_format((memory_get_usage() - $this->app->getBeginMem()) / 1024, 2); - - $time_str = '[运行时间:' . number_format($runtime, 6) . 's] [吞吐率:' . $reqs . 'req/s]'; - $memory_str = ' [内存消耗:' . $memory_use . 'kb]'; - $file_load = ' [文件加载:' . count(get_included_files()) . ']'; - - array_unshift($info, $time_str . $memory_str . $file_load); - } - } - } -} diff --git a/thinkphp/library/think/model/Collection.php b/thinkphp/library/think/model/Collection.php deleted file mode 100755 index 09b61a803..000000000 --- a/thinkphp/library/think/model/Collection.php +++ /dev/null @@ -1,100 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\model; - -use think\Collection as BaseCollection; -use think\Model; - -class Collection extends BaseCollection -{ - /** - * 延迟预载入关联查询 - * @access public - * @param mixed $relation 关联 - * @return $this - */ - public function load($relation) - { - $item = current($this->items); - $item->eagerlyResultSet($this->items, $relation); - - return $this; - } - - /** - * 设置需要隐藏的输出属性 - * @access public - * @param array $hidden 属性列表 - * @param bool $override 是否覆盖 - * @return $this - */ - public function hidden($hidden = [], $override = false) - { - $this->each(function ($model) use ($hidden, $override) { - /** @var Model $model */ - $model->hidden($hidden, $override); - }); - - return $this; - } - - /** - * 设置需要输出的属性 - * @access public - * @param array $visible - * @param bool $override 是否覆盖 - * @return $this - */ - public function visible($visible = [], $override = false) - { - $this->each(function ($model) use ($visible, $override) { - /** @var Model $model */ - $model->visible($visible, $override); - }); - - return $this; - } - - /** - * 设置需要追加的输出属性 - * @access public - * @param array $append 属性列表 - * @param bool $override 是否覆盖 - * @return $this - */ - public function append($append = [], $override = false) - { - $this->each(function ($model) use ($append, $override) { - /** @var Model $model */ - $model && $model->append($append, $override); - }); - - return $this; - } - - /** - * 设置数据字段获取器 - * @access public - * @param string|array $name 字段名 - * @param callable $callback 闭包获取器 - * @return $this - */ - public function withAttr($name, $callback = null) - { - $this->each(function ($model) use ($name, $callback) { - /** @var Model $model */ - $model && $model->withAttribute($name, $callback); - }); - - return $this; - } -} diff --git a/thinkphp/library/think/model/Relation.php b/thinkphp/library/think/model/Relation.php deleted file mode 100755 index c2b9adc7b..000000000 --- a/thinkphp/library/think/model/Relation.php +++ /dev/null @@ -1,166 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\model; - -use think\db\Query; -use think\Exception; -use think\Model; - -/** - * Class Relation - * @package think\model - * - * @mixin Query - */ -abstract class Relation -{ - // 父模型对象 - protected $parent; - /** @var Model 当前关联的模型类 */ - protected $model; - /** @var Query 关联模型查询对象 */ - protected $query; - // 关联表外键 - protected $foreignKey; - // 关联表主键 - protected $localKey; - // 基础查询 - protected $baseQuery; - // 是否为自关联 - protected $selfRelation; - - /** - * 获取关联的所属模型 - * @access public - * @return Model - */ - public function getParent() - { - return $this->parent; - } - - /** - * 获取当前的关联模型类的实例 - * @access public - * @return Model - */ - public function getModel() - { - return $this->query->getModel(); - } - - /** - * 设置当前关联为自关联 - * @access public - * @param bool $self 是否自关联 - * @return $this - */ - public function selfRelation($self = true) - { - $this->selfRelation = $self; - return $this; - } - - /** - * 当前关联是否为自关联 - * @access public - * @return bool - */ - public function isSelfRelation() - { - return $this->selfRelation; - } - - /** - * 封装关联数据集 - * @access public - * @param array $resultSet 数据集 - * @return mixed - */ - protected function resultSetBuild($resultSet) - { - return (new $this->model)->toCollection($resultSet); - } - - protected function getQueryFields($model) - { - $fields = $this->query->getOptions('field'); - return $this->getRelationQueryFields($fields, $model); - } - - protected function getRelationQueryFields($fields, $model) - { - if ($fields) { - - if (is_string($fields)) { - $fields = explode(',', $fields); - } - - foreach ($fields as &$field) { - if (false === strpos($field, '.')) { - $field = $model . '.' . $field; - } - } - } else { - $fields = $model . '.*'; - } - - return $fields; - } - - protected function getQueryWhere(&$where, $relation) - { - foreach ($where as $key => &$val) { - if (is_string($key)) { - $where[] = [false === strpos($key, '.') ? $relation . '.' . $key : $key, '=', $val]; - unset($where[$key]); - } elseif (isset($val[0]) && false === strpos($val[0], '.')) { - $val[0] = $relation . '.' . $val[0]; - } - } - } - - /** - * 删除记录 - * @access public - * @param mixed $data 表达式 true 表示强制删除 - * @return int - * @throws Exception - * @throws PDOException - */ - public function delete($data = null) - { - return $this->query->delete($data); - } - - /** - * 执行基础查询(仅执行一次) - * @access protected - * @return void - */ - protected function baseQuery() - {} - - public function __call($method, $args) - { - if ($this->query) { - // 执行基础查询 - $this->baseQuery(); - - $result = call_user_func_array([$this->query->getModel(), $method], $args); - - return $result === $this->query && !in_array(strtolower($method), ['fetchsql', 'fetchpdo']) ? $this : $result; - } else { - throw new Exception('method not exists:' . __CLASS__ . '->' . $method); - } - } -} diff --git a/thinkphp/library/think/model/concern/Conversion.php b/thinkphp/library/think/model/concern/Conversion.php deleted file mode 100755 index b88528adb..000000000 --- a/thinkphp/library/think/model/concern/Conversion.php +++ /dev/null @@ -1,288 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\model\concern; - -use think\Collection; -use think\Exception; -use think\Loader; -use think\Model; -use think\model\Collection as ModelCollection; - -/** - * 模型数据转换处理 - */ -trait Conversion -{ - /** - * 数据输出显示的属性 - * @var array - */ - protected $visible = []; - - /** - * 数据输出隐藏的属性 - * @var array - */ - protected $hidden = []; - - /** - * 数据输出需要追加的属性 - * @var array - */ - protected $append = []; - - /** - * 数据集对象名 - * @var string - */ - protected $resultSetType; - - /** - * 设置需要附加的输出属性 - * @access public - * @param array $append 属性列表 - * @param bool $override 是否覆盖 - * @return $this - */ - public function append(array $append = [], $override = false) - { - $this->append = $override ? $append : array_merge($this->append, $append); - - return $this; - } - - /** - * 设置附加关联对象的属性 - * @access public - * @param string $attr 关联属性 - * @param string|array $append 追加属性名 - * @return $this - * @throws Exception - */ - public function appendRelationAttr($attr, $append) - { - if (is_string($append)) { - $append = explode(',', $append); - } - - $relation = Loader::parseName($attr, 1, false); - if (isset($this->relation[$relation])) { - $model = $this->relation[$relation]; - } else { - $model = $this->getRelationData($this->$relation()); - } - - if ($model instanceof Model) { - foreach ($append as $key => $attr) { - $key = is_numeric($key) ? $attr : $key; - if (isset($this->data[$key])) { - throw new Exception('bind attr has exists:' . $key); - } else { - $this->data[$key] = $model->$attr; - } - } - } - - return $this; - } - - /** - * 设置需要隐藏的输出属性 - * @access public - * @param array $hidden 属性列表 - * @param bool $override 是否覆盖 - * @return $this - */ - public function hidden(array $hidden = [], $override = false) - { - $this->hidden = $override ? $hidden : array_merge($this->hidden, $hidden); - - return $this; - } - - /** - * 设置需要输出的属性 - * @access public - * @param array $visible - * @param bool $override 是否覆盖 - * @return $this - */ - public function visible(array $visible = [], $override = false) - { - $this->visible = $override ? $visible : array_merge($this->visible, $visible); - - return $this; - } - - /** - * 转换当前模型对象为数组 - * @access public - * @return array - */ - public function toArray() - { - $item = []; - $visible = []; - $hidden = []; - - // 合并关联数据 - $data = array_merge($this->data, $this->relation); - - // 过滤属性 - if (!empty($this->visible)) { - $array = $this->parseAttr($this->visible, $visible); - $data = array_intersect_key($data, array_flip($array)); - } elseif (!empty($this->hidden)) { - $array = $this->parseAttr($this->hidden, $hidden, false); - $data = array_diff_key($data, array_flip($array)); - } - - foreach ($data as $key => $val) { - if ($val instanceof Model || $val instanceof ModelCollection) { - // 关联模型对象 - if (isset($visible[$key])) { - $val->visible($visible[$key]); - } elseif (isset($hidden[$key])) { - $val->hidden($hidden[$key]); - } - // 关联模型对象 - $item[$key] = $val->toArray(); - } else { - // 模型属性 - $item[$key] = $this->getAttr($key); - } - } - - // 追加属性(必须定义获取器) - if (!empty($this->append)) { - foreach ($this->append as $key => $name) { - if (is_array($name)) { - // 追加关联对象属性 - $relation = $this->getRelation($key); - - if (!$relation) { - $relation = $this->getAttr($key); - $relation->visible($name); - } - - $item[$key] = $relation->append($name)->toArray(); - } elseif (strpos($name, '.')) { - list($key, $attr) = explode('.', $name); - // 追加关联对象属性 - $relation = $this->getRelation($key); - - if (!$relation) { - $relation = $this->getAttr($key); - $relation->visible([$attr]); - } - - $item[$key] = $relation->append([$attr])->toArray(); - } else { - $value = $this->getAttr($name, $item); - if (false !== $value) { - $item[$name] = $value; - } - } - } - } - - return $item; - } - - /** - * 转换当前模型对象为JSON字符串 - * @access public - * @param integer $options json参数 - * @return string - */ - public function toJson($options = JSON_UNESCAPED_UNICODE) - { - return json_encode($this->toArray(), $options); - } - - /** - * 移除当前模型的关联属性 - * @access public - * @return $this - */ - public function removeRelation() - { - $this->relation = []; - return $this; - } - - public function __toString() - { - return $this->toJson(); - } - - // JsonSerializable - public function jsonSerialize() - { - return $this->toArray(); - } - - /** - * 转换数据集为数据集对象 - * @access public - * @param array|Collection $collection 数据集 - * @param string $resultSetType 数据集类 - * @return Collection - */ - public function toCollection($collection, $resultSetType = null) - { - $resultSetType = $resultSetType ?: $this->resultSetType; - - if ($resultSetType && false !== strpos($resultSetType, '\\')) { - $collection = new $resultSetType($collection); - } else { - $collection = new ModelCollection($collection); - } - - return $collection; - } - - /** - * 解析隐藏及显示属性 - * @access protected - * @param array $attrs 属性 - * @param array $result 结果集 - * @param bool $visible - * @return array - */ - protected function parseAttr($attrs, &$result, $visible = true) - { - $array = []; - - foreach ($attrs as $key => $val) { - if (is_array($val)) { - if ($visible) { - $array[] = $key; - } - - $result[$key] = $val; - } elseif (strpos($val, '.')) { - list($key, $name) = explode('.', $val); - - if ($visible) { - $array[] = $key; - } - - $result[$key][] = $name; - } else { - $array[] = $val; - } - } - - return $array; - } -} diff --git a/thinkphp/library/think/model/concern/ModelEvent.php b/thinkphp/library/think/model/concern/ModelEvent.php deleted file mode 100755 index 3a874846f..000000000 --- a/thinkphp/library/think/model/concern/ModelEvent.php +++ /dev/null @@ -1,238 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\model\concern; - -use think\Container; -use think\Loader; - -/** - * 模型事件处理 - */ -trait ModelEvent -{ - /** - * 模型回调 - * @var array - */ - private static $event = []; - - /** - * 模型事件观察 - * @var array - */ - protected static $observe = ['before_write', 'after_write', 'before_insert', 'after_insert', 'before_update', 'after_update', 'before_delete', 'after_delete', 'before_restore', 'after_restore']; - - /** - * 绑定模型事件观察者类 - * @var array - */ - protected $observerClass; - - /** - * 是否需要事件响应 - * @var bool - */ - private $withEvent = true; - - /** - * 注册回调方法 - * @access public - * @param string $event 事件名 - * @param callable $callback 回调方法 - * @param bool $override 是否覆盖 - * @return void - */ - public static function event($event, $callback, $override = false) - { - $class = static::class; - - if ($override) { - self::$event[$class][$event] = []; - } - - self::$event[$class][$event][] = $callback; - } - - /** - * 清除回调方法 - * @access public - * @return void - */ - public static function flushEvent() - { - self::$event[static::class] = []; - } - - /** - * 注册一个模型观察者 - * - * @param object|string $class - * @return void - */ - public static function observe($class) - { - self::flushEvent(); - - foreach (static::$observe as $event) { - $eventFuncName = Loader::parseName($event, 1, false); - - if (method_exists($class, $eventFuncName)) { - static::event($event, [$class, $eventFuncName]); - } - } - } - - /** - * 当前操作的事件响应 - * @access protected - * @param bool $event 是否需要事件响应 - * @return $this - */ - public function withEvent($event) - { - $this->withEvent = $event; - return $this; - } - - /** - * 触发事件 - * @access protected - * @param string $event 事件名 - * @return bool - */ - protected function trigger($event) - { - $class = static::class; - - if ($this->withEvent && isset(self::$event[$class][$event])) { - foreach (self::$event[$class][$event] as $callback) { - $result = Container::getInstance()->invoke($callback, [$this]); - - if (false === $result) { - return false; - } - } - } - - return true; - } - - /** - * 模型before_insert事件快捷方法 - * @access protected - * @param callable $callback - * @param bool $override - */ - protected static function beforeInsert($callback, $override = false) - { - self::event('before_insert', $callback, $override); - } - - /** - * 模型after_insert事件快捷方法 - * @access protected - * @param callable $callback - * @param bool $override - */ - protected static function afterInsert($callback, $override = false) - { - self::event('after_insert', $callback, $override); - } - - /** - * 模型before_update事件快捷方法 - * @access protected - * @param callable $callback - * @param bool $override - */ - protected static function beforeUpdate($callback, $override = false) - { - self::event('before_update', $callback, $override); - } - - /** - * 模型after_update事件快捷方法 - * @access protected - * @param callable $callback - * @param bool $override - */ - protected static function afterUpdate($callback, $override = false) - { - self::event('after_update', $callback, $override); - } - - /** - * 模型before_write事件快捷方法 - * @access protected - * @param callable $callback - * @param bool $override - */ - protected static function beforeWrite($callback, $override = false) - { - self::event('before_write', $callback, $override); - } - - /** - * 模型after_write事件快捷方法 - * @access protected - * @param callable $callback - * @param bool $override - */ - protected static function afterWrite($callback, $override = false) - { - self::event('after_write', $callback, $override); - } - - /** - * 模型before_delete事件快捷方法 - * @access protected - * @param callable $callback - * @param bool $override - */ - protected static function beforeDelete($callback, $override = false) - { - self::event('before_delete', $callback, $override); - } - - /** - * 模型after_delete事件快捷方法 - * @access protected - * @param callable $callback - * @param bool $override - */ - protected static function afterDelete($callback, $override = false) - { - self::event('after_delete', $callback, $override); - } - - /** - * 模型before_restore事件快捷方法 - * @access protected - * @param callable $callback - * @param bool $override - */ - protected static function beforeRestore($callback, $override = false) - { - self::event('before_restore', $callback, $override); - } - - /** - * 模型after_restore事件快捷方法 - * @access protected - * @param callable $callback - * @param bool $override - */ - protected static function afterRestore($callback, $override = false) - { - self::event('after_restore', $callback, $override); - } -} diff --git a/thinkphp/library/think/model/concern/TimeStamp.php b/thinkphp/library/think/model/concern/TimeStamp.php deleted file mode 100755 index 99a31fa7d..000000000 --- a/thinkphp/library/think/model/concern/TimeStamp.php +++ /dev/null @@ -1,92 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\model\concern; - -use DateTime; - -/** - * 自动时间戳 - */ -trait TimeStamp -{ - /** - * 是否需要自动写入时间戳 如果设置为字符串 则表示时间字段的类型 - * @var bool|string - */ - protected $autoWriteTimestamp; - - /** - * 创建时间字段 false表示关闭 - * @var false|string - */ - protected $createTime = 'create_time'; - - /** - * 更新时间字段 false表示关闭 - * @var false|string - */ - protected $updateTime = 'update_time'; - - /** - * 时间字段显示格式 - * @var string - */ - protected $dateFormat; - - /** - * 时间日期字段格式化处理 - * @access protected - * @param mixed $format 日期格式 - * @param mixed $time 时间日期表达式 - * @param bool $timestamp 是否进行时间戳转换 - * @return mixed - */ - protected function formatDateTime($format, $time = 'now', $timestamp = false) - { - if (empty($time)) { - return; - } - - if (false === $format) { - return $time; - } elseif (false !== strpos($format, '\\')) { - return new $format($time); - } - - if ($timestamp) { - $dateTime = new DateTime(); - $dateTime->setTimestamp($time); - } else { - $dateTime = new DateTime($time); - } - - return $dateTime->format($format); - } - - /** - * 检查时间字段写入 - * @access protected - * @return void - */ - protected function checkTimeStampWrite() - { - // 自动写入创建时间和更新时间 - if ($this->autoWriteTimestamp) { - if ($this->createTime && !isset($this->data[$this->createTime])) { - $this->data[$this->createTime] = $this->autoWriteTimestamp($this->createTime); - } - if ($this->updateTime && !isset($this->data[$this->updateTime])) { - $this->data[$this->updateTime] = $this->autoWriteTimestamp($this->updateTime); - } - } - } -} diff --git a/thinkphp/library/think/model/relation/HasMany.php b/thinkphp/library/think/model/relation/HasMany.php deleted file mode 100755 index dbb8fa083..000000000 --- a/thinkphp/library/think/model/relation/HasMany.php +++ /dev/null @@ -1,351 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\model\relation; - -use think\db\Query; -use think\Loader; -use think\Model; -use think\model\Relation; - -class HasMany extends Relation -{ - /** - * 架构函数 - * @access public - * @param Model $parent 上级模型对象 - * @param string $model 模型名 - * @param string $foreignKey 关联外键 - * @param string $localKey 当前模型主键 - */ - public function __construct(Model $parent, $model, $foreignKey, $localKey) - { - $this->parent = $parent; - $this->model = $model; - $this->foreignKey = $foreignKey; - $this->localKey = $localKey; - $this->query = (new $model)->db(); - - if (get_class($parent) == $model) { - $this->selfRelation = true; - } - } - - /** - * 延迟获取关联数据 - * @access public - * @param string $subRelation 子关联名 - * @param \Closure $closure 闭包查询条件 - * @return \think\Collection - */ - public function getRelation($subRelation = '', $closure = null) - { - if ($closure) { - $closure($this->query); - } - - $list = $this->query - ->where($this->foreignKey, $this->parent->{$this->localKey}) - ->relation($subRelation) - ->select(); - - $parent = clone $this->parent; - - foreach ($list as &$model) { - $model->setParent($parent); - } - - return $list; - } - - /** - * 预载入关联查询 - * @access public - * @param array $resultSet 数据集 - * @param string $relation 当前关联名 - * @param string $subRelation 子关联名 - * @param \Closure $closure 闭包 - * @return void - */ - public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure) - { - $localKey = $this->localKey; - $range = []; - - foreach ($resultSet as $result) { - // 获取关联外键列表 - if (isset($result->$localKey)) { - $range[] = $result->$localKey; - } - } - - if (!empty($range)) { - $where = [ - [$this->foreignKey, 'in', $range], - ]; - $data = $this->eagerlyOneToMany($where, $relation, $subRelation, $closure); - - // 关联属性名 - $attr = Loader::parseName($relation); - - // 关联数据封装 - foreach ($resultSet as $result) { - $pk = $result->$localKey; - if (!isset($data[$pk])) { - $data[$pk] = []; - } - - foreach ($data[$pk] as &$relationModel) { - $relationModel->setParent(clone $result); - } - - $result->setRelation($attr, $this->resultSetBuild($data[$pk])); - } - } - } - - /** - * 预载入关联查询 - * @access public - * @param Model $result 数据对象 - * @param string $relation 当前关联名 - * @param string $subRelation 子关联名 - * @param \Closure $closure 闭包 - * @return void - */ - public function eagerlyResult(&$result, $relation, $subRelation, $closure) - { - $localKey = $this->localKey; - - if (isset($result->$localKey)) { - $pk = $result->$localKey; - $where = [ - [$this->foreignKey, '=', $pk], - ]; - $data = $this->eagerlyOneToMany($where, $relation, $subRelation, $closure); - - // 关联数据封装 - if (!isset($data[$pk])) { - $data[$pk] = []; - } - - foreach ($data[$pk] as &$relationModel) { - $relationModel->setParent(clone $result); - } - - $result->setRelation(Loader::parseName($relation), $this->resultSetBuild($data[$pk])); - } - } - - /** - * 关联统计 - * @access public - * @param Model $result 数据对象 - * @param \Closure $closure 闭包 - * @param string $aggregate 聚合查询方法 - * @param string $field 字段 - * @param string $name 统计字段别名 - * @return integer - */ - public function relationCount($result, $closure, $aggregate = 'count', $field = '*', &$name = '') - { - $localKey = $this->localKey; - - if (!isset($result->$localKey)) { - return 0; - } - - if ($closure) { - $return = $closure($this->query); - if ($return && is_string($return)) { - $name = $return; - } - } - - return $this->query - ->where($this->foreignKey, '=', $result->$localKey) - ->$aggregate($field); - } - - /** - * 创建关联统计子查询 - * @access public - * @param \Closure $closure 闭包 - * @param string $aggregate 聚合查询方法 - * @param string $field 字段 - * @param string $aggregateAlias 聚合字段别名 - * @return string - */ - public function getRelationCountQuery($closure, $aggregate = 'count', $field = '*', &$aggregateAlias = '') - { - if ($closure) { - $return = $closure($this->query); - - if ($return && is_string($return)) { - $aggregateAlias = $return; - } - } - - return $this->query - ->whereExp($this->foreignKey, '=' . $this->parent->getTable() . '.' . $this->localKey) - ->fetchSql() - ->$aggregate($field); - } - - /** - * 一对多 关联模型预查询 - * @access public - * @param array $where 关联预查询条件 - * @param string $relation 关联名 - * @param string $subRelation 子关联 - * @param \Closure $closure - * @return array - */ - protected function eagerlyOneToMany($where, $relation, $subRelation = '', $closure = null) - { - $foreignKey = $this->foreignKey; - - $this->query->removeWhereField($this->foreignKey); - - // 预载入关联查询 支持嵌套预载入 - if ($closure) { - $closure($this->query); - } - - $list = $this->query->where($where)->with($subRelation)->select(); - - // 组装模型数据 - $data = []; - - foreach ($list as $set) { - $data[$set->$foreignKey][] = $set; - } - - return $data; - } - - /** - * 保存(新增)当前关联数据对象 - * @access public - * @param mixed $data 数据 可以使用数组 关联模型对象 和 关联对象的主键 - * @param boolean $replace 是否自动识别更新和写入 - * @return Model|false - */ - public function save($data, $replace = true) - { - $model = $this->make(); - - return $model->replace($replace)->save($data) ? $model : false; - } - - /** - * 创建关联对象实例 - * @param array $data - * @return Model - */ - public function make($data = []) - { - if ($data instanceof Model) { - $data = $data->getData(); - } - - // 保存关联表数据 - $data[$this->foreignKey] = $this->parent->{$this->localKey}; - - return new $this->model($data); - } - - /** - * 批量保存当前关联数据对象 - * @access public - * @param array $dataSet 数据集 - * @param boolean $replace 是否自动识别更新和写入 - * @return array|false - */ - public function saveAll(array $dataSet, $replace = true) - { - $result = []; - - foreach ($dataSet as $key => $data) { - $result[] = $this->save($data, $replace); - } - - return empty($result) ? false : $result; - } - - /** - * 根据关联条件查询当前模型 - * @access public - * @param string $operator 比较操作符 - * @param integer $count 个数 - * @param string $id 关联表的统计字段 - * @param string $joinType JOIN类型 - * @return Query - */ - public function has($operator = '>=', $count = 1, $id = '*', $joinType = 'INNER') - { - $table = $this->query->getTable(); - $model = basename(str_replace('\\', '/', get_class($this->parent))); - $relation = basename(str_replace('\\', '/', $this->model)); - - return $this->parent->db() - ->alias($model) - ->field($model . '.*') - ->join([$table => $relation], $model . '.' . $this->localKey . '=' . $relation . '.' . $this->foreignKey, $joinType) - ->group($relation . '.' . $this->foreignKey) - ->having('count(' . $id . ')' . $operator . $count); - } - - /** - * 根据关联条件查询当前模型 - * @access public - * @param mixed $where 查询条件(数组或者闭包) - * @param mixed $fields 字段 - * @return Query - */ - public function hasWhere($where = [], $fields = null) - { - $table = $this->query->getTable(); - $model = basename(str_replace('\\', '/', get_class($this->parent))); - $relation = basename(str_replace('\\', '/', $this->model)); - - if (is_array($where)) { - $this->getQueryWhere($where, $relation); - } - - $fields = $this->getRelationQueryFields($fields, $model); - - return $this->parent->db() - ->alias($model) - ->group($model . '.' . $this->localKey) - ->field($fields) - ->join([$table => $relation], $model . '.' . $this->localKey . '=' . $relation . '.' . $this->foreignKey) - ->where($where); - } - - /** - * 执行基础查询(仅执行一次) - * @access protected - * @return void - */ - protected function baseQuery() - { - if (empty($this->baseQuery)) { - if (isset($this->parent->{$this->localKey})) { - // 关联查询带入关联条件 - $this->query->where($this->foreignKey, '=', $this->parent->{$this->localKey}); - } - - $this->baseQuery = true; - } - } - -} diff --git a/thinkphp/library/think/model/relation/HasManyThrough.php b/thinkphp/library/think/model/relation/HasManyThrough.php deleted file mode 100755 index 7c7acaa07..000000000 --- a/thinkphp/library/think/model/relation/HasManyThrough.php +++ /dev/null @@ -1,156 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\model\relation; - -use think\db\Query; -use think\Exception; -use think\Loader; -use think\Model; -use think\model\Relation; - -class HasManyThrough extends Relation -{ - // 中间关联表外键 - protected $throughKey; - // 中间表模型 - protected $through; - - /** - * 架构函数 - * @access public - * @param Model $parent 上级模型对象 - * @param string $model 模型名 - * @param string $through 中间模型名 - * @param string $foreignKey 关联外键 - * @param string $throughKey 关联外键 - * @param string $localKey 当前主键 - */ - public function __construct(Model $parent, $model, $through, $foreignKey, $throughKey, $localKey) - { - $this->parent = $parent; - $this->model = $model; - $this->through = $through; - $this->foreignKey = $foreignKey; - $this->throughKey = $throughKey; - $this->localKey = $localKey; - $this->query = (new $model)->db(); - } - - /** - * 延迟获取关联数据 - * @access public - * @param string $subRelation 子关联名 - * @param \Closure $closure 闭包查询条件 - * @return \think\Collection - */ - public function getRelation($subRelation = '', $closure = null) - { - if ($closure) { - $closure($this->query); - } - - $this->baseQuery(); - - return $this->query->relation($subRelation)->select(); - } - - /** - * 根据关联条件查询当前模型 - * @access public - * @param string $operator 比较操作符 - * @param integer $count 个数 - * @param string $id 关联表的统计字段 - * @param string $joinType JOIN类型 - * @return Query - */ - public function has($operator = '>=', $count = 1, $id = '*', $joinType = 'INNER') - { - return $this->parent; - } - - /** - * 根据关联条件查询当前模型 - * @access public - * @param mixed $where 查询条件(数组或者闭包) - * @param mixed $fields 字段 - * @return Query - */ - public function hasWhere($where = [], $fields = null) - { - throw new Exception('relation not support: hasWhere'); - } - - /** - * 预载入关联查询 - * @access public - * @param array $resultSet 数据集 - * @param string $relation 当前关联名 - * @param string $subRelation 子关联名 - * @param \Closure $closure 闭包 - * @return void - */ - public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure) - {} - - /** - * 预载入关联查询 返回模型对象 - * @access public - * @param Model $result 数据对象 - * @param string $relation 当前关联名 - * @param string $subRelation 子关联名 - * @param \Closure $closure 闭包 - * @return void - */ - public function eagerlyResult(&$result, $relation, $subRelation, $closure) - {} - - /** - * 关联统计 - * @access public - * @param Model $result 数据对象 - * @param \Closure $closure 闭包 - * @param string $aggregate 聚合查询方法 - * @param string $field 字段 - * @param string $name 统计字段别名 - * @return integer - */ - public function relationCount($result, $closure, $aggregate = 'count', $field = '*', &$name = '') - {} - - /** - * 执行基础查询(仅执行一次) - * @access protected - * @return void - */ - protected function baseQuery() - { - if (empty($this->baseQuery) && $this->parent->getData()) { - $through = $this->through; - $alias = Loader::parseName(basename(str_replace('\\', '/', $this->model))); - $throughTable = $through::getTable(); - $pk = (new $through)->getPk(); - $throughKey = $this->throughKey; - $modelTable = $this->parent->getTable(); - $fields = $this->getQueryFields($alias); - - $this->query - ->field($fields) - ->alias($alias) - ->join($throughTable, $throughTable . '.' . $pk . '=' . $alias . '.' . $throughKey) - ->join($modelTable, $modelTable . '.' . $this->localKey . '=' . $throughTable . '.' . $this->foreignKey) - ->where($throughTable . '.' . $this->foreignKey, $this->parent->{$this->localKey}); - - $this->baseQuery = true; - } - } - -} diff --git a/thinkphp/library/think/process/Builder.php b/thinkphp/library/think/process/Builder.php deleted file mode 100755 index da5616397..000000000 --- a/thinkphp/library/think/process/Builder.php +++ /dev/null @@ -1,233 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\process; - -use think\Process; - -class Builder -{ - private $arguments; - private $cwd; - private $env = null; - private $input; - private $timeout = 60; - private $options = []; - private $inheritEnv = true; - private $prefix = []; - private $outputDisabled = false; - - /** - * 构造方法 - * @param string[] $arguments 参数 - */ - public function __construct(array $arguments = []) - { - $this->arguments = $arguments; - } - - /** - * 创建一个实例 - * @param string[] $arguments 参数 - * @return self - */ - public static function create(array $arguments = []) - { - return new static($arguments); - } - - /** - * 添加一个参数 - * @param string $argument 参数 - * @return self - */ - public function add($argument) - { - $this->arguments[] = $argument; - - return $this; - } - - /** - * 添加一个前缀 - * @param string|array $prefix - * @return self - */ - public function setPrefix($prefix) - { - $this->prefix = is_array($prefix) ? $prefix : [$prefix]; - - return $this; - } - - /** - * 设置参数 - * @param string[] $arguments - * @return self - */ - public function setArguments(array $arguments) - { - $this->arguments = $arguments; - - return $this; - } - - /** - * 设置工作目录 - * @param null|string $cwd - * @return self - */ - public function setWorkingDirectory($cwd) - { - $this->cwd = $cwd; - - return $this; - } - - /** - * 是否初始化环境变量 - * @param bool $inheritEnv - * @return self - */ - public function inheritEnvironmentVariables($inheritEnv = true) - { - $this->inheritEnv = $inheritEnv; - - return $this; - } - - /** - * 设置环境变量 - * @param string $name - * @param null|string $value - * @return self - */ - public function setEnv($name, $value) - { - $this->env[$name] = $value; - - return $this; - } - - /** - * 添加环境变量 - * @param array $variables - * @return self - */ - public function addEnvironmentVariables(array $variables) - { - $this->env = array_replace($this->env, $variables); - - return $this; - } - - /** - * 设置输入 - * @param mixed $input - * @return self - */ - public function setInput($input) - { - $this->input = Utils::validateInput(sprintf('%s::%s', __CLASS__, __FUNCTION__), $input); - - return $this; - } - - /** - * 设置超时时间 - * @param float|null $timeout - * @return self - */ - public function setTimeout($timeout) - { - if (null === $timeout) { - $this->timeout = null; - - return $this; - } - - $timeout = (float) $timeout; - - if ($timeout < 0) { - throw new \InvalidArgumentException('The timeout value must be a valid positive integer or float number.'); - } - - $this->timeout = $timeout; - - return $this; - } - - /** - * 设置proc_open选项 - * @param string $name - * @param string $value - * @return self - */ - public function setOption($name, $value) - { - $this->options[$name] = $value; - - return $this; - } - - /** - * 禁止输出 - * @return self - */ - public function disableOutput() - { - $this->outputDisabled = true; - - return $this; - } - - /** - * 开启输出 - * @return self - */ - public function enableOutput() - { - $this->outputDisabled = false; - - return $this; - } - - /** - * 创建一个Process实例 - * @return Process - */ - public function getProcess() - { - if (0 === count($this->prefix) && 0 === count($this->arguments)) { - throw new \LogicException('You must add() command arguments before calling getProcess().'); - } - - $options = $this->options; - - $arguments = array_merge($this->prefix, $this->arguments); - $script = implode(' ', array_map([__NAMESPACE__ . '\\Utils', 'escapeArgument'], $arguments)); - - if ($this->inheritEnv) { - // include $_ENV for BC purposes - $env = array_replace($_ENV, $_SERVER, $this->env); - } else { - $env = $this->env; - } - - $process = new Process($script, $this->cwd, $env, $this->input, $this->timeout, $options); - - if ($this->outputDisabled) { - $process->disableOutput(); - } - - return $process; - } -} diff --git a/thinkphp/library/think/process/Utils.php b/thinkphp/library/think/process/Utils.php deleted file mode 100755 index f94c6488e..000000000 --- a/thinkphp/library/think/process/Utils.php +++ /dev/null @@ -1,75 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\process; - -class Utils -{ - - /** - * 转义字符串 - * @param string $argument - * @return string - */ - public static function escapeArgument($argument) - { - - if ('' === $argument) { - return escapeshellarg($argument); - } - $escapedArgument = ''; - $quote = false; - foreach (preg_split('/(")/i', $argument, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE) as $part) { - if ('"' === $part) { - $escapedArgument .= '\\"'; - } elseif (self::isSurroundedBy($part, '%')) { - // Avoid environment variable expansion - $escapedArgument .= '^%"' . substr($part, 1, -1) . '"^%'; - } else { - // escape trailing backslash - if ('\\' === substr($part, -1)) { - $part .= '\\'; - } - $quote = true; - $escapedArgument .= $part; - } - } - if ($quote) { - $escapedArgument = '"' . $escapedArgument . '"'; - } - return $escapedArgument; - } - - /** - * 验证并进行规范化Process输入。 - * @param string $caller - * @param mixed $input - * @return string - * @throws \InvalidArgumentException - */ - public static function validateInput($caller, $input) - { - if (null !== $input) { - if (is_resource($input)) { - return $input; - } - if (is_scalar($input)) { - return (string) $input; - } - throw new \InvalidArgumentException(sprintf('%s only accepts strings or stream resources.', $caller)); - } - return $input; - } - - private static function isSurroundedBy($arg, $char) - { - return 2 < strlen($arg) && $char === $arg[0] && $char === $arg[strlen($arg) - 1]; - } - -} diff --git a/thinkphp/library/think/process/exception/Faild.php b/thinkphp/library/think/process/exception/Faild.php deleted file mode 100755 index 38647bc11..000000000 --- a/thinkphp/library/think/process/exception/Faild.php +++ /dev/null @@ -1,42 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\process\exception; - -use think\Process; - -class Faild extends \RuntimeException -{ - - private $process; - - public function __construct(Process $process) - { - if ($process->isSuccessful()) { - throw new \InvalidArgumentException('Expected a failed process, but the given process was successful.'); - } - - $error = sprintf('The command "%s" failed.' . "\nExit Code: %s(%s)", $process->getCommandLine(), $process->getExitCode(), $process->getExitCodeText()); - - if (!$process->isOutputDisabled()) { - $error .= sprintf("\n\nOutput:\n================\n%s\n\nError Output:\n================\n%s", $process->getOutput(), $process->getErrorOutput()); - } - - parent::__construct($error); - - $this->process = $process; - } - - public function getProcess() - { - return $this->process; - } -} diff --git a/thinkphp/library/think/process/exception/Failed.php b/thinkphp/library/think/process/exception/Failed.php deleted file mode 100755 index 529508232..000000000 --- a/thinkphp/library/think/process/exception/Failed.php +++ /dev/null @@ -1,42 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\process\exception; - -use think\Process; - -class Failed extends \RuntimeException -{ - - private $process; - - public function __construct(Process $process) - { - if ($process->isSuccessful()) { - throw new \InvalidArgumentException('Expected a failed process, but the given process was successful.'); - } - - $error = sprintf('The command "%s" failed.' . "\nExit Code: %s(%s)", $process->getCommandLine(), $process->getExitCode(), $process->getExitCodeText()); - - if (!$process->isOutputDisabled()) { - $error .= sprintf("\n\nOutput:\n================\n%s\n\nError Output:\n================\n%s", $process->getOutput(), $process->getErrorOutput()); - } - - parent::__construct($error); - - $this->process = $process; - } - - public function getProcess() - { - return $this->process; - } -} diff --git a/thinkphp/library/think/process/exception/Timeout.php b/thinkphp/library/think/process/exception/Timeout.php deleted file mode 100755 index d5f1162f4..000000000 --- a/thinkphp/library/think/process/exception/Timeout.php +++ /dev/null @@ -1,61 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\process\exception; - -use think\Process; - -class Timeout extends \RuntimeException -{ - - const TYPE_GENERAL = 1; - const TYPE_IDLE = 2; - - private $process; - private $timeoutType; - - public function __construct(Process $process, $timeoutType) - { - $this->process = $process; - $this->timeoutType = $timeoutType; - - parent::__construct(sprintf('The process "%s" exceeded the timeout of %s seconds.', $process->getCommandLine(), $this->getExceededTimeout())); - } - - public function getProcess() - { - return $this->process; - } - - public function isGeneralTimeout() - { - return $this->timeoutType === self::TYPE_GENERAL; - } - - public function isIdleTimeout() - { - return $this->timeoutType === self::TYPE_IDLE; - } - - public function getExceededTimeout() - { - switch ($this->timeoutType) { - case self::TYPE_GENERAL: - return $this->process->getTimeout(); - - case self::TYPE_IDLE: - return $this->process->getIdleTimeout(); - - default: - throw new \LogicException(sprintf('Unknown timeout type "%d".', $this->timeoutType)); - } - } -} diff --git a/thinkphp/library/think/process/pipes/Pipes.php b/thinkphp/library/think/process/pipes/Pipes.php deleted file mode 100755 index 82396b8ff..000000000 --- a/thinkphp/library/think/process/pipes/Pipes.php +++ /dev/null @@ -1,93 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\process\pipes; - -abstract class Pipes -{ - - /** @var array */ - public $pipes = []; - - /** @var string */ - protected $inputBuffer = ''; - /** @var resource|null */ - protected $input; - - /** @var bool */ - private $blocked = true; - - const CHUNK_SIZE = 16384; - - /** - * 返回用于 proc_open 描述符的数组 - * @return array - */ - abstract public function getDescriptors(); - - /** - * 返回一个数组的索引由其相关的流,以防这些管道使用的临时文件的文件名。 - * @return string[] - */ - abstract public function getFiles(); - - /** - * 文件句柄和管道中读取数据。 - * @param bool $blocking 是否使用阻塞调用 - * @param bool $close 是否要关闭管道,如果他们已经到达 EOF。 - * @return string[] - */ - abstract public function readAndWrite($blocking, $close = false); - - /** - * 返回当前状态如果有打开的文件句柄或管道。 - * @return bool - */ - abstract public function areOpen(); - - /** - * {@inheritdoc} - */ - public function close() - { - foreach ($this->pipes as $pipe) { - fclose($pipe); - } - $this->pipes = []; - } - - /** - * 检查系统调用已被中断 - * @return bool - */ - protected function hasSystemCallBeenInterrupted() - { - $lastError = error_get_last(); - - return isset($lastError['message']) && false !== stripos($lastError['message'], 'interrupted system call'); - } - - protected function unblock() - { - if (!$this->blocked) { - return; - } - - foreach ($this->pipes as $pipe) { - stream_set_blocking($pipe, 0); - } - if (null !== $this->input) { - stream_set_blocking($this->input, 0); - } - - $this->blocked = false; - } -} diff --git a/thinkphp/library/think/process/pipes/Unix.php b/thinkphp/library/think/process/pipes/Unix.php deleted file mode 100755 index fd99a5d67..000000000 --- a/thinkphp/library/think/process/pipes/Unix.php +++ /dev/null @@ -1,196 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\process\pipes; - -use think\Process; - -class Unix extends Pipes -{ - - /** @var bool */ - private $ttyMode; - /** @var bool */ - private $ptyMode; - /** @var bool */ - private $disableOutput; - - public function __construct($ttyMode, $ptyMode, $input, $disableOutput) - { - $this->ttyMode = (bool) $ttyMode; - $this->ptyMode = (bool) $ptyMode; - $this->disableOutput = (bool) $disableOutput; - - if (is_resource($input)) { - $this->input = $input; - } else { - $this->inputBuffer = (string) $input; - } - } - - public function __destruct() - { - $this->close(); - } - - /** - * {@inheritdoc} - */ - public function getDescriptors() - { - if ($this->disableOutput) { - $nullstream = fopen('/dev/null', 'c'); - - return [ - ['pipe', 'r'], - $nullstream, - $nullstream, - ]; - } - - if ($this->ttyMode) { - return [ - ['file', '/dev/tty', 'r'], - ['file', '/dev/tty', 'w'], - ['file', '/dev/tty', 'w'], - ]; - } - - if ($this->ptyMode && Process::isPtySupported()) { - return [ - ['pty'], - ['pty'], - ['pty'], - ]; - } - - return [ - ['pipe', 'r'], - ['pipe', 'w'], // stdout - ['pipe', 'w'], // stderr - ]; - } - - /** - * {@inheritdoc} - */ - public function getFiles() - { - return []; - } - - /** - * {@inheritdoc} - */ - public function readAndWrite($blocking, $close = false) - { - - if (1 === count($this->pipes) && [0] === array_keys($this->pipes)) { - fclose($this->pipes[0]); - unset($this->pipes[0]); - } - - if (empty($this->pipes)) { - return []; - } - - $this->unblock(); - - $read = []; - - if (null !== $this->input) { - $r = array_merge($this->pipes, ['input' => $this->input]); - } else { - $r = $this->pipes; - } - - unset($r[0]); - - $w = isset($this->pipes[0]) ? [$this->pipes[0]] : null; - $e = null; - - if (false === $n = @stream_select($r, $w, $e, 0, $blocking ? Process::TIMEOUT_PRECISION * 1E6 : 0)) { - - if (!$this->hasSystemCallBeenInterrupted()) { - $this->pipes = []; - } - - return $read; - } - - if (0 === $n) { - return $read; - } - - foreach ($r as $pipe) { - - $type = (false !== $found = array_search($pipe, $this->pipes)) ? $found : 'input'; - $data = ''; - while ('' !== $dataread = (string) fread($pipe, self::CHUNK_SIZE)) { - $data .= $dataread; - } - - if ('' !== $data) { - if ('input' === $type) { - $this->inputBuffer .= $data; - } else { - $read[$type] = $data; - } - } - - if (false === $data || (true === $close && feof($pipe) && '' === $data)) { - if ('input' === $type) { - $this->input = null; - } else { - fclose($this->pipes[$type]); - unset($this->pipes[$type]); - } - } - } - - if (null !== $w && 0 < count($w)) { - while (strlen($this->inputBuffer)) { - $written = fwrite($w[0], $this->inputBuffer, 2 << 18); // write 512k - if ($written > 0) { - $this->inputBuffer = (string) substr($this->inputBuffer, $written); - } else { - break; - } - } - } - - if ('' === $this->inputBuffer && null === $this->input && isset($this->pipes[0])) { - fclose($this->pipes[0]); - unset($this->pipes[0]); - } - - return $read; - } - - /** - * {@inheritdoc} - */ - public function areOpen() - { - return (bool) $this->pipes; - } - - /** - * 创建一个新的 UnixPipes 实例 - * @param Process $process - * @param string|resource $input - * @return self - */ - public static function create(Process $process, $input) - { - return new static($process->isTty(), $process->isPty(), $input, $process->isOutputDisabled()); - } -} diff --git a/thinkphp/library/think/process/pipes/Windows.php b/thinkphp/library/think/process/pipes/Windows.php deleted file mode 100755 index 1b8b0d4f2..000000000 --- a/thinkphp/library/think/process/pipes/Windows.php +++ /dev/null @@ -1,228 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\process\pipes; - -use think\Process; - -class Windows extends Pipes -{ - - /** @var array */ - private $files = []; - /** @var array */ - private $fileHandles = []; - /** @var array */ - private $readBytes = [ - Process::STDOUT => 0, - Process::STDERR => 0, - ]; - /** @var bool */ - private $disableOutput; - - public function __construct($disableOutput, $input) - { - $this->disableOutput = (bool) $disableOutput; - - if (!$this->disableOutput) { - - $this->files = [ - Process::STDOUT => tempnam(sys_get_temp_dir(), 'sf_proc_stdout'), - Process::STDERR => tempnam(sys_get_temp_dir(), 'sf_proc_stderr'), - ]; - foreach ($this->files as $offset => $file) { - $this->fileHandles[$offset] = fopen($this->files[$offset], 'rb'); - if (false === $this->fileHandles[$offset]) { - throw new \RuntimeException('A temporary file could not be opened to write the process output to, verify that your TEMP environment variable is writable'); - } - } - } - - if (is_resource($input)) { - $this->input = $input; - } else { - $this->inputBuffer = $input; - } - } - - public function __destruct() - { - $this->close(); - $this->removeFiles(); - } - - /** - * {@inheritdoc} - */ - public function getDescriptors() - { - if ($this->disableOutput) { - $nullstream = fopen('NUL', 'c'); - - return [ - ['pipe', 'r'], - $nullstream, - $nullstream, - ]; - } - - return [ - ['pipe', 'r'], - ['file', 'NUL', 'w'], - ['file', 'NUL', 'w'], - ]; - } - - /** - * {@inheritdoc} - */ - public function getFiles() - { - return $this->files; - } - - /** - * {@inheritdoc} - */ - public function readAndWrite($blocking, $close = false) - { - $this->write($blocking, $close); - - $read = []; - $fh = $this->fileHandles; - foreach ($fh as $type => $fileHandle) { - if (0 !== fseek($fileHandle, $this->readBytes[$type])) { - continue; - } - $data = ''; - $dataread = null; - while (!feof($fileHandle)) { - if (false !== $dataread = fread($fileHandle, self::CHUNK_SIZE)) { - $data .= $dataread; - } - } - if (0 < $length = strlen($data)) { - $this->readBytes[$type] += $length; - $read[$type] = $data; - } - - if (false === $dataread || (true === $close && feof($fileHandle) && '' === $data)) { - fclose($this->fileHandles[$type]); - unset($this->fileHandles[$type]); - } - } - - return $read; - } - - /** - * {@inheritdoc} - */ - public function areOpen() - { - return (bool) $this->pipes && (bool) $this->fileHandles; - } - - /** - * {@inheritdoc} - */ - public function close() - { - parent::close(); - foreach ($this->fileHandles as $handle) { - fclose($handle); - } - $this->fileHandles = []; - } - - /** - * 创建一个新的 WindowsPipes 实例。 - * @param Process $process - * @param $input - * @return self - */ - public static function create(Process $process, $input) - { - return new static($process->isOutputDisabled(), $input); - } - - /** - * 删除临时文件 - */ - private function removeFiles() - { - foreach ($this->files as $filename) { - if (file_exists($filename)) { - @unlink($filename); - } - } - $this->files = []; - } - - /** - * 写入到 stdin 输入 - * @param bool $blocking - * @param bool $close - */ - private function write($blocking, $close) - { - if (empty($this->pipes)) { - return; - } - - $this->unblock(); - - $r = null !== $this->input ? ['input' => $this->input] : null; - $w = isset($this->pipes[0]) ? [$this->pipes[0]] : null; - $e = null; - - if (false === $n = @stream_select($r, $w, $e, 0, $blocking ? Process::TIMEOUT_PRECISION * 1E6 : 0)) { - if (!$this->hasSystemCallBeenInterrupted()) { - $this->pipes = []; - } - - return; - } - - if (0 === $n) { - return; - } - - if (null !== $r && 0 < count($r)) { - $data = ''; - while ($dataread = fread($r['input'], self::CHUNK_SIZE)) { - $data .= $dataread; - } - - $this->inputBuffer .= $data; - - if (false === $data || (true === $close && feof($r['input']) && '' === $data)) { - $this->input = null; - } - } - - if (null !== $w && 0 < count($w)) { - while (strlen($this->inputBuffer)) { - $written = fwrite($w[0], $this->inputBuffer, 2 << 18); - if ($written > 0) { - $this->inputBuffer = (string) substr($this->inputBuffer, $written); - } else { - break; - } - } - } - - if ('' === $this->inputBuffer && null === $this->input && isset($this->pipes[0])) { - fclose($this->pipes[0]); - unset($this->pipes[0]); - } - } -} diff --git a/thinkphp/library/think/response/View.php b/thinkphp/library/think/response/View.php deleted file mode 100755 index c836ccb5d..000000000 --- a/thinkphp/library/think/response/View.php +++ /dev/null @@ -1,94 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\response; - -use think\Response; - -class View extends Response -{ - // 输出参数 - protected $options = []; - protected $vars = []; - protected $filter; - protected $contentType = 'text/html'; - - /** - * 处理数据 - * @access protected - * @param mixed $data 要处理的数据 - * @return mixed - */ - protected function output($data) - { - // 渲染模板输出 - return $this->app['view'] - ->filter($this->filter) - ->fetch($data, $this->vars); - } - - /** - * 获取视图变量 - * @access public - * @param string $name 模板变量 - * @return mixed - */ - public function getVars($name = null) - { - if (is_null($name)) { - return $this->vars; - } else { - return isset($this->vars[$name]) ? $this->vars[$name] : null; - } - } - - /** - * 模板变量赋值 - * @access public - * @param mixed $name 变量名 - * @param mixed $value 变量值 - * @return $this - */ - public function assign($name, $value = '') - { - if (is_array($name)) { - $this->vars = array_merge($this->vars, $name); - } else { - $this->vars[$name] = $value; - } - - return $this; - } - - /** - * 视图内容过滤 - * @access public - * @param callable $filter - * @return $this - */ - public function filter($filter) - { - $this->filter = $filter; - return $this; - } - - /** - * 检查模板是否存在 - * @access private - * @param string|array $name 参数名 - * @return bool - */ - public function exists($name) - { - return $this->app['view']->exists($name); - } - -} diff --git a/thinkphp/library/think/route/AliasRule.php b/thinkphp/library/think/route/AliasRule.php deleted file mode 100755 index 393cb3107..000000000 --- a/thinkphp/library/think/route/AliasRule.php +++ /dev/null @@ -1,119 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\route; - -use think\Route; - -class AliasRule extends Domain -{ - /** - * 架构函数 - * @access public - * @param Route $router 路由实例 - * @param RuleGroup $parent 上级对象 - * @param string $name 路由别名 - * @param string $route 路由绑定 - * @param array $option 路由参数 - */ - public function __construct(Route $router, RuleGroup $parent, $name, $route, $option = []) - { - $this->router = $router; - $this->parent = $parent; - $this->name = $name; - $this->route = $route; - $this->option = $option; - } - - /** - * 检测路由别名 - * @access public - * @param Request $request 请求对象 - * @param string $url 访问地址 - * @param bool $completeMatch 路由是否完全匹配 - * @return Dispatch|false - */ - public function check($request, $url, $completeMatch = false) - { - if ($dispatch = $this->checkCrossDomain($request)) { - // 允许跨域 - return $dispatch; - } - - // 检查参数有效性 - if (!$this->checkOption($this->option, $request)) { - return false; - } - - list($action, $bind) = array_pad(explode('|', $url, 2), 2, ''); - - if (isset($this->option['allow']) && !in_array($action, $this->option['allow'])) { - // 允许操作 - return false; - } elseif (isset($this->option['except']) && in_array($action, $this->option['except'])) { - // 排除操作 - return false; - } - - if (isset($this->option['method'][$action])) { - $this->option['method'] = $this->option['method'][$action]; - } - - // 匹配后执行的行为 - $this->afterMatchGroup($request); - - if ($this->parent) { - // 合并分组参数 - $this->mergeGroupOptions(); - } - - if (isset($this->option['ext'])) { - // 路由ext参数 优先于系统配置的URL伪静态后缀参数 - $bind = preg_replace('/\.(' . $request->ext() . ')$/i', '', $bind); - } - - $this->parseBindAppendParam($this->route); - - if (0 === strpos($this->route, '\\')) { - // 路由到类 - return $this->bindToClass($request, $bind, substr($this->route, 1)); - } elseif (0 === strpos($this->route, '@')) { - // 路由到控制器类 - return $this->bindToController($request, $bind, substr($this->route, 1)); - } else { - // 路由到模块/控制器 - return $this->bindToModule($request, $bind, $this->route); - } - } - - /** - * 设置允许的操作方法 - * @access public - * @param array $action 操作方法 - * @return $this - */ - public function allow($action = []) - { - return $this->option('allow', $action); - } - - /** - * 设置排除的操作方法 - * @access public - * @param array $action 操作方法 - * @return $this - */ - public function except($action = []) - { - return $this->option('except', $action); - } - -} diff --git a/thinkphp/library/think/route/Dispatch.php b/thinkphp/library/think/route/Dispatch.php deleted file mode 100755 index 93afe73b6..000000000 --- a/thinkphp/library/think/route/Dispatch.php +++ /dev/null @@ -1,365 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\route; - -use think\Container; -use think\exception\ValidateException; -use think\App; -use think\Request; -use think\Response; - -abstract class Dispatch -{ - /** - * 应用对象 - * @var App - */ - protected $app; - - /** - * 请求对象 - * @var Request - */ - protected $request; - - /** - * 路由规则 - * @var Rule - */ - protected $rule; - - /** - * 调度信息 - * @var mixed - */ - protected $dispatch; - - /** - * 调度参数 - * @var array - */ - protected $param; - - /** - * 状态码 - * @var string - */ - protected $code; - - /** - * 是否进行大小写转换 - * @var bool - */ - protected $convert; - - public function __construct(Request $request, Rule $rule, $dispatch, $param = [], $code = null) - { - $this->request = $request; - $this->rule = $rule; - $this->app = Container::get('app'); - $this->dispatch = $dispatch; - $this->param = $param; - $this->code = $code; - - if (isset($param['convert'])) { - $this->convert = $param['convert']; - } - } - - public function init() - { - // 执行路由后置操作 - if ($this->rule->doAfter()) { - // 设置请求的路由信息 - - // 设置当前请求的参数 - $this->request->setRouteVars($this->rule->getVars()); - $this->request->routeInfo([ - 'rule' => $this->rule->getRule(), - 'route' => $this->rule->getRoute(), - 'option' => $this->rule->getOption(), - 'var' => $this->rule->getVars(), - ]); - - $this->doRouteAfter(); - } - - return $this; - } - - /** - * 检查路由后置操作 - * @access protected - * @return void - */ - protected function doRouteAfter() - { - // 记录匹配的路由信息 - $option = $this->rule->getOption(); - $matches = $this->rule->getVars(); - - // 添加中间件 - if (!empty($option['middleware'])) { - $this->app['middleware']->import($option['middleware']); - } - - // 绑定模型数据 - if (!empty($option['model'])) { - $this->createBindModel($option['model'], $matches); - } - - // 指定Header数据 - if (!empty($option['header'])) { - $header = $option['header']; - $this->app['hook']->add('response_send', function ($response) use ($header) { - $response->header($header); - }); - } - - // 指定Response响应数据 - if (!empty($option['response'])) { - foreach ($option['response'] as $response) { - $this->app['hook']->add('response_send', $response); - } - } - - // 开启请求缓存 - if (isset($option['cache']) && $this->request->isGet()) { - $this->parseRequestCache($option['cache']); - } - - if (!empty($option['append'])) { - $this->request->setRouteVars($option['append']); - } - } - - /** - * 执行路由调度 - * @access public - * @return mixed - */ - public function run() - { - $option = $this->rule->getOption(); - - // 检测路由after行为 - if (!empty($option['after'])) { - $dispatch = $this->checkAfter($option['after']); - - if ($dispatch instanceof Response) { - return $dispatch; - } - } - - // 数据自动验证 - if (isset($option['validate'])) { - $this->autoValidate($option['validate']); - } - - $data = $this->exec(); - - return $this->autoResponse($data); - } - - protected function autoResponse($data) - { - if ($data instanceof Response) { - $response = $data; - } elseif (!is_null($data)) { - // 默认自动识别响应输出类型 - $isAjax = $this->request->isAjax(); - $type = $isAjax ? $this->rule->getConfig('default_ajax_return') : $this->rule->getConfig('default_return_type'); - - $response = Response::create($data, $type); - } else { - $data = ob_get_clean(); - $content = false === $data ? '' : $data; - $status = '' === $content && $this->request->isAjax() ? 204 : 200; - $response = Response::create($content, '', $status); - } - - return $response; - } - - /** - * 检查路由后置行为 - * @access protected - * @param mixed $after 后置行为 - * @return mixed - */ - protected function checkAfter($after) - { - $this->app['log']->notice('路由后置行为建议使用中间件替代!'); - - $hook = $this->app['hook']; - - $result = null; - - foreach ((array) $after as $behavior) { - $result = $hook->exec($behavior); - - if (!is_null($result)) { - break; - } - } - - // 路由规则重定向 - if ($result instanceof Response) { - return $result; - } - - return false; - } - - /** - * 验证数据 - * @access protected - * @param array $option - * @return void - * @throws ValidateException - */ - protected function autoValidate($option) - { - list($validate, $scene, $message, $batch) = $option; - - if (is_array($validate)) { - // 指定验证规则 - $v = $this->app->validate(); - $v->rule($validate); - } else { - // 调用验证器 - $v = $this->app->validate($validate); - if (!empty($scene)) { - $v->scene($scene); - } - } - - if (!empty($message)) { - $v->message($message); - } - - // 批量验证 - if ($batch) { - $v->batch(true); - } - - if (!$v->check($this->request->param())) { - throw new ValidateException($v->getError()); - } - } - - /** - * 处理路由请求缓存 - * @access protected - * @param Request $request 请求对象 - * @param string|array $cache 路由缓存 - * @return void - */ - protected function parseRequestCache($cache) - { - if (is_array($cache)) { - list($key, $expire, $tag) = array_pad($cache, 3, null); - } else { - $key = str_replace('|', '/', $this->request->url()); - $expire = $cache; - $tag = null; - } - - $cache = $this->request->cache($key, $expire, $tag); - $this->app->setResponseCache($cache); - } - - /** - * 路由绑定模型实例 - * @access protected - * @param array|\Clousre $bindModel 绑定模型 - * @param array $matches 路由变量 - * @return void - */ - protected function createBindModel($bindModel, $matches) - { - foreach ($bindModel as $key => $val) { - if ($val instanceof \Closure) { - $result = $this->app->invokeFunction($val, $matches); - } else { - $fields = explode('&', $key); - - if (is_array($val)) { - list($model, $exception) = $val; - } else { - $model = $val; - $exception = true; - } - - $where = []; - $match = true; - - foreach ($fields as $field) { - if (!isset($matches[$field])) { - $match = false; - break; - } else { - $where[] = [$field, '=', $matches[$field]]; - } - } - - if ($match) { - $query = strpos($model, '\\') ? $model::where($where) : $this->app->model($model)->where($where); - $result = $query->failException($exception)->find(); - } - } - - if (!empty($result)) { - // 注入容器 - $this->app->instance(get_class($result), $result); - } - } - } - - public function convert($convert) - { - $this->convert = $convert; - - return $this; - } - - public function getDispatch() - { - return $this->dispatch; - } - - public function getParam() - { - return $this->param; - } - - abstract public function exec(); - - public function __sleep() - { - return ['rule', 'dispatch', 'convert', 'param', 'code', 'controller', 'actionName']; - } - - public function __wakeup() - { - $this->app = Container::get('app'); - $this->request = $this->app['request']; - } - - public function __debugInfo() - { - $data = get_object_vars($this); - unset($data['app'], $data['request'], $data['rule']); - - return $data; - } -} diff --git a/thinkphp/library/think/route/Resource.php b/thinkphp/library/think/route/Resource.php deleted file mode 100755 index ff1392824..000000000 --- a/thinkphp/library/think/route/Resource.php +++ /dev/null @@ -1,126 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\route; - -use think\Route; - -class Resource extends RuleGroup -{ - // 资源路由名称 - protected $resource; - - // REST路由方法定义 - protected $rest = []; - - /** - * 架构函数 - * @access public - * @param Route $router 路由对象 - * @param RuleGroup $parent 上级对象 - * @param string $name 资源名称 - * @param string $route 路由地址 - * @param array $option 路由参数 - * @param array $pattern 变量规则 - * @param array $rest 资源定义 - */ - public function __construct(Route $router, RuleGroup $parent = null, $name = '', $route = '', $option = [], $pattern = [], $rest = []) - { - $this->router = $router; - $this->parent = $parent; - $this->resource = $name; - $this->route = $route; - $this->name = strpos($name, '.') ? strstr($name, '.', true) : $name; - - $this->setFullName(); - - // 资源路由默认为完整匹配 - $option['complete_match'] = true; - - $this->pattern = $pattern; - $this->option = $option; - $this->rest = $rest; - - if ($this->parent) { - $this->domain = $this->parent->getDomain(); - $this->parent->addRuleItem($this); - } - - if ($router->isTest()) { - $this->buildResourceRule(); - } - } - - /** - * 生成资源路由规则 - * @access protected - * @return void - */ - protected function buildResourceRule() - { - $origin = $this->router->getGroup(); - $this->router->setGroup($this); - - $rule = $this->resource; - $option = $this->option; - - if (strpos($rule, '.')) { - // 注册嵌套资源路由 - $array = explode('.', $rule); - $last = array_pop($array); - $item = []; - - foreach ($array as $val) { - $item[] = $val . '/<' . (isset($option['var'][$val]) ? $option['var'][$val] : $val . '_id') . '>'; - } - - $rule = implode('/', $item) . '/' . $last; - } - - $prefix = substr($rule, strlen($this->name) + 1); - - // 注册资源路由 - foreach ($this->rest as $key => $val) { - if ((isset($option['only']) && !in_array($key, $option['only'])) - || (isset($option['except']) && in_array($key, $option['except']))) { - continue; - } - - if (isset($last) && strpos($val[1], '') && isset($option['var'][$last])) { - $val[1] = str_replace('', '<' . $option['var'][$last] . '>', $val[1]); - } elseif (strpos($val[1], '') && isset($option['var'][$rule])) { - $val[1] = str_replace('', '<' . $option['var'][$rule] . '>', $val[1]); - } - - $this->addRule(trim($prefix . $val[1], '/'), $this->route . '/' . $val[2], $val[0]); - } - - $this->router->setGroup($origin); - } - - /** - * rest方法定义和修改 - * @access public - * @param string $name 方法名称 - * @param array|bool $resource 资源 - * @return $this - */ - public function rest($name, $resource = []) - { - if (is_array($name)) { - $this->rest = $resource ? $name : array_merge($this->rest, $name); - } else { - $this->rest[$name] = $resource; - } - - return $this; - } -} diff --git a/thinkphp/library/think/route/Rule.php b/thinkphp/library/think/route/Rule.php deleted file mode 100755 index fdfc29d1d..000000000 --- a/thinkphp/library/think/route/Rule.php +++ /dev/null @@ -1,1121 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\route; - -use think\Container; -use think\Request; -use think\Response; -use think\route\dispatch\Callback as CallbackDispatch; -use think\route\dispatch\Controller as ControllerDispatch; -use think\route\dispatch\Module as ModuleDispatch; -use think\route\dispatch\Redirect as RedirectDispatch; -use think\route\dispatch\Response as ResponseDispatch; -use think\route\dispatch\View as ViewDispatch; - -abstract class Rule -{ - /** - * 路由标识 - * @var string - */ - protected $name; - - /** - * 路由对象 - * @var Route - */ - protected $router; - - /** - * 路由所属分组 - * @var RuleGroup - */ - protected $parent; - - /** - * 路由规则 - * @var mixed - */ - protected $rule; - - /** - * 路由地址 - * @var string|\Closure - */ - protected $route; - - /** - * 请求类型 - * @var string - */ - protected $method; - - /** - * 路由变量 - * @var array - */ - protected $vars = []; - - /** - * 路由参数 - * @var array - */ - protected $option = []; - - /** - * 路由变量规则 - * @var array - */ - protected $pattern = []; - - /** - * 需要和分组合并的路由参数 - * @var array - */ - protected $mergeOptions = ['after', 'model', 'header', 'response', 'append', 'middleware']; - - /** - * 是否需要后置操作 - * @var bool - */ - protected $doAfter; - - /** - * 是否锁定参数 - * @var bool - */ - protected $lockOption = false; - - abstract public function check($request, $url, $completeMatch = false); - - /** - * 获取Name - * @access public - * @return string - */ - public function getName() - { - return $this->name; - } - - /** - * 获取当前路由规则 - * @access public - * @return string - */ - public function getRule() - { - return $this->rule; - } - - /** - * 获取当前路由地址 - * @access public - * @return mixed - */ - public function getRoute() - { - return $this->route; - } - - /** - * 获取当前路由的请求类型 - * @access public - * @return string - */ - public function getMethod() - { - return strtolower($this->method); - } - - /** - * 获取当前路由的变量 - * @access public - * @return array - */ - public function getVars() - { - return $this->vars; - } - - /** - * 获取路由对象 - * @access public - * @return Route - */ - public function getRouter() - { - return $this->router; - } - - /** - * 路由是否有后置操作 - * @access public - * @return bool - */ - public function doAfter() - { - return $this->doAfter; - } - - /** - * 获取路由分组 - * @access public - * @return RuleGroup|null - */ - public function getParent() - { - return $this->parent; - } - - /** - * 获取路由所在域名 - * @access public - * @return string - */ - public function getDomain() - { - return $this->parent->getDomain(); - } - - /** - * 获取变量规则定义 - * @access public - * @param string $name 变量名 - * @return mixed - */ - public function getPattern($name = '') - { - if ('' === $name) { - return $this->pattern; - } - - return isset($this->pattern[$name]) ? $this->pattern[$name] : null; - } - - /** - * 获取路由参数 - * @access public - * @param string $name 变量名 - * @return mixed - */ - public function getConfig($name = '') - { - return $this->router->config($name); - } - - /** - * 获取路由参数定义 - * @access public - * @param string $name 参数名 - * @return mixed - */ - public function getOption($name = '') - { - if ('' === $name) { - return $this->option; - } - - return isset($this->option[$name]) ? $this->option[$name] : null; - } - - /** - * 注册路由参数 - * @access public - * @param string|array $name 参数名 - * @param mixed $value 值 - * @return $this - */ - public function option($name, $value = '') - { - if (is_array($name)) { - $this->option = array_merge($this->option, $name); - } else { - $this->option[$name] = $value; - } - - return $this; - } - - /** - * 注册变量规则 - * @access public - * @param string|array $name 变量名 - * @param string $rule 变量规则 - * @return $this - */ - public function pattern($name, $rule = '') - { - if (is_array($name)) { - $this->pattern = array_merge($this->pattern, $name); - } else { - $this->pattern[$name] = $rule; - } - - return $this; - } - - /** - * 设置标识 - * @access public - * @param string $name 标识名 - * @return $this - */ - public function name($name) - { - $this->name = $name; - - return $this; - } - - /** - * 设置变量 - * @access public - * @param array $vars 变量 - * @return $this - */ - public function vars($vars) - { - $this->vars = $vars; - - return $this; - } - - /** - * 设置路由请求类型 - * @access public - * @param string $method - * @return $this - */ - public function method($method) - { - return $this->option('method', strtolower($method)); - } - - /** - * 设置路由前置行为 - * @access public - * @param array|\Closure $before - * @return $this - */ - public function before($before) - { - return $this->option('before', $before); - } - - /** - * 设置路由后置行为 - * @access public - * @param array|\Closure $after - * @return $this - */ - public function after($after) - { - return $this->option('after', $after); - } - - /** - * 检查后缀 - * @access public - * @param string $ext - * @return $this - */ - public function ext($ext = '') - { - return $this->option('ext', $ext); - } - - /** - * 检查禁止后缀 - * @access public - * @param string $ext - * @return $this - */ - public function denyExt($ext = '') - { - return $this->option('deny_ext', $ext); - } - - /** - * 检查域名 - * @access public - * @param string $domain - * @return $this - */ - public function domain($domain) - { - return $this->option('domain', $domain); - } - - /** - * 设置参数过滤检查 - * @access public - * @param string|array $name - * @param mixed $value - * @return $this - */ - public function filter($name, $value = null) - { - if (is_array($name)) { - $this->option['filter'] = $name; - } else { - $this->option['filter'][$name] = $value; - } - - return $this; - } - - /** - * 绑定模型 - * @access public - * @param array|string $var 路由变量名 多个使用 & 分割 - * @param string|\Closure $model 绑定模型类 - * @param bool $exception 是否抛出异常 - * @return $this - */ - public function model($var, $model = null, $exception = true) - { - if ($var instanceof \Closure) { - $this->option['model'][] = $var; - } elseif (is_array($var)) { - $this->option['model'] = $var; - } elseif (is_null($model)) { - $this->option['model']['id'] = [$var, true]; - } else { - $this->option['model'][$var] = [$model, $exception]; - } - - return $this; - } - - /** - * 附加路由隐式参数 - * @access public - * @param array $append - * @return $this - */ - public function append(array $append = []) - { - if (isset($this->option['append'])) { - $this->option['append'] = array_merge($this->option['append'], $append); - } else { - $this->option['append'] = $append; - } - - return $this; - } - - /** - * 绑定验证 - * @access public - * @param mixed $validate 验证器类 - * @param string $scene 验证场景 - * @param array $message 验证提示 - * @param bool $batch 批量验证 - * @return $this - */ - public function validate($validate, $scene = null, $message = [], $batch = false) - { - $this->option['validate'] = [$validate, $scene, $message, $batch]; - - return $this; - } - - /** - * 绑定Response对象 - * @access public - * @param mixed $response - * @return $this - */ - public function response($response) - { - $this->option['response'][] = $response; - return $this; - } - - /** - * 设置Response Header信息 - * @access public - * @param string|array $name 参数名 - * @param string $value 参数值 - * @return $this - */ - public function header($header, $value = null) - { - if (is_array($header)) { - $this->option['header'] = $header; - } else { - $this->option['header'][$header] = $value; - } - - return $this; - } - - /** - * 指定路由中间件 - * @access public - * @param string|array|\Closure $middleware - * @param mixed $param - * @return $this - */ - public function middleware($middleware, $param = null) - { - if (is_null($param) && is_array($middleware)) { - $this->option['middleware'] = $middleware; - } else { - foreach ((array) $middleware as $item) { - $this->option['middleware'][] = [$item, $param]; - } - } - - return $this; - } - - /** - * 设置路由缓存 - * @access public - * @param array|string $cache - * @return $this - */ - public function cache($cache) - { - return $this->option('cache', $cache); - } - - /** - * 检查URL分隔符 - * @access public - * @param bool $depr - * @return $this - */ - public function depr($depr) - { - return $this->option('param_depr', $depr); - } - - /** - * 是否合并额外参数 - * @access public - * @param bool $merge - * @return $this - */ - public function mergeExtraVars($merge = true) - { - return $this->option('merge_extra_vars', $merge); - } - - /** - * 设置需要合并的路由参数 - * @access public - * @param array $option - * @return $this - */ - public function mergeOptions($option = []) - { - $this->mergeOptions = array_merge($this->mergeOptions, $option); - return $this; - } - - /** - * 检查是否为HTTPS请求 - * @access public - * @param bool $https - * @return $this - */ - public function https($https = true) - { - return $this->option('https', $https); - } - - /** - * 检查是否为AJAX请求 - * @access public - * @param bool $ajax - * @return $this - */ - public function ajax($ajax = true) - { - return $this->option('ajax', $ajax); - } - - /** - * 检查是否为PJAX请求 - * @access public - * @param bool $pjax - * @return $this - */ - public function pjax($pjax = true) - { - return $this->option('pjax', $pjax); - } - - /** - * 检查是否为手机访问 - * @access public - * @param bool $mobile - * @return $this - */ - public function mobile($mobile = true) - { - return $this->option('mobile', $mobile); - } - - /** - * 当前路由到一个模板地址 当使用数组的时候可以传入模板变量 - * @access public - * @param bool|array $view - * @return $this - */ - public function view($view = true) - { - return $this->option('view', $view); - } - - /** - * 当前路由为重定向 - * @access public - * @param bool $redirect 是否为重定向 - * @return $this - */ - public function redirect($redirect = true) - { - return $this->option('redirect', $redirect); - } - - /** - * 设置路由完整匹配 - * @access public - * @param bool $match - * @return $this - */ - public function completeMatch($match = true) - { - return $this->option('complete_match', $match); - } - - /** - * 是否去除URL最后的斜线 - * @access public - * @param bool $remove - * @return $this - */ - public function removeSlash($remove = true) - { - return $this->option('remove_slash', $remove); - } - - /** - * 设置是否允许跨域 - * @access public - * @param bool $allow - * @param array $header - * @return $this - */ - public function allowCrossDomain($allow = true, $header = []) - { - if (!empty($header)) { - $this->header($header); - } - - if ($allow && $this->parent) { - $this->parent->addRuleItem($this, 'options'); - } - - return $this->option('cross_domain', $allow); - } - - /** - * 检查OPTIONS请求 - * @access public - * @param Request $request - * @return Dispatch|void - */ - protected function checkCrossDomain($request) - { - if (!empty($this->option['cross_domain'])) { - - $header = [ - 'Access-Control-Allow-Origin' => '*', - 'Access-Control-Allow-Methods' => 'GET, POST, PATCH, PUT, DELETE', - 'Access-Control-Allow-Headers' => 'Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-Requested-With', - ]; - - if (!empty($this->option['header'])) { - $header = array_merge($header, $this->option['header']); - } - - $this->option['header'] = $header; - - if ($request->method(true) == 'OPTIONS') { - return new ResponseDispatch($request, $this, Response::create()->code(204)->header($header)); - } - } - } - - /** - * 设置路由规则全局有效 - * @access public - * @return $this - */ - public function crossDomainRule() - { - if ($this instanceof RuleGroup) { - $method = '*'; - } else { - $method = $this->method; - } - - $this->router->setCrossDomainRule($this, $method); - - return $this; - } - - /** - * 合并分组参数 - * @access public - * @return array - */ - public function mergeGroupOptions() - { - if (!$this->lockOption) { - $parentOption = $this->parent->getOption(); - // 合并分组参数 - foreach ($this->mergeOptions as $item) { - if (isset($parentOption[$item]) && isset($this->option[$item])) { - $this->option[$item] = array_merge($parentOption[$item], $this->option[$item]); - } - } - - $this->option = array_merge($parentOption, $this->option); - $this->lockOption = true; - } - - return $this->option; - } - - /** - * 解析匹配到的规则路由 - * @access public - * @param Request $request 请求对象 - * @param string $rule 路由规则 - * @param string $route 路由地址 - * @param string $url URL地址 - * @param array $option 路由参数 - * @param array $matches 匹配的变量 - * @return Dispatch - */ - public function parseRule($request, $rule, $route, $url, $option = [], $matches = []) - { - if (is_string($route) && isset($option['prefix'])) { - // 路由地址前缀 - $route = $option['prefix'] . $route; - } - - // 替换路由地址中的变量 - if (is_string($route) && !empty($matches)) { - $search = $replace = []; - - foreach ($matches as $key => $value) { - $search[] = '<' . $key . '>'; - $replace[] = $value; - - $search[] = ':' . $key; - $replace[] = $value; - } - - $route = str_replace($search, $replace, $route); - } - - // 解析额外参数 - $count = substr_count($rule, '/'); - $url = array_slice(explode('|', $url), $count + 1); - $this->parseUrlParams($request, implode('|', $url), $matches); - - $this->vars = $matches; - $this->option = $option; - $this->doAfter = true; - - // 发起路由调度 - return $this->dispatch($request, $route, $option); - } - - /** - * 检查路由前置行为 - * @access protected - * @param mixed $before 前置行为 - * @return mixed - */ - protected function checkBefore($before) - { - $hook = Container::get('hook'); - - foreach ((array) $before as $behavior) { - $result = $hook->exec($behavior); - - if (false === $result) { - return false; - } - } - } - - /** - * 发起路由调度 - * @access protected - * @param Request $request Request对象 - * @param mixed $route 路由地址 - * @param array $option 路由参数 - * @return Dispatch - */ - protected function dispatch($request, $route, $option) - { - if ($route instanceof \Closure) { - // 执行闭包 - $result = new CallbackDispatch($request, $this, $route); - } elseif ($route instanceof Response) { - $result = new ResponseDispatch($request, $this, $route); - } elseif (isset($option['view']) && false !== $option['view']) { - $result = new ViewDispatch($request, $this, $route, is_array($option['view']) ? $option['view'] : []); - } elseif (!empty($option['redirect']) || 0 === strpos($route, '/') || strpos($route, '://')) { - // 路由到重定向地址 - $result = new RedirectDispatch($request, $this, $route, [], isset($option['status']) ? $option['status'] : 301); - } elseif (false !== strpos($route, '\\')) { - // 路由到方法 - $result = $this->dispatchMethod($request, $route); - } elseif (0 === strpos($route, '@')) { - // 路由到控制器 - $result = $this->dispatchController($request, substr($route, 1)); - } else { - // 路由到模块/控制器/操作 - $result = $this->dispatchModule($request, $route); - } - - return $result; - } - - /** - * 解析URL地址为 模块/控制器/操作 - * @access protected - * @param Request $request Request对象 - * @param string $route 路由地址 - * @return CallbackDispatch - */ - protected function dispatchMethod($request, $route) - { - list($path, $var) = $this->parseUrlPath($route); - - $route = str_replace('/', '@', implode('/', $path)); - $method = strpos($route, '@') ? explode('@', $route) : $route; - - return new CallbackDispatch($request, $this, $method, $var); - } - - /** - * 解析URL地址为 模块/控制器/操作 - * @access protected - * @param Request $request Request对象 - * @param string $route 路由地址 - * @return ControllerDispatch - */ - protected function dispatchController($request, $route) - { - list($route, $var) = $this->parseUrlPath($route); - - $result = new ControllerDispatch($request, $this, implode('/', $route), $var); - - $request->setAction(array_pop($route)); - $request->setController($route ? array_pop($route) : $this->getConfig('default_controller')); - $request->setModule($route ? array_pop($route) : $this->getConfig('default_module')); - - return $result; - } - - /** - * 解析URL地址为 模块/控制器/操作 - * @access protected - * @param Request $request Request对象 - * @param string $route 路由地址 - * @return ModuleDispatch - */ - protected function dispatchModule($request, $route) - { - list($path, $var) = $this->parseUrlPath($route); - - $action = array_pop($path); - $controller = !empty($path) ? array_pop($path) : null; - $module = $this->getConfig('app_multi_module') && !empty($path) ? array_pop($path) : null; - $method = $request->method(); - - if ($this->getConfig('use_action_prefix') && $this->router->getMethodPrefix($method)) { - $prefix = $this->router->getMethodPrefix($method); - // 操作方法前缀支持 - $action = 0 !== strpos($action, $prefix) ? $prefix . $action : $action; - } - - // 设置当前请求的路由变量 - $request->setRouteVars($var); - - // 路由到模块/控制器/操作 - return new ModuleDispatch($request, $this, [$module, $controller, $action], ['convert' => false]); - } - - /** - * 路由检查 - * @access protected - * @param array $option 路由参数 - * @param Request $request Request对象 - * @return bool - */ - protected function checkOption($option, Request $request) - { - // 请求类型检测 - if (!empty($option['method'])) { - if (is_string($option['method']) && false === stripos($option['method'], $request->method())) { - return false; - } - } - - // AJAX PJAX 请求检查 - foreach (['ajax', 'pjax', 'mobile'] as $item) { - if (isset($option[$item])) { - $call = 'is' . $item; - if ($option[$item] && !$request->$call() || !$option[$item] && $request->$call()) { - return false; - } - } - } - - // 伪静态后缀检测 - if ($request->url() != '/' && ((isset($option['ext']) && false === stripos('|' . $option['ext'] . '|', '|' . $request->ext() . '|')) - || (isset($option['deny_ext']) && false !== stripos('|' . $option['deny_ext'] . '|', '|' . $request->ext() . '|')))) { - return false; - } - - // 域名检查 - if ((isset($option['domain']) && !in_array($option['domain'], [$request->host(true), $request->subDomain()]))) { - return false; - } - - // HTTPS检查 - if ((isset($option['https']) && $option['https'] && !$request->isSsl()) - || (isset($option['https']) && !$option['https'] && $request->isSsl())) { - return false; - } - - // 请求参数检查 - if (isset($option['filter'])) { - foreach ($option['filter'] as $name => $value) { - if ($request->param($name, '', null) != $value) { - return false; - } - } - } - return true; - } - - /** - * 解析URL地址中的参数Request对象 - * @access protected - * @param Request $request - * @param string $rule 路由规则 - * @param array $var 变量 - * @return void - */ - protected function parseUrlParams($request, $url, &$var = []) - { - if ($url) { - if ($this->getConfig('url_param_type')) { - $var += explode('|', $url); - } else { - preg_replace_callback('/(\w+)\|([^\|]+)/', function ($match) use (&$var) { - $var[$match[1]] = strip_tags($match[2]); - }, $url); - } - } - } - - /** - * 解析URL的pathinfo参数和变量 - * @access public - * @param string $url URL地址 - * @return array - */ - public function parseUrlPath($url) - { - // 分隔符替换 确保路由定义使用统一的分隔符 - $url = str_replace('|', '/', $url); - $url = trim($url, '/'); - $var = []; - - if (false !== strpos($url, '?')) { - // [模块/控制器/操作?]参数1=值1&参数2=值2... - $info = parse_url($url); - $path = explode('/', $info['path']); - parse_str($info['query'], $var); - } elseif (strpos($url, '/')) { - // [模块/控制器/操作] - $path = explode('/', $url); - } elseif (false !== strpos($url, '=')) { - // 参数1=值1&参数2=值2... - $path = []; - parse_str($url, $var); - } else { - $path = [$url]; - } - - return [$path, $var]; - } - - /** - * 生成路由的正则规则 - * @access protected - * @param string $rule 路由规则 - * @param array $match 匹配的变量 - * @param array $pattern 路由变量规则 - * @param array $option 路由参数 - * @param bool $completeMatch 路由是否完全匹配 - * @param string $suffix 路由正则变量后缀 - * @return string - */ - protected function buildRuleRegex($rule, $match, $pattern = [], $option = [], $completeMatch = false, $suffix = '') - { - foreach ($match as $name) { - $replace[] = $this->buildNameRegex($name, $pattern, $suffix); - } - - // 是否区分 / 地址访问 - if ('/' != $rule) { - if (!empty($option['remove_slash'])) { - $rule = rtrim($rule, '/'); - } elseif (substr($rule, -1) == '/') { - $rule = rtrim($rule, '/'); - $hasSlash = true; - } - } - - $regex = str_replace($match, $replace, $rule); - $regex = str_replace([')?/', ')/', ')?-', ')-', '\\\\/'], [')\/', ')\/', ')\-', ')\-', '\/'], $regex); - - if (isset($hasSlash)) { - $regex .= '\/'; - } - - return $regex . ($completeMatch ? '$' : ''); - } - - /** - * 生成路由变量的正则规则 - * @access protected - * @param string $name 路由变量 - * @param string $pattern 变量规则 - * @param string $suffix 路由正则变量后缀 - * @return string - */ - protected function buildNameRegex($name, $pattern, $suffix) - { - $optional = ''; - $slash = substr($name, 0, 1); - - if (in_array($slash, ['/', '-'])) { - $prefix = '\\' . $slash; - $name = substr($name, 1); - $slash = substr($name, 0, 1); - } else { - $prefix = ''; - } - - if ('<' != $slash) { - return $prefix . preg_quote($name, '/'); - } - - if (strpos($name, '?')) { - $name = substr($name, 1, -2); - $optional = '?'; - } elseif (strpos($name, '>')) { - $name = substr($name, 1, -1); - } - - if (isset($pattern[$name])) { - $nameRule = $pattern[$name]; - if (0 === strpos($nameRule, '/') && '/' == substr($nameRule, -1)) { - $nameRule = substr($nameRule, 1, -1); - } - } else { - $nameRule = $this->getConfig('default_route_pattern'); - } - - return '(' . $prefix . '(?<' . $name . $suffix . '>' . $nameRule . '))' . $optional; - } - - /** - * 分析路由规则中的变量 - * @access protected - * @param string $rule 路由规则 - * @return array - */ - protected function parseVar($rule) - { - // 提取路由规则中的变量 - $var = []; - - if (preg_match_all('/<\w+\??>/', $rule, $matches)) { - foreach ($matches[0] as $name) { - $optional = false; - - if (strpos($name, '?')) { - $name = substr($name, 1, -2); - $optional = true; - } else { - $name = substr($name, 1, -1); - } - - $var[$name] = $optional ? 2 : 1; - } - } - - return $var; - } - - /** - * 设置路由参数 - * @access public - * @param string $method 方法名 - * @param array $args 调用参数 - * @return $this - */ - public function __call($method, $args) - { - if (count($args) > 1) { - $args[0] = $args; - } - array_unshift($args, $method); - - return call_user_func_array([$this, 'option'], $args); - } - - public function __sleep() - { - return ['name', 'rule', 'route', 'method', 'vars', 'option', 'pattern', 'doAfter']; - } - - public function __wakeup() - { - $this->router = Container::get('route'); - } - - public function __debugInfo() - { - $data = get_object_vars($this); - unset($data['parent'], $data['router'], $data['route']); - - return $data; - } -} diff --git a/thinkphp/library/think/route/RuleName.php b/thinkphp/library/think/route/RuleName.php deleted file mode 100755 index 202fb0e23..000000000 --- a/thinkphp/library/think/route/RuleName.php +++ /dev/null @@ -1,147 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\route; - -class RuleName -{ - protected $item = []; - protected $rule = []; - - /** - * 注册路由标识 - * @access public - * @param string $name 路由标识 - * @param array $value 路由规则 - * @param bool $first 是否置顶 - * @return void - */ - public function set($name, $value, $first = false) - { - if ($first && isset($this->item[$name])) { - array_unshift($this->item[$name], $value); - } else { - $this->item[$name][] = $value; - } - } - - /** - * 注册路由规则 - * @access public - * @param string $rule 路由规则 - * @param RuleItem $route 路由 - * @return void - */ - public function setRule($rule, $route) - { - $this->rule[$route->getDomain()][$rule][$route->getMethod()] = $route; - } - - /** - * 根据路由规则获取路由对象(列表) - * @access public - * @param string $name 路由标识 - * @param string $domain 域名 - * @return array - */ - public function getRule($rule, $domain = null) - { - return isset($this->rule[$domain][$rule]) ? $this->rule[$domain][$rule] : []; - } - - /** - * 获取全部路由列表 - * @access public - * @param string $domain 域名 - * @return array - */ - public function getRuleList($domain = null) - { - $list = []; - - foreach ($this->rule as $ruleDomain => $rules) { - foreach ($rules as $rule => $items) { - foreach ($items as $item) { - $val['domain'] = $ruleDomain; - - foreach (['method', 'rule', 'name', 'route', 'pattern', 'option'] as $param) { - $call = 'get' . $param; - $val[$param] = $item->$call(); - } - - $list[$ruleDomain][] = $val; - } - } - } - - if ($domain) { - return isset($list[$domain]) ? $list[$domain] : []; - } - - return $list; - } - - /** - * 导入路由标识 - * @access public - * @param array $name 路由标识 - * @return void - */ - public function import($item) - { - $this->item = $item; - } - - /** - * 根据路由标识获取路由信息(用于URL生成) - * @access public - * @param string $name 路由标识 - * @param string $domain 域名 - * @return array|null - */ - public function get($name = null, $domain = null, $method = '*') - { - if (is_null($name)) { - return $this->item; - } - - $name = strtolower($name); - $method = strtolower($method); - - if (isset($this->item[$name])) { - if (is_null($domain)) { - $result = $this->item[$name]; - } else { - $result = []; - foreach ($this->item[$name] as $item) { - if ($item[2] == $domain && ('*' == $item[4] || $method == $item[4])) { - $result[] = $item; - } - } - } - } else { - $result = null; - } - - return $result; - } - - /** - * 清空路由规则 - * @access public - * @return void - */ - public function clear() - { - $this->item = []; - $this->rule = []; - } -} diff --git a/thinkphp/library/think/route/dispatch/Controller.php b/thinkphp/library/think/route/dispatch/Controller.php deleted file mode 100755 index 1de829926..000000000 --- a/thinkphp/library/think/route/dispatch/Controller.php +++ /dev/null @@ -1,30 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\route\dispatch; - -use think\route\Dispatch; - -class Controller extends Dispatch -{ - public function exec() - { - // 执行控制器的操作方法 - $vars = array_merge($this->request->param(), $this->param); - - return $this->app->action( - $this->dispatch, $vars, - $this->rule->getConfig('url_controller_layer'), - $this->rule->getConfig('controller_suffix') - ); - } - -} diff --git a/thinkphp/library/think/route/dispatch/Module.php b/thinkphp/library/think/route/dispatch/Module.php deleted file mode 100755 index e8842cd3a..000000000 --- a/thinkphp/library/think/route/dispatch/Module.php +++ /dev/null @@ -1,139 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\route\dispatch; - -use ReflectionMethod; -use think\Controller; -use think\exception\ClassNotFoundException; -use think\exception\HttpException; -use think\Loader; -use think\Request; -use think\route\Dispatch; - -class Module extends Dispatch -{ - protected $controller; - protected $actionName; - - public function init() - { - parent::init(); - - $result = $this->dispatch; - - if (is_string($result)) { - $result = explode('/', $result); - } - - if ($this->rule->getConfig('app_multi_module')) { - // 多模块部署 - $module = strip_tags(strtolower($result[0] ?: $this->rule->getConfig('default_module'))); - $bind = $this->rule->getRouter()->getBind(); - $available = false; - - if ($bind && preg_match('/^[a-z]/is', $bind)) { - // 绑定模块 - list($bindModule) = explode('/', $bind); - if (empty($result[0])) { - $module = $bindModule; - } - $available = true; - } elseif (!in_array($module, $this->rule->getConfig('deny_module_list')) && is_dir($this->app->getAppPath() . $module)) { - $available = true; - } elseif ($this->rule->getConfig('empty_module')) { - $module = $this->rule->getConfig('empty_module'); - $available = true; - } - - // 模块初始化 - if ($module && $available) { - // 初始化模块 - $this->request->setModule($module); - $this->app->init($module); - } else { - throw new HttpException(404, 'module not exists:' . $module); - } - } - - // 是否自动转换控制器和操作名 - $convert = is_bool($this->convert) ? $this->convert : $this->rule->getConfig('url_convert'); - // 获取控制器名 - $controller = strip_tags($result[1] ?: $this->rule->getConfig('default_controller')); - - $this->controller = $convert ? strtolower($controller) : $controller; - - // 获取操作名 - $this->actionName = strip_tags($result[2] ?: $this->rule->getConfig('default_action')); - - // 设置当前请求的控制器、操作 - $this->request - ->setController(Loader::parseName($this->controller, 1)) - ->setAction($this->actionName); - - return $this; - } - - public function exec() - { - // 监听module_init - $this->app['hook']->listen('module_init'); - - try { - // 实例化控制器 - $instance = $this->app->controller($this->controller, - $this->rule->getConfig('url_controller_layer'), - $this->rule->getConfig('controller_suffix'), - $this->rule->getConfig('empty_controller')); - } catch (ClassNotFoundException $e) { - throw new HttpException(404, 'controller not exists:' . $e->getClass()); - } - - $this->app['middleware']->controller(function (Request $request, $next) use ($instance) { - // 获取当前操作名 - $action = $this->actionName . $this->rule->getConfig('action_suffix'); - - if (is_callable([$instance, $action])) { - // 执行操作方法 - $call = [$instance, $action]; - - // 严格获取当前操作方法名 - $reflect = new ReflectionMethod($instance, $action); - $methodName = $reflect->getName(); - $suffix = $this->rule->getConfig('action_suffix'); - $actionName = $suffix ? substr($methodName, 0, -strlen($suffix)) : $methodName; - $this->request->setAction($actionName); - - // 自动获取请求变量 - $vars = $this->rule->getConfig('url_param_type') - ? $this->request->route() - : $this->request->param(); - $vars = array_merge($vars, $this->param); - } elseif (is_callable([$instance, '_empty'])) { - // 空操作 - $call = [$instance, '_empty']; - $vars = [$this->actionName]; - $reflect = new ReflectionMethod($instance, '_empty'); - } else { - // 操作不存在 - throw new HttpException(404, 'method not exists:' . get_class($instance) . '->' . $action . '()'); - } - - $this->app['hook']->listen('action_begin', $call); - - $data = $this->app->invokeReflectMethod($instance, $reflect, $vars); - - return $this->autoResponse($data); - }); - - return $this->app['middleware']->dispatch($this->request, 'controller'); - } -} diff --git a/thinkphp/library/think/route/dispatch/Url.php b/thinkphp/library/think/route/dispatch/Url.php deleted file mode 100755 index 5160cba19..000000000 --- a/thinkphp/library/think/route/dispatch/Url.php +++ /dev/null @@ -1,169 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\route\dispatch; - -use think\exception\HttpException; -use think\Loader; -use think\route\Dispatch; - -class Url extends Dispatch -{ - public function init() - { - // 解析默认的URL规则 - $result = $this->parseUrl($this->dispatch); - - return (new Module($this->request, $this->rule, $result))->init(); - } - - public function exec() - {} - - /** - * 解析URL地址 - * @access protected - * @param string $url URL - * @return array - */ - protected function parseUrl($url) - { - $depr = $this->rule->getConfig('pathinfo_depr'); - $bind = $this->rule->getRouter()->getBind(); - - if (!empty($bind) && preg_match('/^[a-z]/is', $bind)) { - $bind = str_replace('/', $depr, $bind); - // 如果有模块/控制器绑定 - $url = $bind . ('.' != substr($bind, -1) ? $depr : '') . ltrim($url, $depr); - } - - list($path, $var) = $this->rule->parseUrlPath($url); - if (empty($path)) { - return [null, null, null]; - } - - // 解析模块 - $module = $this->rule->getConfig('app_multi_module') ? array_shift($path) : null; - - if ($this->param['auto_search']) { - $controller = $this->autoFindController($module, $path); - } else { - // 解析控制器 - $controller = !empty($path) ? array_shift($path) : null; - } - - if ($controller && !preg_match('/^[A-Za-z](\w|\.)*$/', $controller)) { - throw new HttpException(404, 'controller not exists:' . $controller); - } - - // 解析操作 - $action = !empty($path) ? array_shift($path) : null; - - // 解析额外参数 - if ($path) { - if ($this->rule->getConfig('url_param_type')) { - $var += $path; - } else { - preg_replace_callback('/(\w+)\|([^\|]+)/', function ($match) use (&$var) { - $var[$match[1]] = strip_tags($match[2]); - }, implode('|', $path)); - } - } - - $panDomain = $this->request->panDomain(); - - if ($panDomain && $key = array_search('*', $var)) { - // 泛域名赋值 - $var[$key] = $panDomain; - } - - // 设置当前请求的参数 - $this->request->setRouteVars($var); - - // 封装路由 - $route = [$module, $controller, $action]; - - if ($this->hasDefinedRoute($route, $bind)) { - throw new HttpException(404, 'invalid request:' . str_replace('|', $depr, $url)); - } - - return $route; - } - - /** - * 检查URL是否已经定义过路由 - * @access protected - * @param string $route 路由信息 - * @param string $bind 绑定信息 - * @return bool - */ - protected function hasDefinedRoute($route, $bind) - { - list($module, $controller, $action) = $route; - - // 检查地址是否被定义过路由 - $name = strtolower($module . '/' . Loader::parseName($controller, 1) . '/' . $action); - - $name2 = ''; - - if (empty($module) || $module == $bind) { - $name2 = strtolower(Loader::parseName($controller, 1) . '/' . $action); - } - - $host = $this->request->host(true); - - $method = $this->request->method(); - - if ($this->rule->getRouter()->getName($name, $host, $method) || $this->rule->getRouter()->getName($name2, $host, $method)) { - return true; - } - - return false; - } - - /** - * 自动定位控制器类 - * @access protected - * @param string $module 模块名 - * @param array $path URL - * @return string - */ - protected function autoFindController($module, &$path) - { - $dir = $this->app->getAppPath() . ($module ? $module . '/' : '') . $this->rule->getConfig('url_controller_layer'); - $suffix = $this->app->getSuffix() || $this->rule->getConfig('controller_suffix') ? ucfirst($this->rule->getConfig('url_controller_layer')) : ''; - - $item = []; - $find = false; - - foreach ($path as $val) { - $item[] = $val; - $file = $dir . '/' . str_replace('.', '/', $val) . $suffix . '.php'; - $file = pathinfo($file, PATHINFO_DIRNAME) . '/' . Loader::parseName(pathinfo($file, PATHINFO_FILENAME), 1) . '.php'; - if (is_file($file)) { - $find = true; - break; - } else { - $dir .= '/' . Loader::parseName($val); - } - } - - if ($find) { - $controller = implode('.', $item); - $path = array_slice($path, count($item)); - } else { - $controller = array_shift($path); - } - - return $controller; - } - -} diff --git a/thinkphp/library/think/session/driver/Memcache.php b/thinkphp/library/think/session/driver/Memcache.php deleted file mode 100755 index 40d7bb825..000000000 --- a/thinkphp/library/think/session/driver/Memcache.php +++ /dev/null @@ -1,124 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\session\driver; - -use SessionHandlerInterface; -use think\Exception; - -class Memcache implements SessionHandlerInterface -{ - protected $handler = null; - protected $config = [ - 'host' => '127.0.0.1', // memcache主机 - 'port' => 11211, // memcache端口 - 'expire' => 3600, // session有效期 - 'timeout' => 0, // 连接超时时间(单位:毫秒) - 'persistent' => true, // 长连接 - 'session_name' => '', // memcache key前缀 - ]; - - public function __construct($config = []) - { - $this->config = array_merge($this->config, $config); - } - - /** - * 打开Session - * @access public - * @param string $savePath - * @param mixed $sessName - */ - public function open($savePath, $sessName) - { - // 检测php环境 - if (!extension_loaded('memcache')) { - throw new Exception('not support:memcache'); - } - - $this->handler = new \Memcache; - - // 支持集群 - $hosts = explode(',', $this->config['host']); - $ports = explode(',', $this->config['port']); - - if (empty($ports[0])) { - $ports[0] = 11211; - } - - // 建立连接 - foreach ((array) $hosts as $i => $host) { - $port = isset($ports[$i]) ? $ports[$i] : $ports[0]; - $this->config['timeout'] > 0 ? - $this->handler->addServer($host, $port, $this->config['persistent'], 1, $this->config['timeout']) : - $this->handler->addServer($host, $port, $this->config['persistent'], 1); - } - - return true; - } - - /** - * 关闭Session - * @access public - */ - public function close() - { - $this->gc(ini_get('session.gc_maxlifetime')); - $this->handler->close(); - $this->handler = null; - - return true; - } - - /** - * 读取Session - * @access public - * @param string $sessID - */ - public function read($sessID) - { - return (string) $this->handler->get($this->config['session_name'] . $sessID); - } - - /** - * 写入Session - * @access public - * @param string $sessID - * @param string $sessData - * @return bool - */ - public function write($sessID, $sessData) - { - return $this->handler->set($this->config['session_name'] . $sessID, $sessData, 0, $this->config['expire']); - } - - /** - * 删除Session - * @access public - * @param string $sessID - * @return bool - */ - public function destroy($sessID) - { - return $this->handler->delete($this->config['session_name'] . $sessID); - } - - /** - * Session 垃圾回收 - * @access public - * @param string $sessMaxLifeTime - * @return true - */ - public function gc($sessMaxLifeTime) - { - return true; - } -} diff --git a/thinkphp/library/think/session/driver/Memcached.php b/thinkphp/library/think/session/driver/Memcached.php deleted file mode 100755 index 074b2ff73..000000000 --- a/thinkphp/library/think/session/driver/Memcached.php +++ /dev/null @@ -1,135 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\session\driver; - -use SessionHandlerInterface; -use think\Exception; - -class Memcached implements SessionHandlerInterface -{ - protected $handler = null; - protected $config = [ - 'host' => '127.0.0.1', // memcache主机 - 'port' => 11211, // memcache端口 - 'expire' => 3600, // session有效期 - 'timeout' => 0, // 连接超时时间(单位:毫秒) - 'session_name' => '', // memcache key前缀 - 'username' => '', //账号 - 'password' => '', //密码 - ]; - - public function __construct($config = []) - { - $this->config = array_merge($this->config, $config); - } - - /** - * 打开Session - * @access public - * @param string $savePath - * @param mixed $sessName - */ - public function open($savePath, $sessName) - { - // 检测php环境 - if (!extension_loaded('memcached')) { - throw new Exception('not support:memcached'); - } - - $this->handler = new \Memcached; - - // 设置连接超时时间(单位:毫秒) - if ($this->config['timeout'] > 0) { - $this->handler->setOption(\Memcached::OPT_CONNECT_TIMEOUT, $this->config['timeout']); - } - - // 支持集群 - $hosts = explode(',', $this->config['host']); - $ports = explode(',', $this->config['port']); - - if (empty($ports[0])) { - $ports[0] = 11211; - } - - // 建立连接 - $servers = []; - foreach ((array) $hosts as $i => $host) { - $servers[] = [$host, (isset($ports[$i]) ? $ports[$i] : $ports[0]), 1]; - } - - $this->handler->addServers($servers); - - if ('' != $this->config['username']) { - $this->handler->setOption(\Memcached::OPT_BINARY_PROTOCOL, true); - $this->handler->setSaslAuthData($this->config['username'], $this->config['password']); - } - - return true; - } - - /** - * 关闭Session - * @access public - */ - public function close() - { - $this->gc(ini_get('session.gc_maxlifetime')); - $this->handler->quit(); - $this->handler = null; - - return true; - } - - /** - * 读取Session - * @access public - * @param string $sessID - */ - public function read($sessID) - { - return (string) $this->handler->get($this->config['session_name'] . $sessID); - } - - /** - * 写入Session - * @access public - * @param string $sessID - * @param string $sessData - * @return bool - */ - public function write($sessID, $sessData) - { - return $this->handler->set($this->config['session_name'] . $sessID, $sessData, $this->config['expire']); - } - - /** - * 删除Session - * @access public - * @param string $sessID - * @return bool - */ - public function destroy($sessID) - { - return $this->handler->delete($this->config['session_name'] . $sessID); - } - - /** - * Session 垃圾回收 - * @access public - * @param string $sessMaxLifeTime - * @return true - */ - public function gc($sessMaxLifeTime) - { - return true; - } -} diff --git a/thinkphp/library/think/session/driver/Redis.php b/thinkphp/library/think/session/driver/Redis.php deleted file mode 100755 index 98a580ce0..000000000 --- a/thinkphp/library/think/session/driver/Redis.php +++ /dev/null @@ -1,185 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\session\driver; - -use SessionHandlerInterface; -use think\Exception; - -class Redis implements SessionHandlerInterface -{ - /** @var \Redis */ - protected $handler = null; - protected $config = [ - 'host' => '127.0.0.1', // redis主机 - 'port' => 6379, // redis端口 - 'password' => '', // 密码 - 'select' => 0, // 操作库 - 'expire' => 3600, // 有效期(秒) - 'timeout' => 0, // 超时时间(秒) - 'persistent' => true, // 是否长连接 - 'session_name' => '', // sessionkey前缀 - ]; - - public function __construct($config = []) - { - $this->config = array_merge($this->config, $config); - } - - /** - * 打开Session - * @access public - * @param string $savePath - * @param mixed $sessName - * @return bool - * @throws Exception - */ - public function open($savePath, $sessName) - { - if (extension_loaded('redis')) { - $this->handler = new \Redis; - - // 建立连接 - $func = $this->config['persistent'] ? 'pconnect' : 'connect'; - $this->handler->$func($this->config['host'], $this->config['port'], $this->config['timeout']); - - if ('' != $this->config['password']) { - $this->handler->auth($this->config['password']); - } - - if (0 != $this->config['select']) { - $this->handler->select($this->config['select']); - } - } elseif (class_exists('\Predis\Client')) { - $params = []; - foreach ($this->config as $key => $val) { - if (in_array($key, ['aggregate', 'cluster', 'connections', 'exceptions', 'prefix', 'profile', 'replication'])) { - $params[$key] = $val; - unset($this->config[$key]); - } - } - $this->handler = new \Predis\Client($this->config, $params); - } else { - throw new \BadFunctionCallException('not support: redis'); - } - - return true; - } - - /** - * 关闭Session - * @access public - */ - public function close() - { - $this->gc(ini_get('session.gc_maxlifetime')); - $this->handler->close(); - $this->handler = null; - - return true; - } - - /** - * 读取Session - * @access public - * @param string $sessID - * @return string - */ - public function read($sessID) - { - return (string) $this->handler->get($this->config['session_name'] . $sessID); - } - - /** - * 写入Session - * @access public - * @param string $sessID - * @param string $sessData - * @return bool - */ - public function write($sessID, $sessData) - { - if ($this->config['expire'] > 0) { - $result = $this->handler->setex($this->config['session_name'] . $sessID, $this->config['expire'], $sessData); - } else { - $result = $this->handler->set($this->config['session_name'] . $sessID, $sessData); - } - - return $result ? true : false; - } - - /** - * 删除Session - * @access public - * @param string $sessID - * @return bool - */ - public function destroy($sessID) - { - if(method_exists($this->handler, 'delete')) - { - return $this->handler->delete($this->config['session_name'] . $sessID) > 0; - } elseif(method_exists($this->handler, 'del')) { - return $this->handler->del($this->config['session_name'] . $sessID) > 0; - } - return false; - } - - /** - * Session 垃圾回收 - * @access public - * @param string $sessMaxLifeTime - * @return bool - */ - public function gc($sessMaxLifeTime) - { - return true; - } - - /** - * Redis Session 驱动的加锁机制 - * @access public - * @param string $sessID 用于加锁的sessID - * @param integer $timeout 默认过期时间 - * @return bool - */ - public function lock($sessID, $timeout = 10) - { - if (null == $this->handler) { - $this->open('', ''); - } - - $lockKey = 'LOCK_PREFIX_' . $sessID; - // 使用setnx操作加锁 - $isLock = $this->handler->setnx($lockKey, 1); - if ($isLock) { - // 设置过期时间,防止死任务的出现 - $this->handler->expire($lockKey, $timeout); - return true; - } - - return false; - } - - /** - * Redis Session 驱动的解锁机制 - * @access public - * @param string $sessID 用于解锁的sessID - */ - public function unlock($sessID) - { - if (null == $this->handler) { - $this->open('', ''); - } - - $this->handler->del('LOCK_PREFIX_' . $sessID); - } -} diff --git a/thinkphp/library/think/view/driver/Php.php b/thinkphp/library/think/view/driver/Php.php deleted file mode 100755 index 7948dc053..000000000 --- a/thinkphp/library/think/view/driver/Php.php +++ /dev/null @@ -1,183 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\view\driver; - -use think\App; -use think\exception\TemplateNotFoundException; -use think\Loader; - -class Php -{ - // 模板引擎参数 - protected $config = [ - // 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写 - 'auto_rule' => 1, - // 视图基础目录(集中式) - 'view_base' => '', - // 模板起始路径 - 'view_path' => '', - // 模板文件后缀 - 'view_suffix' => 'php', - // 模板文件名分隔符 - 'view_depr' => DIRECTORY_SEPARATOR, - ]; - - protected $template; - protected $app; - protected $content; - - public function __construct(App $app, $config = []) - { - $this->app = $app; - $this->config = array_merge($this->config, (array) $config); - } - - /** - * 检测是否存在模板文件 - * @access public - * @param string $template 模板文件或者模板规则 - * @return bool - */ - public function exists($template) - { - if ('' == pathinfo($template, PATHINFO_EXTENSION)) { - // 获取模板文件名 - $template = $this->parseTemplate($template); - } - - return is_file($template); - } - - /** - * 渲染模板文件 - * @access public - * @param string $template 模板文件 - * @param array $data 模板变量 - * @return void - */ - public function fetch($template, $data = []) - { - if ('' == pathinfo($template, PATHINFO_EXTENSION)) { - // 获取模板文件名 - $template = $this->parseTemplate($template); - } - - // 模板不存在 抛出异常 - if (!is_file($template)) { - throw new TemplateNotFoundException('template not exists:' . $template, $template); - } - - $this->template = $template; - - // 记录视图信息 - $this->app - ->log('[ VIEW ] ' . $template . ' [ ' . var_export(array_keys($data), true) . ' ]'); - - extract($data, EXTR_OVERWRITE); - include $this->template; - } - - /** - * 渲染模板内容 - * @access public - * @param string $content 模板内容 - * @param array $data 模板变量 - * @return void - */ - public function display($content, $data = []) - { - $this->content = $content; - - extract($data, EXTR_OVERWRITE); - eval('?>' . $this->content); - } - - /** - * 自动定位模板文件 - * @access private - * @param string $template 模板文件规则 - * @return string - */ - private function parseTemplate($template) - { - if (empty($this->config['view_path'])) { - $this->config['view_path'] = $this->app->getModulePath() . 'view' . DIRECTORY_SEPARATOR; - } - - $request = $this->app['request']; - - // 获取视图根目录 - if (strpos($template, '@')) { - // 跨模块调用 - list($module, $template) = explode('@', $template); - } - - if ($this->config['view_base']) { - // 基础视图目录 - $module = isset($module) ? $module : $request->module(); - $path = $this->config['view_base'] . ($module ? $module . DIRECTORY_SEPARATOR : ''); - } else { - $path = isset($module) ? $this->app->getAppPath() . $module . DIRECTORY_SEPARATOR . 'view' . DIRECTORY_SEPARATOR : $this->config['view_path']; - } - - $depr = $this->config['view_depr']; - - if (0 !== strpos($template, '/')) { - $template = str_replace(['/', ':'], $depr, $template); - $controller = Loader::parseName($request->controller()); - - if ($controller) { - if ('' == $template) { - // 如果模板文件名为空 按照默认规则定位 - $template = str_replace('.', DIRECTORY_SEPARATOR, $controller) . $depr . $this->getActionTemplate($request); - } elseif (false === strpos($template, $depr)) { - $template = str_replace('.', DIRECTORY_SEPARATOR, $controller) . $depr . $template; - } - } - } else { - $template = str_replace(['/', ':'], $depr, substr($template, 1)); - } - - return $path . ltrim($template, '/') . '.' . ltrim($this->config['view_suffix'], '.'); - } - - protected function getActionTemplate($request) - { - $rule = [$request->action(true), Loader::parseName($request->action(true)), $request->action()]; - $type = $this->config['auto_rule']; - - return isset($rule[$type]) ? $rule[$type] : $rule[0]; - } - - /** - * 配置模板引擎 - * @access private - * @param string|array $name 参数名 - * @param mixed $value 参数值 - * @return void - */ - public function config($name, $value = null) - { - if (is_array($name)) { - $this->config = array_merge($this->config, $name); - } elseif (is_null($value)) { - return isset($this->config[$name]) ? $this->config[$name] : null; - } else { - $this->config[$name] = $value; - } - } - - public function __debugInfo() - { - return ['config' => $this->config]; - } -} diff --git a/thinkphp/library/think/view/driver/Think.php b/thinkphp/library/think/view/driver/Think.php deleted file mode 100755 index 877aee85b..000000000 --- a/thinkphp/library/think/view/driver/Think.php +++ /dev/null @@ -1,192 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace think\view\driver; - -use think\App; -use think\exception\TemplateNotFoundException; -use think\Loader; -use think\Template; - -class Think -{ - // 模板引擎实例 - private $template; - private $app; - - // 模板引擎参数 - protected $config = [ - // 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写 - 'auto_rule' => 1, - // 视图基础目录(集中式) - 'view_base' => '', - // 模板起始路径 - 'view_path' => '', - // 模板文件后缀 - 'view_suffix' => 'html', - // 模板文件名分隔符 - 'view_depr' => DIRECTORY_SEPARATOR, - // 是否开启模板编译缓存,设为false则每次都会重新编译 - 'tpl_cache' => true, - ]; - - public function __construct(App $app, $config = []) - { - $this->app = $app; - $this->config = array_merge($this->config, (array) $config); - - if (empty($this->config['view_path'])) { - $this->config['view_path'] = $app->getModulePath() . 'view' . DIRECTORY_SEPARATOR; - } - - $this->template = new Template($app, $this->config); - } - - /** - * 检测是否存在模板文件 - * @access public - * @param string $template 模板文件或者模板规则 - * @return bool - */ - public function exists($template) - { - if ('' == pathinfo($template, PATHINFO_EXTENSION)) { - // 获取模板文件名 - $template = $this->parseTemplate($template); - } - - return is_file($template); - } - - /** - * 渲染模板文件 - * @access public - * @param string $template 模板文件 - * @param array $data 模板变量 - * @param array $config 模板参数 - * @return void - */ - public function fetch($template, $data = [], $config = []) - { - if ('' == pathinfo($template, PATHINFO_EXTENSION)) { - // 获取模板文件名 - $template = $this->parseTemplate($template); - } - - // 模板不存在 抛出异常 - if (!is_file($template)) { - throw new TemplateNotFoundException('template not exists:' . $template, $template); - } - - // 记录视图信息 - $this->app - ->log('[ VIEW ] ' . $template . ' [ ' . var_export(array_keys($data), true) . ' ]'); - - $this->template->fetch($template, $data, $config); - } - - /** - * 渲染模板内容 - * @access public - * @param string $template 模板内容 - * @param array $data 模板变量 - * @param array $config 模板参数 - * @return void - */ - public function display($template, $data = [], $config = []) - { - $this->template->display($template, $data, $config); - } - - /** - * 自动定位模板文件 - * @access private - * @param string $template 模板文件规则 - * @return string - */ - private function parseTemplate($template) - { - // 分析模板文件规则 - $request = $this->app['request']; - - // 获取视图根目录 - if (strpos($template, '@')) { - // 跨模块调用 - list($module, $template) = explode('@', $template); - } - - if ($this->config['view_base']) { - // 基础视图目录 - $module = isset($module) ? $module : $request->module(); - $path = $this->config['view_base'] . ($module ? $module . DIRECTORY_SEPARATOR : ''); - } else { - $path = isset($module) ? $this->app->getAppPath() . $module . DIRECTORY_SEPARATOR . 'view' . DIRECTORY_SEPARATOR : $this->config['view_path']; - } - - $depr = $this->config['view_depr']; - - if (0 !== strpos($template, '/')) { - $template = str_replace(['/', ':'], $depr, $template); - $controller = Loader::parseName($request->controller()); - - if ($controller) { - if ('' == $template) { - // 如果模板文件名为空 按照默认规则定位 - $template = str_replace('.', DIRECTORY_SEPARATOR, $controller) . $depr . $this->getActionTemplate($request); - } elseif (false === strpos($template, $depr)) { - $template = str_replace('.', DIRECTORY_SEPARATOR, $controller) . $depr . $template; - } - } - } else { - $template = str_replace(['/', ':'], $depr, substr($template, 1)); - } - - return $path . ltrim($template, '/') . '.' . ltrim($this->config['view_suffix'], '.'); - } - - protected function getActionTemplate($request) - { - $rule = [$request->action(true), Loader::parseName($request->action(true)), $request->action()]; - $type = $this->config['auto_rule']; - - return isset($rule[$type]) ? $rule[$type] : $rule[0]; - } - - /** - * 配置或者获取模板引擎参数 - * @access private - * @param string|array $name 参数名 - * @param mixed $value 参数值 - * @return mixed - */ - public function config($name, $value = null) - { - if (is_array($name)) { - $this->template->config($name); - $this->config = array_merge($this->config, $name); - } elseif (is_null($value)) { - return $this->template->config($name); - } else { - $this->template->$name = $value; - $this->config[$name] = $value; - } - } - - public function __call($method, $params) - { - return call_user_func_array([$this->template, $method], $params); - } - - public function __debugInfo() - { - return ['config' => $this->config]; - } -} diff --git a/thinkphp/library/traits/controller/Jump.php b/thinkphp/library/traits/controller/Jump.php deleted file mode 100755 index 41f7e930a..000000000 --- a/thinkphp/library/traits/controller/Jump.php +++ /dev/null @@ -1,168 +0,0 @@ -error(); - * $this->redirect(); - * } - * } - */ -namespace traits\controller; - -use think\Container; -use think\exception\HttpResponseException; -use think\Response; -use think\response\Redirect; - -trait Jump -{ - /** - * 应用实例 - * @var \think\App - */ - protected $app; - - /** - * 操作成功跳转的快捷方法 - * @access protected - * @param mixed $msg 提示信息 - * @param string $url 跳转的URL地址 - * @param mixed $data 返回的数据 - * @param integer $wait 跳转等待时间 - * @param array $header 发送的Header信息 - * @return void - */ - protected function success($msg = '', $url = null, $data = '', $wait = 3, array $header = []) - { - if (is_null($url) && isset($_SERVER["HTTP_REFERER"])) { - $url = $_SERVER["HTTP_REFERER"]; - } elseif ('' !== $url) { - $url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : Container::get('url')->build($url); - } - - $result = [ - 'code' => 1, - 'msg' => $msg, - 'data' => $data, - 'url' => $url, - 'wait' => $wait, - ]; - - $type = $this->getResponseType(); - // 把跳转模板的渲染下沉,这样在 response_send 行为里通过getData()获得的数据是一致性的格式 - if ('html' == strtolower($type)) { - $type = 'jump'; - } - - $response = Response::create($result, $type)->header($header)->options(['jump_template' => $this->app['config']->get('dispatch_success_tmpl')]); - - throw new HttpResponseException($response); - } - - /** - * 操作错误跳转的快捷方法 - * @access protected - * @param mixed $msg 提示信息 - * @param string $url 跳转的URL地址 - * @param mixed $data 返回的数据 - * @param integer $wait 跳转等待时间 - * @param array $header 发送的Header信息 - * @return void - */ - protected function error($msg = '', $url = null, $data = '', $wait = 3, array $header = []) - { - $type = $this->getResponseType(); - if (is_null($url)) { - $url = $this->app['request']->isAjax() ? '' : 'javascript:history.back(-1);'; - } elseif ('' !== $url) { - $url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : $this->app['url']->build($url); - } - - $result = [ - 'code' => 0, - 'msg' => $msg, - 'data' => $data, - 'url' => $url, - 'wait' => $wait, - ]; - - if ('html' == strtolower($type)) { - $type = 'jump'; - } - - $response = Response::create($result, $type)->header($header)->options(['jump_template' => $this->app['config']->get('dispatch_error_tmpl')]); - - throw new HttpResponseException($response); - } - - /** - * 返回封装后的API数据到客户端 - * @access protected - * @param mixed $data 要返回的数据 - * @param integer $code 返回的code - * @param mixed $msg 提示信息 - * @param string $type 返回数据格式 - * @param array $header 发送的Header信息 - * @return void - */ - protected function result($data, $code = 0, $msg = '', $type = '', array $header = []) - { - $result = [ - 'code' => $code, - 'msg' => $msg, - 'time' => time(), - 'data' => $data, - ]; - - $type = $type ?: $this->getResponseType(); - $response = Response::create($result, $type)->header($header); - - throw new HttpResponseException($response); - } - - /** - * URL重定向 - * @access protected - * @param string $url 跳转的URL表达式 - * @param array|integer $params 其它URL参数 - * @param integer $code http code - * @param array $with 隐式传参 - * @return void - */ - protected function redirect($url, $params = [], $code = 302, $with = []) - { - $response = new Redirect($url); - - if (is_integer($params)) { - $code = $params; - $params = []; - } - - $response->code($code)->params($params)->with($with); - - throw new HttpResponseException($response); - } - - /** - * 获取当前的response 输出类型 - * @access protected - * @return string - */ - protected function getResponseType() - { - if (!$this->app) { - $this->app = Container::get('app'); - } - - $isAjax = $this->app['request']->isAjax(); - $config = $this->app['config']; - - return $isAjax - ? $config->get('default_ajax_return') - : $config->get('default_return_type'); - } -} diff --git a/thinkphp/phpunit.xml.dist b/thinkphp/phpunit.xml.dist deleted file mode 100755 index 37c3d2b53..000000000 --- a/thinkphp/phpunit.xml.dist +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - ./library/think/*/tests/ - - - - - - ./library/ - - ./library/think/*/tests - ./library/think/*/assets - ./library/think/*/resources - ./library/think/*/vendor - - - - \ No newline at end of file diff --git a/thinkphp/tpl/default_index.tpl b/thinkphp/tpl/default_index.tpl deleted file mode 100755 index e5c1363ac..000000000 --- a/thinkphp/tpl/default_index.tpl +++ /dev/null @@ -1,10 +0,0 @@ -*{ padding: 0; margin: 0; } div{ padding: 4px 48px;} a{color:#2E5CD5;cursor: pointer;text-decoration: none} a:hover{text-decoration:underline; } body{ background: #fff; font-family: "Century Gothic","Microsoft yahei"; color: #333;font-size:18px;} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.6em; font-size: 42px }

:)

ThinkPHP V5.1
12载初心不改(2006-2018) - 你值得信赖的PHP框架

'; - } -} diff --git a/thinkphp/tpl/dispatch_jump.tpl b/thinkphp/tpl/dispatch_jump.tpl deleted file mode 100755 index 583376bbb..000000000 --- a/thinkphp/tpl/dispatch_jump.tpl +++ /dev/null @@ -1,49 +0,0 @@ -{__NOLAYOUT__} - - - - - 跳转提示 - - - -
- - -

:)

-

- - -

:(

-

- - -

-

- 页面自动 跳转 等待时间: -

-
- - - diff --git a/thinkphp/tpl/think_exception.tpl b/tpl/think_exception.tpl old mode 100755 new mode 100644 similarity index 62% rename from thinkphp/tpl/think_exception.tpl rename to tpl/think_exception.tpl index dcc9a5034..519cc19ce --- a/thinkphp/tpl/think_exception.tpl +++ b/tpl/think_exception.tpl @@ -1,79 +1,93 @@ '.end($names).''; - } +if (!function_exists('parse_class')) { + function parse_class($name) + { + $names = explode('\\', $name); + return ''.end($names).''; } +} - if(!function_exists('parse_file')){ - function parse_file($file, $line) - { - return ''.basename($file)." line {$line}".''; - } +if (!function_exists('parse_file')) { + function parse_file($file, $line) + { + return ''.basename($file)." line {$line}".''; } +} - if(!function_exists('parse_args')){ - function parse_args($args) - { - $result = []; - - foreach ($args as $key => $item) { - switch (true) { - case is_object($item): - $value = sprintf('object(%s)', parse_class(get_class($item))); - break; - case is_array($item): - if(count($item) > 3){ - $value = sprintf('[%s, ...]', parse_args(array_slice($item, 0, 3))); - } else { - $value = sprintf('[%s]', parse_args($item)); - } - break; - case is_string($item): - if(strlen($item) > 20){ - $value = sprintf( - '\'%s...\'', - htmlentities($item), - htmlentities(substr($item, 0, 20)) - ); - } else { - $value = sprintf("'%s'", htmlentities($item)); - } - break; - case is_int($item): - case is_float($item): - $value = $item; - break; - case is_null($item): - $value = 'null'; - break; - case is_bool($item): - $value = '' . ($item ? 'true' : 'false') . ''; - break; - case is_resource($item): - $value = 'resource'; - break; - default: - $value = htmlentities(str_replace("\n", '', var_export(strval($item), true))); - break; - } - - $result[] = is_int($key) ? $value : "'{$key}' => {$value}"; +if (!function_exists('parse_args')) { + function parse_args($args) + { + $result = []; + foreach ($args as $key => $item) { + switch (true) { + case is_object($item): + $value = sprintf('object(%s)', parse_class(get_class($item))); + break; + case is_array($item): + if (count($item) > 3) { + $value = sprintf('[%s, ...]', parse_args(array_slice($item, 0, 3))); + } else { + $value = sprintf('[%s]', parse_args($item)); + } + break; + case is_string($item): + if (strlen($item) > 20) { + $value = sprintf( + '\'%s...\'', + htmlentities($item), + htmlentities(substr($item, 0, 20)) + ); + } else { + $value = sprintf("'%s'", htmlentities($item)); + } + break; + case is_int($item): + case is_float($item): + $value = $item; + break; + case is_null($item): + $value = 'null'; + break; + case is_bool($item): + $value = '' . ($item ? 'true' : 'false') . ''; + break; + case is_resource($item): + $value = 'resource'; + break; + default: + $value = htmlentities(str_replace("\n", '', var_export(strval($item), true))); + break; } - return implode(', ', $result); + $result[] = is_int($key) ? $value : "'{$key}' => {$value}"; + } + + return implode(', ', $result); + } +} +if (!function_exists('echo_value')) { + function echo_value($val) + { + if (is_array($val) || is_object($val)) { + echo htmlentities(json_encode($val, JSON_PRETTY_PRINT)); + } elseif (is_bool($val)) { + echo $val ? 'true' : 'false'; + } elseif (is_scalar($val)) { + echo htmlentities($val); + } else { + echo 'Resource'; } } +} ?> @@ -88,13 +102,12 @@ font: 16px Verdana, "Helvetica Neue", helvetica, Arial, 'Microsoft YaHei', sans-serif; margin: 0; padding: 0 20px 20px; - } h1{ margin: 10px 0 0; font-size: 28px; font-weight: 500; - line-height: 40px; + line-height: 32px; } h2{ color: #4288ce; @@ -115,9 +128,8 @@ text-decoration-style: dotted; } a{ - color: #888; + color: #868686; cursor: pointer; - text-decoration: none; } a:hover{ text-decoration: underline; @@ -125,11 +137,9 @@ .line-error{ background: #f8cbcb; } - .echo table { width: 100%; } - .echo pre { padding: 16px; overflow: auto; @@ -140,12 +150,10 @@ border-radius: 3px; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; } - .echo pre > pre { padding: 0; margin: 0; } - /* Exception Info */ .exception { margin-top: 20px; @@ -158,9 +166,12 @@ font-size:16px; border-top-left-radius: 4px; border-top-right-radius: 4px; - font-family: Consolas,"Liberation Mono",Courier,Verdana,"微软雅黑"; + font-family: Consolas,"Liberation Mono",Courier,Verdana,"微软雅黑",serif; + } + .exception .error-message h1 { + text-align: center; + margin-top: 10%; } - .exception .code{ float: left; text-align: center; @@ -187,8 +198,8 @@ display: inline-block; min-width: 100%; box-sizing: border-box; - font-size:14px; - font-family: "Century Gothic",Consolas,"Liberation Mono",Courier,Verdana; + font-size:14px; + font-family: "Century Gothic",Consolas,"Liberation Mono",Courier,Verdana,serif; padding-left: px; } .exception .source-code pre li{ @@ -201,16 +212,20 @@ height: 100%; display: inline-block; border-left: 1px solid #fff; - font-size:14px; - font-family: Consolas,"Liberation Mono",Courier,Verdana,"微软雅黑"; + font-size:14px; + font-family: Consolas,"Liberation Mono",Courier,Verdana,"微软雅黑",serif; } .exception .trace{ padding: 6px; border: 1px solid #ddd; border-top: 0 none; line-height: 16px; - font-size:14px; - font-family: Consolas,"Liberation Mono",Courier,Verdana,"微软雅黑"; + font-size:14px; + font-family: Consolas,"Liberation Mono",Courier,Verdana,"微软雅黑",serif; + } + .exception .trace h2:hover { + text-decoration: underline; + cursor: pointer; } .exception .trace ol{ margin: 12px; @@ -229,7 +244,7 @@ margin: 12px 0; box-sizing: border-box; table-layout:fixed; - word-wrap:break-word; + word-wrap:break-word; } .exception-var table caption{ text-align: left; @@ -245,7 +260,7 @@ } .exception-var table tbody{ font-size: 13px; - font-family: Consolas,"Liberation Mono",Courier,"微软雅黑"; + font-family: Consolas, "Liberation Mono", Courier, "微软雅黑",serif; } .exception-var table td{ padding: 0 6px; @@ -260,10 +275,6 @@ .exception-var table td pre{ margin: 0; } - .exception .error-message h1 { - text-align: center; - margin-top: 10%; - } /* Copyright Info */ .copyright{ @@ -277,11 +288,21 @@ text-decoration: none; padding: 10px 15px; border: 1px solid #F44336; + border-radius: 3px; } .copyright a:hover{ background: #F44336; color: #fff; } + .copyright-version { + margin-top: 20px; + } + .copyright-version span { + color: #999; + } + .copyright-version span:not(:last-child) { + margin-right: 20px; + } /* SPAN elements with the classes below are added by prettyprint. */ pre.prettyprint .pln { color: #000 } /* plain text */ @@ -300,66 +321,63 @@ -
- -
- + + $trace) { ?>
-
- +
-

[

+

-

+

- -
- -
-
    $value) { ?>
- + +
+
    $value) { ?>
  1. ">
+
+
-

Call Stack

+

Call Stack

    -
  1. - -
  2. -
  3. + +
  4. + -
  5. + // Show line + if (isset($value['file']) && isset($value['line'])) { + echo sprintf(' in %s', parse_file($value['file'], $value['line'])); + } + ?> +
+

- +

Exception Datas

$value) { ?> - + @@ -367,19 +385,7 @@ $val) { ?> - + @@ -389,12 +395,12 @@ - +

Environment Variables

$value) { ?>
empty
- -
- + @@ -402,19 +408,7 @@ $val) { ?> - + @@ -424,9 +418,13 @@ - + - + diff --git a/vendor/.gitignore b/vendor/.gitignore deleted file mode 100755 index c96a04f00..000000000 --- a/vendor/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/vendor/autoload.php b/vendor/autoload.php new file mode 100644 index 000000000..b26663d77 --- /dev/null +++ b/vendor/autoload.php @@ -0,0 +1,7 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see https://www.php-fig.org/psr/psr-0/ + * @see https://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + private $vendorDir; + + // PSR-4 + private $prefixLengthsPsr4 = array(); + private $prefixDirsPsr4 = array(); + private $fallbackDirsPsr4 = array(); + + // PSR-0 + private $prefixesPsr0 = array(); + private $fallbackDirsPsr0 = array(); + + private $useIncludePath = false; + private $classMap = array(); + private $classMapAuthoritative = false; + private $missingClasses = array(); + private $apcuPrefix; + + private static $registeredLoaders = array(); + + public function __construct($vendorDir = null) + { + $this->vendorDir = $vendorDir; + } + + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); + } + + return array(); + } + + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + */ + public function add($prefix, $paths, $prepend = false) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + (array) $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 base directories + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + + if (null === $this->vendorDir) { + return; + } + + if ($prepend) { + self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; + } else { + unset(self::$registeredLoaders[$this->vendorDir]); + self::$registeredLoaders[$this->vendorDir] = $this; + } + } + + /** + * Unregisters this instance as an autoloader. + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + + if (null !== $this->vendorDir) { + unset(self::$registeredLoaders[$this->vendorDir]); + } + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return true|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + includeFile($file); + + return true; + } + + return null; + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + /** + * Returns the currently registered loaders indexed by their corresponding vendor directories. + * + * @return self[] + */ + public static function getRegisteredLoaders() + { + return self::$registeredLoaders; + } + + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath . '\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } +} + +/** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + */ +function includeFile($file) +{ + include $file; +} diff --git a/vendor/composer/InstalledVersions.php b/vendor/composer/InstalledVersions.php new file mode 100644 index 000000000..b3a4e1611 --- /dev/null +++ b/vendor/composer/InstalledVersions.php @@ -0,0 +1,337 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer; + +use Composer\Autoload\ClassLoader; +use Composer\Semver\VersionParser; + +/** + * This class is copied in every Composer installed project and available to all + * + * See also https://getcomposer.org/doc/07-runtime.md#installed-versions + * + * To require it's presence, you can require `composer-runtime-api ^2.0` + */ +class InstalledVersions +{ + private static $installed; + private static $canGetVendors; + private static $installedByVendor = array(); + + /** + * Returns a list of all package names which are present, either by being installed, replaced or provided + * + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackages() + { + $packages = array(); + foreach (self::getInstalled() as $installed) { + $packages[] = array_keys($installed['versions']); + } + + if (1 === \count($packages)) { + return $packages[0]; + } + + return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); + } + + /** + * Returns a list of all package names with a specific type e.g. 'library' + * + * @param string $type + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackagesByType($type) + { + $packagesByType = array(); + + foreach (self::getInstalled() as $installed) { + foreach ($installed['versions'] as $name => $package) { + if (isset($package['type']) && $package['type'] === $type) { + $packagesByType[] = $name; + } + } + } + + return $packagesByType; + } + + /** + * Checks whether the given package is installed + * + * This also returns true if the package name is provided or replaced by another package + * + * @param string $packageName + * @param bool $includeDevRequirements + * @return bool + */ + public static function isInstalled($packageName, $includeDevRequirements = true) + { + foreach (self::getInstalled() as $installed) { + if (isset($installed['versions'][$packageName])) { + return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']); + } + } + + return false; + } + + /** + * Checks whether the given package satisfies a version constraint + * + * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call: + * + * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3') + * + * @param VersionParser $parser Install composer/semver to have access to this class and functionality + * @param string $packageName + * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package + * @return bool + */ + public static function satisfies(VersionParser $parser, $packageName, $constraint) + { + $constraint = $parser->parseConstraints($constraint); + $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); + + return $provided->matches($constraint); + } + + /** + * Returns a version constraint representing all the range(s) which are installed for a given package + * + * It is easier to use this via isInstalled() with the $constraint argument if you need to check + * whether a given version of a package is installed, and not just whether it exists + * + * @param string $packageName + * @return string Version constraint usable with composer/semver + */ + public static function getVersionRanges($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + $ranges = array(); + if (isset($installed['versions'][$packageName]['pretty_version'])) { + $ranges[] = $installed['versions'][$packageName]['pretty_version']; + } + if (array_key_exists('aliases', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); + } + if (array_key_exists('replaced', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); + } + if (array_key_exists('provided', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); + } + + return implode(' || ', $ranges); + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['version'])) { + return null; + } + + return $installed['versions'][$packageName]['version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getPrettyVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['pretty_version'])) { + return null; + } + + return $installed['versions'][$packageName]['pretty_version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference + */ + public static function getReference($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['reference'])) { + return null; + } + + return $installed['versions'][$packageName]['reference']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path. + */ + public static function getInstallPath($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @return array + * @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string} + */ + public static function getRootPackage() + { + $installed = self::getInstalled(); + + return $installed[0]['root']; + } + + /** + * Returns the raw installed.php data for custom implementations + * + * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. + * @return array[] + * @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array} + */ + public static function getRawData() + { + @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED); + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + self::$installed = include __DIR__ . '/installed.php'; + } else { + self::$installed = array(); + } + } + + return self::$installed; + } + + /** + * Returns the raw data of all installed.php which are currently loaded for custom implementations + * + * @return array[] + * @psalm-return list}> + */ + public static function getAllRawData() + { + return self::getInstalled(); + } + + /** + * Lets you reload the static array from another file + * + * This is only useful for complex integrations in which a project needs to use + * this class but then also needs to execute another project's autoloader in process, + * and wants to ensure both projects have access to their version of installed.php. + * + * A typical case would be PHPUnit, where it would need to make sure it reads all + * the data it needs from this class, then call reload() with + * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure + * the project in which it runs can then also use this class safely, without + * interference between PHPUnit's dependencies and the project's dependencies. + * + * @param array[] $data A vendor/composer/installed.php data set + * @return void + * + * @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array} $data + */ + public static function reload($data) + { + self::$installed = $data; + self::$installedByVendor = array(); + } + + /** + * @return array[] + * @psalm-return list}> + */ + private static function getInstalled() + { + if (null === self::$canGetVendors) { + self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); + } + + $installed = array(); + + if (self::$canGetVendors) { + foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { + if (isset(self::$installedByVendor[$vendorDir])) { + $installed[] = self::$installedByVendor[$vendorDir]; + } elseif (is_file($vendorDir.'/composer/installed.php')) { + $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; + if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { + self::$installed = $installed[count($installed) - 1]; + } + } + } + } + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + self::$installed = require __DIR__ . '/installed.php'; + } else { + self::$installed = array(); + } + } + $installed[] = self::$installed; + + return $installed; + } +} diff --git a/vendor/composer/LICENSE b/vendor/composer/LICENSE new file mode 100644 index 000000000..f27399a04 --- /dev/null +++ b/vendor/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) Nils Adermann, Jordi Boggiano + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php new file mode 100644 index 000000000..4ebd53fca --- /dev/null +++ b/vendor/composer/autoload_classmap.php @@ -0,0 +1,14 @@ + $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php', + 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', + 'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php', + 'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php', + 'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php', +); diff --git a/vendor/composer/autoload_files.php b/vendor/composer/autoload_files.php new file mode 100644 index 000000000..6decc553b --- /dev/null +++ b/vendor/composer/autoload_files.php @@ -0,0 +1,15 @@ + $vendorDir . '/topthink/think-helper/src/helper.php', + '35fab96057f1bf5e7aba31a8a6d5fdde' => $vendorDir . '/topthink/think-orm/stubs/load_stubs.php', + '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', + '25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php', + 'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php', + '667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php', +); diff --git a/vendor/composer/autoload_namespaces.php b/vendor/composer/autoload_namespaces.php new file mode 100644 index 000000000..7cb803d03 --- /dev/null +++ b/vendor/composer/autoload_namespaces.php @@ -0,0 +1,10 @@ + array($baseDir . '/extend'), +); diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php new file mode 100644 index 000000000..8b0de38db --- /dev/null +++ b/vendor/composer/autoload_psr4.php @@ -0,0 +1,25 @@ + array($vendorDir . '/topthink/think-view/src'), + 'think\\trace\\' => array($vendorDir . '/topthink/think-trace/src'), + 'think\\app\\' => array($vendorDir . '/topthink/think-multi-app/src'), + 'think\\' => array($vendorDir . '/topthink/framework/src/think', $vendorDir . '/topthink/think-helper/src', $vendorDir . '/topthink/think-orm/src', $vendorDir . '/topthink/think-template/src'), + 'app\\' => array($baseDir . '/app'), + 'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'), + 'Symfony\\Polyfill\\Php72\\' => array($vendorDir . '/symfony/polyfill-php72'), + 'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'), + 'Symfony\\Component\\VarDumper\\' => array($vendorDir . '/symfony/var-dumper'), + 'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'), + 'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'), + 'Psr\\Container\\' => array($vendorDir . '/psr/container/src'), + 'Psr\\Cache\\' => array($vendorDir . '/psr/cache/src'), + 'League\\MimeTypeDetection\\' => array($vendorDir . '/league/mime-type-detection/src'), + 'League\\Flysystem\\Cached\\' => array($vendorDir . '/league/flysystem-cached-adapter/src'), + 'League\\Flysystem\\' => array($vendorDir . '/league/flysystem/src'), +); diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php new file mode 100644 index 000000000..acb4a9c98 --- /dev/null +++ b/vendor/composer/autoload_real.php @@ -0,0 +1,75 @@ += 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); + if ($useStaticLoader) { + require __DIR__ . '/autoload_static.php'; + + call_user_func(\Composer\Autoload\ComposerStaticInit1ed187777399b73a018d9a6af63a57d1::getInitializer($loader)); + } else { + $map = require __DIR__ . '/autoload_namespaces.php'; + foreach ($map as $namespace => $path) { + $loader->set($namespace, $path); + } + + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); + } + } + + $loader->register(true); + + if ($useStaticLoader) { + $includeFiles = Composer\Autoload\ComposerStaticInit1ed187777399b73a018d9a6af63a57d1::$files; + } else { + $includeFiles = require __DIR__ . '/autoload_files.php'; + } + foreach ($includeFiles as $fileIdentifier => $file) { + composerRequire1ed187777399b73a018d9a6af63a57d1($fileIdentifier, $file); + } + + return $loader; + } +} + +function composerRequire1ed187777399b73a018d9a6af63a57d1($fileIdentifier, $file) +{ + if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { + require $file; + + $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; + } +} diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php new file mode 100644 index 000000000..678bae683 --- /dev/null +++ b/vendor/composer/autoload_static.php @@ -0,0 +1,144 @@ + __DIR__ . '/..' . '/topthink/think-helper/src/helper.php', + '35fab96057f1bf5e7aba31a8a6d5fdde' => __DIR__ . '/..' . '/topthink/think-orm/stubs/load_stubs.php', + '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', + '25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php', + 'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php', + '667aeda72477189d0494fecd327c3641' => __DIR__ . '/..' . '/symfony/var-dumper/Resources/functions/dump.php', + ); + + public static $prefixLengthsPsr4 = array ( + 't' => + array ( + 'think\\view\\driver\\' => 18, + 'think\\trace\\' => 12, + 'think\\app\\' => 10, + 'think\\' => 6, + ), + 'a' => + array ( + 'app\\' => 4, + ), + 'S' => + array ( + 'Symfony\\Polyfill\\Php80\\' => 23, + 'Symfony\\Polyfill\\Php72\\' => 23, + 'Symfony\\Polyfill\\Mbstring\\' => 26, + 'Symfony\\Component\\VarDumper\\' => 28, + ), + 'P' => + array ( + 'Psr\\SimpleCache\\' => 16, + 'Psr\\Log\\' => 8, + 'Psr\\Container\\' => 14, + 'Psr\\Cache\\' => 10, + ), + 'L' => + array ( + 'League\\MimeTypeDetection\\' => 25, + 'League\\Flysystem\\Cached\\' => 24, + 'League\\Flysystem\\' => 17, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'think\\view\\driver\\' => + array ( + 0 => __DIR__ . '/..' . '/topthink/think-view/src', + ), + 'think\\trace\\' => + array ( + 0 => __DIR__ . '/..' . '/topthink/think-trace/src', + ), + 'think\\app\\' => + array ( + 0 => __DIR__ . '/..' . '/topthink/think-multi-app/src', + ), + 'think\\' => + array ( + 0 => __DIR__ . '/..' . '/topthink/framework/src/think', + 1 => __DIR__ . '/..' . '/topthink/think-helper/src', + 2 => __DIR__ . '/..' . '/topthink/think-orm/src', + 3 => __DIR__ . '/..' . '/topthink/think-template/src', + ), + 'app\\' => + array ( + 0 => __DIR__ . '/../..' . '/app', + ), + 'Symfony\\Polyfill\\Php80\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-php80', + ), + 'Symfony\\Polyfill\\Php72\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-php72', + ), + 'Symfony\\Polyfill\\Mbstring\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring', + ), + 'Symfony\\Component\\VarDumper\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/var-dumper', + ), + 'Psr\\SimpleCache\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/simple-cache/src', + ), + 'Psr\\Log\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/log/Psr/Log', + ), + 'Psr\\Container\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/container/src', + ), + 'Psr\\Cache\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/cache/src', + ), + 'League\\MimeTypeDetection\\' => + array ( + 0 => __DIR__ . '/..' . '/league/mime-type-detection/src', + ), + 'League\\Flysystem\\Cached\\' => + array ( + 0 => __DIR__ . '/..' . '/league/flysystem-cached-adapter/src', + ), + 'League\\Flysystem\\' => + array ( + 0 => __DIR__ . '/..' . '/league/flysystem/src', + ), + ); + + public static $fallbackDirsPsr0 = array ( + 0 => __DIR__ . '/../..' . '/extend', + ); + + public static $classMap = array ( + 'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php', + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', + 'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php', + 'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php', + 'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInit1ed187777399b73a018d9a6af63a57d1::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInit1ed187777399b73a018d9a6af63a57d1::$prefixDirsPsr4; + $loader->fallbackDirsPsr0 = ComposerStaticInit1ed187777399b73a018d9a6af63a57d1::$fallbackDirsPsr0; + $loader->classMap = ComposerStaticInit1ed187777399b73a018d9a6af63a57d1::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json new file mode 100644 index 000000000..fb9c6ce6c --- /dev/null +++ b/vendor/composer/installed.json @@ -0,0 +1,1137 @@ +{ + "packages": [ + { + "name": "league/flysystem", + "version": "1.1.4", + "version_normalized": "1.1.4.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "f3ad69181b8afed2c9edf7be5a2918144ff4ea32" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/f3ad69181b8afed2c9edf7be5a2918144ff4ea32", + "reference": "f3ad69181b8afed2c9edf7be5a2918144ff4ea32", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "league/mime-type-detection": "^1.3", + "php": "^7.2.5 || ^8.0" + }, + "conflict": { + "league/flysystem-sftp": "<1.0.6" + }, + "require-dev": { + "phpspec/prophecy": "^1.11.1", + "phpunit/phpunit": "^8.5.8" + }, + "suggest": { + "ext-ftp": "Allows you to use FTP server storage", + "ext-openssl": "Allows you to use FTPS server storage", + "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2", + "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3", + "league/flysystem-azure": "Allows you to use Windows Azure Blob storage", + "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching", + "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem", + "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files", + "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib", + "league/flysystem-webdav": "Allows you to use WebDAV storage", + "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter", + "spatie/flysystem-dropbox": "Allows you to use Dropbox storage", + "srmklive/flysystem-dropbox-v2": "Allows you to use Dropbox storage for PHP 5 applications" + }, + "time": "2021-06-23T21:56:05+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "League\\Flysystem\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frenky.net" + } + ], + "description": "Filesystem abstraction: Many filesystems, one API.", + "keywords": [ + "Cloud Files", + "WebDAV", + "abstraction", + "aws", + "cloud", + "copy.com", + "dropbox", + "file systems", + "files", + "filesystem", + "filesystems", + "ftp", + "rackspace", + "remote", + "s3", + "sftp", + "storage" + ], + "support": { + "issues": "https://github.com/thephpleague/flysystem/issues", + "source": "https://github.com/thephpleague/flysystem/tree/1.1.4" + }, + "funding": [ + { + "url": "https://offset.earth/frankdejonge", + "type": "other" + } + ], + "install-path": "../league/flysystem" + }, + { + "name": "league/flysystem-cached-adapter", + "version": "1.1.0", + "version_normalized": "1.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem-cached-adapter.git", + "reference": "d1925efb2207ac4be3ad0c40b8277175f99ffaff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem-cached-adapter/zipball/d1925efb2207ac4be3ad0c40b8277175f99ffaff", + "reference": "d1925efb2207ac4be3ad0c40b8277175f99ffaff", + "shasum": "" + }, + "require": { + "league/flysystem": "~1.0", + "psr/cache": "^1.0.0" + }, + "require-dev": { + "mockery/mockery": "~0.9", + "phpspec/phpspec": "^3.4", + "phpunit/phpunit": "^5.7", + "predis/predis": "~1.0", + "tedivm/stash": "~0.12" + }, + "suggest": { + "ext-phpredis": "Pure C implemented extension for PHP" + }, + "time": "2020-07-25T15:56:04+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "League\\Flysystem\\Cached\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "frankdejonge", + "email": "info@frenky.net" + } + ], + "description": "An adapter decorator to enable meta-data caching.", + "support": { + "issues": "https://github.com/thephpleague/flysystem-cached-adapter/issues", + "source": "https://github.com/thephpleague/flysystem-cached-adapter/tree/master" + }, + "install-path": "../league/flysystem-cached-adapter" + }, + { + "name": "league/mime-type-detection", + "version": "1.7.0", + "version_normalized": "1.7.0.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/mime-type-detection.git", + "reference": "3b9dff8aaf7323590c1d2e443db701eb1f9aa0d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/3b9dff8aaf7323590c1d2e443db701eb1f9aa0d3", + "reference": "3b9dff8aaf7323590c1d2e443db701eb1f9aa0d3", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.18", + "phpstan/phpstan": "^0.12.68", + "phpunit/phpunit": "^8.5.8 || ^9.3" + }, + "time": "2021-01-18T20:58:21+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "League\\MimeTypeDetection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "Mime-type detection for Flysystem", + "support": { + "issues": "https://github.com/thephpleague/mime-type-detection/issues", + "source": "https://github.com/thephpleague/mime-type-detection/tree/1.7.0" + }, + "funding": [ + { + "url": "https://github.com/frankdejonge", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/flysystem", + "type": "tidelift" + } + ], + "install-path": "../league/mime-type-detection" + }, + { + "name": "psr/cache", + "version": "1.0.1", + "version_normalized": "1.0.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "time": "2016-08-06T20:24:11+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/master" + }, + "install-path": "../psr/cache" + }, + { + "name": "psr/container", + "version": "1.1.1", + "version_normalized": "1.1.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/8622567409010282b7aeebe4bb841fe98b58dcaf", + "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "time": "2021-03-05T17:36:06+00:00", + "type": "library", + "installation-source": "dist", + "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/1.1.1" + }, + "install-path": "../psr/container" + }, + { + "name": "psr/log", + "version": "1.1.4", + "version_normalized": "1.1.4.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "time": "2021-05-03T11:20:27+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "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/1.1.4" + }, + "install-path": "../psr/log" + }, + { + "name": "psr/simple-cache", + "version": "1.0.1", + "version_normalized": "1.0.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "time": "2017-10-23T01:57:42+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/master" + }, + "install-path": "../psr/simple-cache" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.23.0", + "version_normalized": "1.23.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "2df51500adbaebdc4c38dea4c89a2e131c45c8a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/2df51500adbaebdc4c38dea4c89a2e131c45c8a1", + "reference": "2df51500adbaebdc4c38dea4c89a2e131c45c8a1", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "time": "2021-05-27T09:27:20+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.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": "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.23.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" + } + ], + "install-path": "../symfony/polyfill-mbstring" + }, + { + "name": "symfony/polyfill-php72", + "version": "v1.23.0", + "version_normalized": "1.23.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "9a142215a36a3888e30d0a9eeea9766764e96976" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/9a142215a36a3888e30d0a9eeea9766764e96976", + "reference": "9a142215a36a3888e30d0a9eeea9766764e96976", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "time": "2021-05-27T09:17:38+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + }, + "files": [ + "bootstrap.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": "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.23.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" + } + ], + "install-path": "../symfony/polyfill-php72" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.23.0", + "version_normalized": "1.23.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/eca0bf41ed421bed1b57c4958bab16aa86b757d0", + "reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "time": "2021-02-19T12:13:01+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.23.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" + } + ], + "install-path": "../symfony/polyfill-php80" + }, + { + "name": "symfony/var-dumper", + "version": "v4.4.26", + "version_normalized": "4.4.26.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "a586efdf2aa832d05b9249e9115d24f6a2691160" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/a586efdf2aa832d05b9249e9115d24f6a2691160", + "reference": "a586efdf2aa832d05b9249e9115d24f6a2691160", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php72": "~1.5", + "symfony/polyfill-php80": "^1.15" + }, + "conflict": { + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/console": "<3.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/process": "^4.4|^5.0", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "suggest": { + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump", + "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" + }, + "time": "2021-06-17T06:35:48+00:00", + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "installation-source": "dist", + "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/v4.4.26" + }, + "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" + } + ], + "install-path": "../symfony/var-dumper" + }, + { + "name": "topthink/framework", + "version": "v6.0.8", + "version_normalized": "6.0.8.0", + "source": { + "type": "git", + "url": "https://github.com/top-think/framework.git", + "reference": "4789343672aef06d571d556da369c0e156609bce" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/framework/zipball/4789343672aef06d571d556da369c0e156609bce", + "reference": "4789343672aef06d571d556da369c0e156609bce", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "league/flysystem": "^1.0", + "league/flysystem-cached-adapter": "^1.0", + "php": ">=7.1.0", + "psr/container": "~1.0", + "psr/log": "~1.0", + "psr/simple-cache": "^1.0", + "topthink/think-helper": "^3.1.1", + "topthink/think-orm": "^2.0" + }, + "require-dev": { + "mikey179/vfsstream": "^1.6", + "mockery/mockery": "^1.2", + "phpunit/phpunit": "^7.0" + }, + "time": "2021-04-27T00:41:08+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [], + "psr-4": { + "think\\": "src/think/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + }, + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "description": "The ThinkPHP Framework.", + "homepage": "http://thinkphp.cn/", + "keywords": [ + "framework", + "orm", + "thinkphp" + ], + "support": { + "issues": "https://github.com/top-think/framework/issues", + "source": "https://github.com/top-think/framework/tree/v6.0.8" + }, + "install-path": "../topthink/framework" + }, + { + "name": "topthink/think-helper", + "version": "v3.1.5", + "version_normalized": "3.1.5.0", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-helper.git", + "reference": "f98e3ad44acd27ae85a4d923b1bdfd16c6d8d905" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-helper/zipball/f98e3ad44acd27ae85a4d923b1bdfd16c6d8d905", + "reference": "f98e3ad44acd27ae85a4d923b1bdfd16c6d8d905", + "shasum": "" + }, + "require": { + "php": ">=7.1.0" + }, + "time": "2021-06-21T06:17:31+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "think\\": "src" + }, + "files": [ + "src/helper.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "description": "The ThinkPHP6 Helper Package", + "support": { + "issues": "https://github.com/top-think/think-helper/issues", + "source": "https://github.com/top-think/think-helper/tree/v3.1.5" + }, + "install-path": "../topthink/think-helper" + }, + { + "name": "topthink/think-multi-app", + "version": "v1.0.14", + "version_normalized": "1.0.14.0", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-multi-app.git", + "reference": "ccaad7c2d33f42cb1cc2a78d6610aaec02cea4c3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-multi-app/zipball/ccaad7c2d33f42cb1cc2a78d6610aaec02cea4c3", + "reference": "ccaad7c2d33f42cb1cc2a78d6610aaec02cea4c3", + "shasum": "" + }, + "require": { + "php": ">=7.1.0", + "topthink/framework": "^6.0.0" + }, + "time": "2020-07-12T13:50:37+00:00", + "type": "library", + "extra": { + "think": { + "services": [ + "think\\app\\Service" + ] + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "think\\app\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "thinkphp6 multi app support", + "support": { + "issues": "https://github.com/top-think/think-multi-app/issues", + "source": "https://github.com/top-think/think-multi-app/tree/master" + }, + "install-path": "../topthink/think-multi-app" + }, + { + "name": "topthink/think-orm", + "version": "v2.0.40", + "version_normalized": "2.0.40.0", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-orm.git", + "reference": "1119d979b850849f3725856460cf108eec1c3eb8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-orm/zipball/1119d979b850849f3725856460cf108eec1c3eb8", + "reference": "1119d979b850849f3725856460cf108eec1c3eb8", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-pdo": "*", + "php": ">=7.1.0", + "psr/log": "~1.0", + "psr/simple-cache": "^1.0", + "topthink/think-helper": "^3.1" + }, + "require-dev": { + "phpunit/phpunit": "^7|^8|^9.5" + }, + "time": "2021-04-19T13:29:37+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "think\\": "src" + }, + "files": [ + "stubs/load_stubs.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "think orm", + "keywords": [ + "database", + "orm" + ], + "support": { + "issues": "https://github.com/top-think/think-orm/issues", + "source": "https://github.com/top-think/think-orm/tree/v2.0.40" + }, + "install-path": "../topthink/think-orm" + }, + { + "name": "topthink/think-template", + "version": "v2.0.8", + "version_normalized": "2.0.8.0", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-template.git", + "reference": "abfc293f74f9ef5127b5c416310a01fe42e59368" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-template/zipball/abfc293f74f9ef5127b5c416310a01fe42e59368", + "reference": "abfc293f74f9ef5127b5c416310a01fe42e59368", + "shasum": "" + }, + "require": { + "php": ">=7.1.0", + "psr/simple-cache": "^1.0" + }, + "time": "2020-12-10T07:52:03+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "think\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "the php template engine", + "support": { + "issues": "https://github.com/top-think/think-template/issues", + "source": "https://github.com/top-think/think-template/tree/v2.0.8" + }, + "install-path": "../topthink/think-template" + }, + { + "name": "topthink/think-trace", + "version": "v1.4", + "version_normalized": "1.4.0.0", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-trace.git", + "reference": "9a9fa8f767b6c66c5a133ad21ca1bc96ad329444" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-trace/zipball/9a9fa8f767b6c66c5a133ad21ca1bc96ad329444", + "reference": "9a9fa8f767b6c66c5a133ad21ca1bc96ad329444", + "shasum": "" + }, + "require": { + "php": ">=7.1.0", + "topthink/framework": "^6.0.0" + }, + "time": "2020-06-29T05:27:28+00:00", + "type": "library", + "extra": { + "think": { + "services": [ + "think\\trace\\Service" + ], + "config": { + "trace": "src/config.php" + } + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "think\\trace\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "thinkphp debug trace", + "support": { + "issues": "https://github.com/top-think/think-trace/issues", + "source": "https://github.com/top-think/think-trace/tree/v1.4" + }, + "install-path": "../topthink/think-trace" + }, + { + "name": "topthink/think-view", + "version": "v1.0.14", + "version_normalized": "1.0.14.0", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-view.git", + "reference": "edce0ae2c9551ab65f9e94a222604b0dead3576d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-view/zipball/edce0ae2c9551ab65f9e94a222604b0dead3576d", + "reference": "edce0ae2c9551ab65f9e94a222604b0dead3576d", + "shasum": "" + }, + "require": { + "php": ">=7.1.0", + "topthink/think-template": "^2.0" + }, + "time": "2019-11-06T11:40:13+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "think\\view\\driver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "thinkphp template driver", + "support": { + "issues": "https://github.com/top-think/think-view/issues", + "source": "https://github.com/top-think/think-view/tree/v1.0.14" + }, + "install-path": "../topthink/think-view" + } + ], + "dev": true, + "dev-package-names": [ + "symfony/polyfill-mbstring", + "symfony/polyfill-php72", + "symfony/polyfill-php80", + "symfony/var-dumper", + "topthink/think-trace" + ] +} diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php new file mode 100644 index 000000000..d94f1afbc --- /dev/null +++ b/vendor/composer/installed.php @@ -0,0 +1,185 @@ + array( + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'type' => 'project', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'reference' => NULL, + 'name' => 'topthink/think', + 'dev' => true, + ), + 'versions' => array( + 'league/flysystem' => array( + 'pretty_version' => '1.1.4', + 'version' => '1.1.4.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../league/flysystem', + 'aliases' => array(), + 'reference' => 'f3ad69181b8afed2c9edf7be5a2918144ff4ea32', + 'dev_requirement' => false, + ), + 'league/flysystem-cached-adapter' => array( + 'pretty_version' => '1.1.0', + 'version' => '1.1.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../league/flysystem-cached-adapter', + 'aliases' => array(), + 'reference' => 'd1925efb2207ac4be3ad0c40b8277175f99ffaff', + 'dev_requirement' => false, + ), + 'league/mime-type-detection' => array( + 'pretty_version' => '1.7.0', + 'version' => '1.7.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../league/mime-type-detection', + 'aliases' => array(), + 'reference' => '3b9dff8aaf7323590c1d2e443db701eb1f9aa0d3', + 'dev_requirement' => false, + ), + 'psr/cache' => array( + 'pretty_version' => '1.0.1', + 'version' => '1.0.1.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/cache', + 'aliases' => array(), + 'reference' => 'd11b50ad223250cf17b86e38383413f5a6764bf8', + 'dev_requirement' => false, + ), + 'psr/container' => array( + 'pretty_version' => '1.1.1', + 'version' => '1.1.1.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/container', + 'aliases' => array(), + 'reference' => '8622567409010282b7aeebe4bb841fe98b58dcaf', + 'dev_requirement' => false, + ), + 'psr/log' => array( + 'pretty_version' => '1.1.4', + 'version' => '1.1.4.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/log', + 'aliases' => array(), + 'reference' => 'd49695b909c3b7628b6289db5479a1c204601f11', + 'dev_requirement' => false, + ), + 'psr/simple-cache' => array( + 'pretty_version' => '1.0.1', + 'version' => '1.0.1.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/simple-cache', + 'aliases' => array(), + 'reference' => '408d5eafb83c57f6365a3ca330ff23aa4a5fa39b', + 'dev_requirement' => false, + ), + 'symfony/polyfill-mbstring' => array( + 'pretty_version' => 'v1.23.0', + 'version' => '1.23.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-mbstring', + 'aliases' => array(), + 'reference' => '2df51500adbaebdc4c38dea4c89a2e131c45c8a1', + 'dev_requirement' => true, + ), + 'symfony/polyfill-php72' => array( + 'pretty_version' => 'v1.23.0', + 'version' => '1.23.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-php72', + 'aliases' => array(), + 'reference' => '9a142215a36a3888e30d0a9eeea9766764e96976', + 'dev_requirement' => true, + ), + 'symfony/polyfill-php80' => array( + 'pretty_version' => 'v1.23.0', + 'version' => '1.23.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-php80', + 'aliases' => array(), + 'reference' => 'eca0bf41ed421bed1b57c4958bab16aa86b757d0', + 'dev_requirement' => true, + ), + 'symfony/var-dumper' => array( + 'pretty_version' => 'v4.4.26', + 'version' => '4.4.26.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/var-dumper', + 'aliases' => array(), + 'reference' => 'a586efdf2aa832d05b9249e9115d24f6a2691160', + 'dev_requirement' => true, + ), + 'topthink/framework' => array( + 'pretty_version' => 'v6.0.8', + 'version' => '6.0.8.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../topthink/framework', + 'aliases' => array(), + 'reference' => '4789343672aef06d571d556da369c0e156609bce', + 'dev_requirement' => false, + ), + 'topthink/think' => array( + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'type' => 'project', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'reference' => NULL, + 'dev_requirement' => false, + ), + 'topthink/think-helper' => array( + 'pretty_version' => 'v3.1.5', + 'version' => '3.1.5.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../topthink/think-helper', + 'aliases' => array(), + 'reference' => 'f98e3ad44acd27ae85a4d923b1bdfd16c6d8d905', + 'dev_requirement' => false, + ), + 'topthink/think-multi-app' => array( + 'pretty_version' => 'v1.0.14', + 'version' => '1.0.14.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../topthink/think-multi-app', + 'aliases' => array(), + 'reference' => 'ccaad7c2d33f42cb1cc2a78d6610aaec02cea4c3', + 'dev_requirement' => false, + ), + 'topthink/think-orm' => array( + 'pretty_version' => 'v2.0.40', + 'version' => '2.0.40.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../topthink/think-orm', + 'aliases' => array(), + 'reference' => '1119d979b850849f3725856460cf108eec1c3eb8', + 'dev_requirement' => false, + ), + 'topthink/think-template' => array( + 'pretty_version' => 'v2.0.8', + 'version' => '2.0.8.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../topthink/think-template', + 'aliases' => array(), + 'reference' => 'abfc293f74f9ef5127b5c416310a01fe42e59368', + 'dev_requirement' => false, + ), + 'topthink/think-trace' => array( + 'pretty_version' => 'v1.4', + 'version' => '1.4.0.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../topthink/think-trace', + 'aliases' => array(), + 'reference' => '9a9fa8f767b6c66c5a133ad21ca1bc96ad329444', + 'dev_requirement' => true, + ), + 'topthink/think-view' => array( + 'pretty_version' => 'v1.0.14', + 'version' => '1.0.14.0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../topthink/think-view', + 'aliases' => array(), + 'reference' => 'edce0ae2c9551ab65f9e94a222604b0dead3576d', + 'dev_requirement' => false, + ), + ), +); diff --git a/vendor/composer/platform_check.php b/vendor/composer/platform_check.php new file mode 100644 index 000000000..a8b98d5ce --- /dev/null +++ b/vendor/composer/platform_check.php @@ -0,0 +1,26 @@ += 70205)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 7.2.5". You are running ' . PHP_VERSION . '.'; +} + +if ($issues) { + if (!headers_sent()) { + header('HTTP/1.1 500 Internal Server Error'); + } + if (!ini_get('display_errors')) { + if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { + fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL); + } elseif (!headers_sent()) { + echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; + } + } + trigger_error( + 'Composer detected issues in your platform: ' . implode(' ', $issues), + E_USER_ERROR + ); +} diff --git a/vendor/league/flysystem-cached-adapter/.editorconfig b/vendor/league/flysystem-cached-adapter/.editorconfig new file mode 100644 index 000000000..153cf3ef5 --- /dev/null +++ b/vendor/league/flysystem-cached-adapter/.editorconfig @@ -0,0 +1,10 @@ +; top-most EditorConfig file +root = true + +; Unix-style newlines +[*] +end_of_line = LF + +[*.php] +indent_style = space +indent_size = 4 diff --git a/vendor/league/flysystem-cached-adapter/.gitignore b/vendor/league/flysystem-cached-adapter/.gitignore new file mode 100644 index 000000000..7aea75f4f --- /dev/null +++ b/vendor/league/flysystem-cached-adapter/.gitignore @@ -0,0 +1,4 @@ +coverage +coverage.xml +composer.lock +vendor \ No newline at end of file diff --git a/vendor/league/flysystem-cached-adapter/.php_cs b/vendor/league/flysystem-cached-adapter/.php_cs new file mode 100644 index 000000000..6643a32cf --- /dev/null +++ b/vendor/league/flysystem-cached-adapter/.php_cs @@ -0,0 +1,7 @@ +level(Symfony\CS\FixerInterface::PSR2_LEVEL) + ->fixers(['-yoda_conditions', 'ordered_use', 'short_array_syntax']) + ->finder(Symfony\CS\Finder\DefaultFinder::create() + ->in(__DIR__.'/src/')); \ No newline at end of file diff --git a/vendor/league/flysystem-cached-adapter/.scrutinizer.yml b/vendor/league/flysystem-cached-adapter/.scrutinizer.yml new file mode 100644 index 000000000..fa39b52b3 --- /dev/null +++ b/vendor/league/flysystem-cached-adapter/.scrutinizer.yml @@ -0,0 +1,34 @@ +filter: + paths: [src/*] +checks: + php: + code_rating: true + remove_extra_empty_lines: true + remove_php_closing_tag: true + remove_trailing_whitespace: true + fix_use_statements: + remove_unused: true + preserve_multiple: false + preserve_blanklines: true + order_alphabetically: true + fix_php_opening_tag: true + fix_linefeed: true + fix_line_ending: true + fix_identation_4spaces: true + fix_doc_comments: true +tools: + external_code_coverage: + timeout: 900 + runs: 6 + php_code_coverage: false + php_code_sniffer: + config: + standard: PSR2 + filter: + paths: ['src'] + php_loc: + enabled: true + excluded_dirs: [vendor, spec, stubs] + php_cpd: + enabled: true + excluded_dirs: [vendor, spec, stubs] \ No newline at end of file diff --git a/vendor/league/flysystem-cached-adapter/.travis.yml b/vendor/league/flysystem-cached-adapter/.travis.yml new file mode 100644 index 000000000..6706449fd --- /dev/null +++ b/vendor/league/flysystem-cached-adapter/.travis.yml @@ -0,0 +1,29 @@ +language: php + +php: + - 5.5 + - 5.6 + - 7.0 + - 7.1 + - 7.2 + +matrix: + allow_failures: + - php: 5.5 + +env: + - COMPOSER_OPTS="" + - COMPOSER_OPTS="--prefer-lowest" + +install: + - if [[ "${TRAVIS_PHP_VERSION}" == "5.5" ]]; then composer require phpunit/phpunit:^4.8.36 phpspec/phpspec:^2 --prefer-dist --update-with-dependencies; fi + - if [[ "${TRAVIS_PHP_VERSION}" == "7.2" ]]; then composer require phpunit/phpunit:^6.0 --prefer-dist --update-with-dependencies; fi + - travis_retry composer update --prefer-dist $COMPOSER_OPTS + +script: + - vendor/bin/phpspec run + - vendor/bin/phpunit + +after_script: + - wget https://scrutinizer-ci.com/ocular.phar' + - php ocular.phar code-coverage:upload --format=php-clover ./clover/phpunit.xml' diff --git a/vendor/league/flysystem-cached-adapter/LICENSE b/vendor/league/flysystem-cached-adapter/LICENSE new file mode 100644 index 000000000..666f6c826 --- /dev/null +++ b/vendor/league/flysystem-cached-adapter/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015 Frank de Jonge + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/route/.gitignore b/vendor/league/flysystem-cached-adapter/clover/.gitignore similarity index 51% rename from route/.gitignore rename to vendor/league/flysystem-cached-adapter/clover/.gitignore index ed883892b..d6b7ef32c 100644 --- a/route/.gitignore +++ b/vendor/league/flysystem-cached-adapter/clover/.gitignore @@ -1,3 +1,2 @@ * !.gitignore -!route.config \ No newline at end of file diff --git a/vendor/league/flysystem-cached-adapter/composer.json b/vendor/league/flysystem-cached-adapter/composer.json new file mode 100644 index 000000000..df7fb7fd9 --- /dev/null +++ b/vendor/league/flysystem-cached-adapter/composer.json @@ -0,0 +1,30 @@ +{ + "name": "league/flysystem-cached-adapter", + "description": "An adapter decorator to enable meta-data caching.", + "autoload": { + "psr-4": { + "League\\Flysystem\\Cached\\": "src/" + } + }, + "require": { + "league/flysystem": "~1.0", + "psr/cache": "^1.0.0" + }, + "require-dev": { + "phpspec/phpspec": "^3.4", + "phpunit/phpunit": "^5.7", + "mockery/mockery": "~0.9", + "predis/predis": "~1.0", + "tedivm/stash": "~0.12" + }, + "suggest": { + "ext-phpredis": "Pure C implemented extension for PHP" + }, + "license": "MIT", + "authors": [ + { + "name": "frankdejonge", + "email": "info@frenky.net" + } + ] +} diff --git a/vendor/league/flysystem-cached-adapter/phpspec.yml b/vendor/league/flysystem-cached-adapter/phpspec.yml new file mode 100644 index 000000000..5eabcb21b --- /dev/null +++ b/vendor/league/flysystem-cached-adapter/phpspec.yml @@ -0,0 +1,6 @@ +--- +suites: + cached_adapter_suite: + namespace: League\Flysystem\Cached + psr4_prefix: League\Flysystem\Cached +formatter.name: pretty diff --git a/vendor/league/flysystem-cached-adapter/phpunit.php b/vendor/league/flysystem-cached-adapter/phpunit.php new file mode 100644 index 000000000..d10958796 --- /dev/null +++ b/vendor/league/flysystem-cached-adapter/phpunit.php @@ -0,0 +1,3 @@ + + + + + ./tests/ + + + + + ./src/ + + + + + + + + diff --git a/vendor/league/flysystem-cached-adapter/readme.md b/vendor/league/flysystem-cached-adapter/readme.md new file mode 100644 index 000000000..dd1433d98 --- /dev/null +++ b/vendor/league/flysystem-cached-adapter/readme.md @@ -0,0 +1,20 @@ +# Flysystem Cached CachedAdapter + +[![Author](http://img.shields.io/badge/author-@frankdejonge-blue.svg?style=flat-square)](https://twitter.com/frankdejonge) +[![Build Status](https://img.shields.io/travis/thephpleague/flysystem-cached-adapter/master.svg?style=flat-square)](https://travis-ci.org/thephpleague/flysystem-cached-adapter) +[![Coverage Status](https://img.shields.io/scrutinizer/coverage/g/thephpleague/flysystem-cached-adapter.svg?style=flat-square)](https://scrutinizer-ci.com/g/thephpleague/flysystem-cached-adapter/code-structure) +[![Quality Score](https://img.shields.io/scrutinizer/g/thephpleague/flysystem-cached-adapter.svg?style=flat-square)](https://scrutinizer-ci.com/g/thephpleague/flysystem-cached-adapter) +[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE) +[![Packagist Version](https://img.shields.io/packagist/v/league/flysystem-cached-adapter.svg?style=flat-square)](https://packagist.org/packages/league/flysystem-cached-adapter) +[![Total Downloads](https://img.shields.io/packagist/dt/league/flysystem-cached-adapter.svg?style=flat-square)](https://packagist.org/packages/league/flysystem-cached-adapter) + + +The adapter decorator caches metadata and directory listings. + +```bash +composer require league/flysystem-cached-adapter +``` + +## Usage + +[Check out the docs.](https://flysystem.thephpleague.com/docs/advanced/caching/) diff --git a/vendor/league/flysystem-cached-adapter/spec/CachedAdapterSpec.php b/vendor/league/flysystem-cached-adapter/spec/CachedAdapterSpec.php new file mode 100644 index 000000000..69428d990 --- /dev/null +++ b/vendor/league/flysystem-cached-adapter/spec/CachedAdapterSpec.php @@ -0,0 +1,435 @@ +adapter = $adapter; + $this->cache = $cache; + $this->cache->load()->shouldBeCalled(); + $this->beConstructedWith($adapter, $cache); + } + + public function it_is_initializable() + { + $this->shouldHaveType('League\Flysystem\Cached\CachedAdapter'); + $this->shouldHaveType('League\Flysystem\AdapterInterface'); + } + + public function it_should_forward_read_streams() + { + $path = 'path.txt'; + $response = ['path' => $path]; + $this->adapter->readStream($path)->willReturn($response); + $this->readStream($path)->shouldbe($response); + } + + public function it_should_cache_writes() + { + $type = 'file'; + $path = 'path.txt'; + $contents = 'contents'; + $config = new Config(); + $response = compact('path', 'contents', 'type'); + $this->adapter->write($path, $contents, $config)->willReturn($response); + $this->cache->updateObject($path, $response, true)->shouldBeCalled(); + $this->write($path, $contents, $config)->shouldBe($response); + } + + public function it_should_cache_streamed_writes() + { + $type = 'file'; + $path = 'path.txt'; + $stream = tmpfile(); + $config = new Config(); + $response = compact('path', 'stream', 'type'); + $this->adapter->writeStream($path, $stream, $config)->willReturn($response); + $this->cache->updateObject($path, ['contents' => false] + $response, true)->shouldBeCalled(); + $this->writeStream($path, $stream, $config)->shouldBe($response); + fclose($stream); + } + + public function it_should_cache_streamed_updates() + { + $type = 'file'; + $path = 'path.txt'; + $stream = tmpfile(); + $config = new Config(); + $response = compact('path', 'stream', 'type'); + $this->adapter->updateStream($path, $stream, $config)->willReturn($response); + $this->cache->updateObject($path, ['contents' => false] + $response, true)->shouldBeCalled(); + $this->updateStream($path, $stream, $config)->shouldBe($response); + fclose($stream); + } + + public function it_should_ignore_failed_writes() + { + $path = 'path.txt'; + $contents = 'contents'; + $config = new Config(); + $this->adapter->write($path, $contents, $config)->willReturn(false); + $this->write($path, $contents, $config)->shouldBe(false); + } + + public function it_should_ignore_failed_streamed_writes() + { + $path = 'path.txt'; + $contents = tmpfile(); + $config = new Config(); + $this->adapter->writeStream($path, $contents, $config)->willReturn(false); + $this->writeStream($path, $contents, $config)->shouldBe(false); + fclose($contents); + } + + public function it_should_cache_updated() + { + $type = 'file'; + $path = 'path.txt'; + $contents = 'contents'; + $config = new Config(); + $response = compact('path', 'contents', 'type'); + $this->adapter->update($path, $contents, $config)->willReturn($response); + $this->cache->updateObject($path, $response, true)->shouldBeCalled(); + $this->update($path, $contents, $config)->shouldBe($response); + } + + public function it_should_ignore_failed_updates() + { + $path = 'path.txt'; + $contents = 'contents'; + $config = new Config(); + $this->adapter->update($path, $contents, $config)->willReturn(false); + $this->update($path, $contents, $config)->shouldBe(false); + } + + public function it_should_ignore_failed_streamed_updates() + { + $path = 'path.txt'; + $contents = tmpfile(); + $config = new Config(); + $this->adapter->updateStream($path, $contents, $config)->willReturn(false); + $this->updateStream($path, $contents, $config)->shouldBe(false); + fclose($contents); + } + + public function it_should_cache_renames() + { + $old = 'old.txt'; + $new = 'new.txt'; + $this->adapter->rename($old, $new)->willReturn(true); + $this->cache->rename($old, $new)->shouldBeCalled(); + $this->rename($old, $new)->shouldBe(true); + } + + public function it_should_ignore_rename_fails() + { + $old = 'old.txt'; + $new = 'new.txt'; + $this->adapter->rename($old, $new)->willReturn(false); + $this->rename($old, $new)->shouldBe(false); + } + + public function it_should_cache_copies() + { + $old = 'old.txt'; + $new = 'new.txt'; + $this->adapter->copy($old, $new)->willReturn(true); + $this->cache->copy($old, $new)->shouldBeCalled(); + $this->copy($old, $new)->shouldBe(true); + } + + public function it_should_ignore_copy_fails() + { + $old = 'old.txt'; + $new = 'new.txt'; + $this->adapter->copy($old, $new)->willReturn(false); + $this->copy($old, $new)->shouldBe(false); + } + + public function it_should_cache_deletes() + { + $delete = 'delete.txt'; + $this->adapter->delete($delete)->willReturn(true); + $this->cache->delete($delete)->shouldBeCalled(); + $this->delete($delete)->shouldBe(true); + } + + public function it_should_ignore_delete_fails() + { + $delete = 'delete.txt'; + $this->adapter->delete($delete)->willReturn(false); + $this->delete($delete)->shouldBe(false); + } + + public function it_should_cache_dir_deletes() + { + $delete = 'delete'; + $this->adapter->deleteDir($delete)->willReturn(true); + $this->cache->deleteDir($delete)->shouldBeCalled(); + $this->deleteDir($delete)->shouldBe(true); + } + + public function it_should_ignore_delete_dir_fails() + { + $delete = 'delete'; + $this->adapter->deleteDir($delete)->willReturn(false); + $this->deleteDir($delete)->shouldBe(false); + } + + public function it_should_cache_dir_creates() + { + $dirname = 'dirname'; + $config = new Config(); + $response = ['path' => $dirname, 'type' => 'dir']; + $this->adapter->createDir($dirname, $config)->willReturn($response); + $this->cache->updateObject($dirname, $response, true)->shouldBeCalled(); + $this->createDir($dirname, $config)->shouldBe($response); + } + + public function it_should_ignore_create_dir_fails() + { + $dirname = 'dirname'; + $config = new Config(); + $this->adapter->createDir($dirname, $config)->willReturn(false); + $this->createDir($dirname, $config)->shouldBe(false); + } + + public function it_should_cache_set_visibility() + { + $path = 'path.txt'; + $visibility = AdapterInterface::VISIBILITY_PUBLIC; + $this->adapter->setVisibility($path, $visibility)->willReturn(true); + $this->cache->updateObject($path, ['path' => $path, 'visibility' => $visibility], true)->shouldBeCalled(); + $this->setVisibility($path, $visibility)->shouldBe(true); + } + + public function it_should_ignore_set_visibility_fails() + { + $dirname = 'delete'; + $visibility = AdapterInterface::VISIBILITY_PUBLIC; + $this->adapter->setVisibility($dirname, $visibility)->willReturn(false); + $this->setVisibility($dirname, $visibility)->shouldBe(false); + } + + public function it_should_indicate_missing_files() + { + $this->cache->has($path = 'path.txt')->willReturn(false); + $this->has($path)->shouldBe(false); + } + + public function it_should_indicate_file_existance() + { + $this->cache->has($path = 'path.txt')->willReturn(true); + $this->has($path)->shouldBe(true); + } + + public function it_should_cache_missing_files() + { + $this->cache->has($path = 'path.txt')->willReturn(null); + $this->adapter->has($path)->willReturn(false); + $this->cache->storeMiss($path)->shouldBeCalled(); + $this->has($path)->shouldBe(false); + } + + public function it_should_delete_when_metadata_is_missing() + { + $path = 'path.txt'; + $this->cache->has($path)->willReturn(true); + $this->cache->getSize($path)->willReturn(['path' => $path]); + $this->adapter->getSize($path)->willReturn($response = ['path' => $path, 'size' => 1024]); + $this->cache->updateObject($path, $response, true)->shouldBeCalled(); + $this->getSize($path)->shouldBe($response); + } + + public function it_should_cache_has() + { + $this->cache->has($path = 'path.txt')->willReturn(null); + $this->adapter->has($path)->willReturn(true); + $this->cache->updateObject($path, compact('path'), true)->shouldBeCalled(); + $this->has($path)->shouldBe(true); + } + + public function it_should_list_cached_contents() + { + $this->cache->isComplete($dirname = 'dirname', $recursive = true)->willReturn(true); + $response = [['path' => 'path.txt']]; + $this->cache->listContents($dirname, $recursive)->willReturn($response); + $this->listContents($dirname, $recursive)->shouldBe($response); + } + + public function it_should_ignore_failed_list_contents() + { + $this->cache->isComplete($dirname = 'dirname', $recursive = true)->willReturn(false); + $this->adapter->listContents($dirname, $recursive)->willReturn(false); + $this->listContents($dirname, $recursive)->shouldBe(false); + } + + public function it_should_cache_contents_listings() + { + $this->cache->isComplete($dirname = 'dirname', $recursive = true)->willReturn(false); + $response = [['path' => 'path.txt']]; + $this->adapter->listContents($dirname, $recursive)->willReturn($response); + $this->cache->storeContents($dirname, $response, $recursive)->shouldBeCalled(); + $this->listContents($dirname, $recursive)->shouldBe($response); + } + + public function it_should_use_cached_visibility() + { + $this->make_it_use_getter_cache('getVisibility', 'path.txt', [ + 'path' => 'path.txt', + 'visibility' => AdapterInterface::VISIBILITY_PUBLIC, + ]); + } + + public function it_should_cache_get_visibility() + { + $path = 'path.txt'; + $response = ['visibility' => AdapterInterface::VISIBILITY_PUBLIC, 'path' => $path]; + $this->make_it_cache_getter('getVisibility', $path, $response); + } + + public function it_should_ignore_failed_get_visibility() + { + $path = 'path.txt'; + $this->make_it_ignore_failed_getter('getVisibility', $path); + } + + public function it_should_use_cached_timestamp() + { + $this->make_it_use_getter_cache('getTimestamp', 'path.txt', [ + 'path' => 'path.txt', + 'timestamp' => 1234, + ]); + } + + public function it_should_cache_timestamps() + { + $this->make_it_cache_getter('getTimestamp', 'path.txt', [ + 'path' => 'path.txt', + 'timestamp' => 1234, + ]); + } + + public function it_should_ignore_failed_get_timestamps() + { + $this->make_it_ignore_failed_getter('getTimestamp', 'path.txt'); + } + + public function it_should_cache_get_metadata() + { + $path = 'path.txt'; + $response = ['visibility' => AdapterInterface::VISIBILITY_PUBLIC, 'path' => $path]; + $this->make_it_cache_getter('getMetadata', $path, $response); + } + + public function it_should_use_cached_metadata() + { + $this->make_it_use_getter_cache('getMetadata', 'path.txt', [ + 'path' => 'path.txt', + 'timestamp' => 1234, + ]); + } + + public function it_should_ignore_failed_get_metadata() + { + $this->make_it_ignore_failed_getter('getMetadata', 'path.txt'); + } + + public function it_should_cache_get_size() + { + $path = 'path.txt'; + $response = ['size' => 1234, 'path' => $path]; + $this->make_it_cache_getter('getSize', $path, $response); + } + + public function it_should_use_cached_size() + { + $this->make_it_use_getter_cache('getSize', 'path.txt', [ + 'path' => 'path.txt', + 'size' => 1234, + ]); + } + + public function it_should_ignore_failed_get_size() + { + $this->make_it_ignore_failed_getter('getSize', 'path.txt'); + } + + public function it_should_cache_get_mimetype() + { + $path = 'path.txt'; + $response = ['mimetype' => 'text/plain', 'path' => $path]; + $this->make_it_cache_getter('getMimetype', $path, $response); + } + + public function it_should_use_cached_mimetype() + { + $this->make_it_use_getter_cache('getMimetype', 'path.txt', [ + 'path' => 'path.txt', + 'mimetype' => 'text/plain', + ]); + } + + public function it_should_ignore_failed_get_mimetype() + { + $this->make_it_ignore_failed_getter('getMimetype', 'path.txt'); + } + + public function it_should_cache_reads() + { + $path = 'path.txt'; + $response = ['path' => $path, 'contents' => 'contents']; + $this->make_it_cache_getter('read', $path, $response); + } + + public function it_should_use_cached_file_contents() + { + $this->make_it_use_getter_cache('read', 'path.txt', [ + 'path' => 'path.txt', + 'contents' => 'contents' + ]); + } + + public function it_should_ignore_failed_reads() + { + $this->make_it_ignore_failed_getter('read', 'path.txt'); + } + + protected function make_it_use_getter_cache($method, $path, $response) + { + $this->cache->{$method}($path)->willReturn($response); + $this->{$method}($path)->shouldBe($response); + } + + protected function make_it_cache_getter($method, $path, $response) + { + $this->cache->{$method}($path)->willReturn(false); + $this->adapter->{$method}($path)->willReturn($response); + $this->cache->updateObject($path, $response, true)->shouldBeCalled(); + $this->{$method}($path)->shouldBe($response); + } + + protected function make_it_ignore_failed_getter($method, $path) + { + $this->cache->{$method}($path)->willReturn(false); + $this->adapter->{$method}($path)->willReturn(false); + $this->{$method}($path)->shouldBe(false); + } +} diff --git a/vendor/league/flysystem-cached-adapter/src/CacheInterface.php b/vendor/league/flysystem-cached-adapter/src/CacheInterface.php new file mode 100644 index 000000000..de3ab3d90 --- /dev/null +++ b/vendor/league/flysystem-cached-adapter/src/CacheInterface.php @@ -0,0 +1,101 @@ +adapter = $adapter; + $this->cache = $cache; + $this->cache->load(); + } + + /** + * Get the underlying Adapter implementation. + * + * @return AdapterInterface + */ + public function getAdapter() + { + return $this->adapter; + } + + /** + * Get the used Cache implementation. + * + * @return CacheInterface + */ + public function getCache() + { + return $this->cache; + } + + /** + * {@inheritdoc} + */ + public function write($path, $contents, Config $config) + { + $result = $this->adapter->write($path, $contents, $config); + + if ($result !== false) { + $result['type'] = 'file'; + $this->cache->updateObject($path, $result + compact('path', 'contents'), true); + } + + return $result; + } + + /** + * {@inheritdoc} + */ + public function writeStream($path, $resource, Config $config) + { + $result = $this->adapter->writeStream($path, $resource, $config); + + if ($result !== false) { + $result['type'] = 'file'; + $contents = false; + $this->cache->updateObject($path, $result + compact('path', 'contents'), true); + } + + return $result; + } + + /** + * {@inheritdoc} + */ + public function update($path, $contents, Config $config) + { + $result = $this->adapter->update($path, $contents, $config); + + if ($result !== false) { + $result['type'] = 'file'; + $this->cache->updateObject($path, $result + compact('path', 'contents'), true); + } + + return $result; + } + + /** + * {@inheritdoc} + */ + public function updateStream($path, $resource, Config $config) + { + $result = $this->adapter->updateStream($path, $resource, $config); + + if ($result !== false) { + $result['type'] = 'file'; + $contents = false; + $this->cache->updateObject($path, $result + compact('path', 'contents'), true); + } + + return $result; + } + + /** + * {@inheritdoc} + */ + public function rename($path, $newPath) + { + $result = $this->adapter->rename($path, $newPath); + + if ($result !== false) { + $this->cache->rename($path, $newPath); + } + + return $result; + } + + /** + * {@inheritdoc} + */ + public function copy($path, $newpath) + { + $result = $this->adapter->copy($path, $newpath); + + if ($result !== false) { + $this->cache->copy($path, $newpath); + } + + return $result; + } + + /** + * {@inheritdoc} + */ + public function delete($path) + { + $result = $this->adapter->delete($path); + + if ($result !== false) { + $this->cache->delete($path); + } + + return $result; + } + + /** + * {@inheritdoc} + */ + public function deleteDir($dirname) + { + $result = $this->adapter->deleteDir($dirname); + + if ($result !== false) { + $this->cache->deleteDir($dirname); + } + + return $result; + } + + /** + * {@inheritdoc} + */ + public function createDir($dirname, Config $config) + { + $result = $this->adapter->createDir($dirname, $config); + + if ($result !== false) { + $type = 'dir'; + $path = $dirname; + $this->cache->updateObject($dirname, compact('path', 'type'), true); + } + + return $result; + } + + /** + * {@inheritdoc} + */ + public function setVisibility($path, $visibility) + { + $result = $this->adapter->setVisibility($path, $visibility); + + if ($result !== false) { + $this->cache->updateObject($path, compact('path', 'visibility'), true); + } + + return $result; + } + + /** + * {@inheritdoc} + */ + public function has($path) + { + $cacheHas = $this->cache->has($path); + + if ($cacheHas !== null) { + return $cacheHas; + } + + $adapterResponse = $this->adapter->has($path); + + if (! $adapterResponse) { + $this->cache->storeMiss($path); + } else { + $cacheEntry = is_array($adapterResponse) ? $adapterResponse : compact('path'); + $this->cache->updateObject($path, $cacheEntry, true); + } + + return $adapterResponse; + } + + /** + * {@inheritdoc} + */ + public function read($path) + { + return $this->callWithFallback('contents', $path, 'read'); + } + + /** + * {@inheritdoc} + */ + public function readStream($path) + { + return $this->adapter->readStream($path); + } + + /** + * Get the path prefix. + * + * @return string|null path prefix or null if pathPrefix is empty + */ + public function getPathPrefix() + { + return $this->adapter->getPathPrefix(); + } + + /** + * Prefix a path. + * + * @param string $path + * + * @return string prefixed path + */ + public function applyPathPrefix($path) + { + return $this->adapter->applyPathPrefix($path); + } + + /** + * {@inheritdoc} + */ + public function listContents($directory = '', $recursive = false) + { + if ($this->cache->isComplete($directory, $recursive)) { + return $this->cache->listContents($directory, $recursive); + } + + $result = $this->adapter->listContents($directory, $recursive); + + if ($result !== false) { + $this->cache->storeContents($directory, $result, $recursive); + } + + return $result; + } + + /** + * {@inheritdoc} + */ + public function getMetadata($path) + { + return $this->callWithFallback(null, $path, 'getMetadata'); + } + + /** + * {@inheritdoc} + */ + public function getSize($path) + { + return $this->callWithFallback('size', $path, 'getSize'); + } + + /** + * {@inheritdoc} + */ + public function getMimetype($path) + { + return $this->callWithFallback('mimetype', $path, 'getMimetype'); + } + + /** + * {@inheritdoc} + */ + public function getTimestamp($path) + { + return $this->callWithFallback('timestamp', $path, 'getTimestamp'); + } + + /** + * {@inheritdoc} + */ + public function getVisibility($path) + { + return $this->callWithFallback('visibility', $path, 'getVisibility'); + } + + /** + * Call a method and cache the response. + * + * @param string $property + * @param string $path + * @param string $method + * + * @return mixed + */ + protected function callWithFallback($property, $path, $method) + { + $result = $this->cache->{$method}($path); + + if ($result !== false && ($property === null || array_key_exists($property, $result))) { + return $result; + } + + $result = $this->adapter->{$method}($path); + + if ($result) { + $object = $result + compact('path'); + $this->cache->updateObject($path, $object, true); + } + + return $result; + } +} diff --git a/vendor/league/flysystem-cached-adapter/src/Storage/AbstractCache.php b/vendor/league/flysystem-cached-adapter/src/Storage/AbstractCache.php new file mode 100644 index 000000000..141b46822 --- /dev/null +++ b/vendor/league/flysystem-cached-adapter/src/Storage/AbstractCache.php @@ -0,0 +1,418 @@ +autosave) { + $this->save(); + } + } + + /** + * Get the autosave setting. + * + * @return bool autosave + */ + public function getAutosave() + { + return $this->autosave; + } + + /** + * Get the autosave setting. + * + * @param bool $autosave + */ + public function setAutosave($autosave) + { + $this->autosave = $autosave; + } + + /** + * Store the contents listing. + * + * @param string $directory + * @param array $contents + * @param bool $recursive + * + * @return array contents listing + */ + public function storeContents($directory, array $contents, $recursive = false) + { + $directories = [$directory]; + + foreach ($contents as $object) { + $this->updateObject($object['path'], $object); + $object = $this->cache[$object['path']]; + + if ($recursive && $this->pathIsInDirectory($directory, $object['path'])) { + $directories[] = $object['dirname']; + } + } + + foreach (array_unique($directories) as $directory) { + $this->setComplete($directory, $recursive); + } + + $this->autosave(); + } + + /** + * Update the metadata for an object. + * + * @param string $path object path + * @param array $object object metadata + * @param bool $autosave whether to trigger the autosave routine + */ + public function updateObject($path, array $object, $autosave = false) + { + if (! $this->has($path)) { + $this->cache[$path] = Util::pathinfo($path); + } + + $this->cache[$path] = array_merge($this->cache[$path], $object); + + if ($autosave) { + $this->autosave(); + } + + $this->ensureParentDirectories($path); + } + + /** + * Store object hit miss. + * + * @param string $path + */ + public function storeMiss($path) + { + $this->cache[$path] = false; + $this->autosave(); + } + + /** + * Get the contents listing. + * + * @param string $dirname + * @param bool $recursive + * + * @return array contents listing + */ + public function listContents($dirname = '', $recursive = false) + { + $result = []; + + foreach ($this->cache as $object) { + if ($object === false) { + continue; + } + if ($object['dirname'] === $dirname) { + $result[] = $object; + } elseif ($recursive && $this->pathIsInDirectory($dirname, $object['path'])) { + $result[] = $object; + } + } + + return $result; + } + + /** + * {@inheritdoc} + */ + public function has($path) + { + if ($path !== false && array_key_exists($path, $this->cache)) { + return $this->cache[$path] !== false; + } + + if ($this->isComplete(Util::dirname($path), false)) { + return false; + } + } + + /** + * {@inheritdoc} + */ + public function read($path) + { + if (isset($this->cache[$path]['contents']) && $this->cache[$path]['contents'] !== false) { + return $this->cache[$path]; + } + + return false; + } + + /** + * {@inheritdoc} + */ + public function readStream($path) + { + return false; + } + + /** + * {@inheritdoc} + */ + public function rename($path, $newpath) + { + if ($this->has($path)) { + $object = $this->cache[$path]; + unset($this->cache[$path]); + $object['path'] = $newpath; + $object = array_merge($object, Util::pathinfo($newpath)); + $this->cache[$newpath] = $object; + $this->autosave(); + } + } + + /** + * {@inheritdoc} + */ + public function copy($path, $newpath) + { + if ($this->has($path)) { + $object = $this->cache[$path]; + $object = array_merge($object, Util::pathinfo($newpath)); + $this->updateObject($newpath, $object, true); + } + } + + /** + * {@inheritdoc} + */ + public function delete($path) + { + $this->storeMiss($path); + } + + /** + * {@inheritdoc} + */ + public function deleteDir($dirname) + { + foreach ($this->cache as $path => $object) { + if ($this->pathIsInDirectory($dirname, $path) || $path === $dirname) { + unset($this->cache[$path]); + } + } + + unset($this->complete[$dirname]); + + $this->autosave(); + } + + /** + * {@inheritdoc} + */ + public function getMimetype($path) + { + if (isset($this->cache[$path]['mimetype'])) { + return $this->cache[$path]; + } + + if (! $result = $this->read($path)) { + return false; + } + + $mimetype = Util::guessMimeType($path, $result['contents']); + $this->cache[$path]['mimetype'] = $mimetype; + + return $this->cache[$path]; + } + + /** + * {@inheritdoc} + */ + public function getSize($path) + { + if (isset($this->cache[$path]['size'])) { + return $this->cache[$path]; + } + + return false; + } + + /** + * {@inheritdoc} + */ + public function getTimestamp($path) + { + if (isset($this->cache[$path]['timestamp'])) { + return $this->cache[$path]; + } + + return false; + } + + /** + * {@inheritdoc} + */ + public function getVisibility($path) + { + if (isset($this->cache[$path]['visibility'])) { + return $this->cache[$path]; + } + + return false; + } + + /** + * {@inheritdoc} + */ + public function getMetadata($path) + { + if (isset($this->cache[$path]['type'])) { + return $this->cache[$path]; + } + + return false; + } + + /** + * {@inheritdoc} + */ + public function isComplete($dirname, $recursive) + { + if (! array_key_exists($dirname, $this->complete)) { + return false; + } + + if ($recursive && $this->complete[$dirname] !== 'recursive') { + return false; + } + + return true; + } + + /** + * {@inheritdoc} + */ + public function setComplete($dirname, $recursive) + { + $this->complete[$dirname] = $recursive ? 'recursive' : true; + } + + /** + * Filter the contents from a listing. + * + * @param array $contents object listing + * + * @return array filtered contents + */ + public function cleanContents(array $contents) + { + $cachedProperties = array_flip([ + 'path', 'dirname', 'basename', 'extension', 'filename', + 'size', 'mimetype', 'visibility', 'timestamp', 'type', + 'md5', + ]); + + foreach ($contents as $path => $object) { + if (is_array($object)) { + $contents[$path] = array_intersect_key($object, $cachedProperties); + } + } + + return $contents; + } + + /** + * {@inheritdoc} + */ + public function flush() + { + $this->cache = []; + $this->complete = []; + $this->autosave(); + } + + /** + * {@inheritdoc} + */ + public function autosave() + { + if ($this->autosave) { + $this->save(); + } + } + + /** + * Retrieve serialized cache data. + * + * @return string serialized data + */ + public function getForStorage() + { + $cleaned = $this->cleanContents($this->cache); + + return json_encode([$cleaned, $this->complete]); + } + + /** + * Load from serialized cache data. + * + * @param string $json + */ + public function setFromStorage($json) + { + list($cache, $complete) = json_decode($json, true); + + if (json_last_error() === JSON_ERROR_NONE && is_array($cache) && is_array($complete)) { + $this->cache = $cache; + $this->complete = $complete; + } + } + + /** + * Ensure parent directories of an object. + * + * @param string $path object path + */ + public function ensureParentDirectories($path) + { + $object = $this->cache[$path]; + + while ($object['dirname'] !== '' && ! isset($this->cache[$object['dirname']])) { + $object = Util::pathinfo($object['dirname']); + $object['type'] = 'dir'; + $this->cache[$object['path']] = $object; + } + } + + /** + * Determines if the path is inside the directory. + * + * @param string $directory + * @param string $path + * + * @return bool + */ + protected function pathIsInDirectory($directory, $path) + { + return $directory === '' || strpos($path, $directory . '/') === 0; + } +} diff --git a/vendor/league/flysystem-cached-adapter/src/Storage/Adapter.php b/vendor/league/flysystem-cached-adapter/src/Storage/Adapter.php new file mode 100644 index 000000000..649a60e3b --- /dev/null +++ b/vendor/league/flysystem-cached-adapter/src/Storage/Adapter.php @@ -0,0 +1,115 @@ +adapter = $adapter; + $this->file = $file; + $this->setExpire($expire); + } + + /** + * Set the expiration time in seconds. + * + * @param int $expire relative expiration time + */ + protected function setExpire($expire) + { + if ($expire) { + $this->expire = $this->getTime($expire); + } + } + + /** + * Get expiration time in seconds. + * + * @param int $time relative expiration time + * + * @return int actual expiration time + */ + protected function getTime($time = 0) + { + return intval(microtime(true)) + $time; + } + + /** + * {@inheritdoc} + */ + public function setFromStorage($json) + { + list($cache, $complete, $expire) = json_decode($json, true); + + if (! $expire || $expire > $this->getTime()) { + $this->cache = is_array($cache) ? $cache : []; + $this->complete = is_array($complete) ? $complete : []; + } else { + $this->adapter->delete($this->file); + } + } + + /** + * {@inheritdoc} + */ + public function load() + { + if ($this->adapter->has($this->file)) { + $file = $this->adapter->read($this->file); + if ($file && !empty($file['contents'])) { + $this->setFromStorage($file['contents']); + } + } + } + + /** + * {@inheritdoc} + */ + public function getForStorage() + { + $cleaned = $this->cleanContents($this->cache); + + return json_encode([$cleaned, $this->complete, $this->expire]); + } + + /** + * {@inheritdoc} + */ + public function save() + { + $config = new Config(); + $contents = $this->getForStorage(); + + if ($this->adapter->has($this->file)) { + $this->adapter->update($this->file, $contents, $config); + } else { + $this->adapter->write($this->file, $contents, $config); + } + } +} diff --git a/vendor/league/flysystem-cached-adapter/src/Storage/Memcached.php b/vendor/league/flysystem-cached-adapter/src/Storage/Memcached.php new file mode 100644 index 000000000..f67d2717a --- /dev/null +++ b/vendor/league/flysystem-cached-adapter/src/Storage/Memcached.php @@ -0,0 +1,59 @@ +key = $key; + $this->expire = $expire; + $this->memcached = $memcached; + } + + /** + * {@inheritdoc} + */ + public function load() + { + $contents = $this->memcached->get($this->key); + + if ($contents !== false) { + $this->setFromStorage($contents); + } + } + + /** + * {@inheritdoc} + */ + public function save() + { + $contents = $this->getForStorage(); + $expiration = $this->expire === null ? 0 : time() + $this->expire; + $this->memcached->set($this->key, $contents, $expiration); + } +} diff --git a/vendor/league/flysystem-cached-adapter/src/Storage/Memory.php b/vendor/league/flysystem-cached-adapter/src/Storage/Memory.php new file mode 100644 index 000000000..d0914fabd --- /dev/null +++ b/vendor/league/flysystem-cached-adapter/src/Storage/Memory.php @@ -0,0 +1,22 @@ +client = $client ?: new Redis(); + $this->key = $key; + $this->expire = $expire; + } + + /** + * {@inheritdoc} + */ + public function load() + { + $contents = $this->client->get($this->key); + + if ($contents !== false) { + $this->setFromStorage($contents); + } + } + + /** + * {@inheritdoc} + */ + public function save() + { + $contents = $this->getForStorage(); + $this->client->set($this->key, $contents); + + if ($this->expire !== null) { + $this->client->expire($this->key, $this->expire); + } + } +} diff --git a/vendor/league/flysystem-cached-adapter/src/Storage/Predis.php b/vendor/league/flysystem-cached-adapter/src/Storage/Predis.php new file mode 100644 index 000000000..8a295744b --- /dev/null +++ b/vendor/league/flysystem-cached-adapter/src/Storage/Predis.php @@ -0,0 +1,75 @@ +client = $client ?: new Client(); + $this->key = $key; + $this->expire = $expire; + } + + /** + * {@inheritdoc} + */ + public function load() + { + if (($contents = $this->executeCommand('get', [$this->key])) !== null) { + $this->setFromStorage($contents); + } + } + + /** + * {@inheritdoc} + */ + public function save() + { + $contents = $this->getForStorage(); + $this->executeCommand('set', [$this->key, $contents]); + + if ($this->expire !== null) { + $this->executeCommand('expire', [$this->key, $this->expire]); + } + } + + /** + * Execute a Predis command. + * + * @param string $name + * @param array $arguments + * + * @return string + */ + protected function executeCommand($name, array $arguments) + { + $command = $this->client->createCommand($name, $arguments); + + return $this->client->executeCommand($command); + } +} diff --git a/vendor/league/flysystem-cached-adapter/src/Storage/Psr6Cache.php b/vendor/league/flysystem-cached-adapter/src/Storage/Psr6Cache.php new file mode 100644 index 000000000..43be87e53 --- /dev/null +++ b/vendor/league/flysystem-cached-adapter/src/Storage/Psr6Cache.php @@ -0,0 +1,59 @@ +pool = $pool; + $this->key = $key; + $this->expire = $expire; + } + + /** + * {@inheritdoc} + */ + public function save() + { + $item = $this->pool->getItem($this->key); + $item->set($this->getForStorage()); + $item->expiresAfter($this->expire); + $this->pool->save($item); + } + + /** + * {@inheritdoc} + */ + public function load() + { + $item = $this->pool->getItem($this->key); + if ($item->isHit()) { + $this->setFromStorage($item->get()); + } + } +} \ No newline at end of file diff --git a/vendor/league/flysystem-cached-adapter/src/Storage/Stash.php b/vendor/league/flysystem-cached-adapter/src/Storage/Stash.php new file mode 100644 index 000000000..e05b83228 --- /dev/null +++ b/vendor/league/flysystem-cached-adapter/src/Storage/Stash.php @@ -0,0 +1,60 @@ +key = $key; + $this->expire = $expire; + $this->pool = $pool; + } + + /** + * {@inheritdoc} + */ + public function load() + { + $item = $this->pool->getItem($this->key); + $contents = $item->get(); + + if ($item->isMiss() === false) { + $this->setFromStorage($contents); + } + } + + /** + * {@inheritdoc} + */ + public function save() + { + $contents = $this->getForStorage(); + $item = $this->pool->getItem($this->key); + $item->set($contents, $this->expire); + } +} diff --git a/vendor/league/flysystem-cached-adapter/tests/AdapterCacheTests.php b/vendor/league/flysystem-cached-adapter/tests/AdapterCacheTests.php new file mode 100644 index 000000000..b63cba788 --- /dev/null +++ b/vendor/league/flysystem-cached-adapter/tests/AdapterCacheTests.php @@ -0,0 +1,104 @@ +shouldReceive('has')->once()->with('file.json')->andReturn(false); + $cache = new Adapter($adapter, 'file.json', 10); + $cache->load(); + $this->assertFalse($cache->isComplete('', false)); + } + + public function testLoadExpired() + { + $response = ['contents' => json_encode([[], ['' => true], 1234567890]), 'path' => 'file.json']; + $adapter = Mockery::mock('League\Flysystem\AdapterInterface'); + $adapter->shouldReceive('has')->once()->with('file.json')->andReturn(true); + $adapter->shouldReceive('read')->once()->with('file.json')->andReturn($response); + $adapter->shouldReceive('delete')->once()->with('file.json'); + $cache = new Adapter($adapter, 'file.json', 10); + $cache->load(); + $this->assertFalse($cache->isComplete('', false)); + } + + public function testLoadSuccess() + { + $response = ['contents' => json_encode([[], ['' => true], 9876543210]), 'path' => 'file.json']; + $adapter = Mockery::mock('League\Flysystem\AdapterInterface'); + $adapter->shouldReceive('has')->once()->with('file.json')->andReturn(true); + $adapter->shouldReceive('read')->once()->with('file.json')->andReturn($response); + $cache = new Adapter($adapter, 'file.json', 10); + $cache->load(); + $this->assertTrue($cache->isComplete('', false)); + } + + public function testSaveExists() + { + $response = json_encode([[], [], null]); + $adapter = Mockery::mock('League\Flysystem\AdapterInterface'); + $adapter->shouldReceive('has')->once()->with('file.json')->andReturn(true); + $adapter->shouldReceive('update')->once()->with('file.json', $response, Mockery::any()); + $cache = new Adapter($adapter, 'file.json', null); + $cache->save(); + } + + public function testSaveNew() + { + $response = json_encode([[], [], null]); + $adapter = Mockery::mock('League\Flysystem\AdapterInterface'); + $adapter->shouldReceive('has')->once()->with('file.json')->andReturn(false); + $adapter->shouldReceive('write')->once()->with('file.json', $response, Mockery::any()); + $cache = new Adapter($adapter, 'file.json', null); + $cache->save(); + } + + public function testStoreContentsRecursive() + { + $adapter = Mockery::mock('League\Flysystem\AdapterInterface'); + $adapter->shouldReceive('has')->once()->with('file.json')->andReturn(false); + $adapter->shouldReceive('write')->once()->with('file.json', Mockery::any(), Mockery::any()); + + $cache = new Adapter($adapter, 'file.json', null); + + $contents = [ + ['path' => 'foo/bar', 'dirname' => 'foo'], + ['path' => 'afoo/bang', 'dirname' => 'afoo'], + ]; + + $cache->storeContents('foo', $contents, true); + + $this->assertTrue($cache->isComplete('foo', true)); + $this->assertFalse($cache->isComplete('afoo', true)); + } + + public function testDeleteDir() + { + $cache_data = [ + 'foo' => ['path' => 'foo', 'type' => 'dir', 'dirname' => ''], + 'foo/bar' => ['path' => 'foo/bar', 'type' => 'file', 'dirname' => 'foo'], + 'foobaz' => ['path' => 'foobaz', 'type' => 'file', 'dirname' => ''], + ]; + + $response = [ + 'contents' => json_encode([$cache_data, [], null]), + 'path' => 'file.json', + ]; + + $adapter = Mockery::mock('League\Flysystem\AdapterInterface'); + $adapter->shouldReceive('has')->zeroOrMoreTimes()->with('file.json')->andReturn(true); + $adapter->shouldReceive('read')->once()->with('file.json')->andReturn($response); + $adapter->shouldReceive('update')->once()->with('file.json', Mockery::any(), Mockery::any())->andReturn(true); + + $cache = new Adapter($adapter, 'file.json', null); + $cache->load(); + + $cache->deleteDir('foo', true); + + $this->assertSame(1, count($cache->listContents('', true))); + } +} diff --git a/vendor/league/flysystem-cached-adapter/tests/InspectionTests.php b/vendor/league/flysystem-cached-adapter/tests/InspectionTests.php new file mode 100644 index 000000000..40d4c915e --- /dev/null +++ b/vendor/league/flysystem-cached-adapter/tests/InspectionTests.php @@ -0,0 +1,16 @@ +shouldReceive('load')->once(); + $cached_adapter = new CachedAdapter($adapter, $cache); + $this->assertInstanceOf('League\Flysystem\AdapterInterface', $cached_adapter->getAdapter()); + } +} diff --git a/vendor/league/flysystem-cached-adapter/tests/MemcachedTests.php b/vendor/league/flysystem-cached-adapter/tests/MemcachedTests.php new file mode 100644 index 000000000..e3d9ad939 --- /dev/null +++ b/vendor/league/flysystem-cached-adapter/tests/MemcachedTests.php @@ -0,0 +1,35 @@ +shouldReceive('get')->once()->andReturn(false); + $cache = new Memcached($client); + $cache->load(); + $this->assertFalse($cache->isComplete('', false)); + } + + public function testLoadSuccess() + { + $response = json_encode([[], ['' => true]]); + $client = Mockery::mock('Memcached'); + $client->shouldReceive('get')->once()->andReturn($response); + $cache = new Memcached($client); + $cache->load(); + $this->assertTrue($cache->isComplete('', false)); + } + + public function testSave() + { + $response = json_encode([[], []]); + $client = Mockery::mock('Memcached'); + $client->shouldReceive('set')->once()->andReturn($response); + $cache = new Memcached($client); + $cache->save(); + } +} diff --git a/vendor/league/flysystem-cached-adapter/tests/MemoryCacheTests.php b/vendor/league/flysystem-cached-adapter/tests/MemoryCacheTests.php new file mode 100644 index 000000000..3ac58fd08 --- /dev/null +++ b/vendor/league/flysystem-cached-adapter/tests/MemoryCacheTests.php @@ -0,0 +1,255 @@ +setAutosave(true); + $this->assertTrue($cache->getAutosave()); + $cache->setAutosave(false); + $this->assertFalse($cache->getAutosave()); + } + + public function testCacheMiss() + { + $cache = new Memory(); + $cache->storeMiss('path.txt'); + $this->assertFalse($cache->has('path.txt')); + } + + public function testIsComplete() + { + $cache = new Memory(); + $this->assertFalse($cache->isComplete('dirname', false)); + $cache->setComplete('dirname', false); + $this->assertFalse($cache->isComplete('dirname', true)); + $cache->setComplete('dirname', true); + $this->assertTrue($cache->isComplete('dirname', true)); + } + + public function testCleanContents() + { + $cache = new Memory(); + $input = [[ + 'path' => 'path.txt', + 'visibility' => 'public', + 'invalid' => 'thing', + ]]; + + $expected = [[ + 'path' => 'path.txt', + 'visibility' => 'public', + ]]; + + $output = $cache->cleanContents($input); + $this->assertEquals($expected, $output); + } + + public function testGetForStorage() + { + $cache = new Memory(); + $input = [[ + 'path' => 'path.txt', + 'visibility' => 'public', + 'type' => 'file', + ]]; + + $cache->storeContents('', $input, true); + $contents = $cache->listContents('', true); + $cached = []; + foreach ($contents as $item) { + $cached[$item['path']] = $item; + } + + $this->assertEquals(json_encode([$cached, ['' => 'recursive']]), $cache->getForStorage()); + } + + public function testParentCompleteIsUsedDuringHas() + { + $cache = new Memory(); + $cache->setComplete('dirname', false); + $this->assertFalse($cache->has('dirname/path.txt')); + } + + public function testFlush() + { + $cache = new Memory(); + $cache->setComplete('dirname', true); + $cache->updateObject('path.txt', [ + 'path' => 'path.txt', + 'visibility' => 'public', + ]); + $cache->flush(); + $this->assertFalse($cache->isComplete('dirname', true)); + $this->assertNull($cache->has('path.txt')); + } + + public function testSetFromStorage() + { + $cache = new Memory(); + $json = [[ + 'path.txt' => ['path' => 'path.txt', 'type' => 'file'], + ], ['dirname' => 'recursive']]; + $jsonString = json_encode($json); + $cache->setFromStorage($jsonString); + $this->assertTrue($cache->has('path.txt')); + $this->assertTrue($cache->isComplete('dirname', true)); + } + + public function testGetMetadataFail() + { + $cache = new Memory(); + $this->assertFalse($cache->getMetadata('path.txt')); + } + + public function metaGetterProvider() + { + return [ + ['getTimestamp', 'timestamp', 12344], + ['getMimetype', 'mimetype', 'text/plain'], + ['getSize', 'size', 12], + ['getVisibility', 'visibility', 'private'], + ['read', 'contents', '__contents__'], + ]; + } + + /** + * @dataProvider metaGetterProvider + * + * @param $method + * @param $key + * @param $value + */ + public function testMetaGetters($method, $key, $value) + { + $cache = new Memory(); + $this->assertFalse($cache->{$method}('path.txt')); + $cache->updateObject('path.txt', $object = [ + 'path' => 'path.txt', + 'type' => 'file', + $key => $value, + ] + Util::pathinfo('path.txt'), true); + $this->assertEquals($object, $cache->{$method}('path.txt')); + $this->assertEquals($object, $cache->getMetadata('path.txt')); + } + + public function testGetDerivedMimetype() + { + $cache = new Memory(); + $cache->updateObject('path.txt', [ + 'contents' => 'something', + ]); + $response = $cache->getMimetype('path.txt'); + $this->assertEquals('text/plain', $response['mimetype']); + } + + public function testCopyFail() + { + $cache = new Memory(); + $cache->copy('one', 'two'); + $this->assertNull($cache->has('two')); + $this->assertNull($cache->load()); + } + + public function testStoreContents() + { + $cache = new Memory(); + $cache->storeContents('dirname', [ + ['path' => 'dirname', 'type' => 'dir'], + ['path' => 'dirname/nested', 'type' => 'dir'], + ['path' => 'dirname/nested/deep', 'type' => 'dir'], + ['path' => 'other/nested/deep', 'type' => 'dir'], + ], true); + + $this->isTrue($cache->isComplete('other/nested', true)); + } + + public function testDelete() + { + $cache = new Memory(); + $cache->updateObject('path.txt', ['type' => 'file']); + $this->assertTrue($cache->has('path.txt')); + $cache->delete('path.txt'); + $this->assertFalse($cache->has('path.txt')); + } + + public function testDeleteDir() + { + $cache = new Memory(); + $cache->storeContents('dirname', [ + ['path' => 'dirname/path.txt', 'type' => 'file'], + ]); + $this->assertTrue($cache->isComplete('dirname', false)); + $this->assertTrue($cache->has('dirname/path.txt')); + $cache->deleteDir('dirname'); + $this->assertFalse($cache->isComplete('dirname', false)); + $this->assertNull($cache->has('dirname/path.txt')); + } + + public function testReadStream() + { + $cache = new Memory(); + $this->assertFalse($cache->readStream('path.txt')); + } + + public function testRename() + { + $cache = new Memory(); + $cache->updateObject('path.txt', ['type' => 'file']); + $cache->rename('path.txt', 'newpath.txt'); + $this->assertTrue($cache->has('newpath.txt')); + } + + public function testCopy() + { + $cache = new Memory(); + $cache->updateObject('path.txt', ['type' => 'file']); + $cache->copy('path.txt', 'newpath.txt'); + $this->assertTrue($cache->has('newpath.txt')); + } + + public function testComplextListContents() + { + $cache = new Memory(); + $cache->storeContents('', [ + ['path' => 'dirname', 'type' => 'dir'], + ['path' => 'dirname/file.txt', 'type' => 'file'], + ['path' => 'other', 'type' => 'dir'], + ['path' => 'other/file.txt', 'type' => 'file'], + ['path' => 'other/nested/file.txt', 'type' => 'file'], + ]); + + $this->assertCount(3, $cache->listContents('other', true)); + } + + public function testComplextListContentsWithDeletedFile() + { + $cache = new Memory(); + $cache->storeContents('', [ + ['path' => 'dirname', 'type' => 'dir'], + ['path' => 'dirname/file.txt', 'type' => 'file'], + ['path' => 'other', 'type' => 'dir'], + ['path' => 'other/file.txt', 'type' => 'file'], + ['path' => 'other/another_file.txt', 'type' => 'file'], + ]); + + $cache->delete('other/another_file.txt'); + $this->assertCount(4, $cache->listContents('', true)); + } + + public function testCacheMissIfContentsIsFalse() + { + $cache = new Memory(); + $cache->updateObject('path.txt', [ + 'path' => 'path.txt', + 'contents' => false, + ], true); + + $this->assertFalse($cache->read('path.txt')); + } +} diff --git a/vendor/league/flysystem-cached-adapter/tests/NoopCacheTests.php b/vendor/league/flysystem-cached-adapter/tests/NoopCacheTests.php new file mode 100644 index 000000000..148616ff1 --- /dev/null +++ b/vendor/league/flysystem-cached-adapter/tests/NoopCacheTests.php @@ -0,0 +1,35 @@ +assertEquals($cache, $cache->storeMiss('file.txt')); + $this->assertNull($cache->setComplete('', false)); + $this->assertNull($cache->load()); + $this->assertNull($cache->flush()); + $this->assertNull($cache->has('path.txt')); + $this->assertNull($cache->autosave()); + $this->assertFalse($cache->isComplete('', false)); + $this->assertFalse($cache->read('something')); + $this->assertFalse($cache->readStream('something')); + $this->assertFalse($cache->getMetadata('something')); + $this->assertFalse($cache->getMimetype('something')); + $this->assertFalse($cache->getSize('something')); + $this->assertFalse($cache->getTimestamp('something')); + $this->assertFalse($cache->getVisibility('something')); + $this->assertEmpty($cache->listContents('', false)); + $this->assertFalse($cache->rename('', '')); + $this->assertFalse($cache->copy('', '')); + $this->assertNull($cache->save()); + $object = ['path' => 'path.ext']; + $this->assertEquals($object, $cache->updateObject('path.txt', $object)); + $this->assertEquals([['path' => 'some/file.txt']], $cache->storeContents('unknwon', [ + ['path' => 'some/file.txt'], + ], false)); + } +} diff --git a/vendor/league/flysystem-cached-adapter/tests/PhpRedisTests.php b/vendor/league/flysystem-cached-adapter/tests/PhpRedisTests.php new file mode 100644 index 000000000..d1ccb6545 --- /dev/null +++ b/vendor/league/flysystem-cached-adapter/tests/PhpRedisTests.php @@ -0,0 +1,45 @@ +shouldReceive('get')->with('flysystem')->once()->andReturn(false); + $cache = new PhpRedis($client); + $cache->load(); + $this->assertFalse($cache->isComplete('', false)); + } + + public function testLoadSuccess() + { + $response = json_encode([[], ['' => true]]); + $client = Mockery::mock('Redis'); + $client->shouldReceive('get')->with('flysystem')->once()->andReturn($response); + $cache = new PhpRedis($client); + $cache->load(); + $this->assertTrue($cache->isComplete('', false)); + } + + public function testSave() + { + $data = json_encode([[], []]); + $client = Mockery::mock('Redis'); + $client->shouldReceive('set')->with('flysystem', $data)->once(); + $cache = new PhpRedis($client); + $cache->save(); + } + + public function testSaveWithExpire() + { + $data = json_encode([[], []]); + $client = Mockery::mock('Redis'); + $client->shouldReceive('set')->with('flysystem', $data)->once(); + $client->shouldReceive('expire')->with('flysystem', 20)->once(); + $cache = new PhpRedis($client, 'flysystem', 20); + $cache->save(); + } +} diff --git a/vendor/league/flysystem-cached-adapter/tests/PredisTests.php b/vendor/league/flysystem-cached-adapter/tests/PredisTests.php new file mode 100644 index 000000000..e33e10468 --- /dev/null +++ b/vendor/league/flysystem-cached-adapter/tests/PredisTests.php @@ -0,0 +1,55 @@ +shouldReceive('createCommand')->with('get', ['flysystem'])->once()->andReturn($command); + $client->shouldReceive('executeCommand')->with($command)->andReturn(null); + $cache = new Predis($client); + $cache->load(); + $this->assertFalse($cache->isComplete('', false)); + } + + public function testLoadSuccess() + { + $response = json_encode([[], ['' => true]]); + $client = Mockery::mock('Predis\Client'); + $command = Mockery::mock('Predis\Command\CommandInterface'); + $client->shouldReceive('createCommand')->with('get', ['flysystem'])->once()->andReturn($command); + $client->shouldReceive('executeCommand')->with($command)->andReturn($response); + $cache = new Predis($client); + $cache->load(); + $this->assertTrue($cache->isComplete('', false)); + } + + public function testSave() + { + $data = json_encode([[], []]); + $client = Mockery::mock('Predis\Client'); + $command = Mockery::mock('Predis\Command\CommandInterface'); + $client->shouldReceive('createCommand')->with('set', ['flysystem', $data])->once()->andReturn($command); + $client->shouldReceive('executeCommand')->with($command)->once(); + $cache = new Predis($client); + $cache->save(); + } + + public function testSaveWithExpire() + { + $data = json_encode([[], []]); + $client = Mockery::mock('Predis\Client'); + $command = Mockery::mock('Predis\Command\CommandInterface'); + $client->shouldReceive('createCommand')->with('set', ['flysystem', $data])->once()->andReturn($command); + $client->shouldReceive('executeCommand')->with($command)->once(); + $expireCommand = Mockery::mock('Predis\Command\CommandInterface'); + $client->shouldReceive('createCommand')->with('expire', ['flysystem', 20])->once()->andReturn($expireCommand); + $client->shouldReceive('executeCommand')->with($expireCommand)->once(); + $cache = new Predis($client, 'flysystem', 20); + $cache->save(); + } +} diff --git a/vendor/league/flysystem-cached-adapter/tests/Psr6CacheTest.php b/vendor/league/flysystem-cached-adapter/tests/Psr6CacheTest.php new file mode 100644 index 000000000..d5e5700cf --- /dev/null +++ b/vendor/league/flysystem-cached-adapter/tests/Psr6CacheTest.php @@ -0,0 +1,45 @@ +shouldReceive('isHit')->once()->andReturn(false); + $pool->shouldReceive('getItem')->once()->andReturn($item); + $cache = new Psr6Cache($pool); + $cache->load(); + $this->assertFalse($cache->isComplete('', false)); + } + + public function testLoadSuccess() + { + $response = json_encode([[], ['' => true]]); + $pool = Mockery::mock('Psr\Cache\CacheItemPoolInterface'); + $item = Mockery::mock('Psr\Cache\CacheItemInterface'); + $item->shouldReceive('get')->once()->andReturn($response); + $item->shouldReceive('isHit')->once()->andReturn(true); + $pool->shouldReceive('getItem')->once()->andReturn($item); + $cache = new Psr6Cache($pool); + $cache->load(); + $this->assertTrue($cache->isComplete('', false)); + } + + public function testSave() + { + $response = json_encode([[], []]); + $ttl = 4711; + $pool = Mockery::mock('Psr\Cache\CacheItemPoolInterface'); + $item = Mockery::mock('Psr\Cache\CacheItemInterface'); + $item->shouldReceive('expiresAfter')->once()->with($ttl); + $item->shouldReceive('set')->once()->andReturn($response); + $pool->shouldReceive('getItem')->once()->andReturn($item); + $pool->shouldReceive('save')->once()->with($item); + $cache = new Psr6Cache($pool, 'foo', $ttl); + $cache->save(); + } +} diff --git a/vendor/league/flysystem-cached-adapter/tests/StashTest.php b/vendor/league/flysystem-cached-adapter/tests/StashTest.php new file mode 100644 index 000000000..29e142d79 --- /dev/null +++ b/vendor/league/flysystem-cached-adapter/tests/StashTest.php @@ -0,0 +1,43 @@ +shouldReceive('get')->once()->andReturn(null); + $item->shouldReceive('isMiss')->once()->andReturn(true); + $pool->shouldReceive('getItem')->once()->andReturn($item); + $cache = new Stash($pool); + $cache->load(); + $this->assertFalse($cache->isComplete('', false)); + } + + public function testLoadSuccess() + { + $response = json_encode([[], ['' => true]]); + $pool = Mockery::mock('Stash\Pool'); + $item = Mockery::mock('Stash\Item'); + $item->shouldReceive('get')->once()->andReturn($response); + $item->shouldReceive('isMiss')->once()->andReturn(false); + $pool->shouldReceive('getItem')->once()->andReturn($item); + $cache = new Stash($pool); + $cache->load(); + $this->assertTrue($cache->isComplete('', false)); + } + + public function testSave() + { + $response = json_encode([[], []]); + $pool = Mockery::mock('Stash\Pool'); + $item = Mockery::mock('Stash\Item'); + $item->shouldReceive('set')->once()->andReturn($response); + $pool->shouldReceive('getItem')->once()->andReturn($item); + $cache = new Stash($pool); + $cache->save(); + } +} diff --git a/vendor/league/flysystem/CODE_OF_CONDUCT.md b/vendor/league/flysystem/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..89569c015 --- /dev/null +++ b/vendor/league/flysystem/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at info+flysystem@frankdejonge.nl. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/vendor/league/flysystem/LICENSE b/vendor/league/flysystem/LICENSE new file mode 100644 index 000000000..f2684c841 --- /dev/null +++ b/vendor/league/flysystem/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2013-2019 Frank de Jonge + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/league/flysystem/SECURITY.md b/vendor/league/flysystem/SECURITY.md new file mode 100644 index 000000000..f5b205ed0 --- /dev/null +++ b/vendor/league/flysystem/SECURITY.md @@ -0,0 +1,16 @@ +# Security Policy + +## Supported Versions + +| Version | Supported | +| ------- | ------------------ | +| 1.0.x | :white_check_mark: | +| 2.0.x | :x: | + +## Reporting a Vulnerability + +When you've encountered a security vulnerability, please disclose it securely. + +The security process is described at: +[https://flysystem.thephpleague.com/docs/security/](https://flysystem.thephpleague.com/docs/security/) + diff --git a/vendor/league/flysystem/composer.json b/vendor/league/flysystem/composer.json new file mode 100644 index 000000000..32ec81d1b --- /dev/null +++ b/vendor/league/flysystem/composer.json @@ -0,0 +1,68 @@ +{ + "name": "league/flysystem", + "type": "library", + "description": "Filesystem abstraction: Many filesystems, one API.", + "keywords": [ + "filesystem", "filesystems", "files", "storage", "dropbox", "aws", + "abstraction", "s3", "ftp", "sftp", "remote", "webdav", + "file systems", "cloud", "cloud files", "rackspace", "copy.com" + ], + "funding": [ + { + "type": "other", + "url": "https://offset.earth/frankdejonge" + } + ], + "license": "MIT", + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frenky.net" + } + ], + "require": { + "php": "^7.2.5 || ^8.0", + "ext-fileinfo": "*", + "league/mime-type-detection": "^1.3" + }, + "require-dev": { + "phpspec/prophecy": "^1.11.1", + "phpunit/phpunit": "^8.5.8" + }, + "autoload": { + "psr-4": { + "League\\Flysystem\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "League\\Flysystem\\Stub\\": "stub/" + } + }, + "suggest": { + "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem", + "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files", + "league/flysystem-azure": "Allows you to use Windows Azure Blob storage", + "league/flysystem-webdav": "Allows you to use WebDAV storage", + "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2", + "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3", + "spatie/flysystem-dropbox": "Allows you to use Dropbox storage", + "srmklive/flysystem-dropbox-v2": "Allows you to use Dropbox storage for PHP 5 applications", + "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching", + "ext-ftp": "Allows you to use FTP server storage", + "ext-openssl": "Allows you to use FTPS server storage", + "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib", + "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter" + }, + "conflict": { + "league/flysystem-sftp": "<1.0.6" + }, + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "scripts": { + "phpstan": "php phpstan.php" + } +} diff --git a/vendor/league/flysystem/deprecations.md b/vendor/league/flysystem/deprecations.md new file mode 100644 index 000000000..c336a425d --- /dev/null +++ b/vendor/league/flysystem/deprecations.md @@ -0,0 +1,19 @@ +# Deprecations + +This document lists all the planned deprecations. + +## Handlers will be removed in 2.0 + +The `Handler` type and associated calls will be removed in version 2.0. + +### Upgrade path + +You should create your own implementation for handling OOP usage, +but it's recommended to move away from using an OOP-style wrapper entirely. + +The reason for this is that it's too easy for implementation details (for +your application this is Flysystem) to leak into the application. The most +important part for Flysystem is that it improves portability and creates a +solid boundary between your application core and the infrastructure you use. +The OOP-style handling breaks this principle, therefore I want to stop +promoting it. diff --git a/vendor/league/flysystem/src/Adapter/AbstractAdapter.php b/vendor/league/flysystem/src/Adapter/AbstractAdapter.php new file mode 100644 index 000000000..e577ac4a7 --- /dev/null +++ b/vendor/league/flysystem/src/Adapter/AbstractAdapter.php @@ -0,0 +1,72 @@ +pathPrefix = null; + + return; + } + + $this->pathPrefix = rtrim($prefix, '\\/') . $this->pathSeparator; + } + + /** + * Get the path prefix. + * + * @return string|null path prefix or null if pathPrefix is empty + */ + public function getPathPrefix() + { + return $this->pathPrefix; + } + + /** + * Prefix a path. + * + * @param string $path + * + * @return string prefixed path + */ + public function applyPathPrefix($path) + { + return $this->getPathPrefix() . ltrim($path, '\\/'); + } + + /** + * Remove a path prefix. + * + * @param string $path + * + * @return string path without the prefix + */ + public function removePathPrefix($path) + { + return substr($path, strlen($this->getPathPrefix())); + } +} diff --git a/vendor/league/flysystem/src/Adapter/AbstractFtpAdapter.php b/vendor/league/flysystem/src/Adapter/AbstractFtpAdapter.php new file mode 100644 index 000000000..b232cdc4b --- /dev/null +++ b/vendor/league/flysystem/src/Adapter/AbstractFtpAdapter.php @@ -0,0 +1,705 @@ +safeStorage = new SafeStorage(); + $this->setConfig($config); + } + + /** + * Set the config. + * + * @param array $config + * + * @return $this + */ + public function setConfig(array $config) + { + foreach ($this->configurable as $setting) { + if ( ! isset($config[$setting])) { + continue; + } + + $method = 'set' . ucfirst($setting); + + if (method_exists($this, $method)) { + $this->$method($config[$setting]); + } + } + + return $this; + } + + /** + * Returns the host. + * + * @return string + */ + public function getHost() + { + return $this->host; + } + + /** + * Set the host. + * + * @param string $host + * + * @return $this + */ + public function setHost($host) + { + $this->host = $host; + + return $this; + } + + /** + * Set the public permission value. + * + * @param int $permPublic + * + * @return $this + */ + public function setPermPublic($permPublic) + { + $this->permPublic = $permPublic; + + return $this; + } + + /** + * Set the private permission value. + * + * @param int $permPrivate + * + * @return $this + */ + public function setPermPrivate($permPrivate) + { + $this->permPrivate = $permPrivate; + + return $this; + } + + /** + * Returns the ftp port. + * + * @return int + */ + public function getPort() + { + return $this->port; + } + + /** + * Returns the root folder to work from. + * + * @return string + */ + public function getRoot() + { + return $this->root; + } + + /** + * Set the ftp port. + * + * @param int|string $port + * + * @return $this + */ + public function setPort($port) + { + $this->port = (int) $port; + + return $this; + } + + /** + * Set the root folder to work from. + * + * @param string $root + * + * @return $this + */ + public function setRoot($root) + { + $this->root = rtrim($root, '\\/') . $this->separator; + + return $this; + } + + /** + * Returns the ftp username. + * + * @return string username + */ + public function getUsername() + { + $username = $this->safeStorage->retrieveSafely('username'); + + return $username !== null ? $username : 'anonymous'; + } + + /** + * Set ftp username. + * + * @param string $username + * + * @return $this + */ + public function setUsername($username) + { + $this->safeStorage->storeSafely('username', $username); + + return $this; + } + + /** + * Returns the password. + * + * @return string password + */ + public function getPassword() + { + return $this->safeStorage->retrieveSafely('password'); + } + + /** + * Set the ftp password. + * + * @param string $password + * + * @return $this + */ + public function setPassword($password) + { + $this->safeStorage->storeSafely('password', $password); + + return $this; + } + + /** + * Returns the amount of seconds before the connection will timeout. + * + * @return int + */ + public function getTimeout() + { + return $this->timeout; + } + + /** + * Set the amount of seconds before the connection should timeout. + * + * @param int $timeout + * + * @return $this + */ + public function setTimeout($timeout) + { + $this->timeout = (int) $timeout; + + return $this; + } + + /** + * Return the FTP system type. + * + * @return string + */ + public function getSystemType() + { + return $this->systemType; + } + + /** + * Set the FTP system type (windows or unix). + * + * @param string $systemType + * + * @return $this + */ + public function setSystemType($systemType) + { + $this->systemType = strtolower($systemType); + + return $this; + } + + /** + * True to enable timestamps for FTP servers that return unix-style listings. + * + * @param bool $bool + * + * @return $this + */ + public function setEnableTimestampsOnUnixListings($bool = false) + { + $this->enableTimestampsOnUnixListings = $bool; + + return $this; + } + + /** + * @inheritdoc + */ + public function listContents($directory = '', $recursive = false) + { + return $this->listDirectoryContents($directory, $recursive); + } + + abstract protected function listDirectoryContents($directory, $recursive = false); + + /** + * Normalize a directory listing. + * + * @param array $listing + * @param string $prefix + * + * @return array directory listing + */ + protected function normalizeListing(array $listing, $prefix = '') + { + $base = $prefix; + $result = []; + $listing = $this->removeDotDirectories($listing); + + while ($item = array_shift($listing)) { + if (preg_match('#^.*:$#', $item)) { + $base = preg_replace('~^\./*|:$~', '', $item); + continue; + } + + $result[] = $this->normalizeObject($item, $base); + } + + return $this->sortListing($result); + } + + /** + * Sort a directory listing. + * + * @param array $result + * + * @return array sorted listing + */ + protected function sortListing(array $result) + { + $compare = function ($one, $two) { + return strnatcmp($one['path'], $two['path']); + }; + + usort($result, $compare); + + return $result; + } + + /** + * Normalize a file entry. + * + * @param string $item + * @param string $base + * + * @return array normalized file array + * + * @throws NotSupportedException + */ + protected function normalizeObject($item, $base) + { + $systemType = $this->systemType ?: $this->detectSystemType($item); + + if ($systemType === 'unix') { + return $this->normalizeUnixObject($item, $base); + } elseif ($systemType === 'windows') { + return $this->normalizeWindowsObject($item, $base); + } + + throw NotSupportedException::forFtpSystemType($systemType); + } + + /** + * Normalize a Unix file entry. + * + * Given $item contains: + * '-rw-r--r-- 1 ftp ftp 409 Aug 19 09:01 file1.txt' + * + * This function will return: + * [ + * 'type' => 'file', + * 'path' => 'file1.txt', + * 'visibility' => 'public', + * 'size' => 409, + * 'timestamp' => 1566205260 + * ] + * + * @param string $item + * @param string $base + * + * @return array normalized file array + */ + protected function normalizeUnixObject($item, $base) + { + $item = preg_replace('#\s+#', ' ', trim($item), 7); + + if (count(explode(' ', $item, 9)) !== 9) { + throw new RuntimeException("Metadata can't be parsed from item '$item' , not enough parts."); + } + + list($permissions, /* $number */, /* $owner */, /* $group */, $size, $month, $day, $timeOrYear, $name) = explode(' ', $item, 9); + $type = $this->detectType($permissions); + $path = $base === '' ? $name : $base . $this->separator . $name; + + if ($type === 'dir') { + $result = compact('type', 'path'); + if ($this->enableTimestampsOnUnixListings) { + $timestamp = $this->normalizeUnixTimestamp($month, $day, $timeOrYear); + $result += compact('timestamp'); + } + + return $result; + } + + $permissions = $this->normalizePermissions($permissions); + $visibility = $permissions & 0044 ? AdapterInterface::VISIBILITY_PUBLIC : AdapterInterface::VISIBILITY_PRIVATE; + $size = (int) $size; + + $result = compact('type', 'path', 'visibility', 'size'); + if ($this->enableTimestampsOnUnixListings) { + $timestamp = $this->normalizeUnixTimestamp($month, $day, $timeOrYear); + $result += compact('timestamp'); + } + + return $result; + } + + /** + * Only accurate to the minute (current year), or to the day. + * + * Inadequacies in timestamp accuracy are due to limitations of the FTP 'LIST' command + * + * Note: The 'MLSD' command is a machine-readable replacement for 'LIST' + * but many FTP servers do not support it :( + * + * @param string $month e.g. 'Aug' + * @param string $day e.g. '19' + * @param string $timeOrYear e.g. '09:01' OR '2015' + * + * @return int + */ + protected function normalizeUnixTimestamp($month, $day, $timeOrYear) + { + if (is_numeric($timeOrYear)) { + $year = $timeOrYear; + $hour = '00'; + $minute = '00'; + $seconds = '00'; + } else { + $year = date('Y'); + list($hour, $minute) = explode(':', $timeOrYear); + $seconds = '00'; + } + $dateTime = DateTime::createFromFormat('Y-M-j-G:i:s', "{$year}-{$month}-{$day}-{$hour}:{$minute}:{$seconds}"); + + return $dateTime->getTimestamp(); + } + + /** + * Normalize a Windows/DOS file entry. + * + * @param string $item + * @param string $base + * + * @return array normalized file array + */ + protected function normalizeWindowsObject($item, $base) + { + $item = preg_replace('#\s+#', ' ', trim($item), 3); + + if (count(explode(' ', $item, 4)) !== 4) { + throw new RuntimeException("Metadata can't be parsed from item '$item' , not enough parts."); + } + + list($date, $time, $size, $name) = explode(' ', $item, 4); + $path = $base === '' ? $name : $base . $this->separator . $name; + + // Check for the correct date/time format + $format = strlen($date) === 8 ? 'm-d-yH:iA' : 'Y-m-dH:i'; + $dt = DateTime::createFromFormat($format, $date . $time); + $timestamp = $dt ? $dt->getTimestamp() : (int) strtotime("$date $time"); + + if ($size === '') { + $type = 'dir'; + + return compact('type', 'path', 'timestamp'); + } + + $type = 'file'; + $visibility = AdapterInterface::VISIBILITY_PUBLIC; + $size = (int) $size; + + return compact('type', 'path', 'visibility', 'size', 'timestamp'); + } + + /** + * Get the system type from a listing item. + * + * @param string $item + * + * @return string the system type + */ + protected function detectSystemType($item) + { + return preg_match('/^[0-9]{2,4}-[0-9]{2}-[0-9]{2}/', $item) ? 'windows' : 'unix'; + } + + /** + * Get the file type from the permissions. + * + * @param string $permissions + * + * @return string file type + */ + protected function detectType($permissions) + { + return substr($permissions, 0, 1) === 'd' ? 'dir' : 'file'; + } + + /** + * Normalize a permissions string. + * + * @param string $permissions + * + * @return int + */ + protected function normalizePermissions($permissions) + { + if (is_numeric($permissions)) { + return ((int) $permissions) & 0777; + } + + // remove the type identifier + $permissions = substr($permissions, 1); + + // map the string rights to the numeric counterparts + $map = ['-' => '0', 'r' => '4', 'w' => '2', 'x' => '1']; + $permissions = strtr($permissions, $map); + + // split up the permission groups + $parts = str_split($permissions, 3); + + // convert the groups + $mapper = function ($part) { + return array_sum(str_split($part)); + }; + + // converts to decimal number + return octdec(implode('', array_map($mapper, $parts))); + } + + /** + * Filter out dot-directories. + * + * @param array $list + * + * @return array + */ + public function removeDotDirectories(array $list) + { + $filter = function ($line) { + return $line !== '' && ! preg_match('#.* \.(\.)?$|^total#', $line); + }; + + return array_filter($list, $filter); + } + + /** + * @inheritdoc + */ + public function has($path) + { + return $this->getMetadata($path); + } + + /** + * @inheritdoc + */ + public function getSize($path) + { + return $this->getMetadata($path); + } + + /** + * @inheritdoc + */ + public function getVisibility($path) + { + return $this->getMetadata($path); + } + + /** + * Ensure a directory exists. + * + * @param string $dirname + */ + public function ensureDirectory($dirname) + { + $dirname = (string) $dirname; + + if ($dirname !== '' && ! $this->has($dirname)) { + $this->createDir($dirname, new Config()); + } + } + + /** + * @return mixed + */ + public function getConnection() + { + if ( ! $this->isConnected()) { + $this->disconnect(); + $this->connect(); + } + + return $this->connection; + } + + /** + * Get the public permission value. + * + * @return int + */ + public function getPermPublic() + { + return $this->permPublic; + } + + /** + * Get the private permission value. + * + * @return int + */ + public function getPermPrivate() + { + return $this->permPrivate; + } + + /** + * Disconnect on destruction. + */ + public function __destruct() + { + $this->disconnect(); + } + + /** + * Establish a connection. + */ + abstract public function connect(); + + /** + * Close the connection. + */ + abstract public function disconnect(); + + /** + * Check if a connection is active. + * + * @return bool + */ + abstract public function isConnected(); + + protected function escapePath($path) + { + return str_replace(['*', '[', ']'], ['\\*', '\\[', '\\]'], $path); + } +} diff --git a/vendor/league/flysystem/src/Adapter/CanOverwriteFiles.php b/vendor/league/flysystem/src/Adapter/CanOverwriteFiles.php new file mode 100644 index 000000000..fd8d2161e --- /dev/null +++ b/vendor/league/flysystem/src/Adapter/CanOverwriteFiles.php @@ -0,0 +1,12 @@ +transferMode = $mode; + + return $this; + } + + /** + * Set if Ssl is enabled. + * + * @param bool $ssl + * + * @return $this + */ + public function setSsl($ssl) + { + $this->ssl = (bool) $ssl; + + return $this; + } + + /** + * Set if passive mode should be used. + * + * @param bool $passive + */ + public function setPassive($passive = true) + { + $this->passive = $passive; + } + + /** + * @param bool $ignorePassiveAddress + */ + public function setIgnorePassiveAddress($ignorePassiveAddress) + { + $this->ignorePassiveAddress = $ignorePassiveAddress; + } + + /** + * @param bool $recurseManually + */ + public function setRecurseManually($recurseManually) + { + $this->recurseManually = $recurseManually; + } + + /** + * @param bool $utf8 + */ + public function setUtf8($utf8) + { + $this->utf8 = (bool) $utf8; + } + + /** + * Connect to the FTP server. + */ + public function connect() + { + $tries = 3; + start_connecting: + + if ($this->ssl) { + $this->connection = @ftp_ssl_connect($this->getHost(), $this->getPort(), $this->getTimeout()); + } else { + $this->connection = @ftp_connect($this->getHost(), $this->getPort(), $this->getTimeout()); + } + + if ( ! $this->connection) { + $tries--; + + if ($tries > 0) goto start_connecting; + + throw new ConnectionRuntimeException('Could not connect to host: ' . $this->getHost() . ', port:' . $this->getPort()); + } + + $this->login(); + $this->setUtf8Mode(); + $this->setConnectionPassiveMode(); + $this->setConnectionRoot(); + $this->isPureFtpd = $this->isPureFtpdServer(); + } + + /** + * Set the connection to UTF-8 mode. + */ + protected function setUtf8Mode() + { + if ($this->utf8) { + $response = ftp_raw($this->connection, "OPTS UTF8 ON"); + if (substr($response[0], 0, 3) !== '200') { + throw new ConnectionRuntimeException( + 'Could not set UTF-8 mode for connection: ' . $this->getHost() . '::' . $this->getPort() + ); + } + } + } + + /** + * Set the connections to passive mode. + * + * @throws ConnectionRuntimeException + */ + protected function setConnectionPassiveMode() + { + if (is_bool($this->ignorePassiveAddress) && defined('FTP_USEPASVADDRESS')) { + ftp_set_option($this->connection, FTP_USEPASVADDRESS, ! $this->ignorePassiveAddress); + } + + if ( ! ftp_pasv($this->connection, $this->passive)) { + throw new ConnectionRuntimeException( + 'Could not set passive mode for connection: ' . $this->getHost() . '::' . $this->getPort() + ); + } + } + + /** + * Set the connection root. + */ + protected function setConnectionRoot() + { + $root = $this->getRoot(); + $connection = $this->connection; + + if ($root && ! ftp_chdir($connection, $root)) { + throw new InvalidRootException('Root is invalid or does not exist: ' . $this->getRoot()); + } + + // Store absolute path for further reference. + // This is needed when creating directories and + // initial root was a relative path, else the root + // would be relative to the chdir'd path. + $this->root = ftp_pwd($connection); + } + + /** + * Login. + * + * @throws ConnectionRuntimeException + */ + protected function login() + { + set_error_handler(function () { + }); + $isLoggedIn = ftp_login( + $this->connection, + $this->getUsername(), + $this->getPassword() + ); + restore_error_handler(); + + if ( ! $isLoggedIn) { + $this->disconnect(); + throw new ConnectionRuntimeException( + 'Could not login with connection: ' . $this->getHost() . '::' . $this->getPort( + ) . ', username: ' . $this->getUsername() + ); + } + } + + /** + * Disconnect from the FTP server. + */ + public function disconnect() + { + if (is_resource($this->connection)) { + @ftp_close($this->connection); + } + + $this->connection = null; + } + + /** + * @inheritdoc + */ + public function write($path, $contents, Config $config) + { + $stream = fopen('php://temp', 'w+b'); + fwrite($stream, $contents); + rewind($stream); + $result = $this->writeStream($path, $stream, $config); + fclose($stream); + + if ($result === false) { + return false; + } + + $result['contents'] = $contents; + $result['mimetype'] = $config->get('mimetype') ?: Util::guessMimeType($path, $contents); + + return $result; + } + + /** + * @inheritdoc + */ + public function writeStream($path, $resource, Config $config) + { + $this->ensureDirectory(Util::dirname($path)); + + if ( ! ftp_fput($this->getConnection(), $path, $resource, $this->transferMode)) { + return false; + } + + if ($visibility = $config->get('visibility')) { + $this->setVisibility($path, $visibility); + } + + $type = 'file'; + + return compact('type', 'path', 'visibility'); + } + + /** + * @inheritdoc + */ + public function update($path, $contents, Config $config) + { + return $this->write($path, $contents, $config); + } + + /** + * @inheritdoc + */ + public function updateStream($path, $resource, Config $config) + { + return $this->writeStream($path, $resource, $config); + } + + /** + * @inheritdoc + */ + public function rename($path, $newpath) + { + return ftp_rename($this->getConnection(), $path, $newpath); + } + + /** + * @inheritdoc + */ + public function delete($path) + { + return ftp_delete($this->getConnection(), $path); + } + + /** + * @inheritdoc + */ + public function deleteDir($dirname) + { + $connection = $this->getConnection(); + $contents = array_reverse($this->listDirectoryContents($dirname, false)); + + foreach ($contents as $object) { + if ($object['type'] === 'file') { + if ( ! ftp_delete($connection, $object['path'])) { + return false; + } + } elseif ( ! $this->deleteDir($object['path'])) { + return false; + } + } + + return ftp_rmdir($connection, $dirname); + } + + /** + * @inheritdoc + */ + public function createDir($dirname, Config $config) + { + $connection = $this->getConnection(); + $directories = explode('/', $dirname); + + foreach ($directories as $directory) { + if (false === $this->createActualDirectory($directory, $connection)) { + $this->setConnectionRoot(); + + return false; + } + + ftp_chdir($connection, $directory); + } + + $this->setConnectionRoot(); + + return ['type' => 'dir', 'path' => $dirname]; + } + + /** + * Create a directory. + * + * @param string $directory + * @param resource $connection + * + * @return bool + */ + protected function createActualDirectory($directory, $connection) + { + // List the current directory + $listing = ftp_nlist($connection, '.') ?: []; + + foreach ($listing as $key => $item) { + if (preg_match('~^\./.*~', $item)) { + $listing[$key] = substr($item, 2); + } + } + + if (in_array($directory, $listing, true)) { + return true; + } + + return (boolean) ftp_mkdir($connection, $directory); + } + + /** + * @inheritdoc + */ + public function getMetadata($path) + { + if ($path === '') { + return ['type' => 'dir', 'path' => '']; + } + + if (@ftp_chdir($this->getConnection(), $path) === true) { + $this->setConnectionRoot(); + + return ['type' => 'dir', 'path' => $path]; + } + + $listing = $this->ftpRawlist('-A', $path); + + if (empty($listing) || in_array('total 0', $listing, true)) { + return false; + } + + if (preg_match('/.* not found/', $listing[0])) { + return false; + } + + if (preg_match('/^total [0-9]*$/', $listing[0])) { + array_shift($listing); + } + + return $this->normalizeObject($listing[0], ''); + } + + /** + * @inheritdoc + */ + public function getMimetype($path) + { + if ( ! $metadata = $this->getMetadata($path)) { + return false; + } + + $metadata['mimetype'] = MimeType::detectByFilename($path); + + return $metadata; + } + + /** + * @inheritdoc + */ + public function getTimestamp($path) + { + $timestamp = ftp_mdtm($this->getConnection(), $path); + + return ($timestamp !== -1) ? ['path' => $path, 'timestamp' => $timestamp] : false; + } + + /** + * @inheritdoc + */ + public function read($path) + { + if ( ! $object = $this->readStream($path)) { + return false; + } + + $object['contents'] = stream_get_contents($object['stream']); + fclose($object['stream']); + unset($object['stream']); + + return $object; + } + + /** + * @inheritdoc + */ + public function readStream($path) + { + $stream = fopen('php://temp', 'w+b'); + $result = ftp_fget($this->getConnection(), $stream, $path, $this->transferMode); + rewind($stream); + + if ( ! $result) { + fclose($stream); + + return false; + } + + return ['type' => 'file', 'path' => $path, 'stream' => $stream]; + } + + /** + * @inheritdoc + */ + public function setVisibility($path, $visibility) + { + $mode = $visibility === AdapterInterface::VISIBILITY_PUBLIC ? $this->getPermPublic() : $this->getPermPrivate(); + + if ( ! ftp_chmod($this->getConnection(), $mode, $path)) { + return false; + } + + return compact('path', 'visibility'); + } + + /** + * @inheritdoc + * + * @param string $directory + */ + protected function listDirectoryContents($directory, $recursive = true) + { + if ($recursive && $this->recurseManually) { + return $this->listDirectoryContentsRecursive($directory); + } + + $options = $recursive ? '-alnR' : '-aln'; + $listing = $this->ftpRawlist($options, $directory); + + return $listing ? $this->normalizeListing($listing, $directory) : []; + } + + /** + * @inheritdoc + * + * @param string $directory + */ + protected function listDirectoryContentsRecursive($directory) + { + $listing = $this->normalizeListing($this->ftpRawlist('-aln', $directory) ?: [], $directory); + $output = []; + + foreach ($listing as $item) { + $output[] = $item; + if ($item['type'] !== 'dir') { + continue; + } + $output = array_merge($output, $this->listDirectoryContentsRecursive($item['path'])); + } + + return $output; + } + + /** + * Check if the connection is open. + * + * @return bool + * + * @throws ConnectionErrorException + */ + public function isConnected() + { + return is_resource($this->connection) + && $this->getRawExecResponseCode('NOOP') === 200; + } + + /** + * @return bool + */ + protected function isPureFtpdServer() + { + $response = ftp_raw($this->connection, 'HELP'); + + return stripos(implode(' ', $response), 'Pure-FTPd') !== false; + } + + /** + * The ftp_rawlist function with optional escaping. + * + * @param string $options + * @param string $path + * + * @return array + */ + protected function ftpRawlist($options, $path) + { + $connection = $this->getConnection(); + + if ($this->isPureFtpd) { + $path = str_replace(' ', '\ ', $path); + $this->escapePath($path); + } + + return ftp_rawlist($connection, $options . ' ' . $path); + } + + private function getRawExecResponseCode($command) + { + $response = @ftp_raw($this->connection, trim($command)); + + return (int) preg_replace('/\D/', '', implode(' ', $response)); + } +} diff --git a/vendor/league/flysystem/src/Adapter/Ftpd.php b/vendor/league/flysystem/src/Adapter/Ftpd.php new file mode 100644 index 000000000..7e71d19f6 --- /dev/null +++ b/vendor/league/flysystem/src/Adapter/Ftpd.php @@ -0,0 +1,48 @@ + 'dir', 'path' => '']; + } + + if (@ftp_chdir($this->getConnection(), $path) === true) { + $this->setConnectionRoot(); + + return ['type' => 'dir', 'path' => $path]; + } + + $object = ftp_raw($this->getConnection(), 'STAT ' . $this->escapePath($path)); + + if ( ! $object || count($object) < 3) { + return false; + } + + if (substr($object[1], 0, 5) === "ftpd:") { + return false; + } + + return $this->normalizeObject($object[1], ''); + } + + /** + * @inheritdoc + */ + protected function listDirectoryContents($directory, $recursive = true) + { + $listing = ftp_rawlist($this->getConnection(), $this->escapePath($directory), $recursive); + + if ($listing === false || ( ! empty($listing) && substr($listing[0], 0, 5) === "ftpd:")) { + return []; + } + + return $this->normalizeListing($listing, $directory); + } +} diff --git a/vendor/league/flysystem/src/Adapter/Local.php b/vendor/league/flysystem/src/Adapter/Local.php new file mode 100644 index 000000000..747c463ec --- /dev/null +++ b/vendor/league/flysystem/src/Adapter/Local.php @@ -0,0 +1,533 @@ + [ + 'public' => 0644, + 'private' => 0600, + ], + 'dir' => [ + 'public' => 0755, + 'private' => 0700, + ], + ]; + + /** + * @var string + */ + protected $pathSeparator = DIRECTORY_SEPARATOR; + + /** + * @var array + */ + protected $permissionMap; + + /** + * @var int + */ + protected $writeFlags; + + /** + * @var int + */ + private $linkHandling; + + /** + * Constructor. + * + * @param string $root + * @param int $writeFlags + * @param int $linkHandling + * @param array $permissions + * + * @throws LogicException + */ + public function __construct($root, $writeFlags = LOCK_EX, $linkHandling = self::DISALLOW_LINKS, array $permissions = []) + { + $root = is_link($root) ? realpath($root) : $root; + $this->permissionMap = array_replace_recursive(static::$permissions, $permissions); + $this->ensureDirectory($root); + + if ( ! is_dir($root) || ! is_readable($root)) { + throw new LogicException('The root path ' . $root . ' is not readable.'); + } + + $this->setPathPrefix($root); + $this->writeFlags = $writeFlags; + $this->linkHandling = $linkHandling; + } + + /** + * Ensure the root directory exists. + * + * @param string $root root directory path + * + * @return void + * + * @throws Exception in case the root directory can not be created + */ + protected function ensureDirectory($root) + { + if ( ! is_dir($root)) { + $umask = umask(0); + + if ( ! @mkdir($root, $this->permissionMap['dir']['public'], true)) { + $mkdirError = error_get_last(); + } + + umask($umask); + clearstatcache(false, $root); + + if ( ! is_dir($root)) { + $errorMessage = isset($mkdirError['message']) ? $mkdirError['message'] : ''; + throw new Exception(sprintf('Impossible to create the root directory "%s". %s', $root, $errorMessage)); + } + } + } + + /** + * @inheritdoc + */ + public function has($path) + { + $location = $this->applyPathPrefix($path); + + return file_exists($location); + } + + /** + * @inheritdoc + */ + public function write($path, $contents, Config $config) + { + $location = $this->applyPathPrefix($path); + $this->ensureDirectory(dirname($location)); + + if (($size = file_put_contents($location, $contents, $this->writeFlags)) === false) { + return false; + } + + $type = 'file'; + $result = compact('contents', 'type', 'size', 'path'); + + if ($visibility = $config->get('visibility')) { + $result['visibility'] = $visibility; + $this->setVisibility($path, $visibility); + } + + return $result; + } + + /** + * @inheritdoc + */ + public function writeStream($path, $resource, Config $config) + { + $location = $this->applyPathPrefix($path); + $this->ensureDirectory(dirname($location)); + $stream = fopen($location, 'w+b'); + + if ( ! $stream || stream_copy_to_stream($resource, $stream) === false || ! fclose($stream)) { + return false; + } + + $type = 'file'; + $result = compact('type', 'path'); + + if ($visibility = $config->get('visibility')) { + $this->setVisibility($path, $visibility); + $result['visibility'] = $visibility; + } + + return $result; + } + + /** + * @inheritdoc + */ + public function readStream($path) + { + $location = $this->applyPathPrefix($path); + $stream = fopen($location, 'rb'); + + return ['type' => 'file', 'path' => $path, 'stream' => $stream]; + } + + /** + * @inheritdoc + */ + public function updateStream($path, $resource, Config $config) + { + return $this->writeStream($path, $resource, $config); + } + + /** + * @inheritdoc + */ + public function update($path, $contents, Config $config) + { + $location = $this->applyPathPrefix($path); + $size = file_put_contents($location, $contents, $this->writeFlags); + + if ($size === false) { + return false; + } + + $type = 'file'; + + $result = compact('type', 'path', 'size', 'contents'); + + if ($visibility = $config->get('visibility')) { + $this->setVisibility($path, $visibility); + $result['visibility'] = $visibility; + } + + return $result; + } + + /** + * @inheritdoc + */ + public function read($path) + { + $location = $this->applyPathPrefix($path); + $contents = @file_get_contents($location); + + if ($contents === false) { + return false; + } + + return ['type' => 'file', 'path' => $path, 'contents' => $contents]; + } + + /** + * @inheritdoc + */ + public function rename($path, $newpath) + { + $location = $this->applyPathPrefix($path); + $destination = $this->applyPathPrefix($newpath); + $parentDirectory = $this->applyPathPrefix(Util::dirname($newpath)); + $this->ensureDirectory($parentDirectory); + + return rename($location, $destination); + } + + /** + * @inheritdoc + */ + public function copy($path, $newpath) + { + $location = $this->applyPathPrefix($path); + $destination = $this->applyPathPrefix($newpath); + $this->ensureDirectory(dirname($destination)); + + return copy($location, $destination); + } + + /** + * @inheritdoc + */ + public function delete($path) + { + $location = $this->applyPathPrefix($path); + + return @unlink($location); + } + + /** + * @inheritdoc + */ + public function listContents($directory = '', $recursive = false) + { + $result = []; + $location = $this->applyPathPrefix($directory); + + if ( ! is_dir($location)) { + return []; + } + + $iterator = $recursive ? $this->getRecursiveDirectoryIterator($location) : $this->getDirectoryIterator($location); + + foreach ($iterator as $file) { + $path = $this->getFilePath($file); + + if (preg_match('#(^|/|\\\\)\.{1,2}$#', $path)) { + continue; + } + + $result[] = $this->normalizeFileInfo($file); + } + + unset($iterator); + + return array_filter($result); + } + + /** + * @inheritdoc + */ + public function getMetadata($path) + { + $location = $this->applyPathPrefix($path); + clearstatcache(false, $location); + $info = new SplFileInfo($location); + + return $this->normalizeFileInfo($info); + } + + /** + * @inheritdoc + */ + public function getSize($path) + { + return $this->getMetadata($path); + } + + /** + * @inheritdoc + */ + public function getMimetype($path) + { + $location = $this->applyPathPrefix($path); + $finfo = new Finfo(FILEINFO_MIME_TYPE); + $mimetype = $finfo->file($location); + + if (in_array($mimetype, ['application/octet-stream', 'inode/x-empty', 'application/x-empty'])) { + $mimetype = Util\MimeType::detectByFilename($location); + } + + return ['path' => $path, 'type' => 'file', 'mimetype' => $mimetype]; + } + + /** + * @inheritdoc + */ + public function getTimestamp($path) + { + return $this->getMetadata($path); + } + + /** + * @inheritdoc + */ + public function getVisibility($path) + { + $location = $this->applyPathPrefix($path); + clearstatcache(false, $location); + $permissions = octdec(substr(sprintf('%o', fileperms($location)), -4)); + $type = is_dir($location) ? 'dir' : 'file'; + + foreach ($this->permissionMap[$type] as $visibility => $visibilityPermissions) { + if ($visibilityPermissions == $permissions) { + return compact('path', 'visibility'); + } + } + + $visibility = substr(sprintf('%o', fileperms($location)), -4); + + return compact('path', 'visibility'); + } + + /** + * @inheritdoc + */ + public function setVisibility($path, $visibility) + { + $location = $this->applyPathPrefix($path); + $type = is_dir($location) ? 'dir' : 'file'; + $success = chmod($location, $this->permissionMap[$type][$visibility]); + + if ($success === false) { + return false; + } + + return compact('path', 'visibility'); + } + + /** + * @inheritdoc + */ + public function createDir($dirname, Config $config) + { + $location = $this->applyPathPrefix($dirname); + $umask = umask(0); + $visibility = $config->get('visibility', 'public'); + $return = ['path' => $dirname, 'type' => 'dir']; + + if ( ! is_dir($location)) { + if (false === @mkdir($location, $this->permissionMap['dir'][$visibility], true) + || false === is_dir($location)) { + $return = false; + } + } + + umask($umask); + + return $return; + } + + /** + * @inheritdoc + */ + public function deleteDir($dirname) + { + $location = $this->applyPathPrefix($dirname); + + if ( ! is_dir($location)) { + return false; + } + + $contents = $this->getRecursiveDirectoryIterator($location, RecursiveIteratorIterator::CHILD_FIRST); + + /** @var SplFileInfo $file */ + foreach ($contents as $file) { + $this->guardAgainstUnreadableFileInfo($file); + $this->deleteFileInfoObject($file); + } + + unset($contents); + + return rmdir($location); + } + + /** + * @param SplFileInfo $file + */ + protected function deleteFileInfoObject(SplFileInfo $file) + { + switch ($file->getType()) { + case 'dir': + rmdir($file->getRealPath()); + break; + case 'link': + unlink($file->getPathname()); + break; + default: + unlink($file->getRealPath()); + } + } + + /** + * Normalize the file info. + * + * @param SplFileInfo $file + * + * @return array|void + * + * @throws NotSupportedException + */ + protected function normalizeFileInfo(SplFileInfo $file) + { + if ( ! $file->isLink()) { + return $this->mapFileInfo($file); + } + + if ($this->linkHandling & self::DISALLOW_LINKS) { + throw NotSupportedException::forLink($file); + } + } + + /** + * Get the normalized path from a SplFileInfo object. + * + * @param SplFileInfo $file + * + * @return string + */ + protected function getFilePath(SplFileInfo $file) + { + $location = $file->getPathname(); + $path = $this->removePathPrefix($location); + + return trim(str_replace('\\', '/', $path), '/'); + } + + /** + * @param string $path + * @param int $mode + * + * @return RecursiveIteratorIterator + */ + protected function getRecursiveDirectoryIterator($path, $mode = RecursiveIteratorIterator::SELF_FIRST) + { + return new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS), + $mode + ); + } + + /** + * @param string $path + * + * @return DirectoryIterator + */ + protected function getDirectoryIterator($path) + { + $iterator = new DirectoryIterator($path); + + return $iterator; + } + + /** + * @param SplFileInfo $file + * + * @return array + */ + protected function mapFileInfo(SplFileInfo $file) + { + $normalized = [ + 'type' => $file->getType(), + 'path' => $this->getFilePath($file), + ]; + + $normalized['timestamp'] = $file->getMTime(); + + if ($normalized['type'] === 'file') { + $normalized['size'] = $file->getSize(); + } + + return $normalized; + } + + /** + * @param SplFileInfo $file + * + * @throws UnreadableFileException + */ + protected function guardAgainstUnreadableFileInfo(SplFileInfo $file) + { + if ( ! $file->isReadable()) { + throw UnreadableFileException::forFileInfo($file); + } + } +} diff --git a/vendor/league/flysystem/src/Adapter/NullAdapter.php b/vendor/league/flysystem/src/Adapter/NullAdapter.php new file mode 100644 index 000000000..2527087f7 --- /dev/null +++ b/vendor/league/flysystem/src/Adapter/NullAdapter.php @@ -0,0 +1,144 @@ +get('visibility')) { + $result['visibility'] = $visibility; + } + + return $result; + } + + /** + * @inheritdoc + */ + public function update($path, $contents, Config $config) + { + return false; + } + + /** + * @inheritdoc + */ + public function read($path) + { + return false; + } + + /** + * @inheritdoc + */ + public function rename($path, $newpath) + { + return false; + } + + /** + * @inheritdoc + */ + public function delete($path) + { + return false; + } + + /** + * @inheritdoc + */ + public function listContents($directory = '', $recursive = false) + { + return []; + } + + /** + * @inheritdoc + */ + public function getMetadata($path) + { + return false; + } + + /** + * @inheritdoc + */ + public function getSize($path) + { + return false; + } + + /** + * @inheritdoc + */ + public function getMimetype($path) + { + return false; + } + + /** + * @inheritdoc + */ + public function getTimestamp($path) + { + return false; + } + + /** + * @inheritdoc + */ + public function getVisibility($path) + { + return false; + } + + /** + * @inheritdoc + */ + public function setVisibility($path, $visibility) + { + return compact('visibility'); + } + + /** + * @inheritdoc + */ + public function createDir($dirname, Config $config) + { + return ['path' => $dirname, 'type' => 'dir']; + } + + /** + * @inheritdoc + */ + public function deleteDir($dirname) + { + return false; + } +} diff --git a/vendor/league/flysystem/src/Adapter/Polyfill/NotSupportingVisibilityTrait.php b/vendor/league/flysystem/src/Adapter/Polyfill/NotSupportingVisibilityTrait.php new file mode 100644 index 000000000..fc0a747ac --- /dev/null +++ b/vendor/league/flysystem/src/Adapter/Polyfill/NotSupportingVisibilityTrait.php @@ -0,0 +1,33 @@ +readStream($path); + + if ($response === false || ! is_resource($response['stream'])) { + return false; + } + + $result = $this->writeStream($newpath, $response['stream'], new Config()); + + if ($result !== false && is_resource($response['stream'])) { + fclose($response['stream']); + } + + return $result !== false; + } + + // Required abstract method + + /** + * @param string $path + * + * @return resource + */ + abstract public function readStream($path); + + /** + * @param string $path + * @param resource $resource + * @param Config $config + * + * @return resource + */ + abstract public function writeStream($path, $resource, Config $config); +} diff --git a/vendor/league/flysystem/src/Adapter/Polyfill/StreamedReadingTrait.php b/vendor/league/flysystem/src/Adapter/Polyfill/StreamedReadingTrait.php new file mode 100644 index 000000000..2b31c01d6 --- /dev/null +++ b/vendor/league/flysystem/src/Adapter/Polyfill/StreamedReadingTrait.php @@ -0,0 +1,44 @@ +read($path)) { + return false; + } + + $stream = fopen('php://temp', 'w+b'); + fwrite($stream, $data['contents']); + rewind($stream); + $data['stream'] = $stream; + unset($data['contents']); + + return $data; + } + + /** + * Reads a file. + * + * @param string $path + * + * @return array|false + * + * @see League\Flysystem\ReadInterface::read() + */ + abstract public function read($path); +} diff --git a/vendor/league/flysystem/src/Adapter/Polyfill/StreamedTrait.php b/vendor/league/flysystem/src/Adapter/Polyfill/StreamedTrait.php new file mode 100644 index 000000000..80424960c --- /dev/null +++ b/vendor/league/flysystem/src/Adapter/Polyfill/StreamedTrait.php @@ -0,0 +1,9 @@ +stream($path, $resource, $config, 'write'); + } + + /** + * Update a file using a stream. + * + * @param string $path + * @param resource $resource + * @param Config $config Config object or visibility setting + * + * @return mixed false of file metadata + */ + public function updateStream($path, $resource, Config $config) + { + return $this->stream($path, $resource, $config, 'update'); + } + + // Required abstract methods + abstract public function write($pash, $contents, Config $config); + abstract public function update($pash, $contents, Config $config); +} diff --git a/vendor/league/flysystem/src/Adapter/SynologyFtp.php b/vendor/league/flysystem/src/Adapter/SynologyFtp.php new file mode 100644 index 000000000..fe0d344cf --- /dev/null +++ b/vendor/league/flysystem/src/Adapter/SynologyFtp.php @@ -0,0 +1,8 @@ +settings = $settings; + } + + /** + * Get a setting. + * + * @param string $key + * @param mixed $default + * + * @return mixed config setting or default when not found + */ + public function get($key, $default = null) + { + if ( ! array_key_exists($key, $this->settings)) { + return $this->getDefault($key, $default); + } + + return $this->settings[$key]; + } + + /** + * Check if an item exists by key. + * + * @param string $key + * + * @return bool + */ + public function has($key) + { + if (array_key_exists($key, $this->settings)) { + return true; + } + + return $this->fallback instanceof Config + ? $this->fallback->has($key) + : false; + } + + /** + * Try to retrieve a default setting from a config fallback. + * + * @param string $key + * @param mixed $default + * + * @return mixed config setting or default when not found + */ + protected function getDefault($key, $default) + { + if ( ! $this->fallback) { + return $default; + } + + return $this->fallback->get($key, $default); + } + + /** + * Set a setting. + * + * @param string $key + * @param mixed $value + * + * @return $this + */ + public function set($key, $value) + { + $this->settings[$key] = $value; + + return $this; + } + + /** + * Set the fallback. + * + * @param Config $fallback + * + * @return $this + */ + public function setFallback(Config $fallback) + { + $this->fallback = $fallback; + + return $this; + } +} diff --git a/vendor/league/flysystem/src/ConfigAwareTrait.php b/vendor/league/flysystem/src/ConfigAwareTrait.php new file mode 100644 index 000000000..202d605da --- /dev/null +++ b/vendor/league/flysystem/src/ConfigAwareTrait.php @@ -0,0 +1,49 @@ +config = $config ? Util::ensureConfig($config) : new Config; + } + + /** + * Get the Config. + * + * @return Config config object + */ + public function getConfig() + { + return $this->config; + } + + /** + * Convert a config array to a Config object with the correct fallback. + * + * @param array $config + * + * @return Config + */ + protected function prepareConfig(array $config) + { + $config = new Config($config); + $config->setFallback($this->getConfig()); + + return $config; + } +} diff --git a/vendor/league/flysystem/src/ConnectionErrorException.php b/vendor/league/flysystem/src/ConnectionErrorException.php new file mode 100644 index 000000000..adb651d3d --- /dev/null +++ b/vendor/league/flysystem/src/ConnectionErrorException.php @@ -0,0 +1,9 @@ +filesystem->deleteDir($this->path); + } + + /** + * List the directory contents. + * + * @param bool $recursive + * + * @return array|bool directory contents or false + */ + public function getContents($recursive = false) + { + return $this->filesystem->listContents($this->path, $recursive); + } +} diff --git a/vendor/league/flysystem/src/Exception.php b/vendor/league/flysystem/src/Exception.php new file mode 100644 index 000000000..4596c0a9a --- /dev/null +++ b/vendor/league/flysystem/src/Exception.php @@ -0,0 +1,8 @@ +filesystem->has($this->path); + } + + /** + * Read the file. + * + * @return string|false file contents + */ + public function read() + { + return $this->filesystem->read($this->path); + } + + /** + * Read the file as a stream. + * + * @return resource|false file stream + */ + public function readStream() + { + return $this->filesystem->readStream($this->path); + } + + /** + * Write the new file. + * + * @param string $content + * + * @return bool success boolean + */ + public function write($content) + { + return $this->filesystem->write($this->path, $content); + } + + /** + * Write the new file using a stream. + * + * @param resource $resource + * + * @return bool success boolean + */ + public function writeStream($resource) + { + return $this->filesystem->writeStream($this->path, $resource); + } + + /** + * Update the file contents. + * + * @param string $content + * + * @return bool success boolean + */ + public function update($content) + { + return $this->filesystem->update($this->path, $content); + } + + /** + * Update the file contents with a stream. + * + * @param resource $resource + * + * @return bool success boolean + */ + public function updateStream($resource) + { + return $this->filesystem->updateStream($this->path, $resource); + } + + /** + * Create the file or update if exists. + * + * @param string $content + * + * @return bool success boolean + */ + public function put($content) + { + return $this->filesystem->put($this->path, $content); + } + + /** + * Create the file or update if exists using a stream. + * + * @param resource $resource + * + * @return bool success boolean + */ + public function putStream($resource) + { + return $this->filesystem->putStream($this->path, $resource); + } + + /** + * Rename the file. + * + * @param string $newpath + * + * @return bool success boolean + */ + public function rename($newpath) + { + if ($this->filesystem->rename($this->path, $newpath)) { + $this->path = $newpath; + + return true; + } + + return false; + } + + /** + * Copy the file. + * + * @param string $newpath + * + * @return File|false new file or false + */ + public function copy($newpath) + { + if ($this->filesystem->copy($this->path, $newpath)) { + return new File($this->filesystem, $newpath); + } + + return false; + } + + /** + * Get the file's timestamp. + * + * @return string|false The timestamp or false on failure. + */ + public function getTimestamp() + { + return $this->filesystem->getTimestamp($this->path); + } + + /** + * Get the file's mimetype. + * + * @return string|false The file mime-type or false on failure. + */ + public function getMimetype() + { + return $this->filesystem->getMimetype($this->path); + } + + /** + * Get the file's visibility. + * + * @return string|false The visibility (public|private) or false on failure. + */ + public function getVisibility() + { + return $this->filesystem->getVisibility($this->path); + } + + /** + * Get the file's metadata. + * + * @return array|false The file metadata or false on failure. + */ + public function getMetadata() + { + return $this->filesystem->getMetadata($this->path); + } + + /** + * Get the file size. + * + * @return int|false The file size or false on failure. + */ + public function getSize() + { + return $this->filesystem->getSize($this->path); + } + + /** + * Delete the file. + * + * @return bool success boolean + */ + public function delete() + { + return $this->filesystem->delete($this->path); + } +} diff --git a/vendor/league/flysystem/src/FileExistsException.php b/vendor/league/flysystem/src/FileExistsException.php new file mode 100644 index 000000000..c82e20c16 --- /dev/null +++ b/vendor/league/flysystem/src/FileExistsException.php @@ -0,0 +1,37 @@ +path = $path; + + parent::__construct('File already exists at path: ' . $this->getPath(), $code, $previous); + } + + /** + * Get the path which was found. + * + * @return string + */ + public function getPath() + { + return $this->path; + } +} diff --git a/vendor/league/flysystem/src/FileNotFoundException.php b/vendor/league/flysystem/src/FileNotFoundException.php new file mode 100644 index 000000000..989df69bb --- /dev/null +++ b/vendor/league/flysystem/src/FileNotFoundException.php @@ -0,0 +1,37 @@ +path = $path; + + parent::__construct('File not found at path: ' . $this->getPath(), $code, $previous); + } + + /** + * Get the path which was not found. + * + * @return string + */ + public function getPath() + { + return $this->path; + } +} diff --git a/vendor/league/flysystem/src/Filesystem.php b/vendor/league/flysystem/src/Filesystem.php new file mode 100644 index 000000000..c4eaf2781 --- /dev/null +++ b/vendor/league/flysystem/src/Filesystem.php @@ -0,0 +1,409 @@ +adapter = $adapter; + $this->setConfig($config); + } + + /** + * Get the Adapter. + * + * @return AdapterInterface adapter + */ + public function getAdapter() + { + return $this->adapter; + } + + /** + * @inheritdoc + */ + public function has($path) + { + $path = Util::normalizePath($path); + + return strlen($path) === 0 ? false : (bool) $this->getAdapter()->has($path); + } + + /** + * @inheritdoc + */ + public function write($path, $contents, array $config = []) + { + $path = Util::normalizePath($path); + $this->assertAbsent($path); + $config = $this->prepareConfig($config); + + return (bool) $this->getAdapter()->write($path, $contents, $config); + } + + /** + * @inheritdoc + */ + public function writeStream($path, $resource, array $config = []) + { + if ( ! is_resource($resource) || get_resource_type($resource) !== 'stream') { + throw new InvalidArgumentException(__METHOD__ . ' expects argument #2 to be a valid resource.'); + } + + $path = Util::normalizePath($path); + $this->assertAbsent($path); + $config = $this->prepareConfig($config); + + Util::rewindStream($resource); + + return (bool) $this->getAdapter()->writeStream($path, $resource, $config); + } + + /** + * @inheritdoc + */ + public function put($path, $contents, array $config = []) + { + $path = Util::normalizePath($path); + $config = $this->prepareConfig($config); + + if ( ! $this->getAdapter() instanceof CanOverwriteFiles && $this->has($path)) { + return (bool) $this->getAdapter()->update($path, $contents, $config); + } + + return (bool) $this->getAdapter()->write($path, $contents, $config); + } + + /** + * @inheritdoc + */ + public function putStream($path, $resource, array $config = []) + { + if ( ! is_resource($resource) || get_resource_type($resource) !== 'stream') { + throw new InvalidArgumentException(__METHOD__ . ' expects argument #2 to be a valid resource.'); + } + + $path = Util::normalizePath($path); + $config = $this->prepareConfig($config); + Util::rewindStream($resource); + + if ( ! $this->getAdapter() instanceof CanOverwriteFiles && $this->has($path)) { + return (bool) $this->getAdapter()->updateStream($path, $resource, $config); + } + + return (bool) $this->getAdapter()->writeStream($path, $resource, $config); + } + + /** + * @inheritdoc + */ + public function readAndDelete($path) + { + $path = Util::normalizePath($path); + $this->assertPresent($path); + $contents = $this->read($path); + + if ($contents === false) { + return false; + } + + $this->delete($path); + + return $contents; + } + + /** + * @inheritdoc + */ + public function update($path, $contents, array $config = []) + { + $path = Util::normalizePath($path); + $config = $this->prepareConfig($config); + + $this->assertPresent($path); + + return (bool) $this->getAdapter()->update($path, $contents, $config); + } + + /** + * @inheritdoc + */ + public function updateStream($path, $resource, array $config = []) + { + if ( ! is_resource($resource) || get_resource_type($resource) !== 'stream') { + throw new InvalidArgumentException(__METHOD__ . ' expects argument #2 to be a valid resource.'); + } + + $path = Util::normalizePath($path); + $config = $this->prepareConfig($config); + $this->assertPresent($path); + Util::rewindStream($resource); + + return (bool) $this->getAdapter()->updateStream($path, $resource, $config); + } + + /** + * @inheritdoc + */ + public function read($path) + { + $path = Util::normalizePath($path); + $this->assertPresent($path); + + if ( ! ($object = $this->getAdapter()->read($path))) { + return false; + } + + return $object['contents']; + } + + /** + * @inheritdoc + */ + public function readStream($path) + { + $path = Util::normalizePath($path); + $this->assertPresent($path); + + if ( ! $object = $this->getAdapter()->readStream($path)) { + return false; + } + + return $object['stream']; + } + + /** + * @inheritdoc + */ + public function rename($path, $newpath) + { + $path = Util::normalizePath($path); + $newpath = Util::normalizePath($newpath); + $this->assertPresent($path); + $this->assertAbsent($newpath); + + return (bool) $this->getAdapter()->rename($path, $newpath); + } + + /** + * @inheritdoc + */ + public function copy($path, $newpath) + { + $path = Util::normalizePath($path); + $newpath = Util::normalizePath($newpath); + $this->assertPresent($path); + $this->assertAbsent($newpath); + + return $this->getAdapter()->copy($path, $newpath); + } + + /** + * @inheritdoc + */ + public function delete($path) + { + $path = Util::normalizePath($path); + $this->assertPresent($path); + + return $this->getAdapter()->delete($path); + } + + /** + * @inheritdoc + */ + public function deleteDir($dirname) + { + $dirname = Util::normalizePath($dirname); + + if ($dirname === '') { + throw new RootViolationException('Root directories can not be deleted.'); + } + + return (bool) $this->getAdapter()->deleteDir($dirname); + } + + /** + * @inheritdoc + */ + public function createDir($dirname, array $config = []) + { + $dirname = Util::normalizePath($dirname); + $config = $this->prepareConfig($config); + + return (bool) $this->getAdapter()->createDir($dirname, $config); + } + + /** + * @inheritdoc + */ + public function listContents($directory = '', $recursive = false) + { + $directory = Util::normalizePath($directory); + $contents = $this->getAdapter()->listContents($directory, $recursive); + + return (new ContentListingFormatter($directory, $recursive, $this->config->get('case_sensitive', true))) + ->formatListing($contents); + } + + /** + * @inheritdoc + */ + public function getMimetype($path) + { + $path = Util::normalizePath($path); + $this->assertPresent($path); + + if (( ! $object = $this->getAdapter()->getMimetype($path)) || ! array_key_exists('mimetype', $object)) { + return false; + } + + return $object['mimetype']; + } + + /** + * @inheritdoc + */ + public function getTimestamp($path) + { + $path = Util::normalizePath($path); + $this->assertPresent($path); + + if (( ! $object = $this->getAdapter()->getTimestamp($path)) || ! array_key_exists('timestamp', $object)) { + return false; + } + + return (int) $object['timestamp']; + } + + /** + * @inheritdoc + */ + public function getVisibility($path) + { + $path = Util::normalizePath($path); + $this->assertPresent($path); + + if (( ! $object = $this->getAdapter()->getVisibility($path)) || ! array_key_exists('visibility', $object)) { + return false; + } + + return $object['visibility']; + } + + /** + * @inheritdoc + */ + public function getSize($path) + { + $path = Util::normalizePath($path); + $this->assertPresent($path); + + if (( ! $object = $this->getAdapter()->getSize($path)) || ! array_key_exists('size', $object)) { + return false; + } + + return (int) $object['size']; + } + + /** + * @inheritdoc + */ + public function setVisibility($path, $visibility) + { + $path = Util::normalizePath($path); + $this->assertPresent($path); + + return (bool) $this->getAdapter()->setVisibility($path, $visibility); + } + + /** + * @inheritdoc + */ + public function getMetadata($path) + { + $path = Util::normalizePath($path); + $this->assertPresent($path); + + return $this->getAdapter()->getMetadata($path); + } + + /** + * @inheritdoc + */ + public function get($path, Handler $handler = null) + { + $path = Util::normalizePath($path); + + if ( ! $handler) { + $metadata = $this->getMetadata($path); + $handler = ($metadata && $metadata['type'] === 'file') ? new File($this, $path) : new Directory($this, $path); + } + + $handler->setPath($path); + $handler->setFilesystem($this); + + return $handler; + } + + /** + * Assert a file is present. + * + * @param string $path path to file + * + * @throws FileNotFoundException + * + * @return void + */ + public function assertPresent($path) + { + if ($this->config->get('disable_asserts', false) === false && ! $this->has($path)) { + throw new FileNotFoundException($path); + } + } + + /** + * Assert a file is absent. + * + * @param string $path path to file + * + * @throws FileExistsException + * + * @return void + */ + public function assertAbsent($path) + { + if ($this->config->get('disable_asserts', false) === false && $this->has($path)) { + throw new FileExistsException($path); + } + } +} diff --git a/vendor/league/flysystem/src/FilesystemException.php b/vendor/league/flysystem/src/FilesystemException.php new file mode 100644 index 000000000..3121e533d --- /dev/null +++ b/vendor/league/flysystem/src/FilesystemException.php @@ -0,0 +1,7 @@ +path = $path; + $this->filesystem = $filesystem; + } + + /** + * Check whether the entree is a directory. + * + * @return bool + */ + public function isDir() + { + return $this->getType() === 'dir'; + } + + /** + * Check whether the entree is a file. + * + * @return bool + */ + public function isFile() + { + return $this->getType() === 'file'; + } + + /** + * Retrieve the entree type (file|dir). + * + * @return string file or dir + */ + public function getType() + { + $metadata = $this->filesystem->getMetadata($this->path); + + return $metadata ? $metadata['type'] : 'dir'; + } + + /** + * Set the Filesystem object. + * + * @param FilesystemInterface $filesystem + * + * @return $this + */ + public function setFilesystem(FilesystemInterface $filesystem) + { + $this->filesystem = $filesystem; + + return $this; + } + + /** + * Retrieve the Filesystem object. + * + * @return FilesystemInterface + */ + public function getFilesystem() + { + return $this->filesystem; + } + + /** + * Set the entree path. + * + * @param string $path + * + * @return $this + */ + public function setPath($path) + { + $this->path = $path; + + return $this; + } + + /** + * Retrieve the entree path. + * + * @return string path + */ + public function getPath() + { + return $this->path; + } + + /** + * Plugins pass-through. + * + * @param string $method + * @param array $arguments + * + * @return mixed + */ + public function __call($method, array $arguments) + { + array_unshift($arguments, $this->path); + $callback = [$this->filesystem, $method]; + + try { + return call_user_func_array($callback, $arguments); + } catch (BadMethodCallException $e) { + throw new BadMethodCallException( + 'Call to undefined method ' + . get_called_class() + . '::' . $method + ); + } + } +} diff --git a/vendor/league/flysystem/src/InvalidRootException.php b/vendor/league/flysystem/src/InvalidRootException.php new file mode 100644 index 000000000..468d1d58c --- /dev/null +++ b/vendor/league/flysystem/src/InvalidRootException.php @@ -0,0 +1,9 @@ + Filesystem,] + * + * @throws InvalidArgumentException + */ + public function __construct(array $filesystems = []) + { + $this->mountFilesystems($filesystems); + } + + /** + * Mount filesystems. + * + * @param FilesystemInterface[] $filesystems [:prefix => Filesystem,] + * + * @throws InvalidArgumentException + * + * @return $this + */ + public function mountFilesystems(array $filesystems) + { + foreach ($filesystems as $prefix => $filesystem) { + $this->mountFilesystem($prefix, $filesystem); + } + + return $this; + } + + /** + * Mount filesystems. + * + * @param string $prefix + * @param FilesystemInterface $filesystem + * + * @throws InvalidArgumentException + * + * @return $this + */ + public function mountFilesystem($prefix, FilesystemInterface $filesystem) + { + if ( ! is_string($prefix)) { + throw new InvalidArgumentException(__METHOD__ . ' expects argument #1 to be a string.'); + } + + $this->filesystems[$prefix] = $filesystem; + + return $this; + } + + /** + * Get the filesystem with the corresponding prefix. + * + * @param string $prefix + * + * @throws FilesystemNotFoundException + * + * @return FilesystemInterface + */ + public function getFilesystem($prefix) + { + if ( ! isset($this->filesystems[$prefix])) { + throw new FilesystemNotFoundException('No filesystem mounted with prefix ' . $prefix); + } + + return $this->filesystems[$prefix]; + } + + /** + * Retrieve the prefix from an arguments array. + * + * @param array $arguments + * + * @throws InvalidArgumentException + * + * @return array [:prefix, :arguments] + */ + public function filterPrefix(array $arguments) + { + if (empty($arguments)) { + throw new InvalidArgumentException('At least one argument needed'); + } + + $path = array_shift($arguments); + + if ( ! is_string($path)) { + throw new InvalidArgumentException('First argument should be a string'); + } + + list($prefix, $path) = $this->getPrefixAndPath($path); + array_unshift($arguments, $path); + + return [$prefix, $arguments]; + } + + /** + * @param string $directory + * @param bool $recursive + * + * @throws InvalidArgumentException + * @throws FilesystemNotFoundException + * + * @return array + */ + public function listContents($directory = '', $recursive = false) + { + list($prefix, $directory) = $this->getPrefixAndPath($directory); + $filesystem = $this->getFilesystem($prefix); + $result = $filesystem->listContents($directory, $recursive); + + foreach ($result as &$file) { + $file['filesystem'] = $prefix; + } + + return $result; + } + + /** + * Call forwarder. + * + * @param string $method + * @param array $arguments + * + * @throws InvalidArgumentException + * @throws FilesystemNotFoundException + * + * @return mixed + */ + public function __call($method, $arguments) + { + list($prefix, $arguments) = $this->filterPrefix($arguments); + + return $this->invokePluginOnFilesystem($method, $arguments, $prefix); + } + + /** + * @param string $from + * @param string $to + * @param array $config + * + * @throws InvalidArgumentException + * @throws FilesystemNotFoundException + * @throws FileExistsException + * + * @return bool + */ + public function copy($from, $to, array $config = []) + { + list($prefixFrom, $from) = $this->getPrefixAndPath($from); + + $buffer = $this->getFilesystem($prefixFrom)->readStream($from); + + if ($buffer === false) { + return false; + } + + list($prefixTo, $to) = $this->getPrefixAndPath($to); + + $result = $this->getFilesystem($prefixTo)->writeStream($to, $buffer, $config); + + if (is_resource($buffer)) { + fclose($buffer); + } + + return $result; + } + + /** + * List with plugin adapter. + * + * @param array $keys + * @param string $directory + * @param bool $recursive + * + * @throws InvalidArgumentException + * @throws FilesystemNotFoundException + * + * @return array + */ + public function listWith(array $keys = [], $directory = '', $recursive = false) + { + list($prefix, $directory) = $this->getPrefixAndPath($directory); + $arguments = [$keys, $directory, $recursive]; + + return $this->invokePluginOnFilesystem('listWith', $arguments, $prefix); + } + + /** + * Move a file. + * + * @param string $from + * @param string $to + * @param array $config + * + * @throws InvalidArgumentException + * @throws FilesystemNotFoundException + * + * @return bool + */ + public function move($from, $to, array $config = []) + { + list($prefixFrom, $pathFrom) = $this->getPrefixAndPath($from); + list($prefixTo, $pathTo) = $this->getPrefixAndPath($to); + + if ($prefixFrom === $prefixTo) { + $filesystem = $this->getFilesystem($prefixFrom); + $renamed = $filesystem->rename($pathFrom, $pathTo); + + if ($renamed && isset($config['visibility'])) { + return $filesystem->setVisibility($pathTo, $config['visibility']); + } + + return $renamed; + } + + $copied = $this->copy($from, $to, $config); + + if ($copied) { + return $this->delete($from); + } + + return false; + } + + /** + * Invoke a plugin on a filesystem mounted on a given prefix. + * + * @param string $method + * @param array $arguments + * @param string $prefix + * + * @throws FilesystemNotFoundException + * + * @return mixed + */ + public function invokePluginOnFilesystem($method, $arguments, $prefix) + { + $filesystem = $this->getFilesystem($prefix); + + try { + return $this->invokePlugin($method, $arguments, $filesystem); + } catch (PluginNotFoundException $e) { + // Let it pass, it's ok, don't panic. + } + + $callback = [$filesystem, $method]; + + return call_user_func_array($callback, $arguments); + } + + /** + * @param string $path + * + * @throws InvalidArgumentException + * + * @return string[] [:prefix, :path] + */ + protected function getPrefixAndPath($path) + { + if (strpos($path, '://') < 1) { + throw new InvalidArgumentException('No prefix detected in path: ' . $path); + } + + return explode('://', $path, 2); + } + + /** + * Check whether a file exists. + * + * @param string $path + * + * @return bool + */ + public function has($path) + { + list($prefix, $path) = $this->getPrefixAndPath($path); + + return $this->getFilesystem($prefix)->has($path); + } + + /** + * Read a file. + * + * @param string $path The path to the file. + * + * @throws FileNotFoundException + * + * @return string|false The file contents or false on failure. + */ + public function read($path) + { + list($prefix, $path) = $this->getPrefixAndPath($path); + + return $this->getFilesystem($prefix)->read($path); + } + + /** + * Retrieves a read-stream for a path. + * + * @param string $path The path to the file. + * + * @throws FileNotFoundException + * + * @return resource|false The path resource or false on failure. + */ + public function readStream($path) + { + list($prefix, $path) = $this->getPrefixAndPath($path); + + return $this->getFilesystem($prefix)->readStream($path); + } + + /** + * Get a file's metadata. + * + * @param string $path The path to the file. + * + * @throws FileNotFoundException + * + * @return array|false The file metadata or false on failure. + */ + public function getMetadata($path) + { + list($prefix, $path) = $this->getPrefixAndPath($path); + + return $this->getFilesystem($prefix)->getMetadata($path); + } + + /** + * Get a file's size. + * + * @param string $path The path to the file. + * + * @throws FileNotFoundException + * + * @return int|false The file size or false on failure. + */ + public function getSize($path) + { + list($prefix, $path) = $this->getPrefixAndPath($path); + + return $this->getFilesystem($prefix)->getSize($path); + } + + /** + * Get a file's mime-type. + * + * @param string $path The path to the file. + * + * @throws FileNotFoundException + * + * @return string|false The file mime-type or false on failure. + */ + public function getMimetype($path) + { + list($prefix, $path) = $this->getPrefixAndPath($path); + + return $this->getFilesystem($prefix)->getMimetype($path); + } + + /** + * Get a file's timestamp. + * + * @param string $path The path to the file. + * + * @throws FileNotFoundException + * + * @return string|false The timestamp or false on failure. + */ + public function getTimestamp($path) + { + list($prefix, $path) = $this->getPrefixAndPath($path); + + return $this->getFilesystem($prefix)->getTimestamp($path); + } + + /** + * Get a file's visibility. + * + * @param string $path The path to the file. + * + * @throws FileNotFoundException + * + * @return string|false The visibility (public|private) or false on failure. + */ + public function getVisibility($path) + { + list($prefix, $path) = $this->getPrefixAndPath($path); + + return $this->getFilesystem($prefix)->getVisibility($path); + } + + /** + * Write a new file. + * + * @param string $path The path of the new file. + * @param string $contents The file contents. + * @param array $config An optional configuration array. + * + * @throws FileExistsException + * + * @return bool True on success, false on failure. + */ + public function write($path, $contents, array $config = []) + { + list($prefix, $path) = $this->getPrefixAndPath($path); + + return $this->getFilesystem($prefix)->write($path, $contents, $config); + } + + /** + * Write a new file using a stream. + * + * @param string $path The path of the new file. + * @param resource $resource The file handle. + * @param array $config An optional configuration array. + * + * @throws InvalidArgumentException If $resource is not a file handle. + * @throws FileExistsException + * + * @return bool True on success, false on failure. + */ + public function writeStream($path, $resource, array $config = []) + { + list($prefix, $path) = $this->getPrefixAndPath($path); + + return $this->getFilesystem($prefix)->writeStream($path, $resource, $config); + } + + /** + * Update an existing file. + * + * @param string $path The path of the existing file. + * @param string $contents The file contents. + * @param array $config An optional configuration array. + * + * @throws FileNotFoundException + * + * @return bool True on success, false on failure. + */ + public function update($path, $contents, array $config = []) + { + list($prefix, $path) = $this->getPrefixAndPath($path); + + return $this->getFilesystem($prefix)->update($path, $contents, $config); + } + + /** + * Update an existing file using a stream. + * + * @param string $path The path of the existing file. + * @param resource $resource The file handle. + * @param array $config An optional configuration array. + * + * @throws InvalidArgumentException If $resource is not a file handle. + * @throws FileNotFoundException + * + * @return bool True on success, false on failure. + */ + public function updateStream($path, $resource, array $config = []) + { + list($prefix, $path) = $this->getPrefixAndPath($path); + + return $this->getFilesystem($prefix)->updateStream($path, $resource, $config); + } + + /** + * Rename a file. + * + * @param string $path Path to the existing file. + * @param string $newpath The new path of the file. + * + * @throws FileExistsException Thrown if $newpath exists. + * @throws FileNotFoundException Thrown if $path does not exist. + * + * @return bool True on success, false on failure. + */ + public function rename($path, $newpath) + { + list($prefix, $path) = $this->getPrefixAndPath($path); + + return $this->getFilesystem($prefix)->rename($path, $newpath); + } + + /** + * Delete a file. + * + * @param string $path + * + * @throws FileNotFoundException + * + * @return bool True on success, false on failure. + */ + public function delete($path) + { + list($prefix, $path) = $this->getPrefixAndPath($path); + + return $this->getFilesystem($prefix)->delete($path); + } + + /** + * Delete a directory. + * + * @param string $dirname + * + * @throws RootViolationException Thrown if $dirname is empty. + * + * @return bool True on success, false on failure. + */ + public function deleteDir($dirname) + { + list($prefix, $dirname) = $this->getPrefixAndPath($dirname); + + return $this->getFilesystem($prefix)->deleteDir($dirname); + } + + /** + * Create a directory. + * + * @param string $dirname The name of the new directory. + * @param array $config An optional configuration array. + * + * @return bool True on success, false on failure. + */ + public function createDir($dirname, array $config = []) + { + list($prefix, $dirname) = $this->getPrefixAndPath($dirname); + + return $this->getFilesystem($prefix)->createDir($dirname); + } + + /** + * Set the visibility for a file. + * + * @param string $path The path to the file. + * @param string $visibility One of 'public' or 'private'. + * + * @throws FileNotFoundException + * + * @return bool True on success, false on failure. + */ + public function setVisibility($path, $visibility) + { + list($prefix, $path) = $this->getPrefixAndPath($path); + + return $this->getFilesystem($prefix)->setVisibility($path, $visibility); + } + + /** + * Create a file or update if exists. + * + * @param string $path The path to the file. + * @param string $contents The file contents. + * @param array $config An optional configuration array. + * + * @return bool True on success, false on failure. + */ + public function put($path, $contents, array $config = []) + { + list($prefix, $path) = $this->getPrefixAndPath($path); + + return $this->getFilesystem($prefix)->put($path, $contents, $config); + } + + /** + * Create a file or update if exists. + * + * @param string $path The path to the file. + * @param resource $resource The file handle. + * @param array $config An optional configuration array. + * + * @throws InvalidArgumentException Thrown if $resource is not a resource. + * + * @return bool True on success, false on failure. + */ + public function putStream($path, $resource, array $config = []) + { + list($prefix, $path) = $this->getPrefixAndPath($path); + + return $this->getFilesystem($prefix)->putStream($path, $resource, $config); + } + + /** + * Read and delete a file. + * + * @param string $path The path to the file. + * + * @throws FileNotFoundException + * + * @return string|false The file contents, or false on failure. + */ + public function readAndDelete($path) + { + list($prefix, $path) = $this->getPrefixAndPath($path); + + return $this->getFilesystem($prefix)->readAndDelete($path); + } + + /** + * Get a file/directory handler. + * + * @deprecated + * + * @param string $path The path to the file. + * @param Handler $handler An optional existing handler to populate. + * + * @return Handler Either a file or directory handler. + */ + public function get($path, Handler $handler = null) + { + list($prefix, $path) = $this->getPrefixAndPath($path); + + return $this->getFilesystem($prefix)->get($path); + } +} diff --git a/vendor/league/flysystem/src/NotSupportedException.php b/vendor/league/flysystem/src/NotSupportedException.php new file mode 100644 index 000000000..e0a989b22 --- /dev/null +++ b/vendor/league/flysystem/src/NotSupportedException.php @@ -0,0 +1,37 @@ +getPathname()); + } + + /** + * Create a new exception for a link. + * + * @param string $systemType + * + * @return static + */ + public static function forFtpSystemType($systemType) + { + $message = "The FTP system type '$systemType' is currently not supported."; + + return new static($message); + } +} diff --git a/vendor/league/flysystem/src/Plugin/AbstractPlugin.php b/vendor/league/flysystem/src/Plugin/AbstractPlugin.php new file mode 100644 index 000000000..0d5678976 --- /dev/null +++ b/vendor/league/flysystem/src/Plugin/AbstractPlugin.php @@ -0,0 +1,24 @@ +filesystem = $filesystem; + } +} diff --git a/vendor/league/flysystem/src/Plugin/EmptyDir.php b/vendor/league/flysystem/src/Plugin/EmptyDir.php new file mode 100644 index 000000000..b5ae7f582 --- /dev/null +++ b/vendor/league/flysystem/src/Plugin/EmptyDir.php @@ -0,0 +1,34 @@ +filesystem->listContents($dirname, false); + + foreach ($listing as $item) { + if ($item['type'] === 'dir') { + $this->filesystem->deleteDir($item['path']); + } else { + $this->filesystem->delete($item['path']); + } + } + } +} diff --git a/vendor/league/flysystem/src/Plugin/ForcedCopy.php b/vendor/league/flysystem/src/Plugin/ForcedCopy.php new file mode 100644 index 000000000..a41e9f3ae --- /dev/null +++ b/vendor/league/flysystem/src/Plugin/ForcedCopy.php @@ -0,0 +1,44 @@ +filesystem->delete($newpath); + } catch (FileNotFoundException $e) { + // The destination path does not exist. That's ok. + $deleted = true; + } + + if ($deleted) { + return $this->filesystem->copy($path, $newpath); + } + + return false; + } +} diff --git a/vendor/league/flysystem/src/Plugin/ForcedRename.php b/vendor/league/flysystem/src/Plugin/ForcedRename.php new file mode 100644 index 000000000..3f51cd607 --- /dev/null +++ b/vendor/league/flysystem/src/Plugin/ForcedRename.php @@ -0,0 +1,44 @@ +filesystem->delete($newpath); + } catch (FileNotFoundException $e) { + // The destination path does not exist. That's ok. + $deleted = true; + } + + if ($deleted) { + return $this->filesystem->rename($path, $newpath); + } + + return false; + } +} diff --git a/vendor/league/flysystem/src/Plugin/GetWithMetadata.php b/vendor/league/flysystem/src/Plugin/GetWithMetadata.php new file mode 100644 index 000000000..2f13d2fd2 --- /dev/null +++ b/vendor/league/flysystem/src/Plugin/GetWithMetadata.php @@ -0,0 +1,51 @@ +filesystem->getMetadata($path); + + if ( ! $object) { + return false; + } + + $keys = array_diff($metadata, array_keys($object)); + + foreach ($keys as $key) { + if ( ! method_exists($this->filesystem, $method = 'get' . ucfirst($key))) { + throw new InvalidArgumentException('Could not fetch metadata: ' . $key); + } + + $object[$key] = $this->filesystem->{$method}($path); + } + + return $object; + } +} diff --git a/vendor/league/flysystem/src/Plugin/ListFiles.php b/vendor/league/flysystem/src/Plugin/ListFiles.php new file mode 100644 index 000000000..9669fe7e7 --- /dev/null +++ b/vendor/league/flysystem/src/Plugin/ListFiles.php @@ -0,0 +1,35 @@ +filesystem->listContents($directory, $recursive); + + $filter = function ($object) { + return $object['type'] === 'file'; + }; + + return array_values(array_filter($contents, $filter)); + } +} diff --git a/vendor/league/flysystem/src/Plugin/ListPaths.php b/vendor/league/flysystem/src/Plugin/ListPaths.php new file mode 100644 index 000000000..0889d1f8d --- /dev/null +++ b/vendor/league/flysystem/src/Plugin/ListPaths.php @@ -0,0 +1,36 @@ +filesystem->listContents($directory, $recursive); + + foreach ($contents as $object) { + $result[] = $object['path']; + } + + return $result; + } +} diff --git a/vendor/league/flysystem/src/Plugin/ListWith.php b/vendor/league/flysystem/src/Plugin/ListWith.php new file mode 100644 index 000000000..d64debeca --- /dev/null +++ b/vendor/league/flysystem/src/Plugin/ListWith.php @@ -0,0 +1,60 @@ +filesystem->listContents($directory, $recursive); + + foreach ($contents as $index => $object) { + if ($object['type'] === 'file') { + $missingKeys = array_diff($keys, array_keys($object)); + $contents[$index] = array_reduce($missingKeys, [$this, 'getMetadataByName'], $object); + } + } + + return $contents; + } + + /** + * Get a meta-data value by key name. + * + * @param array $object + * @param string $key + * + * @return array + */ + protected function getMetadataByName(array $object, $key) + { + $method = 'get' . ucfirst($key); + + if ( ! method_exists($this->filesystem, $method)) { + throw new \InvalidArgumentException('Could not get meta-data for key: ' . $key); + } + + $object[$key] = $this->filesystem->{$method}($object['path']); + + return $object; + } +} diff --git a/vendor/league/flysystem/src/Plugin/PluggableTrait.php b/vendor/league/flysystem/src/Plugin/PluggableTrait.php new file mode 100644 index 000000000..922edfe52 --- /dev/null +++ b/vendor/league/flysystem/src/Plugin/PluggableTrait.php @@ -0,0 +1,97 @@ +plugins[$plugin->getMethod()] = $plugin; + + return $this; + } + + /** + * Find a specific plugin. + * + * @param string $method + * + * @throws PluginNotFoundException + * + * @return PluginInterface + */ + protected function findPlugin($method) + { + if ( ! isset($this->plugins[$method])) { + throw new PluginNotFoundException('Plugin not found for method: ' . $method); + } + + return $this->plugins[$method]; + } + + /** + * Invoke a plugin by method name. + * + * @param string $method + * @param array $arguments + * @param FilesystemInterface $filesystem + * + * @throws PluginNotFoundException + * + * @return mixed + */ + protected function invokePlugin($method, array $arguments, FilesystemInterface $filesystem) + { + $plugin = $this->findPlugin($method); + $plugin->setFilesystem($filesystem); + $callback = [$plugin, 'handle']; + + return call_user_func_array($callback, $arguments); + } + + /** + * Plugins pass-through. + * + * @param string $method + * @param array $arguments + * + * @throws BadMethodCallException + * + * @return mixed + */ + public function __call($method, array $arguments) + { + try { + return $this->invokePlugin($method, $arguments, $this); + } catch (PluginNotFoundException $e) { + throw new BadMethodCallException( + 'Call to undefined method ' + . get_class($this) + . '::' . $method + ); + } + } +} diff --git a/vendor/league/flysystem/src/Plugin/PluginNotFoundException.php b/vendor/league/flysystem/src/Plugin/PluginNotFoundException.php new file mode 100644 index 000000000..fd1d7e7e3 --- /dev/null +++ b/vendor/league/flysystem/src/Plugin/PluginNotFoundException.php @@ -0,0 +1,10 @@ +hash = spl_object_hash($this); + static::$safeStorage[$this->hash] = []; + } + + public function storeSafely($key, $value) + { + static::$safeStorage[$this->hash][$key] = $value; + } + + public function retrieveSafely($key) + { + if (array_key_exists($key, static::$safeStorage[$this->hash])) { + return static::$safeStorage[$this->hash][$key]; + } + } + + public function __destruct() + { + unset(static::$safeStorage[$this->hash]); + } +} diff --git a/vendor/league/flysystem/src/UnreadableFileException.php b/vendor/league/flysystem/src/UnreadableFileException.php new file mode 100644 index 000000000..e66803383 --- /dev/null +++ b/vendor/league/flysystem/src/UnreadableFileException.php @@ -0,0 +1,18 @@ +getRealPath() + ) + ); + } +} diff --git a/vendor/league/flysystem/src/Util.php b/vendor/league/flysystem/src/Util.php new file mode 100644 index 000000000..1a2db718d --- /dev/null +++ b/vendor/league/flysystem/src/Util.php @@ -0,0 +1,354 @@ + '']; + } + + /** + * Normalize a dirname return value. + * + * @param string $dirname + * + * @return string normalized dirname + */ + public static function normalizeDirname($dirname) + { + return $dirname === '.' ? '' : $dirname; + } + + /** + * Get a normalized dirname from a path. + * + * @param string $path + * + * @return string dirname + */ + public static function dirname($path) + { + return static::normalizeDirname(dirname($path)); + } + + /** + * Map result arrays. + * + * @param array $object + * @param array $map + * + * @return array mapped result + */ + public static function map(array $object, array $map) + { + $result = []; + + foreach ($map as $from => $to) { + if ( ! isset($object[$from])) { + continue; + } + + $result[$to] = $object[$from]; + } + + return $result; + } + + /** + * Normalize path. + * + * @param string $path + * + * @throws LogicException + * + * @return string + */ + public static function normalizePath($path) + { + return static::normalizeRelativePath($path); + } + + /** + * Normalize relative directories in a path. + * + * @param string $path + * + * @throws LogicException + * + * @return string + */ + public static function normalizeRelativePath($path) + { + $path = str_replace('\\', '/', $path); + $path = static::removeFunkyWhiteSpace($path); + $parts = []; + + foreach (explode('/', $path) as $part) { + switch ($part) { + case '': + case '.': + break; + + case '..': + if (empty($parts)) { + throw new LogicException( + 'Path is outside of the defined root, path: [' . $path . ']' + ); + } + array_pop($parts); + break; + + default: + $parts[] = $part; + break; + } + } + + $path = implode('/', $parts); + + return $path; + } + + /** + * Rejects unprintable characters and invalid unicode characters. + * + * @param string $path + * + * @return string $path + */ + protected static function removeFunkyWhiteSpace($path) + { + if (preg_match('#\p{C}+#u', $path)) { + throw CorruptedPathDetected::forPath($path); + } + + return $path; + } + + /** + * Normalize prefix. + * + * @param string $prefix + * @param string $separator + * + * @return string normalized path + */ + public static function normalizePrefix($prefix, $separator) + { + return rtrim($prefix, $separator) . $separator; + } + + /** + * Get content size. + * + * @param string $contents + * + * @return int content size + */ + public static function contentSize($contents) + { + return defined('MB_OVERLOAD_STRING') ? mb_strlen($contents, '8bit') : strlen($contents); + } + + /** + * Guess MIME Type based on the path of the file and it's content. + * + * @param string $path + * @param string|resource $content + * + * @return string|null MIME Type or NULL if no extension detected + */ + public static function guessMimeType($path, $content) + { + $mimeType = MimeType::detectByContent($content); + + if ( ! (empty($mimeType) || in_array($mimeType, ['application/x-empty', 'text/plain', 'text/x-asm']))) { + return $mimeType; + } + + return MimeType::detectByFilename($path); + } + + /** + * Emulate directories. + * + * @param array $listing + * + * @return array listing with emulated directories + */ + public static function emulateDirectories(array $listing) + { + $directories = []; + $listedDirectories = []; + + foreach ($listing as $object) { + [$directories, $listedDirectories] = static::emulateObjectDirectories($object, $directories, $listedDirectories); + } + + $directories = array_diff(array_unique($directories), array_unique($listedDirectories)); + + foreach ($directories as $directory) { + $listing[] = static::pathinfo($directory) + ['type' => 'dir']; + } + + return $listing; + } + + /** + * Ensure a Config instance. + * + * @param null|array|Config $config + * + * @return Config config instance + * + * @throw LogicException + */ + public static function ensureConfig($config) + { + if ($config === null) { + return new Config(); + } + + if ($config instanceof Config) { + return $config; + } + + if (is_array($config)) { + return new Config($config); + } + + throw new LogicException('A config should either be an array or a Flysystem\Config object.'); + } + + /** + * Rewind a stream. + * + * @param resource $resource + */ + public static function rewindStream($resource) + { + if (ftell($resource) !== 0 && static::isSeekableStream($resource)) { + rewind($resource); + } + } + + public static function isSeekableStream($resource) + { + $metadata = stream_get_meta_data($resource); + + return $metadata['seekable']; + } + + /** + * Get the size of a stream. + * + * @param resource $resource + * + * @return int|null stream size + */ + public static function getStreamSize($resource) + { + $stat = fstat($resource); + + if ( ! is_array($stat) || ! isset($stat['size'])) { + return null; + } + + return $stat['size']; + } + + /** + * Emulate the directories of a single object. + * + * @param array $object + * @param array $directories + * @param array $listedDirectories + * + * @return array + */ + protected static function emulateObjectDirectories(array $object, array $directories, array $listedDirectories) + { + if ($object['type'] === 'dir') { + $listedDirectories[] = $object['path']; + } + + if ( ! isset($object['dirname']) || trim($object['dirname']) === '') { + return [$directories, $listedDirectories]; + } + + $parent = $object['dirname']; + + while (isset($parent) && trim($parent) !== '' && ! in_array($parent, $directories)) { + $directories[] = $parent; + $parent = static::dirname($parent); + } + + if (isset($object['type']) && $object['type'] === 'dir') { + $listedDirectories[] = $object['path']; + + return [$directories, $listedDirectories]; + } + + return [$directories, $listedDirectories]; + } + + /** + * Returns the trailing name component of the path. + * + * @param string $path + * + * @return string + */ + private static function basename($path) + { + $separators = DIRECTORY_SEPARATOR === '/' ? '/' : '\/'; + + $path = rtrim($path, $separators); + + $basename = preg_replace('#.*?([^' . preg_quote($separators, '#') . ']+$)#', '$1', $path); + + if (DIRECTORY_SEPARATOR === '/') { + return $basename; + } + // @codeCoverageIgnoreStart + // Extra Windows path munging. This is tested via AppVeyor, but code + // coverage is not reported. + + // Handle relative paths with drive letters. c:file.txt. + while (preg_match('#^[a-zA-Z]{1}:[^\\\/]#', $basename)) { + $basename = substr($basename, 2); + } + + // Remove colon for standalone drive letter names. + if (preg_match('#^[a-zA-Z]{1}:$#', $basename)) { + $basename = rtrim($basename, ':'); + } + + return $basename; + // @codeCoverageIgnoreEnd + } +} diff --git a/vendor/league/flysystem/src/Util/ContentListingFormatter.php b/vendor/league/flysystem/src/Util/ContentListingFormatter.php new file mode 100644 index 000000000..ae0d3b91d --- /dev/null +++ b/vendor/league/flysystem/src/Util/ContentListingFormatter.php @@ -0,0 +1,122 @@ +directory = rtrim($directory, '/'); + $this->recursive = $recursive; + $this->caseSensitive = $caseSensitive; + } + + /** + * Format contents listing. + * + * @param array $listing + * + * @return array + */ + public function formatListing(array $listing) + { + $listing = array_filter(array_map([$this, 'addPathInfo'], $listing), [$this, 'isEntryOutOfScope']); + + return $this->sortListing(array_values($listing)); + } + + private function addPathInfo(array $entry) + { + return $entry + Util::pathinfo($entry['path']); + } + + /** + * Determine if the entry is out of scope. + * + * @param array $entry + * + * @return bool + */ + private function isEntryOutOfScope(array $entry) + { + if (empty($entry['path']) && $entry['path'] !== '0') { + return false; + } + + if ($this->recursive) { + return $this->residesInDirectory($entry); + } + + return $this->isDirectChild($entry); + } + + /** + * Check if the entry resides within the parent directory. + * + * @param array $entry + * + * @return bool + */ + private function residesInDirectory(array $entry) + { + if ($this->directory === '') { + return true; + } + + return $this->caseSensitive + ? strpos($entry['path'], $this->directory . '/') === 0 + : stripos($entry['path'], $this->directory . '/') === 0; + } + + /** + * Check if the entry is a direct child of the directory. + * + * @param array $entry + * + * @return bool + */ + private function isDirectChild(array $entry) + { + return $this->caseSensitive + ? $entry['dirname'] === $this->directory + : strcasecmp($this->directory, $entry['dirname']) === 0; + } + + /** + * @param array $listing + * + * @return array + */ + private function sortListing(array $listing) + { + usort($listing, function ($a, $b) { + return strcasecmp($a['path'], $b['path']); + }); + + return $listing; + } +} diff --git a/vendor/league/flysystem/src/Util/MimeType.php b/vendor/league/flysystem/src/Util/MimeType.php new file mode 100644 index 000000000..35cba3fb8 --- /dev/null +++ b/vendor/league/flysystem/src/Util/MimeType.php @@ -0,0 +1,80 @@ +detectMimeTypeFromBuffer($content); + } + + return 'text/plain'; + } + + /** + * Detects MIME Type based on file extension. + * + * @param string $extension + * + * @return string MIME Type + */ + public static function detectByFileExtension($extension) + { + return static::detector()->detectMimeTypeFromPath('artificial.' . $extension) ?: 'text/plain'; + } + + /** + * @param string $filename + * + * @return string MIME Type + */ + public static function detectByFilename($filename) + { + return static::detector()->detectMimeTypeFromPath($filename) ?: 'text/plain'; + } + + /** + * @return array Map of file extension to MIME Type + */ + public static function getExtensionToMimeTypeMap() + { + return static::$extensionToMimeTypeMap; + } +} diff --git a/vendor/league/flysystem/src/Util/StreamHasher.php b/vendor/league/flysystem/src/Util/StreamHasher.php new file mode 100644 index 000000000..938ec5db7 --- /dev/null +++ b/vendor/league/flysystem/src/Util/StreamHasher.php @@ -0,0 +1,36 @@ +algo = $algo; + } + + /** + * @param resource $resource + * + * @return string + */ + public function hash($resource) + { + rewind($resource); + $context = hash_init($this->algo); + hash_update_stream($context, $resource); + fclose($resource); + + return hash_final($context); + } +} diff --git a/vendor/league/mime-type-detection/CHANGELOG.md b/vendor/league/mime-type-detection/CHANGELOG.md new file mode 100644 index 000000000..d9eab90da --- /dev/null +++ b/vendor/league/mime-type-detection/CHANGELOG.md @@ -0,0 +1,13 @@ +# Changelog + +## 1.7.0 - 2021-01-18 + +### Added + +- Added a `bufferSampleSize` parameter to the `FinfoMimeTypeDetector` class that allows you to send a reduced content sample which costs less memory. + +## 1.6.0 - 2021-01-18 + +### Changes + +- Updated generated mime-type map diff --git a/vendor/league/mime-type-detection/LICENSE b/vendor/league/mime-type-detection/LICENSE new file mode 100644 index 000000000..7c1027d3e --- /dev/null +++ b/vendor/league/mime-type-detection/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2013-2020 Frank de Jonge + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/league/mime-type-detection/composer.json b/vendor/league/mime-type-detection/composer.json new file mode 100644 index 000000000..765b05c2d --- /dev/null +++ b/vendor/league/mime-type-detection/composer.json @@ -0,0 +1,33 @@ +{ + "name": "league/mime-type-detection", + "description": "Mime-type detection for Flysystem", + "license": "MIT", + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "scripts": { + "phpstan": "vendor/bin/phpstan analyse -l 6 src" + }, + "require": { + "php": "^7.2 || ^8.0", + "ext-fileinfo": "*" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.8 || ^9.3", + "phpstan/phpstan": "^0.12.68", + "friendsofphp/php-cs-fixer": "^2.18" + }, + "autoload": { + "psr-4": { + "League\\MimeTypeDetection\\": "src" + } + }, + "config": { + "platform": { + "php": "7.2.0" + } + } +} diff --git a/vendor/league/mime-type-detection/src/EmptyExtensionToMimeTypeMap.php b/vendor/league/mime-type-detection/src/EmptyExtensionToMimeTypeMap.php new file mode 100644 index 000000000..fc0424161 --- /dev/null +++ b/vendor/league/mime-type-detection/src/EmptyExtensionToMimeTypeMap.php @@ -0,0 +1,13 @@ +extensions = $extensions ?: new GeneratedExtensionToMimeTypeMap(); + } + + public function detectMimeType(string $path, $contents): ?string + { + return $this->detectMimeTypeFromPath($path); + } + + public function detectMimeTypeFromPath(string $path): ?string + { + $extension = strtolower(pathinfo($path, PATHINFO_EXTENSION)); + + return $this->extensions->lookupMimeType($extension); + } + + public function detectMimeTypeFromFile(string $path): ?string + { + return $this->detectMimeTypeFromPath($path); + } + + public function detectMimeTypeFromBuffer(string $contents): ?string + { + return null; + } +} diff --git a/vendor/league/mime-type-detection/src/ExtensionToMimeTypeMap.php b/vendor/league/mime-type-detection/src/ExtensionToMimeTypeMap.php new file mode 100644 index 000000000..1dad7bc1a --- /dev/null +++ b/vendor/league/mime-type-detection/src/ExtensionToMimeTypeMap.php @@ -0,0 +1,10 @@ +finfo = new finfo(FILEINFO_MIME_TYPE, $magicFile); + $this->extensionMap = $extensionMap ?: new GeneratedExtensionToMimeTypeMap(); + $this->bufferSampleSize = $bufferSampleSize; + } + + public function detectMimeType(string $path, $contents): ?string + { + $mimeType = is_string($contents) + ? (@$this->finfo->buffer($this->takeSample($contents)) ?: null) + : null; + + if ($mimeType !== null && ! in_array($mimeType, self::INCONCLUSIVE_MIME_TYPES)) { + return $mimeType; + } + + return $this->detectMimeTypeFromPath($path); + } + + public function detectMimeTypeFromPath(string $path): ?string + { + $extension = strtolower(pathinfo($path, PATHINFO_EXTENSION)); + + return $this->extensionMap->lookupMimeType($extension); + } + + public function detectMimeTypeFromFile(string $path): ?string + { + return @$this->finfo->file($path) ?: null; + } + + public function detectMimeTypeFromBuffer(string $contents): ?string + { + return @$this->finfo->buffer($this->takeSample($contents)) ?: null; + } + + private function takeSample(string $contents): string + { + if ($this->bufferSampleSize === null) { + return $contents; + } + + return (string) substr($contents, 0, $this->bufferSampleSize); + } +} diff --git a/vendor/league/mime-type-detection/src/GeneratedExtensionToMimeTypeMap.php b/vendor/league/mime-type-detection/src/GeneratedExtensionToMimeTypeMap.php new file mode 100644 index 000000000..698e2761f --- /dev/null +++ b/vendor/league/mime-type-detection/src/GeneratedExtensionToMimeTypeMap.php @@ -0,0 +1,1209 @@ + 'application/vnd.1000minds.decision-model+xml', + '3dml' => 'text/vnd.in3d.3dml', + '3ds' => 'image/x-3ds', + '3g2' => 'video/3gpp2', + '3gp' => 'video/3gp', + '3gpp' => 'video/3gpp', + '3mf' => 'model/3mf', + '7z' => 'application/x-7z-compressed', + '7zip' => 'application/x-7z-compressed', + '123' => 'application/vnd.lotus-1-2-3', + 'aab' => 'application/x-authorware-bin', + 'aac' => 'audio/x-acc', + 'aam' => 'application/x-authorware-map', + 'aas' => 'application/x-authorware-seg', + 'abw' => 'application/x-abiword', + 'ac' => 'application/vnd.nokia.n-gage.ac+xml', + 'ac3' => 'audio/ac3', + 'acc' => 'application/vnd.americandynamics.acc', + 'ace' => 'application/x-ace-compressed', + 'acu' => 'application/vnd.acucobol', + 'acutc' => 'application/vnd.acucorp', + 'adp' => 'audio/adpcm', + 'aep' => 'application/vnd.audiograph', + 'afm' => 'application/x-font-type1', + 'afp' => 'application/vnd.ibm.modcap', + 'ahead' => 'application/vnd.ahead.space', + 'ai' => 'application/pdf', + 'aif' => 'audio/x-aiff', + 'aifc' => 'audio/x-aiff', + 'aiff' => 'audio/x-aiff', + 'air' => 'application/vnd.adobe.air-application-installer-package+zip', + 'ait' => 'application/vnd.dvb.ait', + 'ami' => 'application/vnd.amiga.ami', + 'apk' => 'application/vnd.android.package-archive', + 'apng' => 'image/apng', + 'appcache' => 'text/cache-manifest', + 'application' => 'application/x-ms-application', + 'apr' => 'application/vnd.lotus-approach', + 'arc' => 'application/x-freearc', + 'arj' => 'application/x-arj', + 'asc' => 'application/pgp-signature', + 'asf' => 'video/x-ms-asf', + 'asm' => 'text/x-asm', + 'aso' => 'application/vnd.accpac.simply.aso', + 'asx' => 'video/x-ms-asf', + 'atc' => 'application/vnd.acucorp', + 'atom' => 'application/atom+xml', + 'atomcat' => 'application/atomcat+xml', + 'atomdeleted' => 'application/atomdeleted+xml', + 'atomsvc' => 'application/atomsvc+xml', + 'atx' => 'application/vnd.antix.game-component', + 'au' => 'audio/x-au', + 'avi' => 'video/x-msvideo', + 'avif' => 'image/avif', + 'aw' => 'application/applixware', + 'azf' => 'application/vnd.airzip.filesecure.azf', + 'azs' => 'application/vnd.airzip.filesecure.azs', + 'azv' => 'image/vnd.airzip.accelerator.azv', + 'azw' => 'application/vnd.amazon.ebook', + 'b16' => 'image/vnd.pco.b16', + 'bat' => 'application/x-msdownload', + 'bcpio' => 'application/x-bcpio', + 'bdf' => 'application/x-font-bdf', + 'bdm' => 'application/vnd.syncml.dm+wbxml', + 'bdoc' => 'application/x-bdoc', + 'bed' => 'application/vnd.realvnc.bed', + 'bh2' => 'application/vnd.fujitsu.oasysprs', + 'bin' => 'application/octet-stream', + 'blb' => 'application/x-blorb', + 'blorb' => 'application/x-blorb', + 'bmi' => 'application/vnd.bmi', + 'bmml' => 'application/vnd.balsamiq.bmml+xml', + 'bmp' => 'image/bmp', + 'book' => 'application/vnd.framemaker', + 'box' => 'application/vnd.previewsystems.box', + 'boz' => 'application/x-bzip2', + 'bpk' => 'application/octet-stream', + 'bpmn' => 'application/octet-stream', + 'bsp' => 'model/vnd.valve.source.compiled-map', + 'btif' => 'image/prs.btif', + 'buffer' => 'application/octet-stream', + 'bz' => 'application/x-bzip', + 'bz2' => 'application/x-bzip2', + 'c' => 'text/x-c', + 'c4d' => 'application/vnd.clonk.c4group', + 'c4f' => 'application/vnd.clonk.c4group', + 'c4g' => 'application/vnd.clonk.c4group', + 'c4p' => 'application/vnd.clonk.c4group', + 'c4u' => 'application/vnd.clonk.c4group', + 'c11amc' => 'application/vnd.cluetrust.cartomobile-config', + 'c11amz' => 'application/vnd.cluetrust.cartomobile-config-pkg', + 'cab' => 'application/vnd.ms-cab-compressed', + 'caf' => 'audio/x-caf', + 'cap' => 'application/vnd.tcpdump.pcap', + 'car' => 'application/vnd.curl.car', + 'cat' => 'application/vnd.ms-pki.seccat', + 'cb7' => 'application/x-cbr', + 'cba' => 'application/x-cbr', + 'cbr' => 'application/x-cbr', + 'cbt' => 'application/x-cbr', + 'cbz' => 'application/x-cbr', + 'cc' => 'text/x-c', + 'cco' => 'application/x-cocoa', + 'cct' => 'application/x-director', + 'ccxml' => 'application/ccxml+xml', + 'cdbcmsg' => 'application/vnd.contact.cmsg', + 'cdf' => 'application/x-netcdf', + 'cdfx' => 'application/cdfx+xml', + 'cdkey' => 'application/vnd.mediastation.cdkey', + 'cdmia' => 'application/cdmi-capability', + 'cdmic' => 'application/cdmi-container', + 'cdmid' => 'application/cdmi-domain', + 'cdmio' => 'application/cdmi-object', + 'cdmiq' => 'application/cdmi-queue', + 'cdr' => 'application/cdr', + 'cdx' => 'chemical/x-cdx', + 'cdxml' => 'application/vnd.chemdraw+xml', + 'cdy' => 'application/vnd.cinderella', + 'cer' => 'application/pkix-cert', + 'cfs' => 'application/x-cfs-compressed', + 'cgm' => 'image/cgm', + 'chat' => 'application/x-chat', + 'chm' => 'application/vnd.ms-htmlhelp', + 'chrt' => 'application/vnd.kde.kchart', + 'cif' => 'chemical/x-cif', + 'cii' => 'application/vnd.anser-web-certificate-issue-initiation', + 'cil' => 'application/vnd.ms-artgalry', + 'cjs' => 'application/node', + 'cla' => 'application/vnd.claymore', + 'class' => 'application/octet-stream', + 'clkk' => 'application/vnd.crick.clicker.keyboard', + 'clkp' => 'application/vnd.crick.clicker.palette', + 'clkt' => 'application/vnd.crick.clicker.template', + 'clkw' => 'application/vnd.crick.clicker.wordbank', + 'clkx' => 'application/vnd.crick.clicker', + 'clp' => 'application/x-msclip', + 'cmc' => 'application/vnd.cosmocaller', + 'cmdf' => 'chemical/x-cmdf', + 'cml' => 'chemical/x-cml', + 'cmp' => 'application/vnd.yellowriver-custom-menu', + 'cmx' => 'image/x-cmx', + 'cod' => 'application/vnd.rim.cod', + 'coffee' => 'text/coffeescript', + 'com' => 'application/x-msdownload', + 'conf' => 'text/plain', + 'cpio' => 'application/x-cpio', + 'cpp' => 'text/x-c', + 'cpt' => 'application/mac-compactpro', + 'crd' => 'application/x-mscardfile', + 'crl' => 'application/pkix-crl', + 'crt' => 'application/x-x509-ca-cert', + 'crx' => 'application/x-chrome-extension', + 'cryptonote' => 'application/vnd.rig.cryptonote', + 'csh' => 'application/x-csh', + 'csl' => 'application/vnd.citationstyles.style+xml', + 'csml' => 'chemical/x-csml', + 'csp' => 'application/vnd.commonspace', + 'csr' => 'application/octet-stream', + 'css' => 'text/css', + 'cst' => 'application/x-director', + 'csv' => 'text/csv', + 'cu' => 'application/cu-seeme', + 'curl' => 'text/vnd.curl', + 'cww' => 'application/prs.cww', + 'cxt' => 'application/x-director', + 'cxx' => 'text/x-c', + 'dae' => 'model/vnd.collada+xml', + 'daf' => 'application/vnd.mobius.daf', + 'dart' => 'application/vnd.dart', + 'dataless' => 'application/vnd.fdsn.seed', + 'davmount' => 'application/davmount+xml', + 'dbf' => 'application/vnd.dbf', + 'dbk' => 'application/docbook+xml', + 'dcr' => 'application/x-director', + 'dcurl' => 'text/vnd.curl.dcurl', + 'dd2' => 'application/vnd.oma.dd2+xml', + 'ddd' => 'application/vnd.fujixerox.ddd', + 'ddf' => 'application/vnd.syncml.dmddf+xml', + 'dds' => 'image/vnd.ms-dds', + 'deb' => 'application/x-debian-package', + 'def' => 'text/plain', + 'deploy' => 'application/octet-stream', + 'der' => 'application/x-x509-ca-cert', + 'dfac' => 'application/vnd.dreamfactory', + 'dgc' => 'application/x-dgc-compressed', + 'dic' => 'text/x-c', + 'dir' => 'application/x-director', + 'dis' => 'application/vnd.mobius.dis', + 'disposition-notification' => 'message/disposition-notification', + 'dist' => 'application/octet-stream', + 'distz' => 'application/octet-stream', + 'djv' => 'image/vnd.djvu', + 'djvu' => 'image/vnd.djvu', + 'dll' => 'application/octet-stream', + 'dmg' => 'application/x-apple-diskimage', + 'dmn' => 'application/octet-stream', + 'dmp' => 'application/vnd.tcpdump.pcap', + 'dms' => 'application/octet-stream', + 'dna' => 'application/vnd.dna', + 'doc' => 'application/msword', + 'docm' => 'application/vnd.ms-word.template.macroEnabled.12', + 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'dot' => 'application/msword', + 'dotm' => 'application/vnd.ms-word.template.macroEnabled.12', + 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', + 'dp' => 'application/vnd.osgi.dp', + 'dpg' => 'application/vnd.dpgraph', + 'dra' => 'audio/vnd.dra', + 'drle' => 'image/dicom-rle', + 'dsc' => 'text/prs.lines.tag', + 'dssc' => 'application/dssc+der', + 'dtb' => 'application/x-dtbook+xml', + 'dtd' => 'application/xml-dtd', + 'dts' => 'audio/vnd.dts', + 'dtshd' => 'audio/vnd.dts.hd', + 'dump' => 'application/octet-stream', + 'dvb' => 'video/vnd.dvb.file', + 'dvi' => 'application/x-dvi', + 'dwd' => 'application/atsc-dwd+xml', + 'dwf' => 'model/vnd.dwf', + 'dwg' => 'image/vnd.dwg', + 'dxf' => 'image/vnd.dxf', + 'dxp' => 'application/vnd.spotfire.dxp', + 'dxr' => 'application/x-director', + 'ear' => 'application/java-archive', + 'ecelp4800' => 'audio/vnd.nuera.ecelp4800', + 'ecelp7470' => 'audio/vnd.nuera.ecelp7470', + 'ecelp9600' => 'audio/vnd.nuera.ecelp9600', + 'ecma' => 'application/ecmascript', + 'edm' => 'application/vnd.novadigm.edm', + 'edx' => 'application/vnd.novadigm.edx', + 'efif' => 'application/vnd.picsel', + 'ei6' => 'application/vnd.pg.osasli', + 'elc' => 'application/octet-stream', + 'emf' => 'image/emf', + 'eml' => 'message/rfc822', + 'emma' => 'application/emma+xml', + 'emotionml' => 'application/emotionml+xml', + 'emz' => 'application/x-msmetafile', + 'eol' => 'audio/vnd.digital-winds', + 'eot' => 'application/vnd.ms-fontobject', + 'eps' => 'application/postscript', + 'epub' => 'application/epub+zip', + 'es' => 'application/ecmascript', + 'es3' => 'application/vnd.eszigno3+xml', + 'esa' => 'application/vnd.osgi.subsystem', + 'esf' => 'application/vnd.epson.esf', + 'et3' => 'application/vnd.eszigno3+xml', + 'etx' => 'text/x-setext', + 'eva' => 'application/x-eva', + 'evy' => 'application/x-envoy', + 'exe' => 'application/octet-stream', + 'exi' => 'application/exi', + 'exr' => 'image/aces', + 'ext' => 'application/vnd.novadigm.ext', + 'ez' => 'application/andrew-inset', + 'ez2' => 'application/vnd.ezpix-album', + 'ez3' => 'application/vnd.ezpix-package', + 'f' => 'text/x-fortran', + 'f4v' => 'video/mp4', + 'f77' => 'text/x-fortran', + 'f90' => 'text/x-fortran', + 'fbs' => 'image/vnd.fastbidsheet', + 'fcdt' => 'application/vnd.adobe.formscentral.fcdt', + 'fcs' => 'application/vnd.isac.fcs', + 'fdf' => 'application/vnd.fdf', + 'fdt' => 'application/fdt+xml', + 'fe_launch' => 'application/vnd.denovo.fcselayout-link', + 'fg5' => 'application/vnd.fujitsu.oasysgp', + 'fgd' => 'application/x-director', + 'fh' => 'image/x-freehand', + 'fh4' => 'image/x-freehand', + 'fh5' => 'image/x-freehand', + 'fh7' => 'image/x-freehand', + 'fhc' => 'image/x-freehand', + 'fig' => 'application/x-xfig', + 'fits' => 'image/fits', + 'flac' => 'audio/x-flac', + 'fli' => 'video/x-fli', + 'flo' => 'application/vnd.micrografx.flo', + 'flv' => 'video/x-flv', + 'flw' => 'application/vnd.kde.kivio', + 'flx' => 'text/vnd.fmi.flexstor', + 'fly' => 'text/vnd.fly', + 'fm' => 'application/vnd.framemaker', + 'fnc' => 'application/vnd.frogans.fnc', + 'fo' => 'application/vnd.software602.filler.form+xml', + 'for' => 'text/x-fortran', + 'fpx' => 'image/vnd.fpx', + 'frame' => 'application/vnd.framemaker', + 'fsc' => 'application/vnd.fsc.weblaunch', + 'fst' => 'image/vnd.fst', + 'ftc' => 'application/vnd.fluxtime.clip', + 'fti' => 'application/vnd.anser-web-funds-transfer-initiation', + 'fvt' => 'video/vnd.fvt', + 'fxp' => 'application/vnd.adobe.fxp', + 'fxpl' => 'application/vnd.adobe.fxp', + 'fzs' => 'application/vnd.fuzzysheet', + 'g2w' => 'application/vnd.geoplan', + 'g3' => 'image/g3fax', + 'g3w' => 'application/vnd.geospace', + 'gac' => 'application/vnd.groove-account', + 'gam' => 'application/x-tads', + 'gbr' => 'application/rpki-ghostbusters', + 'gca' => 'application/x-gca-compressed', + 'gdl' => 'model/vnd.gdl', + 'gdoc' => 'application/vnd.google-apps.document', + 'geo' => 'application/vnd.dynageo', + 'geojson' => 'application/geo+json', + 'gex' => 'application/vnd.geometry-explorer', + 'ggb' => 'application/vnd.geogebra.file', + 'ggt' => 'application/vnd.geogebra.tool', + 'ghf' => 'application/vnd.groove-help', + 'gif' => 'image/gif', + 'gim' => 'application/vnd.groove-identity-message', + 'glb' => 'model/gltf-binary', + 'gltf' => 'model/gltf+json', + 'gml' => 'application/gml+xml', + 'gmx' => 'application/vnd.gmx', + 'gnumeric' => 'application/x-gnumeric', + 'gpg' => 'application/gpg-keys', + 'gph' => 'application/vnd.flographit', + 'gpx' => 'application/gpx+xml', + 'gqf' => 'application/vnd.grafeq', + 'gqs' => 'application/vnd.grafeq', + 'gram' => 'application/srgs', + 'gramps' => 'application/x-gramps-xml', + 'gre' => 'application/vnd.geometry-explorer', + 'grv' => 'application/vnd.groove-injector', + 'grxml' => 'application/srgs+xml', + 'gsf' => 'application/x-font-ghostscript', + 'gsheet' => 'application/vnd.google-apps.spreadsheet', + 'gslides' => 'application/vnd.google-apps.presentation', + 'gtar' => 'application/x-gtar', + 'gtm' => 'application/vnd.groove-tool-message', + 'gtw' => 'model/vnd.gtw', + 'gv' => 'text/vnd.graphviz', + 'gxf' => 'application/gxf', + 'gxt' => 'application/vnd.geonext', + 'gz' => 'application/x-gzip', + 'gzip' => 'application/x-gzip', + 'h' => 'text/x-c', + 'h261' => 'video/h261', + 'h263' => 'video/h263', + 'h264' => 'video/h264', + 'hal' => 'application/vnd.hal+xml', + 'hbci' => 'application/vnd.hbci', + 'hbs' => 'text/x-handlebars-template', + 'hdd' => 'application/x-virtualbox-hdd', + 'hdf' => 'application/x-hdf', + 'heic' => 'image/heic', + 'heics' => 'image/heic-sequence', + 'heif' => 'image/heif', + 'heifs' => 'image/heif-sequence', + 'hej2' => 'image/hej2k', + 'held' => 'application/atsc-held+xml', + 'hh' => 'text/x-c', + 'hjson' => 'application/hjson', + 'hlp' => 'application/winhlp', + 'hpgl' => 'application/vnd.hp-hpgl', + 'hpid' => 'application/vnd.hp-hpid', + 'hps' => 'application/vnd.hp-hps', + 'hqx' => 'application/mac-binhex40', + 'hsj2' => 'image/hsj2', + 'htc' => 'text/x-component', + 'htke' => 'application/vnd.kenameaapp', + 'htm' => 'text/html', + 'html' => 'text/html', + 'hvd' => 'application/vnd.yamaha.hv-dic', + 'hvp' => 'application/vnd.yamaha.hv-voice', + 'hvs' => 'application/vnd.yamaha.hv-script', + 'i2g' => 'application/vnd.intergeo', + 'icc' => 'application/vnd.iccprofile', + 'ice' => 'x-conference/x-cooltalk', + 'icm' => 'application/vnd.iccprofile', + 'ico' => 'image/x-icon', + 'ics' => 'text/calendar', + 'ief' => 'image/ief', + 'ifb' => 'text/calendar', + 'ifm' => 'application/vnd.shana.informed.formdata', + 'iges' => 'model/iges', + 'igl' => 'application/vnd.igloader', + 'igm' => 'application/vnd.insors.igm', + 'igs' => 'model/iges', + 'igx' => 'application/vnd.micrografx.igx', + 'iif' => 'application/vnd.shana.informed.interchange', + 'img' => 'application/octet-stream', + 'imp' => 'application/vnd.accpac.simply.imp', + 'ims' => 'application/vnd.ms-ims', + 'in' => 'text/plain', + 'ini' => 'text/plain', + 'ink' => 'application/inkml+xml', + 'inkml' => 'application/inkml+xml', + 'install' => 'application/x-install-instructions', + 'iota' => 'application/vnd.astraea-software.iota', + 'ipfix' => 'application/ipfix', + 'ipk' => 'application/vnd.shana.informed.package', + 'irm' => 'application/vnd.ibm.rights-management', + 'irp' => 'application/vnd.irepository.package+xml', + 'iso' => 'application/x-iso9660-image', + 'itp' => 'application/vnd.shana.informed.formtemplate', + 'its' => 'application/its+xml', + 'ivp' => 'application/vnd.immervision-ivp', + 'ivu' => 'application/vnd.immervision-ivu', + 'jad' => 'text/vnd.sun.j2me.app-descriptor', + 'jade' => 'text/jade', + 'jam' => 'application/vnd.jam', + 'jar' => 'application/java-archive', + 'jardiff' => 'application/x-java-archive-diff', + 'java' => 'text/x-java-source', + 'jhc' => 'image/jphc', + 'jisp' => 'application/vnd.jisp', + 'jls' => 'image/jls', + 'jlt' => 'application/vnd.hp-jlyt', + 'jng' => 'image/x-jng', + 'jnlp' => 'application/x-java-jnlp-file', + 'joda' => 'application/vnd.joost.joda-archive', + 'jp2' => 'image/jp2', + 'jpe' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'jpf' => 'image/jpx', + 'jpg' => 'image/jpeg', + 'jpg2' => 'image/jp2', + 'jpgm' => 'video/jpm', + 'jpgv' => 'video/jpeg', + 'jph' => 'image/jph', + 'jpm' => 'video/jpm', + 'jpx' => 'image/jpx', + 'js' => 'application/javascript', + 'json' => 'application/json', + 'json5' => 'application/json5', + 'jsonld' => 'application/ld+json', + 'jsonml' => 'application/jsonml+json', + 'jsx' => 'text/jsx', + 'jxr' => 'image/jxr', + 'jxra' => 'image/jxra', + 'jxrs' => 'image/jxrs', + 'jxs' => 'image/jxs', + 'jxsc' => 'image/jxsc', + 'jxsi' => 'image/jxsi', + 'jxss' => 'image/jxss', + 'kar' => 'audio/midi', + 'karbon' => 'application/vnd.kde.karbon', + 'kdb' => 'application/octet-stream', + 'kdbx' => 'application/x-keepass2', + 'key' => 'application/vnd.apple.keynote', + 'kfo' => 'application/vnd.kde.kformula', + 'kia' => 'application/vnd.kidspiration', + 'kml' => 'application/vnd.google-earth.kml+xml', + 'kmz' => 'application/vnd.google-earth.kmz', + 'kne' => 'application/vnd.kinar', + 'knp' => 'application/vnd.kinar', + 'kon' => 'application/vnd.kde.kontour', + 'kpr' => 'application/vnd.kde.kpresenter', + 'kpt' => 'application/vnd.kde.kpresenter', + 'kpxx' => 'application/vnd.ds-keypoint', + 'ksp' => 'application/vnd.kde.kspread', + 'ktr' => 'application/vnd.kahootz', + 'ktx' => 'image/ktx', + 'ktx2' => 'image/ktx2', + 'ktz' => 'application/vnd.kahootz', + 'kwd' => 'application/vnd.kde.kword', + 'kwt' => 'application/vnd.kde.kword', + 'lasxml' => 'application/vnd.las.las+xml', + 'latex' => 'application/x-latex', + 'lbd' => 'application/vnd.llamagraphics.life-balance.desktop', + 'lbe' => 'application/vnd.llamagraphics.life-balance.exchange+xml', + 'les' => 'application/vnd.hhe.lesson-player', + 'less' => 'text/less', + 'lgr' => 'application/lgr+xml', + 'lha' => 'application/octet-stream', + 'link66' => 'application/vnd.route66.link66+xml', + 'list' => 'text/plain', + 'list3820' => 'application/vnd.ibm.modcap', + 'listafp' => 'application/vnd.ibm.modcap', + 'litcoffee' => 'text/coffeescript', + 'lnk' => 'application/x-ms-shortcut', + 'log' => 'text/plain', + 'lostxml' => 'application/lost+xml', + 'lrf' => 'application/octet-stream', + 'lrm' => 'application/vnd.ms-lrm', + 'ltf' => 'application/vnd.frogans.ltf', + 'lua' => 'text/x-lua', + 'luac' => 'application/x-lua-bytecode', + 'lvp' => 'audio/vnd.lucent.voice', + 'lwp' => 'application/vnd.lotus-wordpro', + 'lzh' => 'application/octet-stream', + 'm1v' => 'video/mpeg', + 'm2a' => 'audio/mpeg', + 'm2v' => 'video/mpeg', + 'm3a' => 'audio/mpeg', + 'm3u' => 'text/plain', + 'm3u8' => 'application/vnd.apple.mpegurl', + 'm4a' => 'audio/x-m4a', + 'm4p' => 'application/mp4', + 'm4u' => 'application/vnd.mpegurl', + 'm4v' => 'video/x-m4v', + 'm13' => 'application/x-msmediaview', + 'm14' => 'application/x-msmediaview', + 'm21' => 'application/mp21', + 'ma' => 'application/mathematica', + 'mads' => 'application/mads+xml', + 'maei' => 'application/mmt-aei+xml', + 'mag' => 'application/vnd.ecowin.chart', + 'maker' => 'application/vnd.framemaker', + 'man' => 'text/troff', + 'manifest' => 'text/cache-manifest', + 'map' => 'application/json', + 'mar' => 'application/octet-stream', + 'markdown' => 'text/markdown', + 'mathml' => 'application/mathml+xml', + 'mb' => 'application/mathematica', + 'mbk' => 'application/vnd.mobius.mbk', + 'mbox' => 'application/mbox', + 'mc1' => 'application/vnd.medcalcdata', + 'mcd' => 'application/vnd.mcd', + 'mcurl' => 'text/vnd.curl.mcurl', + 'md' => 'text/markdown', + 'mdb' => 'application/x-msaccess', + 'mdi' => 'image/vnd.ms-modi', + 'mdx' => 'text/mdx', + 'me' => 'text/troff', + 'mesh' => 'model/mesh', + 'meta4' => 'application/metalink4+xml', + 'metalink' => 'application/metalink+xml', + 'mets' => 'application/mets+xml', + 'mfm' => 'application/vnd.mfmp', + 'mft' => 'application/rpki-manifest', + 'mgp' => 'application/vnd.osgeo.mapguide.package', + 'mgz' => 'application/vnd.proteus.magazine', + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'mie' => 'application/x-mie', + 'mif' => 'application/vnd.mif', + 'mime' => 'message/rfc822', + 'mj2' => 'video/mj2', + 'mjp2' => 'video/mj2', + 'mjs' => 'application/javascript', + 'mk3d' => 'video/x-matroska', + 'mka' => 'audio/x-matroska', + 'mkd' => 'text/x-markdown', + 'mks' => 'video/x-matroska', + 'mkv' => 'video/x-matroska', + 'mlp' => 'application/vnd.dolby.mlp', + 'mmd' => 'application/vnd.chipnuts.karaoke-mmd', + 'mmf' => 'application/vnd.smaf', + 'mml' => 'text/mathml', + 'mmr' => 'image/vnd.fujixerox.edmics-mmr', + 'mng' => 'video/x-mng', + 'mny' => 'application/x-msmoney', + 'mobi' => 'application/x-mobipocket-ebook', + 'mods' => 'application/mods+xml', + 'mov' => 'video/quicktime', + 'movie' => 'video/x-sgi-movie', + 'mp2' => 'audio/mpeg', + 'mp2a' => 'audio/mpeg', + 'mp3' => 'audio/mpeg', + 'mp4' => 'video/mp4', + 'mp4a' => 'audio/mp4', + 'mp4s' => 'application/mp4', + 'mp4v' => 'video/mp4', + 'mp21' => 'application/mp21', + 'mpc' => 'application/vnd.mophun.certificate', + 'mpd' => 'application/dash+xml', + 'mpe' => 'video/mpeg', + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mpg4' => 'video/mp4', + 'mpga' => 'audio/mpeg', + 'mpkg' => 'application/vnd.apple.installer+xml', + 'mpm' => 'application/vnd.blueice.multipass', + 'mpn' => 'application/vnd.mophun.application', + 'mpp' => 'application/vnd.ms-project', + 'mpt' => 'application/vnd.ms-project', + 'mpy' => 'application/vnd.ibm.minipay', + 'mqy' => 'application/vnd.mobius.mqy', + 'mrc' => 'application/marc', + 'mrcx' => 'application/marcxml+xml', + 'ms' => 'text/troff', + 'mscml' => 'application/mediaservercontrol+xml', + 'mseed' => 'application/vnd.fdsn.mseed', + 'mseq' => 'application/vnd.mseq', + 'msf' => 'application/vnd.epson.msf', + 'msg' => 'application/vnd.ms-outlook', + 'msh' => 'model/mesh', + 'msi' => 'application/x-msdownload', + 'msl' => 'application/vnd.mobius.msl', + 'msm' => 'application/octet-stream', + 'msp' => 'application/octet-stream', + 'msty' => 'application/vnd.muvee.style', + 'mtl' => 'model/mtl', + 'mts' => 'model/vnd.mts', + 'mus' => 'application/vnd.musician', + 'musd' => 'application/mmt-usd+xml', + 'musicxml' => 'application/vnd.recordare.musicxml+xml', + 'mvb' => 'application/x-msmediaview', + 'mwf' => 'application/vnd.mfer', + 'mxf' => 'application/mxf', + 'mxl' => 'application/vnd.recordare.musicxml', + 'mxmf' => 'audio/mobile-xmf', + 'mxml' => 'application/xv+xml', + 'mxs' => 'application/vnd.triscape.mxs', + 'mxu' => 'video/vnd.mpegurl', + 'n-gage' => 'application/vnd.nokia.n-gage.symbian.install', + 'n3' => 'text/n3', + 'nb' => 'application/mathematica', + 'nbp' => 'application/vnd.wolfram.player', + 'nc' => 'application/x-netcdf', + 'ncx' => 'application/x-dtbncx+xml', + 'nfo' => 'text/x-nfo', + 'ngdat' => 'application/vnd.nokia.n-gage.data', + 'nitf' => 'application/vnd.nitf', + 'nlu' => 'application/vnd.neurolanguage.nlu', + 'nml' => 'application/vnd.enliven', + 'nnd' => 'application/vnd.noblenet-directory', + 'nns' => 'application/vnd.noblenet-sealer', + 'nnw' => 'application/vnd.noblenet-web', + 'npx' => 'image/vnd.net-fpx', + 'nq' => 'application/n-quads', + 'nsc' => 'application/x-conference', + 'nsf' => 'application/vnd.lotus-notes', + 'nt' => 'application/n-triples', + 'ntf' => 'application/vnd.nitf', + 'numbers' => 'application/vnd.apple.numbers', + 'nzb' => 'application/x-nzb', + 'oa2' => 'application/vnd.fujitsu.oasys2', + 'oa3' => 'application/vnd.fujitsu.oasys3', + 'oas' => 'application/vnd.fujitsu.oasys', + 'obd' => 'application/x-msbinder', + 'obgx' => 'application/vnd.openblox.game+xml', + 'obj' => 'model/obj', + 'oda' => 'application/oda', + 'odb' => 'application/vnd.oasis.opendocument.database', + 'odc' => 'application/vnd.oasis.opendocument.chart', + 'odf' => 'application/vnd.oasis.opendocument.formula', + 'odft' => 'application/vnd.oasis.opendocument.formula-template', + 'odg' => 'application/vnd.oasis.opendocument.graphics', + 'odi' => 'application/vnd.oasis.opendocument.image', + 'odm' => 'application/vnd.oasis.opendocument.text-master', + 'odp' => 'application/vnd.oasis.opendocument.presentation', + 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', + 'odt' => 'application/vnd.oasis.opendocument.text', + 'oga' => 'audio/ogg', + 'ogex' => 'model/vnd.opengex', + 'ogg' => 'audio/ogg', + 'ogv' => 'video/ogg', + 'ogx' => 'application/ogg', + 'omdoc' => 'application/omdoc+xml', + 'onepkg' => 'application/onenote', + 'onetmp' => 'application/onenote', + 'onetoc' => 'application/onenote', + 'onetoc2' => 'application/onenote', + 'opf' => 'application/oebps-package+xml', + 'opml' => 'text/x-opml', + 'oprc' => 'application/vnd.palm', + 'opus' => 'audio/ogg', + 'org' => 'text/x-org', + 'osf' => 'application/vnd.yamaha.openscoreformat', + 'osfpvg' => 'application/vnd.yamaha.openscoreformat.osfpvg+xml', + 'osm' => 'application/vnd.openstreetmap.data+xml', + 'otc' => 'application/vnd.oasis.opendocument.chart-template', + 'otf' => 'font/otf', + 'otg' => 'application/vnd.oasis.opendocument.graphics-template', + 'oth' => 'application/vnd.oasis.opendocument.text-web', + 'oti' => 'application/vnd.oasis.opendocument.image-template', + 'otp' => 'application/vnd.oasis.opendocument.presentation-template', + 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template', + 'ott' => 'application/vnd.oasis.opendocument.text-template', + 'ova' => 'application/x-virtualbox-ova', + 'ovf' => 'application/x-virtualbox-ovf', + 'owl' => 'application/rdf+xml', + 'oxps' => 'application/oxps', + 'oxt' => 'application/vnd.openofficeorg.extension', + 'p' => 'text/x-pascal', + 'p7a' => 'application/x-pkcs7-signature', + 'p7b' => 'application/x-pkcs7-certificates', + 'p7c' => 'application/pkcs7-mime', + 'p7m' => 'application/pkcs7-mime', + 'p7r' => 'application/x-pkcs7-certreqresp', + 'p7s' => 'application/pkcs7-signature', + 'p8' => 'application/pkcs8', + 'p10' => 'application/x-pkcs10', + 'p12' => 'application/x-pkcs12', + 'pac' => 'application/x-ns-proxy-autoconfig', + 'pages' => 'application/vnd.apple.pages', + 'pas' => 'text/x-pascal', + 'paw' => 'application/vnd.pawaafile', + 'pbd' => 'application/vnd.powerbuilder6', + 'pbm' => 'image/x-portable-bitmap', + 'pcap' => 'application/vnd.tcpdump.pcap', + 'pcf' => 'application/x-font-pcf', + 'pcl' => 'application/vnd.hp-pcl', + 'pclxl' => 'application/vnd.hp-pclxl', + 'pct' => 'image/x-pict', + 'pcurl' => 'application/vnd.curl.pcurl', + 'pcx' => 'image/x-pcx', + 'pdb' => 'application/x-pilot', + 'pde' => 'text/x-processing', + 'pdf' => 'application/pdf', + 'pem' => 'application/x-x509-user-cert', + 'pfa' => 'application/x-font-type1', + 'pfb' => 'application/x-font-type1', + 'pfm' => 'application/x-font-type1', + 'pfr' => 'application/font-tdpfr', + 'pfx' => 'application/x-pkcs12', + 'pgm' => 'image/x-portable-graymap', + 'pgn' => 'application/x-chess-pgn', + 'pgp' => 'application/pgp', + 'php' => 'application/x-httpd-php', + 'php3' => 'application/x-httpd-php', + 'php4' => 'application/x-httpd-php', + 'phps' => 'application/x-httpd-php-source', + 'phtml' => 'application/x-httpd-php', + 'pic' => 'image/x-pict', + 'pkg' => 'application/octet-stream', + 'pki' => 'application/pkixcmp', + 'pkipath' => 'application/pkix-pkipath', + 'pkpass' => 'application/vnd.apple.pkpass', + 'pl' => 'application/x-perl', + 'plb' => 'application/vnd.3gpp.pic-bw-large', + 'plc' => 'application/vnd.mobius.plc', + 'plf' => 'application/vnd.pocketlearn', + 'pls' => 'application/pls+xml', + 'pm' => 'application/x-perl', + 'pml' => 'application/vnd.ctc-posml', + 'png' => 'image/png', + 'pnm' => 'image/x-portable-anymap', + 'portpkg' => 'application/vnd.macports.portpkg', + 'pot' => 'application/vnd.ms-powerpoint', + 'potm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12', + 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template', + 'ppa' => 'application/vnd.ms-powerpoint', + 'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12', + 'ppd' => 'application/vnd.cups-ppd', + 'ppm' => 'image/x-portable-pixmap', + 'pps' => 'application/vnd.ms-powerpoint', + 'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12', + 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', + 'ppt' => 'application/powerpoint', + 'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12', + 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'pqa' => 'application/vnd.palm', + 'prc' => 'application/x-pilot', + 'pre' => 'application/vnd.lotus-freelance', + 'prf' => 'application/pics-rules', + 'provx' => 'application/provenance+xml', + 'ps' => 'application/postscript', + 'psb' => 'application/vnd.3gpp.pic-bw-small', + 'psd' => 'application/x-photoshop', + 'psf' => 'application/x-font-linux-psf', + 'pskcxml' => 'application/pskc+xml', + 'pti' => 'image/prs.pti', + 'ptid' => 'application/vnd.pvi.ptid1', + 'pub' => 'application/x-mspublisher', + 'pvb' => 'application/vnd.3gpp.pic-bw-var', + 'pwn' => 'application/vnd.3m.post-it-notes', + 'pya' => 'audio/vnd.ms-playready.media.pya', + 'pyv' => 'video/vnd.ms-playready.media.pyv', + 'qam' => 'application/vnd.epson.quickanime', + 'qbo' => 'application/vnd.intu.qbo', + 'qfx' => 'application/vnd.intu.qfx', + 'qps' => 'application/vnd.publishare-delta-tree', + 'qt' => 'video/quicktime', + 'qwd' => 'application/vnd.quark.quarkxpress', + 'qwt' => 'application/vnd.quark.quarkxpress', + 'qxb' => 'application/vnd.quark.quarkxpress', + 'qxd' => 'application/vnd.quark.quarkxpress', + 'qxl' => 'application/vnd.quark.quarkxpress', + 'qxt' => 'application/vnd.quark.quarkxpress', + 'ra' => 'audio/x-realaudio', + 'ram' => 'audio/x-pn-realaudio', + 'raml' => 'application/raml+yaml', + 'rapd' => 'application/route-apd+xml', + 'rar' => 'application/x-rar', + 'ras' => 'image/x-cmu-raster', + 'rcprofile' => 'application/vnd.ipunplugged.rcprofile', + 'rdf' => 'application/rdf+xml', + 'rdz' => 'application/vnd.data-vision.rdz', + 'relo' => 'application/p2p-overlay+xml', + 'rep' => 'application/vnd.businessobjects', + 'res' => 'application/x-dtbresource+xml', + 'rgb' => 'image/x-rgb', + 'rif' => 'application/reginfo+xml', + 'rip' => 'audio/vnd.rip', + 'ris' => 'application/x-research-info-systems', + 'rl' => 'application/resource-lists+xml', + 'rlc' => 'image/vnd.fujixerox.edmics-rlc', + 'rld' => 'application/resource-lists-diff+xml', + 'rm' => 'audio/x-pn-realaudio', + 'rmi' => 'audio/midi', + 'rmp' => 'audio/x-pn-realaudio-plugin', + 'rms' => 'application/vnd.jcp.javame.midlet-rms', + 'rmvb' => 'application/vnd.rn-realmedia-vbr', + 'rnc' => 'application/relax-ng-compact-syntax', + 'rng' => 'application/xml', + 'roa' => 'application/rpki-roa', + 'roff' => 'text/troff', + 'rp9' => 'application/vnd.cloanto.rp9', + 'rpm' => 'audio/x-pn-realaudio-plugin', + 'rpss' => 'application/vnd.nokia.radio-presets', + 'rpst' => 'application/vnd.nokia.radio-preset', + 'rq' => 'application/sparql-query', + 'rs' => 'application/rls-services+xml', + 'rsa' => 'application/x-pkcs7', + 'rsat' => 'application/atsc-rsat+xml', + 'rsd' => 'application/rsd+xml', + 'rsheet' => 'application/urc-ressheet+xml', + 'rss' => 'application/rss+xml', + 'rtf' => 'text/rtf', + 'rtx' => 'text/richtext', + 'run' => 'application/x-makeself', + 'rusd' => 'application/route-usd+xml', + 'rv' => 'video/vnd.rn-realvideo', + 's' => 'text/x-asm', + 's3m' => 'audio/s3m', + 'saf' => 'application/vnd.yamaha.smaf-audio', + 'sass' => 'text/x-sass', + 'sbml' => 'application/sbml+xml', + 'sc' => 'application/vnd.ibm.secure-container', + 'scd' => 'application/x-msschedule', + 'scm' => 'application/vnd.lotus-screencam', + 'scq' => 'application/scvp-cv-request', + 'scs' => 'application/scvp-cv-response', + 'scss' => 'text/x-scss', + 'scurl' => 'text/vnd.curl.scurl', + 'sda' => 'application/vnd.stardivision.draw', + 'sdc' => 'application/vnd.stardivision.calc', + 'sdd' => 'application/vnd.stardivision.impress', + 'sdkd' => 'application/vnd.solent.sdkm+xml', + 'sdkm' => 'application/vnd.solent.sdkm+xml', + 'sdp' => 'application/sdp', + 'sdw' => 'application/vnd.stardivision.writer', + 'sea' => 'application/octet-stream', + 'see' => 'application/vnd.seemail', + 'seed' => 'application/vnd.fdsn.seed', + 'sema' => 'application/vnd.sema', + 'semd' => 'application/vnd.semd', + 'semf' => 'application/vnd.semf', + 'senmlx' => 'application/senml+xml', + 'sensmlx' => 'application/sensml+xml', + 'ser' => 'application/java-serialized-object', + 'setpay' => 'application/set-payment-initiation', + 'setreg' => 'application/set-registration-initiation', + 'sfd-hdstx' => 'application/vnd.hydrostatix.sof-data', + 'sfs' => 'application/vnd.spotfire.sfs', + 'sfv' => 'text/x-sfv', + 'sgi' => 'image/sgi', + 'sgl' => 'application/vnd.stardivision.writer-global', + 'sgm' => 'text/sgml', + 'sgml' => 'text/sgml', + 'sh' => 'application/x-sh', + 'shar' => 'application/x-shar', + 'shex' => 'text/shex', + 'shf' => 'application/shf+xml', + 'shtml' => 'text/html', + 'sid' => 'image/x-mrsid-image', + 'sieve' => 'application/sieve', + 'sig' => 'application/pgp-signature', + 'sil' => 'audio/silk', + 'silo' => 'model/mesh', + 'sis' => 'application/vnd.symbian.install', + 'sisx' => 'application/vnd.symbian.install', + 'sit' => 'application/x-stuffit', + 'sitx' => 'application/x-stuffitx', + 'siv' => 'application/sieve', + 'skd' => 'application/vnd.koan', + 'skm' => 'application/vnd.koan', + 'skp' => 'application/vnd.koan', + 'skt' => 'application/vnd.koan', + 'sldm' => 'application/vnd.ms-powerpoint.slide.macroenabled.12', + 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide', + 'slim' => 'text/slim', + 'slm' => 'text/slim', + 'sls' => 'application/route-s-tsid+xml', + 'slt' => 'application/vnd.epson.salt', + 'sm' => 'application/vnd.stepmania.stepchart', + 'smf' => 'application/vnd.stardivision.math', + 'smi' => 'application/smil', + 'smil' => 'application/smil', + 'smv' => 'video/x-smv', + 'smzip' => 'application/vnd.stepmania.package', + 'snd' => 'audio/basic', + 'snf' => 'application/x-font-snf', + 'so' => 'application/octet-stream', + 'spc' => 'application/x-pkcs7-certificates', + 'spdx' => 'text/spdx', + 'spf' => 'application/vnd.yamaha.smaf-phrase', + 'spl' => 'application/x-futuresplash', + 'spot' => 'text/vnd.in3d.spot', + 'spp' => 'application/scvp-vp-response', + 'spq' => 'application/scvp-vp-request', + 'spx' => 'audio/ogg', + 'sql' => 'application/x-sql', + 'src' => 'application/x-wais-source', + 'srt' => 'application/x-subrip', + 'sru' => 'application/sru+xml', + 'srx' => 'application/sparql-results+xml', + 'ssdl' => 'application/ssdl+xml', + 'sse' => 'application/vnd.kodak-descriptor', + 'ssf' => 'application/vnd.epson.ssf', + 'ssml' => 'application/ssml+xml', + 'sst' => 'application/octet-stream', + 'st' => 'application/vnd.sailingtracker.track', + 'stc' => 'application/vnd.sun.xml.calc.template', + 'std' => 'application/vnd.sun.xml.draw.template', + 'stf' => 'application/vnd.wt.stf', + 'sti' => 'application/vnd.sun.xml.impress.template', + 'stk' => 'application/hyperstudio', + 'stl' => 'model/stl', + 'str' => 'application/vnd.pg.format', + 'stw' => 'application/vnd.sun.xml.writer.template', + 'styl' => 'text/stylus', + 'stylus' => 'text/stylus', + 'sub' => 'text/vnd.dvb.subtitle', + 'sus' => 'application/vnd.sus-calendar', + 'susp' => 'application/vnd.sus-calendar', + 'sv4cpio' => 'application/x-sv4cpio', + 'sv4crc' => 'application/x-sv4crc', + 'svc' => 'application/vnd.dvb.service', + 'svd' => 'application/vnd.svd', + 'svg' => 'image/svg+xml', + 'svgz' => 'image/svg+xml', + 'swa' => 'application/x-director', + 'swf' => 'application/x-shockwave-flash', + 'swi' => 'application/vnd.aristanetworks.swi', + 'swidtag' => 'application/swid+xml', + 'sxc' => 'application/vnd.sun.xml.calc', + 'sxd' => 'application/vnd.sun.xml.draw', + 'sxg' => 'application/vnd.sun.xml.writer.global', + 'sxi' => 'application/vnd.sun.xml.impress', + 'sxm' => 'application/vnd.sun.xml.math', + 'sxw' => 'application/vnd.sun.xml.writer', + 't' => 'text/troff', + 't3' => 'application/x-t3vm-image', + 't38' => 'image/t38', + 'taglet' => 'application/vnd.mynfc', + 'tao' => 'application/vnd.tao.intent-module-archive', + 'tap' => 'image/vnd.tencent.tap', + 'tar' => 'application/x-tar', + 'tcap' => 'application/vnd.3gpp2.tcap', + 'tcl' => 'application/x-tcl', + 'td' => 'application/urc-targetdesc+xml', + 'teacher' => 'application/vnd.smart.teacher', + 'tei' => 'application/tei+xml', + 'teicorpus' => 'application/tei+xml', + 'tex' => 'application/x-tex', + 'texi' => 'application/x-texinfo', + 'texinfo' => 'application/x-texinfo', + 'text' => 'text/plain', + 'tfi' => 'application/thraud+xml', + 'tfm' => 'application/x-tex-tfm', + 'tfx' => 'image/tiff-fx', + 'tga' => 'image/x-tga', + 'tgz' => 'application/x-tar', + 'thmx' => 'application/vnd.ms-officetheme', + 'tif' => 'image/tiff', + 'tiff' => 'image/tiff', + 'tk' => 'application/x-tcl', + 'tmo' => 'application/vnd.tmobile-livetv', + 'toml' => 'application/toml', + 'torrent' => 'application/x-bittorrent', + 'tpl' => 'application/vnd.groove-tool-template', + 'tpt' => 'application/vnd.trid.tpt', + 'tr' => 'text/troff', + 'tra' => 'application/vnd.trueapp', + 'trm' => 'application/x-msterminal', + 'ts' => 'video/mp2t', + 'tsd' => 'application/timestamped-data', + 'tsv' => 'text/tab-separated-values', + 'ttc' => 'font/collection', + 'ttf' => 'font/ttf', + 'ttl' => 'text/turtle', + 'ttml' => 'application/ttml+xml', + 'twd' => 'application/vnd.simtech-mindmapper', + 'twds' => 'application/vnd.simtech-mindmapper', + 'txd' => 'application/vnd.genomatix.tuxedo', + 'txf' => 'application/vnd.mobius.txf', + 'txt' => 'text/plain', + 'u8dsn' => 'message/global-delivery-status', + 'u8hdr' => 'message/global-headers', + 'u8mdn' => 'message/global-disposition-notification', + 'u8msg' => 'message/global', + 'u32' => 'application/x-authorware-bin', + 'ubj' => 'application/ubjson', + 'udeb' => 'application/x-debian-package', + 'ufd' => 'application/vnd.ufdl', + 'ufdl' => 'application/vnd.ufdl', + 'ulx' => 'application/x-glulx', + 'umj' => 'application/vnd.umajin', + 'unityweb' => 'application/vnd.unity', + 'uoml' => 'application/vnd.uoml+xml', + 'uri' => 'text/uri-list', + 'uris' => 'text/uri-list', + 'urls' => 'text/uri-list', + 'usdz' => 'model/vnd.usdz+zip', + 'ustar' => 'application/x-ustar', + 'utz' => 'application/vnd.uiq.theme', + 'uu' => 'text/x-uuencode', + 'uva' => 'audio/vnd.dece.audio', + 'uvd' => 'application/vnd.dece.data', + 'uvf' => 'application/vnd.dece.data', + 'uvg' => 'image/vnd.dece.graphic', + 'uvh' => 'video/vnd.dece.hd', + 'uvi' => 'image/vnd.dece.graphic', + 'uvm' => 'video/vnd.dece.mobile', + 'uvp' => 'video/vnd.dece.pd', + 'uvs' => 'video/vnd.dece.sd', + 'uvt' => 'application/vnd.dece.ttml+xml', + 'uvu' => 'video/vnd.uvvu.mp4', + 'uvv' => 'video/vnd.dece.video', + 'uvva' => 'audio/vnd.dece.audio', + 'uvvd' => 'application/vnd.dece.data', + 'uvvf' => 'application/vnd.dece.data', + 'uvvg' => 'image/vnd.dece.graphic', + 'uvvh' => 'video/vnd.dece.hd', + 'uvvi' => 'image/vnd.dece.graphic', + 'uvvm' => 'video/vnd.dece.mobile', + 'uvvp' => 'video/vnd.dece.pd', + 'uvvs' => 'video/vnd.dece.sd', + 'uvvt' => 'application/vnd.dece.ttml+xml', + 'uvvu' => 'video/vnd.uvvu.mp4', + 'uvvv' => 'video/vnd.dece.video', + 'uvvx' => 'application/vnd.dece.unspecified', + 'uvvz' => 'application/vnd.dece.zip', + 'uvx' => 'application/vnd.dece.unspecified', + 'uvz' => 'application/vnd.dece.zip', + 'vbox' => 'application/x-virtualbox-vbox', + 'vbox-extpack' => 'application/x-virtualbox-vbox-extpack', + 'vcard' => 'text/vcard', + 'vcd' => 'application/x-cdlink', + 'vcf' => 'text/x-vcard', + 'vcg' => 'application/vnd.groove-vcard', + 'vcs' => 'text/x-vcalendar', + 'vcx' => 'application/vnd.vcx', + 'vdi' => 'application/x-virtualbox-vdi', + 'vhd' => 'application/x-virtualbox-vhd', + 'vis' => 'application/vnd.visionary', + 'viv' => 'video/vnd.vivo', + 'vlc' => 'application/videolan', + 'vmdk' => 'application/x-virtualbox-vmdk', + 'vob' => 'video/x-ms-vob', + 'vor' => 'application/vnd.stardivision.writer', + 'vox' => 'application/x-authorware-bin', + 'vrml' => 'model/vrml', + 'vsd' => 'application/vnd.visio', + 'vsf' => 'application/vnd.vsf', + 'vss' => 'application/vnd.visio', + 'vst' => 'application/vnd.visio', + 'vsw' => 'application/vnd.visio', + 'vtf' => 'image/vnd.valve.source.texture', + 'vtt' => 'text/vtt', + 'vtu' => 'model/vnd.vtu', + 'vxml' => 'application/voicexml+xml', + 'w3d' => 'application/x-director', + 'wad' => 'application/x-doom', + 'wadl' => 'application/vnd.sun.wadl+xml', + 'war' => 'application/java-archive', + 'wasm' => 'application/wasm', + 'wav' => 'audio/x-wav', + 'wax' => 'audio/x-ms-wax', + 'wbmp' => 'image/vnd.wap.wbmp', + 'wbs' => 'application/vnd.criticaltools.wbs+xml', + 'wbxml' => 'application/wbxml', + 'wcm' => 'application/vnd.ms-works', + 'wdb' => 'application/vnd.ms-works', + 'wdp' => 'image/vnd.ms-photo', + 'weba' => 'audio/webm', + 'webapp' => 'application/x-web-app-manifest+json', + 'webm' => 'video/webm', + 'webmanifest' => 'application/manifest+json', + 'webp' => 'image/webp', + 'wg' => 'application/vnd.pmi.widget', + 'wgt' => 'application/widget', + 'wks' => 'application/vnd.ms-works', + 'wm' => 'video/x-ms-wm', + 'wma' => 'audio/x-ms-wma', + 'wmd' => 'application/x-ms-wmd', + 'wmf' => 'image/wmf', + 'wml' => 'text/vnd.wap.wml', + 'wmlc' => 'application/wmlc', + 'wmls' => 'text/vnd.wap.wmlscript', + 'wmlsc' => 'application/vnd.wap.wmlscriptc', + 'wmv' => 'video/x-ms-wmv', + 'wmx' => 'video/x-ms-wmx', + 'wmz' => 'application/x-msmetafile', + 'woff' => 'font/woff', + 'woff2' => 'font/woff2', + 'word' => 'application/msword', + 'wpd' => 'application/vnd.wordperfect', + 'wpl' => 'application/vnd.ms-wpl', + 'wps' => 'application/vnd.ms-works', + 'wqd' => 'application/vnd.wqd', + 'wri' => 'application/x-mswrite', + 'wrl' => 'model/vrml', + 'wsc' => 'message/vnd.wfa.wsc', + 'wsdl' => 'application/wsdl+xml', + 'wspolicy' => 'application/wspolicy+xml', + 'wtb' => 'application/vnd.webturbo', + 'wvx' => 'video/x-ms-wvx', + 'x3d' => 'model/x3d+xml', + 'x3db' => 'model/x3d+fastinfoset', + 'x3dbz' => 'model/x3d+binary', + 'x3dv' => 'model/x3d-vrml', + 'x3dvz' => 'model/x3d+vrml', + 'x3dz' => 'model/x3d+xml', + 'x32' => 'application/x-authorware-bin', + 'x_b' => 'model/vnd.parasolid.transmit.binary', + 'x_t' => 'model/vnd.parasolid.transmit.text', + 'xaml' => 'application/xaml+xml', + 'xap' => 'application/x-silverlight-app', + 'xar' => 'application/vnd.xara', + 'xav' => 'application/xcap-att+xml', + 'xbap' => 'application/x-ms-xbap', + 'xbd' => 'application/vnd.fujixerox.docuworks.binder', + 'xbm' => 'image/x-xbitmap', + 'xca' => 'application/xcap-caps+xml', + 'xcs' => 'application/calendar+xml', + 'xdf' => 'application/xcap-diff+xml', + 'xdm' => 'application/vnd.syncml.dm+xml', + 'xdp' => 'application/vnd.adobe.xdp+xml', + 'xdssc' => 'application/dssc+xml', + 'xdw' => 'application/vnd.fujixerox.docuworks', + 'xel' => 'application/xcap-el+xml', + 'xenc' => 'application/xenc+xml', + 'xer' => 'application/xcap-error+xml', + 'xfdf' => 'application/vnd.adobe.xfdf', + 'xfdl' => 'application/vnd.xfdl', + 'xht' => 'application/xhtml+xml', + 'xhtml' => 'application/xhtml+xml', + 'xhvml' => 'application/xv+xml', + 'xif' => 'image/vnd.xiff', + 'xl' => 'application/excel', + 'xla' => 'application/vnd.ms-excel', + 'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12', + 'xlc' => 'application/vnd.ms-excel', + 'xlf' => 'application/xliff+xml', + 'xlm' => 'application/vnd.ms-excel', + 'xls' => 'application/vnd.ms-excel', + 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12', + 'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12', + 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'xlt' => 'application/vnd.ms-excel', + 'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12', + 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', + 'xlw' => 'application/vnd.ms-excel', + 'xm' => 'audio/xm', + 'xml' => 'application/xml', + 'xns' => 'application/xcap-ns+xml', + 'xo' => 'application/vnd.olpc-sugar', + 'xop' => 'application/xop+xml', + 'xpi' => 'application/x-xpinstall', + 'xpl' => 'application/xproc+xml', + 'xpm' => 'image/x-xpixmap', + 'xpr' => 'application/vnd.is-xpr', + 'xps' => 'application/vnd.ms-xpsdocument', + 'xpw' => 'application/vnd.intercon.formnet', + 'xpx' => 'application/vnd.intercon.formnet', + 'xsd' => 'application/xml', + 'xsl' => 'application/xml', + 'xslt' => 'application/xslt+xml', + 'xsm' => 'application/vnd.syncml+xml', + 'xspf' => 'application/xspf+xml', + 'xul' => 'application/vnd.mozilla.xul+xml', + 'xvm' => 'application/xv+xml', + 'xvml' => 'application/xv+xml', + 'xwd' => 'image/x-xwindowdump', + 'xyz' => 'chemical/x-xyz', + 'xz' => 'application/x-xz', + 'yaml' => 'text/yaml', + 'yang' => 'application/yang', + 'yin' => 'application/yin+xml', + 'yml' => 'text/yaml', + 'ymp' => 'text/x-suse-ymp', + 'z' => 'application/x-compress', + 'z1' => 'application/x-zmachine', + 'z2' => 'application/x-zmachine', + 'z3' => 'application/x-zmachine', + 'z4' => 'application/x-zmachine', + 'z5' => 'application/x-zmachine', + 'z6' => 'application/x-zmachine', + 'z7' => 'application/x-zmachine', + 'z8' => 'application/x-zmachine', + 'zaz' => 'application/vnd.zzazz.deck+xml', + 'zip' => 'application/x-zip', + 'zir' => 'application/vnd.zul', + 'zirz' => 'application/vnd.zul', + 'zmm' => 'application/vnd.handheld-entertainment+xml', + 'zsh' => 'text/x-scriptzsh', + ]; + + public function lookupMimeType(string $extension): ?string + { + return self::MIME_TYPES_FOR_EXTENSIONS[$extension] ?? null; + } +} diff --git a/vendor/league/mime-type-detection/src/MimeTypeDetector.php b/vendor/league/mime-type-detection/src/MimeTypeDetector.php new file mode 100644 index 000000000..5d799d2a8 --- /dev/null +++ b/vendor/league/mime-type-detection/src/MimeTypeDetector.php @@ -0,0 +1,19 @@ +=5.3.0" + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + } +} diff --git a/vendor/psr/cache/src/CacheException.php b/vendor/psr/cache/src/CacheException.php new file mode 100644 index 000000000..e27f22f8d --- /dev/null +++ b/vendor/psr/cache/src/CacheException.php @@ -0,0 +1,10 @@ +=7.2.0" + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + } +} diff --git a/vendor/psr/container/src/ContainerExceptionInterface.php b/vendor/psr/container/src/ContainerExceptionInterface.php new file mode 100644 index 000000000..cf10b8b4f --- /dev/null +++ b/vendor/psr/container/src/ContainerExceptionInterface.php @@ -0,0 +1,10 @@ +log(LogLevel::EMERGENCY, $message, $context); + } + + /** + * Action must be taken immediately. + * + * Example: Entire website down, database unavailable, etc. This should + * trigger the SMS alerts and wake you up. + * + * @param string $message + * @param mixed[] $context + * + * @return void + */ + public function alert($message, array $context = array()) + { + $this->log(LogLevel::ALERT, $message, $context); + } + + /** + * Critical conditions. + * + * Example: Application component unavailable, unexpected exception. + * + * @param string $message + * @param mixed[] $context + * + * @return void + */ + public function critical($message, array $context = array()) + { + $this->log(LogLevel::CRITICAL, $message, $context); + } + + /** + * Runtime errors that do not require immediate action but should typically + * be logged and monitored. + * + * @param string $message + * @param mixed[] $context + * + * @return void + */ + public function error($message, array $context = array()) + { + $this->log(LogLevel::ERROR, $message, $context); + } + + /** + * Exceptional occurrences that are not errors. + * + * Example: Use of deprecated APIs, poor use of an API, undesirable things + * that are not necessarily wrong. + * + * @param string $message + * @param mixed[] $context + * + * @return void + */ + public function warning($message, array $context = array()) + { + $this->log(LogLevel::WARNING, $message, $context); + } + + /** + * Normal but significant events. + * + * @param string $message + * @param mixed[] $context + * + * @return void + */ + public function notice($message, array $context = array()) + { + $this->log(LogLevel::NOTICE, $message, $context); + } + + /** + * Interesting events. + * + * Example: User logs in, SQL logs. + * + * @param string $message + * @param mixed[] $context + * + * @return void + */ + public function info($message, array $context = array()) + { + $this->log(LogLevel::INFO, $message, $context); + } + + /** + * Detailed debug information. + * + * @param string $message + * @param mixed[] $context + * + * @return void + */ + public function debug($message, array $context = array()) + { + $this->log(LogLevel::DEBUG, $message, $context); + } +} diff --git a/vendor/psr/log/Psr/Log/InvalidArgumentException.php b/vendor/psr/log/Psr/Log/InvalidArgumentException.php new file mode 100644 index 000000000..67f852d1d --- /dev/null +++ b/vendor/psr/log/Psr/Log/InvalidArgumentException.php @@ -0,0 +1,7 @@ +logger = $logger; + } +} diff --git a/vendor/psr/log/Psr/Log/LoggerInterface.php b/vendor/psr/log/Psr/Log/LoggerInterface.php new file mode 100644 index 000000000..2206cfde4 --- /dev/null +++ b/vendor/psr/log/Psr/Log/LoggerInterface.php @@ -0,0 +1,125 @@ +log(LogLevel::EMERGENCY, $message, $context); + } + + /** + * Action must be taken immediately. + * + * Example: Entire website down, database unavailable, etc. This should + * trigger the SMS alerts and wake you up. + * + * @param string $message + * @param array $context + * + * @return void + */ + public function alert($message, array $context = array()) + { + $this->log(LogLevel::ALERT, $message, $context); + } + + /** + * Critical conditions. + * + * Example: Application component unavailable, unexpected exception. + * + * @param string $message + * @param array $context + * + * @return void + */ + public function critical($message, array $context = array()) + { + $this->log(LogLevel::CRITICAL, $message, $context); + } + + /** + * Runtime errors that do not require immediate action but should typically + * be logged and monitored. + * + * @param string $message + * @param array $context + * + * @return void + */ + public function error($message, array $context = array()) + { + $this->log(LogLevel::ERROR, $message, $context); + } + + /** + * Exceptional occurrences that are not errors. + * + * Example: Use of deprecated APIs, poor use of an API, undesirable things + * that are not necessarily wrong. + * + * @param string $message + * @param array $context + * + * @return void + */ + public function warning($message, array $context = array()) + { + $this->log(LogLevel::WARNING, $message, $context); + } + + /** + * Normal but significant events. + * + * @param string $message + * @param array $context + * + * @return void + */ + public function notice($message, array $context = array()) + { + $this->log(LogLevel::NOTICE, $message, $context); + } + + /** + * Interesting events. + * + * Example: User logs in, SQL logs. + * + * @param string $message + * @param array $context + * + * @return void + */ + public function info($message, array $context = array()) + { + $this->log(LogLevel::INFO, $message, $context); + } + + /** + * Detailed debug information. + * + * @param string $message + * @param array $context + * + * @return void + */ + public function debug($message, array $context = array()) + { + $this->log(LogLevel::DEBUG, $message, $context); + } + + /** + * Logs with an arbitrary level. + * + * @param mixed $level + * @param string $message + * @param array $context + * + * @return void + * + * @throws \Psr\Log\InvalidArgumentException + */ + abstract public function log($level, $message, array $context = array()); +} diff --git a/vendor/psr/log/Psr/Log/NullLogger.php b/vendor/psr/log/Psr/Log/NullLogger.php new file mode 100644 index 000000000..c8f7293b1 --- /dev/null +++ b/vendor/psr/log/Psr/Log/NullLogger.php @@ -0,0 +1,30 @@ +logger) { }` + * blocks. + */ +class NullLogger extends AbstractLogger +{ + /** + * Logs with an arbitrary level. + * + * @param mixed $level + * @param string $message + * @param array $context + * + * @return void + * + * @throws \Psr\Log\InvalidArgumentException + */ + public function log($level, $message, array $context = array()) + { + // noop + } +} diff --git a/vendor/psr/log/Psr/Log/Test/DummyTest.php b/vendor/psr/log/Psr/Log/Test/DummyTest.php new file mode 100644 index 000000000..9638c1101 --- /dev/null +++ b/vendor/psr/log/Psr/Log/Test/DummyTest.php @@ -0,0 +1,18 @@ + ". + * + * Example ->error('Foo') would yield "error Foo". + * + * @return string[] + */ + abstract public function getLogs(); + + public function testImplements() + { + $this->assertInstanceOf('Psr\Log\LoggerInterface', $this->getLogger()); + } + + /** + * @dataProvider provideLevelsAndMessages + */ + public function testLogsAtAllLevels($level, $message) + { + $logger = $this->getLogger(); + $logger->{$level}($message, array('user' => 'Bob')); + $logger->log($level, $message, array('user' => 'Bob')); + + $expected = array( + $level.' message of level '.$level.' with context: Bob', + $level.' message of level '.$level.' with context: Bob', + ); + $this->assertEquals($expected, $this->getLogs()); + } + + public function provideLevelsAndMessages() + { + return array( + LogLevel::EMERGENCY => array(LogLevel::EMERGENCY, 'message of level emergency with context: {user}'), + LogLevel::ALERT => array(LogLevel::ALERT, 'message of level alert with context: {user}'), + LogLevel::CRITICAL => array(LogLevel::CRITICAL, 'message of level critical with context: {user}'), + LogLevel::ERROR => array(LogLevel::ERROR, 'message of level error with context: {user}'), + LogLevel::WARNING => array(LogLevel::WARNING, 'message of level warning with context: {user}'), + LogLevel::NOTICE => array(LogLevel::NOTICE, 'message of level notice with context: {user}'), + LogLevel::INFO => array(LogLevel::INFO, 'message of level info with context: {user}'), + LogLevel::DEBUG => array(LogLevel::DEBUG, 'message of level debug with context: {user}'), + ); + } + + /** + * @expectedException \Psr\Log\InvalidArgumentException + */ + public function testThrowsOnInvalidLevel() + { + $logger = $this->getLogger(); + $logger->log('invalid level', 'Foo'); + } + + public function testContextReplacement() + { + $logger = $this->getLogger(); + $logger->info('{Message {nothing} {user} {foo.bar} a}', array('user' => 'Bob', 'foo.bar' => 'Bar')); + + $expected = array('info {Message {nothing} Bob Bar a}'); + $this->assertEquals($expected, $this->getLogs()); + } + + public function testObjectCastToString() + { + if (method_exists($this, 'createPartialMock')) { + $dummy = $this->createPartialMock('Psr\Log\Test\DummyTest', array('__toString')); + } else { + $dummy = $this->getMock('Psr\Log\Test\DummyTest', array('__toString')); + } + $dummy->expects($this->once()) + ->method('__toString') + ->will($this->returnValue('DUMMY')); + + $this->getLogger()->warning($dummy); + + $expected = array('warning DUMMY'); + $this->assertEquals($expected, $this->getLogs()); + } + + public function testContextCanContainAnything() + { + $closed = fopen('php://memory', 'r'); + fclose($closed); + + $context = array( + 'bool' => true, + 'null' => null, + 'string' => 'Foo', + 'int' => 0, + 'float' => 0.5, + 'nested' => array('with object' => new DummyTest), + 'object' => new \DateTime, + 'resource' => fopen('php://memory', 'r'), + 'closed' => $closed, + ); + + $this->getLogger()->warning('Crazy context data', $context); + + $expected = array('warning Crazy context data'); + $this->assertEquals($expected, $this->getLogs()); + } + + public function testContextExceptionKeyCanBeExceptionOrOtherValues() + { + $logger = $this->getLogger(); + $logger->warning('Random message', array('exception' => 'oops')); + $logger->critical('Uncaught Exception!', array('exception' => new \LogicException('Fail'))); + + $expected = array( + 'warning Random message', + 'critical Uncaught Exception!' + ); + $this->assertEquals($expected, $this->getLogs()); + } +} diff --git a/vendor/psr/log/Psr/Log/Test/TestLogger.php b/vendor/psr/log/Psr/Log/Test/TestLogger.php new file mode 100644 index 000000000..1be323049 --- /dev/null +++ b/vendor/psr/log/Psr/Log/Test/TestLogger.php @@ -0,0 +1,147 @@ + $level, + 'message' => $message, + 'context' => $context, + ]; + + $this->recordsByLevel[$record['level']][] = $record; + $this->records[] = $record; + } + + public function hasRecords($level) + { + return isset($this->recordsByLevel[$level]); + } + + public function hasRecord($record, $level) + { + if (is_string($record)) { + $record = ['message' => $record]; + } + return $this->hasRecordThatPasses(function ($rec) use ($record) { + if ($rec['message'] !== $record['message']) { + return false; + } + if (isset($record['context']) && $rec['context'] !== $record['context']) { + return false; + } + return true; + }, $level); + } + + public function hasRecordThatContains($message, $level) + { + return $this->hasRecordThatPasses(function ($rec) use ($message) { + return strpos($rec['message'], $message) !== false; + }, $level); + } + + public function hasRecordThatMatches($regex, $level) + { + return $this->hasRecordThatPasses(function ($rec) use ($regex) { + return preg_match($regex, $rec['message']) > 0; + }, $level); + } + + public function hasRecordThatPasses(callable $predicate, $level) + { + if (!isset($this->recordsByLevel[$level])) { + return false; + } + foreach ($this->recordsByLevel[$level] as $i => $rec) { + if (call_user_func($predicate, $rec, $i)) { + return true; + } + } + return false; + } + + public function __call($method, $args) + { + if (preg_match('/(.*)(Debug|Info|Notice|Warning|Error|Critical|Alert|Emergency)(.*)/', $method, $matches) > 0) { + $genericMethod = $matches[1] . ('Records' !== $matches[3] ? 'Record' : '') . $matches[3]; + $level = strtolower($matches[2]); + if (method_exists($this, $genericMethod)) { + $args[] = $level; + return call_user_func_array([$this, $genericMethod], $args); + } + } + throw new \BadMethodCallException('Call to undefined method ' . get_class($this) . '::' . $method . '()'); + } + + public function reset() + { + $this->records = []; + $this->recordsByLevel = []; + } +} diff --git a/vendor/psr/log/README.md b/vendor/psr/log/README.md new file mode 100644 index 000000000..a9f20c437 --- /dev/null +++ b/vendor/psr/log/README.md @@ -0,0 +1,58 @@ +PSR Log +======= + +This repository holds all interfaces/classes/traits related to +[PSR-3](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md). + +Note that this is not a logger of its own. It is merely an interface that +describes a logger. See the specification for more details. + +Installation +------------ + +```bash +composer require psr/log +``` + +Usage +----- + +If you need a logger, you can use the interface like this: + +```php +logger = $logger; + } + + public function doSomething() + { + if ($this->logger) { + $this->logger->info('Doing work'); + } + + try { + $this->doSomethingElse(); + } catch (Exception $exception) { + $this->logger->error('Oh no!', array('exception' => $exception)); + } + + // do something useful + } +} +``` + +You can then pick one of the implementations of the interface to get a logger. + +If you want to implement the interface, you can require this package and +implement `Psr\Log\LoggerInterface` in your code. Please read the +[specification text](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md) +for details. diff --git a/vendor/psr/log/composer.json b/vendor/psr/log/composer.json new file mode 100644 index 000000000..ca0569537 --- /dev/null +++ b/vendor/psr/log/composer.json @@ -0,0 +1,26 @@ +{ + "name": "psr/log", + "description": "Common interface for logging libraries", + "keywords": ["psr", "psr-3", "log"], + "homepage": "https://github.com/php-fig/log", + "license": "MIT", + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "require": { + "php": ">=5.3.0" + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + } +} diff --git a/vendor/psr/simple-cache/.editorconfig b/vendor/psr/simple-cache/.editorconfig new file mode 100644 index 000000000..48542cbb4 --- /dev/null +++ b/vendor/psr/simple-cache/.editorconfig @@ -0,0 +1,12 @@ +; This file is for unifying the coding style for different editors and IDEs. +; More information at http://editorconfig.org + +root = true + +[*] +charset = utf-8 +indent_size = 4 +indent_style = space +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/vendor/psr/simple-cache/LICENSE.md b/vendor/psr/simple-cache/LICENSE.md new file mode 100644 index 000000000..e49a7c85a --- /dev/null +++ b/vendor/psr/simple-cache/LICENSE.md @@ -0,0 +1,21 @@ +# The MIT License (MIT) + +Copyright (c) 2016 PHP Framework Interoperability Group + +> Permission is hereby granted, free of charge, to any person obtaining a copy +> of this software and associated documentation files (the "Software"), to deal +> in the Software without restriction, including without limitation the rights +> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +> copies of the Software, and to permit persons to whom the Software is +> furnished to do so, subject to the following conditions: +> +> The above copyright notice and this permission notice shall be included in +> all copies or substantial portions of the Software. +> +> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +> THE SOFTWARE. diff --git a/vendor/psr/simple-cache/README.md b/vendor/psr/simple-cache/README.md new file mode 100644 index 000000000..43641d175 --- /dev/null +++ b/vendor/psr/simple-cache/README.md @@ -0,0 +1,8 @@ +PHP FIG Simple Cache PSR +======================== + +This repository holds all interfaces related to PSR-16. + +Note that this is not a cache implementation of its own. It is merely an interface that describes a cache implementation. See [the specification](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-16-simple-cache.md) for more details. + +You can find implementations of the specification by looking for packages providing the [psr/simple-cache-implementation](https://packagist.org/providers/psr/simple-cache-implementation) virtual package. diff --git a/vendor/psr/simple-cache/composer.json b/vendor/psr/simple-cache/composer.json new file mode 100644 index 000000000..2978fa559 --- /dev/null +++ b/vendor/psr/simple-cache/composer.json @@ -0,0 +1,25 @@ +{ + "name": "psr/simple-cache", + "description": "Common interfaces for simple caching", + "keywords": ["psr", "psr-16", "cache", "simple-cache", "caching"], + "license": "MIT", + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "require": { + "php": ">=5.3.0" + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + } +} diff --git a/vendor/psr/simple-cache/src/CacheException.php b/vendor/psr/simple-cache/src/CacheException.php new file mode 100644 index 000000000..eba53815c --- /dev/null +++ b/vendor/psr/simple-cache/src/CacheException.php @@ -0,0 +1,10 @@ + value pairs. Cache keys that do not exist or are stale will have $default as value. + * + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if $keys is neither an array nor a Traversable, + * or if any of the $keys are not a legal value. + */ + public function getMultiple($keys, $default = null); + + /** + * Persists a set of key => value pairs in the cache, with an optional TTL. + * + * @param iterable $values A list of key => value pairs for a multiple-set operation. + * @param null|int|\DateInterval $ttl Optional. The TTL value of this item. If no value is sent and + * the driver supports TTL then the library may set a default value + * for it or let the driver take care of that. + * + * @return bool True on success and false on failure. + * + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if $values is neither an array nor a Traversable, + * or if any of the $values are not a legal value. + */ + public function setMultiple($values, $ttl = null); + + /** + * Deletes multiple cache items in a single operation. + * + * @param iterable $keys A list of string-based keys to be deleted. + * + * @return bool True if the items were successfully removed. False if there was an error. + * + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if $keys is neither an array nor a Traversable, + * or if any of the $keys are not a legal value. + */ + public function deleteMultiple($keys); + + /** + * Determines whether an item is present in the cache. + * + * NOTE: It is recommended that has() is only to be used for cache warming type purposes + * and not to be used within your live applications operations for get/set, as this method + * is subject to a race condition where your has() will return true and immediately after, + * another script can remove it making the state of your app out of date. + * + * @param string $key The cache item key. + * + * @return bool + * + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if the $key string is not a legal value. + */ + public function has($key); +} diff --git a/vendor/psr/simple-cache/src/InvalidArgumentException.php b/vendor/psr/simple-cache/src/InvalidArgumentException.php new file mode 100644 index 000000000..6a9524a20 --- /dev/null +++ b/vendor/psr/simple-cache/src/InvalidArgumentException.php @@ -0,0 +1,13 @@ + 'think\\app\\Service', + 1 => 'think\\trace\\Service', +); \ No newline at end of file diff --git a/vendor/symfony/polyfill-mbstring/LICENSE b/vendor/symfony/polyfill-mbstring/LICENSE new file mode 100644 index 000000000..4cd8bdd30 --- /dev/null +++ b/vendor/symfony/polyfill-mbstring/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015-2019 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/polyfill-mbstring/Mbstring.php b/vendor/symfony/polyfill-mbstring/Mbstring.php new file mode 100644 index 000000000..c31611fb8 --- /dev/null +++ b/vendor/symfony/polyfill-mbstring/Mbstring.php @@ -0,0 +1,869 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Mbstring; + +/** + * Partial mbstring implementation in PHP, iconv based, UTF-8 centric. + * + * Implemented: + * - mb_chr - Returns a specific character from its Unicode code point + * - mb_convert_encoding - Convert character encoding + * - mb_convert_variables - Convert character code in variable(s) + * - mb_decode_mimeheader - Decode string in MIME header field + * - mb_encode_mimeheader - Encode string for MIME header XXX NATIVE IMPLEMENTATION IS REALLY BUGGED + * - mb_decode_numericentity - Decode HTML numeric string reference to character + * - mb_encode_numericentity - Encode character to HTML numeric string reference + * - mb_convert_case - Perform case folding on a string + * - mb_detect_encoding - Detect character encoding + * - mb_get_info - Get internal settings of mbstring + * - mb_http_input - Detect HTTP input character encoding + * - mb_http_output - Set/Get HTTP output character encoding + * - mb_internal_encoding - Set/Get internal character encoding + * - mb_list_encodings - Returns an array of all supported encodings + * - mb_ord - Returns the Unicode code point of a character + * - mb_output_handler - Callback function converts character encoding in output buffer + * - mb_scrub - Replaces ill-formed byte sequences with substitute characters + * - mb_strlen - Get string length + * - mb_strpos - Find position of first occurrence of string in a string + * - mb_strrpos - Find position of last occurrence of a string in a string + * - mb_str_split - Convert a string to an array + * - mb_strtolower - Make a string lowercase + * - mb_strtoupper - Make a string uppercase + * - mb_substitute_character - Set/Get substitution character + * - mb_substr - Get part of string + * - mb_stripos - Finds position of first occurrence of a string within another, case insensitive + * - mb_stristr - Finds first occurrence of a string within another, case insensitive + * - mb_strrchr - Finds the last occurrence of a character in a string within another + * - mb_strrichr - Finds the last occurrence of a character in a string within another, case insensitive + * - mb_strripos - Finds position of last occurrence of a string within another, case insensitive + * - mb_strstr - Finds first occurrence of a string within another + * - mb_strwidth - Return width of string + * - mb_substr_count - Count the number of substring occurrences + * + * Not implemented: + * - mb_convert_kana - Convert "kana" one from another ("zen-kaku", "han-kaku" and more) + * - mb_ereg_* - Regular expression with multibyte support + * - mb_parse_str - Parse GET/POST/COOKIE data and set global variable + * - mb_preferred_mime_name - Get MIME charset string + * - mb_regex_encoding - Returns current encoding for multibyte regex as string + * - mb_regex_set_options - Set/Get the default options for mbregex functions + * - mb_send_mail - Send encoded mail + * - mb_split - Split multibyte string using regular expression + * - mb_strcut - Get part of string + * - mb_strimwidth - Get truncated string with specified width + * + * @author Nicolas Grekas + * + * @internal + */ +final class Mbstring +{ + public const MB_CASE_FOLD = \PHP_INT_MAX; + + private static $encodingList = ['ASCII', 'UTF-8']; + private static $language = 'neutral'; + private static $internalEncoding = 'UTF-8'; + private static $caseFold = [ + ['µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"], + ['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1", 'ι'], + ]; + + public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null) + { + if (\is_array($fromEncoding) || false !== strpos($fromEncoding, ',')) { + $fromEncoding = self::mb_detect_encoding($s, $fromEncoding); + } else { + $fromEncoding = self::getEncoding($fromEncoding); + } + + $toEncoding = self::getEncoding($toEncoding); + + if ('BASE64' === $fromEncoding) { + $s = base64_decode($s); + $fromEncoding = $toEncoding; + } + + if ('BASE64' === $toEncoding) { + return base64_encode($s); + } + + if ('HTML-ENTITIES' === $toEncoding || 'HTML' === $toEncoding) { + if ('HTML-ENTITIES' === $fromEncoding || 'HTML' === $fromEncoding) { + $fromEncoding = 'Windows-1252'; + } + if ('UTF-8' !== $fromEncoding) { + $s = \iconv($fromEncoding, 'UTF-8//IGNORE', $s); + } + + return preg_replace_callback('/[\x80-\xFF]+/', [__CLASS__, 'html_encoding_callback'], $s); + } + + if ('HTML-ENTITIES' === $fromEncoding) { + $s = html_entity_decode($s, \ENT_COMPAT, 'UTF-8'); + $fromEncoding = 'UTF-8'; + } + + return \iconv($fromEncoding, $toEncoding.'//IGNORE', $s); + } + + public static function mb_convert_variables($toEncoding, $fromEncoding, &...$vars) + { + $ok = true; + array_walk_recursive($vars, function (&$v) use (&$ok, $toEncoding, $fromEncoding) { + if (false === $v = self::mb_convert_encoding($v, $toEncoding, $fromEncoding)) { + $ok = false; + } + }); + + return $ok ? $fromEncoding : false; + } + + public static function mb_decode_mimeheader($s) + { + return \iconv_mime_decode($s, 2, self::$internalEncoding); + } + + public static function mb_encode_mimeheader($s, $charset = null, $transferEncoding = null, $linefeed = null, $indent = null) + { + trigger_error('mb_encode_mimeheader() is bugged. Please use iconv_mime_encode() instead', \E_USER_WARNING); + } + + public static function mb_decode_numericentity($s, $convmap, $encoding = null) + { + if (null !== $s && !is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) { + trigger_error('mb_decode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING); + + return null; + } + + if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) { + return false; + } + + if (null !== $encoding && !is_scalar($encoding)) { + trigger_error('mb_decode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING); + + return ''; // Instead of null (cf. mb_encode_numericentity). + } + + $s = (string) $s; + if ('' === $s) { + return ''; + } + + $encoding = self::getEncoding($encoding); + + if ('UTF-8' === $encoding) { + $encoding = null; + if (!preg_match('//u', $s)) { + $s = @\iconv('UTF-8', 'UTF-8//IGNORE', $s); + } + } else { + $s = \iconv($encoding, 'UTF-8//IGNORE', $s); + } + + $cnt = floor(\count($convmap) / 4) * 4; + + for ($i = 0; $i < $cnt; $i += 4) { + // collector_decode_htmlnumericentity ignores $convmap[$i + 3] + $convmap[$i] += $convmap[$i + 2]; + $convmap[$i + 1] += $convmap[$i + 2]; + } + + $s = preg_replace_callback('/&#(?:0*([0-9]+)|x0*([0-9a-fA-F]+))(?!&);?/', function (array $m) use ($cnt, $convmap) { + $c = isset($m[2]) ? (int) hexdec($m[2]) : $m[1]; + for ($i = 0; $i < $cnt; $i += 4) { + if ($c >= $convmap[$i] && $c <= $convmap[$i + 1]) { + return self::mb_chr($c - $convmap[$i + 2]); + } + } + + return $m[0]; + }, $s); + + if (null === $encoding) { + return $s; + } + + return \iconv('UTF-8', $encoding.'//IGNORE', $s); + } + + public static function mb_encode_numericentity($s, $convmap, $encoding = null, $is_hex = false) + { + if (null !== $s && !is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) { + trigger_error('mb_encode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING); + + return null; + } + + if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) { + return false; + } + + if (null !== $encoding && !is_scalar($encoding)) { + trigger_error('mb_encode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING); + + return null; // Instead of '' (cf. mb_decode_numericentity). + } + + if (null !== $is_hex && !is_scalar($is_hex)) { + trigger_error('mb_encode_numericentity() expects parameter 4 to be boolean, '.\gettype($s).' given', \E_USER_WARNING); + + return null; + } + + $s = (string) $s; + if ('' === $s) { + return ''; + } + + $encoding = self::getEncoding($encoding); + + if ('UTF-8' === $encoding) { + $encoding = null; + if (!preg_match('//u', $s)) { + $s = @\iconv('UTF-8', 'UTF-8//IGNORE', $s); + } + } else { + $s = \iconv($encoding, 'UTF-8//IGNORE', $s); + } + + static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4]; + + $cnt = floor(\count($convmap) / 4) * 4; + $i = 0; + $len = \strlen($s); + $result = ''; + + while ($i < $len) { + $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"]; + $uchr = substr($s, $i, $ulen); + $i += $ulen; + $c = self::mb_ord($uchr); + + for ($j = 0; $j < $cnt; $j += 4) { + if ($c >= $convmap[$j] && $c <= $convmap[$j + 1]) { + $cOffset = ($c + $convmap[$j + 2]) & $convmap[$j + 3]; + $result .= $is_hex ? sprintf('&#x%X;', $cOffset) : '&#'.$cOffset.';'; + continue 2; + } + } + $result .= $uchr; + } + + if (null === $encoding) { + return $result; + } + + return \iconv('UTF-8', $encoding.'//IGNORE', $result); + } + + public static function mb_convert_case($s, $mode, $encoding = null) + { + $s = (string) $s; + if ('' === $s) { + return ''; + } + + $encoding = self::getEncoding($encoding); + + if ('UTF-8' === $encoding) { + $encoding = null; + if (!preg_match('//u', $s)) { + $s = @\iconv('UTF-8', 'UTF-8//IGNORE', $s); + } + } else { + $s = \iconv($encoding, 'UTF-8//IGNORE', $s); + } + + if (\MB_CASE_TITLE == $mode) { + static $titleRegexp = null; + if (null === $titleRegexp) { + $titleRegexp = self::getData('titleCaseRegexp'); + } + $s = preg_replace_callback($titleRegexp, [__CLASS__, 'title_case'], $s); + } else { + if (\MB_CASE_UPPER == $mode) { + static $upper = null; + if (null === $upper) { + $upper = self::getData('upperCase'); + } + $map = $upper; + } else { + if (self::MB_CASE_FOLD === $mode) { + $s = str_replace(self::$caseFold[0], self::$caseFold[1], $s); + } + + static $lower = null; + if (null === $lower) { + $lower = self::getData('lowerCase'); + } + $map = $lower; + } + + static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4]; + + $i = 0; + $len = \strlen($s); + + while ($i < $len) { + $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"]; + $uchr = substr($s, $i, $ulen); + $i += $ulen; + + if (isset($map[$uchr])) { + $uchr = $map[$uchr]; + $nlen = \strlen($uchr); + + if ($nlen == $ulen) { + $nlen = $i; + do { + $s[--$nlen] = $uchr[--$ulen]; + } while ($ulen); + } else { + $s = substr_replace($s, $uchr, $i - $ulen, $ulen); + $len += $nlen - $ulen; + $i += $nlen - $ulen; + } + } + } + } + + if (null === $encoding) { + return $s; + } + + return \iconv('UTF-8', $encoding.'//IGNORE', $s); + } + + public static function mb_internal_encoding($encoding = null) + { + if (null === $encoding) { + return self::$internalEncoding; + } + + $normalizedEncoding = self::getEncoding($encoding); + + if ('UTF-8' === $normalizedEncoding || false !== @\iconv($normalizedEncoding, $normalizedEncoding, ' ')) { + self::$internalEncoding = $normalizedEncoding; + + return true; + } + + if (80000 > \PHP_VERSION_ID) { + return false; + } + + throw new \ValueError(sprintf('Argument #1 ($encoding) must be a valid encoding, "%s" given', $encoding)); + } + + public static function mb_language($lang = null) + { + if (null === $lang) { + return self::$language; + } + + switch ($normalizedLang = strtolower($lang)) { + case 'uni': + case 'neutral': + self::$language = $normalizedLang; + + return true; + } + + if (80000 > \PHP_VERSION_ID) { + return false; + } + + throw new \ValueError(sprintf('Argument #1 ($language) must be a valid language, "%s" given', $lang)); + } + + public static function mb_list_encodings() + { + return ['UTF-8']; + } + + public static function mb_encoding_aliases($encoding) + { + switch (strtoupper($encoding)) { + case 'UTF8': + case 'UTF-8': + return ['utf8']; + } + + return false; + } + + public static function mb_check_encoding($var = null, $encoding = null) + { + if (null === $encoding) { + if (null === $var) { + return false; + } + $encoding = self::$internalEncoding; + } + + return self::mb_detect_encoding($var, [$encoding]) || false !== @\iconv($encoding, $encoding, $var); + } + + public static function mb_detect_encoding($str, $encodingList = null, $strict = false) + { + if (null === $encodingList) { + $encodingList = self::$encodingList; + } else { + if (!\is_array($encodingList)) { + $encodingList = array_map('trim', explode(',', $encodingList)); + } + $encodingList = array_map('strtoupper', $encodingList); + } + + foreach ($encodingList as $enc) { + switch ($enc) { + case 'ASCII': + if (!preg_match('/[\x80-\xFF]/', $str)) { + return $enc; + } + break; + + case 'UTF8': + case 'UTF-8': + if (preg_match('//u', $str)) { + return 'UTF-8'; + } + break; + + default: + if (0 === strncmp($enc, 'ISO-8859-', 9)) { + return $enc; + } + } + } + + return false; + } + + public static function mb_detect_order($encodingList = null) + { + if (null === $encodingList) { + return self::$encodingList; + } + + if (!\is_array($encodingList)) { + $encodingList = array_map('trim', explode(',', $encodingList)); + } + $encodingList = array_map('strtoupper', $encodingList); + + foreach ($encodingList as $enc) { + switch ($enc) { + default: + if (strncmp($enc, 'ISO-8859-', 9)) { + return false; + } + // no break + case 'ASCII': + case 'UTF8': + case 'UTF-8': + } + } + + self::$encodingList = $encodingList; + + return true; + } + + public static function mb_strlen($s, $encoding = null) + { + $encoding = self::getEncoding($encoding); + if ('CP850' === $encoding || 'ASCII' === $encoding) { + return \strlen($s); + } + + return @\iconv_strlen($s, $encoding); + } + + public static function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) + { + $encoding = self::getEncoding($encoding); + if ('CP850' === $encoding || 'ASCII' === $encoding) { + return strpos($haystack, $needle, $offset); + } + + $needle = (string) $needle; + if ('' === $needle) { + if (80000 > \PHP_VERSION_ID) { + trigger_error(__METHOD__.': Empty delimiter', \E_USER_WARNING); + + return false; + } + + return 0; + } + + return \iconv_strpos($haystack, $needle, $offset, $encoding); + } + + public static function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null) + { + $encoding = self::getEncoding($encoding); + if ('CP850' === $encoding || 'ASCII' === $encoding) { + return strrpos($haystack, $needle, $offset); + } + + if ($offset != (int) $offset) { + $offset = 0; + } elseif ($offset = (int) $offset) { + if ($offset < 0) { + if (0 > $offset += self::mb_strlen($needle)) { + $haystack = self::mb_substr($haystack, 0, $offset, $encoding); + } + $offset = 0; + } else { + $haystack = self::mb_substr($haystack, $offset, 2147483647, $encoding); + } + } + + $pos = '' !== $needle || 80000 > \PHP_VERSION_ID + ? \iconv_strrpos($haystack, $needle, $encoding) + : self::mb_strlen($haystack, $encoding); + + return false !== $pos ? $offset + $pos : false; + } + + public static function mb_str_split($string, $split_length = 1, $encoding = null) + { + if (null !== $string && !is_scalar($string) && !(\is_object($string) && method_exists($string, '__toString'))) { + trigger_error('mb_str_split() expects parameter 1 to be string, '.\gettype($string).' given', \E_USER_WARNING); + + return null; + } + + if (1 > $split_length = (int) $split_length) { + if (80000 > \PHP_VERSION_ID) { + trigger_error('The length of each segment must be greater than zero', \E_USER_WARNING); + return false; + } + + throw new \ValueError('Argument #2 ($length) must be greater than 0'); + } + + if (null === $encoding) { + $encoding = mb_internal_encoding(); + } + + if ('UTF-8' === $encoding = self::getEncoding($encoding)) { + $rx = '/('; + while (65535 < $split_length) { + $rx .= '.{65535}'; + $split_length -= 65535; + } + $rx .= '.{'.$split_length.'})/us'; + + return preg_split($rx, $string, null, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY); + } + + $result = []; + $length = mb_strlen($string, $encoding); + + for ($i = 0; $i < $length; $i += $split_length) { + $result[] = mb_substr($string, $i, $split_length, $encoding); + } + + return $result; + } + + public static function mb_strtolower($s, $encoding = null) + { + return self::mb_convert_case($s, \MB_CASE_LOWER, $encoding); + } + + public static function mb_strtoupper($s, $encoding = null) + { + return self::mb_convert_case($s, \MB_CASE_UPPER, $encoding); + } + + public static function mb_substitute_character($c = null) + { + if (null === $c) { + return 'none'; + } + if (0 === strcasecmp($c, 'none')) { + return true; + } + if (80000 > \PHP_VERSION_ID) { + return false; + } + + throw new \ValueError('Argument #1 ($substitute_character) must be "none", "long", "entity" or a valid codepoint'); + } + + public static function mb_substr($s, $start, $length = null, $encoding = null) + { + $encoding = self::getEncoding($encoding); + if ('CP850' === $encoding || 'ASCII' === $encoding) { + return (string) substr($s, $start, null === $length ? 2147483647 : $length); + } + + if ($start < 0) { + $start = \iconv_strlen($s, $encoding) + $start; + if ($start < 0) { + $start = 0; + } + } + + if (null === $length) { + $length = 2147483647; + } elseif ($length < 0) { + $length = \iconv_strlen($s, $encoding) + $length - $start; + if ($length < 0) { + return ''; + } + } + + return (string) \iconv_substr($s, $start, $length, $encoding); + } + + public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) + { + $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding); + $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding); + + return self::mb_strpos($haystack, $needle, $offset, $encoding); + } + + public static function mb_stristr($haystack, $needle, $part = false, $encoding = null) + { + $pos = self::mb_stripos($haystack, $needle, 0, $encoding); + + return self::getSubpart($pos, $part, $haystack, $encoding); + } + + public static function mb_strrchr($haystack, $needle, $part = false, $encoding = null) + { + $encoding = self::getEncoding($encoding); + if ('CP850' === $encoding || 'ASCII' === $encoding) { + $pos = strrpos($haystack, $needle); + } else { + $needle = self::mb_substr($needle, 0, 1, $encoding); + $pos = \iconv_strrpos($haystack, $needle, $encoding); + } + + return self::getSubpart($pos, $part, $haystack, $encoding); + } + + public static function mb_strrichr($haystack, $needle, $part = false, $encoding = null) + { + $needle = self::mb_substr($needle, 0, 1, $encoding); + $pos = self::mb_strripos($haystack, $needle, $encoding); + + return self::getSubpart($pos, $part, $haystack, $encoding); + } + + public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) + { + $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding); + $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding); + + return self::mb_strrpos($haystack, $needle, $offset, $encoding); + } + + public static function mb_strstr($haystack, $needle, $part = false, $encoding = null) + { + $pos = strpos($haystack, $needle); + if (false === $pos) { + return false; + } + if ($part) { + return substr($haystack, 0, $pos); + } + + return substr($haystack, $pos); + } + + public static function mb_get_info($type = 'all') + { + $info = [ + 'internal_encoding' => self::$internalEncoding, + 'http_output' => 'pass', + 'http_output_conv_mimetypes' => '^(text/|application/xhtml\+xml)', + 'func_overload' => 0, + 'func_overload_list' => 'no overload', + 'mail_charset' => 'UTF-8', + 'mail_header_encoding' => 'BASE64', + 'mail_body_encoding' => 'BASE64', + 'illegal_chars' => 0, + 'encoding_translation' => 'Off', + 'language' => self::$language, + 'detect_order' => self::$encodingList, + 'substitute_character' => 'none', + 'strict_detection' => 'Off', + ]; + + if ('all' === $type) { + return $info; + } + if (isset($info[$type])) { + return $info[$type]; + } + + return false; + } + + public static function mb_http_input($type = '') + { + return false; + } + + public static function mb_http_output($encoding = null) + { + return null !== $encoding ? 'pass' === $encoding : 'pass'; + } + + public static function mb_strwidth($s, $encoding = null) + { + $encoding = self::getEncoding($encoding); + + if ('UTF-8' !== $encoding) { + $s = \iconv($encoding, 'UTF-8//IGNORE', $s); + } + + $s = preg_replace('/[\x{1100}-\x{115F}\x{2329}\x{232A}\x{2E80}-\x{303E}\x{3040}-\x{A4CF}\x{AC00}-\x{D7A3}\x{F900}-\x{FAFF}\x{FE10}-\x{FE19}\x{FE30}-\x{FE6F}\x{FF00}-\x{FF60}\x{FFE0}-\x{FFE6}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}]/u', '', $s, -1, $wide); + + return ($wide << 1) + \iconv_strlen($s, 'UTF-8'); + } + + public static function mb_substr_count($haystack, $needle, $encoding = null) + { + return substr_count($haystack, $needle); + } + + public static function mb_output_handler($contents, $status) + { + return $contents; + } + + public static function mb_chr($code, $encoding = null) + { + if (0x80 > $code %= 0x200000) { + $s = \chr($code); + } elseif (0x800 > $code) { + $s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F); + } elseif (0x10000 > $code) { + $s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F); + } else { + $s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F); + } + + if ('UTF-8' !== $encoding = self::getEncoding($encoding)) { + $s = mb_convert_encoding($s, $encoding, 'UTF-8'); + } + + return $s; + } + + public static function mb_ord($s, $encoding = null) + { + if ('UTF-8' !== $encoding = self::getEncoding($encoding)) { + $s = mb_convert_encoding($s, 'UTF-8', $encoding); + } + + if (1 === \strlen($s)) { + return \ord($s); + } + + $code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0; + if (0xF0 <= $code) { + return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80; + } + if (0xE0 <= $code) { + return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80; + } + if (0xC0 <= $code) { + return (($code - 0xC0) << 6) + $s[2] - 0x80; + } + + return $code; + } + + private static function getSubpart($pos, $part, $haystack, $encoding) + { + if (false === $pos) { + return false; + } + if ($part) { + return self::mb_substr($haystack, 0, $pos, $encoding); + } + + return self::mb_substr($haystack, $pos, null, $encoding); + } + + private static function html_encoding_callback(array $m) + { + $i = 1; + $entities = ''; + $m = unpack('C*', htmlentities($m[0], \ENT_COMPAT, 'UTF-8')); + + while (isset($m[$i])) { + if (0x80 > $m[$i]) { + $entities .= \chr($m[$i++]); + continue; + } + if (0xF0 <= $m[$i]) { + $c = (($m[$i++] - 0xF0) << 18) + (($m[$i++] - 0x80) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80; + } elseif (0xE0 <= $m[$i]) { + $c = (($m[$i++] - 0xE0) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80; + } else { + $c = (($m[$i++] - 0xC0) << 6) + $m[$i++] - 0x80; + } + + $entities .= '&#'.$c.';'; + } + + return $entities; + } + + private static function title_case(array $s) + { + return self::mb_convert_case($s[1], \MB_CASE_UPPER, 'UTF-8').self::mb_convert_case($s[2], \MB_CASE_LOWER, 'UTF-8'); + } + + private static function getData($file) + { + if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) { + return require $file; + } + + return false; + } + + private static function getEncoding($encoding) + { + if (null === $encoding) { + return self::$internalEncoding; + } + + if ('UTF-8' === $encoding) { + return 'UTF-8'; + } + + $encoding = strtoupper($encoding); + + if ('8BIT' === $encoding || 'BINARY' === $encoding) { + return 'CP850'; + } + + if ('UTF8' === $encoding) { + return 'UTF-8'; + } + + return $encoding; + } +} diff --git a/vendor/symfony/polyfill-mbstring/README.md b/vendor/symfony/polyfill-mbstring/README.md new file mode 100644 index 000000000..4efb599d8 --- /dev/null +++ b/vendor/symfony/polyfill-mbstring/README.md @@ -0,0 +1,13 @@ +Symfony Polyfill / Mbstring +=========================== + +This component provides a partial, native PHP implementation for the +[Mbstring](https://php.net/mbstring) extension. + +More information can be found in the +[main Polyfill README](https://github.com/symfony/polyfill/blob/master/README.md). + +License +======= + +This library is released under the [MIT license](LICENSE). diff --git a/vendor/symfony/polyfill-mbstring/Resources/unidata/lowerCase.php b/vendor/symfony/polyfill-mbstring/Resources/unidata/lowerCase.php new file mode 100644 index 000000000..fac60b081 --- /dev/null +++ b/vendor/symfony/polyfill-mbstring/Resources/unidata/lowerCase.php @@ -0,0 +1,1397 @@ + 'a', + 'B' => 'b', + 'C' => 'c', + 'D' => 'd', + 'E' => 'e', + 'F' => 'f', + 'G' => 'g', + 'H' => 'h', + 'I' => 'i', + 'J' => 'j', + 'K' => 'k', + 'L' => 'l', + 'M' => 'm', + 'N' => 'n', + 'O' => 'o', + 'P' => 'p', + 'Q' => 'q', + 'R' => 'r', + 'S' => 's', + 'T' => 't', + 'U' => 'u', + 'V' => 'v', + 'W' => 'w', + 'X' => 'x', + 'Y' => 'y', + 'Z' => 'z', + 'À' => 'à', + 'Á' => 'á', + 'Â' => 'â', + 'Ã' => 'ã', + 'Ä' => 'ä', + 'Å' => 'å', + 'Æ' => 'æ', + 'Ç' => 'ç', + 'È' => 'è', + 'É' => 'é', + 'Ê' => 'ê', + 'Ë' => 'ë', + 'Ì' => 'ì', + 'Í' => 'í', + 'Î' => 'î', + 'Ï' => 'ï', + 'Ð' => 'ð', + 'Ñ' => 'ñ', + 'Ò' => 'ò', + 'Ó' => 'ó', + 'Ô' => 'ô', + 'Õ' => 'õ', + 'Ö' => 'ö', + 'Ø' => 'ø', + 'Ù' => 'ù', + 'Ú' => 'ú', + 'Û' => 'û', + 'Ü' => 'ü', + 'Ý' => 'ý', + 'Þ' => 'þ', + 'Ā' => 'ā', + 'Ă' => 'ă', + 'Ą' => 'ą', + 'Ć' => 'ć', + 'Ĉ' => 'ĉ', + 'Ċ' => 'ċ', + 'Č' => 'č', + 'Ď' => 'ď', + 'Đ' => 'đ', + 'Ē' => 'ē', + 'Ĕ' => 'ĕ', + 'Ė' => 'ė', + 'Ę' => 'ę', + 'Ě' => 'ě', + 'Ĝ' => 'ĝ', + 'Ğ' => 'ğ', + 'Ġ' => 'ġ', + 'Ģ' => 'ģ', + 'Ĥ' => 'ĥ', + 'Ħ' => 'ħ', + 'Ĩ' => 'ĩ', + 'Ī' => 'ī', + 'Ĭ' => 'ĭ', + 'Į' => 'į', + 'İ' => 'i̇', + 'IJ' => 'ij', + 'Ĵ' => 'ĵ', + 'Ķ' => 'ķ', + 'Ĺ' => 'ĺ', + 'Ļ' => 'ļ', + 'Ľ' => 'ľ', + 'Ŀ' => 'ŀ', + 'Ł' => 'ł', + 'Ń' => 'ń', + 'Ņ' => 'ņ', + 'Ň' => 'ň', + 'Ŋ' => 'ŋ', + 'Ō' => 'ō', + 'Ŏ' => 'ŏ', + 'Ő' => 'ő', + 'Œ' => 'œ', + 'Ŕ' => 'ŕ', + 'Ŗ' => 'ŗ', + 'Ř' => 'ř', + 'Ś' => 'ś', + 'Ŝ' => 'ŝ', + 'Ş' => 'ş', + 'Š' => 'š', + 'Ţ' => 'ţ', + 'Ť' => 'ť', + 'Ŧ' => 'ŧ', + 'Ũ' => 'ũ', + 'Ū' => 'ū', + 'Ŭ' => 'ŭ', + 'Ů' => 'ů', + 'Ű' => 'ű', + 'Ų' => 'ų', + 'Ŵ' => 'ŵ', + 'Ŷ' => 'ŷ', + 'Ÿ' => 'ÿ', + 'Ź' => 'ź', + 'Ż' => 'ż', + 'Ž' => 'ž', + 'Ɓ' => 'ɓ', + 'Ƃ' => 'ƃ', + 'Ƅ' => 'ƅ', + 'Ɔ' => 'ɔ', + 'Ƈ' => 'ƈ', + 'Ɖ' => 'ɖ', + 'Ɗ' => 'ɗ', + 'Ƌ' => 'ƌ', + 'Ǝ' => 'ǝ', + 'Ə' => 'ə', + 'Ɛ' => 'ɛ', + 'Ƒ' => 'ƒ', + 'Ɠ' => 'ɠ', + 'Ɣ' => 'ɣ', + 'Ɩ' => 'ɩ', + 'Ɨ' => 'ɨ', + 'Ƙ' => 'ƙ', + 'Ɯ' => 'ɯ', + 'Ɲ' => 'ɲ', + 'Ɵ' => 'ɵ', + 'Ơ' => 'ơ', + 'Ƣ' => 'ƣ', + 'Ƥ' => 'ƥ', + 'Ʀ' => 'ʀ', + 'Ƨ' => 'ƨ', + 'Ʃ' => 'ʃ', + 'Ƭ' => 'ƭ', + 'Ʈ' => 'ʈ', + 'Ư' => 'ư', + 'Ʊ' => 'ʊ', + 'Ʋ' => 'ʋ', + 'Ƴ' => 'ƴ', + 'Ƶ' => 'ƶ', + 'Ʒ' => 'ʒ', + 'Ƹ' => 'ƹ', + 'Ƽ' => 'ƽ', + 'DŽ' => 'dž', + 'Dž' => 'dž', + 'LJ' => 'lj', + 'Lj' => 'lj', + 'NJ' => 'nj', + 'Nj' => 'nj', + 'Ǎ' => 'ǎ', + 'Ǐ' => 'ǐ', + 'Ǒ' => 'ǒ', + 'Ǔ' => 'ǔ', + 'Ǖ' => 'ǖ', + 'Ǘ' => 'ǘ', + 'Ǚ' => 'ǚ', + 'Ǜ' => 'ǜ', + 'Ǟ' => 'ǟ', + 'Ǡ' => 'ǡ', + 'Ǣ' => 'ǣ', + 'Ǥ' => 'ǥ', + 'Ǧ' => 'ǧ', + 'Ǩ' => 'ǩ', + 'Ǫ' => 'ǫ', + 'Ǭ' => 'ǭ', + 'Ǯ' => 'ǯ', + 'DZ' => 'dz', + 'Dz' => 'dz', + 'Ǵ' => 'ǵ', + 'Ƕ' => 'ƕ', + 'Ƿ' => 'ƿ', + 'Ǹ' => 'ǹ', + 'Ǻ' => 'ǻ', + 'Ǽ' => 'ǽ', + 'Ǿ' => 'ǿ', + 'Ȁ' => 'ȁ', + 'Ȃ' => 'ȃ', + 'Ȅ' => 'ȅ', + 'Ȇ' => 'ȇ', + 'Ȉ' => 'ȉ', + 'Ȋ' => 'ȋ', + 'Ȍ' => 'ȍ', + 'Ȏ' => 'ȏ', + 'Ȑ' => 'ȑ', + 'Ȓ' => 'ȓ', + 'Ȕ' => 'ȕ', + 'Ȗ' => 'ȗ', + 'Ș' => 'ș', + 'Ț' => 'ț', + 'Ȝ' => 'ȝ', + 'Ȟ' => 'ȟ', + 'Ƞ' => 'ƞ', + 'Ȣ' => 'ȣ', + 'Ȥ' => 'ȥ', + 'Ȧ' => 'ȧ', + 'Ȩ' => 'ȩ', + 'Ȫ' => 'ȫ', + 'Ȭ' => 'ȭ', + 'Ȯ' => 'ȯ', + 'Ȱ' => 'ȱ', + 'Ȳ' => 'ȳ', + 'Ⱥ' => 'ⱥ', + 'Ȼ' => 'ȼ', + 'Ƚ' => 'ƚ', + 'Ⱦ' => 'ⱦ', + 'Ɂ' => 'ɂ', + 'Ƀ' => 'ƀ', + 'Ʉ' => 'ʉ', + 'Ʌ' => 'ʌ', + 'Ɇ' => 'ɇ', + 'Ɉ' => 'ɉ', + 'Ɋ' => 'ɋ', + 'Ɍ' => 'ɍ', + 'Ɏ' => 'ɏ', + 'Ͱ' => 'ͱ', + 'Ͳ' => 'ͳ', + 'Ͷ' => 'ͷ', + 'Ϳ' => 'ϳ', + 'Ά' => 'ά', + 'Έ' => 'έ', + 'Ή' => 'ή', + 'Ί' => 'ί', + 'Ό' => 'ό', + 'Ύ' => 'ύ', + 'Ώ' => 'ώ', + 'Α' => 'α', + 'Β' => 'β', + 'Γ' => 'γ', + 'Δ' => 'δ', + 'Ε' => 'ε', + 'Ζ' => 'ζ', + 'Η' => 'η', + 'Θ' => 'θ', + 'Ι' => 'ι', + 'Κ' => 'κ', + 'Λ' => 'λ', + 'Μ' => 'μ', + 'Ν' => 'ν', + 'Ξ' => 'ξ', + 'Ο' => 'ο', + 'Π' => 'π', + 'Ρ' => 'ρ', + 'Σ' => 'σ', + 'Τ' => 'τ', + 'Υ' => 'υ', + 'Φ' => 'φ', + 'Χ' => 'χ', + 'Ψ' => 'ψ', + 'Ω' => 'ω', + 'Ϊ' => 'ϊ', + 'Ϋ' => 'ϋ', + 'Ϗ' => 'ϗ', + 'Ϙ' => 'ϙ', + 'Ϛ' => 'ϛ', + 'Ϝ' => 'ϝ', + 'Ϟ' => 'ϟ', + 'Ϡ' => 'ϡ', + 'Ϣ' => 'ϣ', + 'Ϥ' => 'ϥ', + 'Ϧ' => 'ϧ', + 'Ϩ' => 'ϩ', + 'Ϫ' => 'ϫ', + 'Ϭ' => 'ϭ', + 'Ϯ' => 'ϯ', + 'ϴ' => 'θ', + 'Ϸ' => 'ϸ', + 'Ϲ' => 'ϲ', + 'Ϻ' => 'ϻ', + 'Ͻ' => 'ͻ', + 'Ͼ' => 'ͼ', + 'Ͽ' => 'ͽ', + 'Ѐ' => 'ѐ', + 'Ё' => 'ё', + 'Ђ' => 'ђ', + 'Ѓ' => 'ѓ', + 'Є' => 'є', + 'Ѕ' => 'ѕ', + 'І' => 'і', + 'Ї' => 'ї', + 'Ј' => 'ј', + 'Љ' => 'љ', + 'Њ' => 'њ', + 'Ћ' => 'ћ', + 'Ќ' => 'ќ', + 'Ѝ' => 'ѝ', + 'Ў' => 'ў', + 'Џ' => 'џ', + 'А' => 'а', + 'Б' => 'б', + 'В' => 'в', + 'Г' => 'г', + 'Д' => 'д', + 'Е' => 'е', + 'Ж' => 'ж', + 'З' => 'з', + 'И' => 'и', + 'Й' => 'й', + 'К' => 'к', + 'Л' => 'л', + 'М' => 'м', + 'Н' => 'н', + 'О' => 'о', + 'П' => 'п', + 'Р' => 'р', + 'С' => 'с', + 'Т' => 'т', + 'У' => 'у', + 'Ф' => 'ф', + 'Х' => 'х', + 'Ц' => 'ц', + 'Ч' => 'ч', + 'Ш' => 'ш', + 'Щ' => 'щ', + 'Ъ' => 'ъ', + 'Ы' => 'ы', + 'Ь' => 'ь', + 'Э' => 'э', + 'Ю' => 'ю', + 'Я' => 'я', + 'Ѡ' => 'ѡ', + 'Ѣ' => 'ѣ', + 'Ѥ' => 'ѥ', + 'Ѧ' => 'ѧ', + 'Ѩ' => 'ѩ', + 'Ѫ' => 'ѫ', + 'Ѭ' => 'ѭ', + 'Ѯ' => 'ѯ', + 'Ѱ' => 'ѱ', + 'Ѳ' => 'ѳ', + 'Ѵ' => 'ѵ', + 'Ѷ' => 'ѷ', + 'Ѹ' => 'ѹ', + 'Ѻ' => 'ѻ', + 'Ѽ' => 'ѽ', + 'Ѿ' => 'ѿ', + 'Ҁ' => 'ҁ', + 'Ҋ' => 'ҋ', + 'Ҍ' => 'ҍ', + 'Ҏ' => 'ҏ', + 'Ґ' => 'ґ', + 'Ғ' => 'ғ', + 'Ҕ' => 'ҕ', + 'Җ' => 'җ', + 'Ҙ' => 'ҙ', + 'Қ' => 'қ', + 'Ҝ' => 'ҝ', + 'Ҟ' => 'ҟ', + 'Ҡ' => 'ҡ', + 'Ң' => 'ң', + 'Ҥ' => 'ҥ', + 'Ҧ' => 'ҧ', + 'Ҩ' => 'ҩ', + 'Ҫ' => 'ҫ', + 'Ҭ' => 'ҭ', + 'Ү' => 'ү', + 'Ұ' => 'ұ', + 'Ҳ' => 'ҳ', + 'Ҵ' => 'ҵ', + 'Ҷ' => 'ҷ', + 'Ҹ' => 'ҹ', + 'Һ' => 'һ', + 'Ҽ' => 'ҽ', + 'Ҿ' => 'ҿ', + 'Ӏ' => 'ӏ', + 'Ӂ' => 'ӂ', + 'Ӄ' => 'ӄ', + 'Ӆ' => 'ӆ', + 'Ӈ' => 'ӈ', + 'Ӊ' => 'ӊ', + 'Ӌ' => 'ӌ', + 'Ӎ' => 'ӎ', + 'Ӑ' => 'ӑ', + 'Ӓ' => 'ӓ', + 'Ӕ' => 'ӕ', + 'Ӗ' => 'ӗ', + 'Ә' => 'ә', + 'Ӛ' => 'ӛ', + 'Ӝ' => 'ӝ', + 'Ӟ' => 'ӟ', + 'Ӡ' => 'ӡ', + 'Ӣ' => 'ӣ', + 'Ӥ' => 'ӥ', + 'Ӧ' => 'ӧ', + 'Ө' => 'ө', + 'Ӫ' => 'ӫ', + 'Ӭ' => 'ӭ', + 'Ӯ' => 'ӯ', + 'Ӱ' => 'ӱ', + 'Ӳ' => 'ӳ', + 'Ӵ' => 'ӵ', + 'Ӷ' => 'ӷ', + 'Ӹ' => 'ӹ', + 'Ӻ' => 'ӻ', + 'Ӽ' => 'ӽ', + 'Ӿ' => 'ӿ', + 'Ԁ' => 'ԁ', + 'Ԃ' => 'ԃ', + 'Ԅ' => 'ԅ', + 'Ԇ' => 'ԇ', + 'Ԉ' => 'ԉ', + 'Ԋ' => 'ԋ', + 'Ԍ' => 'ԍ', + 'Ԏ' => 'ԏ', + 'Ԑ' => 'ԑ', + 'Ԓ' => 'ԓ', + 'Ԕ' => 'ԕ', + 'Ԗ' => 'ԗ', + 'Ԙ' => 'ԙ', + 'Ԛ' => 'ԛ', + 'Ԝ' => 'ԝ', + 'Ԟ' => 'ԟ', + 'Ԡ' => 'ԡ', + 'Ԣ' => 'ԣ', + 'Ԥ' => 'ԥ', + 'Ԧ' => 'ԧ', + 'Ԩ' => 'ԩ', + 'Ԫ' => 'ԫ', + 'Ԭ' => 'ԭ', + 'Ԯ' => 'ԯ', + 'Ա' => 'ա', + 'Բ' => 'բ', + 'Գ' => 'գ', + 'Դ' => 'դ', + 'Ե' => 'ե', + 'Զ' => 'զ', + 'Է' => 'է', + 'Ը' => 'ը', + 'Թ' => 'թ', + 'Ժ' => 'ժ', + 'Ի' => 'ի', + 'Լ' => 'լ', + 'Խ' => 'խ', + 'Ծ' => 'ծ', + 'Կ' => 'կ', + 'Հ' => 'հ', + 'Ձ' => 'ձ', + 'Ղ' => 'ղ', + 'Ճ' => 'ճ', + 'Մ' => 'մ', + 'Յ' => 'յ', + 'Ն' => 'ն', + 'Շ' => 'շ', + 'Ո' => 'ո', + 'Չ' => 'չ', + 'Պ' => 'պ', + 'Ջ' => 'ջ', + 'Ռ' => 'ռ', + 'Ս' => 'ս', + 'Վ' => 'վ', + 'Տ' => 'տ', + 'Ր' => 'ր', + 'Ց' => 'ց', + 'Ւ' => 'ւ', + 'Փ' => 'փ', + 'Ք' => 'ք', + 'Օ' => 'օ', + 'Ֆ' => 'ֆ', + 'Ⴀ' => 'ⴀ', + 'Ⴁ' => 'ⴁ', + 'Ⴂ' => 'ⴂ', + 'Ⴃ' => 'ⴃ', + 'Ⴄ' => 'ⴄ', + 'Ⴅ' => 'ⴅ', + 'Ⴆ' => 'ⴆ', + 'Ⴇ' => 'ⴇ', + 'Ⴈ' => 'ⴈ', + 'Ⴉ' => 'ⴉ', + 'Ⴊ' => 'ⴊ', + 'Ⴋ' => 'ⴋ', + 'Ⴌ' => 'ⴌ', + 'Ⴍ' => 'ⴍ', + 'Ⴎ' => 'ⴎ', + 'Ⴏ' => 'ⴏ', + 'Ⴐ' => 'ⴐ', + 'Ⴑ' => 'ⴑ', + 'Ⴒ' => 'ⴒ', + 'Ⴓ' => 'ⴓ', + 'Ⴔ' => 'ⴔ', + 'Ⴕ' => 'ⴕ', + 'Ⴖ' => 'ⴖ', + 'Ⴗ' => 'ⴗ', + 'Ⴘ' => 'ⴘ', + 'Ⴙ' => 'ⴙ', + 'Ⴚ' => 'ⴚ', + 'Ⴛ' => 'ⴛ', + 'Ⴜ' => 'ⴜ', + 'Ⴝ' => 'ⴝ', + 'Ⴞ' => 'ⴞ', + 'Ⴟ' => 'ⴟ', + 'Ⴠ' => 'ⴠ', + 'Ⴡ' => 'ⴡ', + 'Ⴢ' => 'ⴢ', + 'Ⴣ' => 'ⴣ', + 'Ⴤ' => 'ⴤ', + 'Ⴥ' => 'ⴥ', + 'Ⴧ' => 'ⴧ', + 'Ⴭ' => 'ⴭ', + 'Ꭰ' => 'ꭰ', + 'Ꭱ' => 'ꭱ', + 'Ꭲ' => 'ꭲ', + 'Ꭳ' => 'ꭳ', + 'Ꭴ' => 'ꭴ', + 'Ꭵ' => 'ꭵ', + 'Ꭶ' => 'ꭶ', + 'Ꭷ' => 'ꭷ', + 'Ꭸ' => 'ꭸ', + 'Ꭹ' => 'ꭹ', + 'Ꭺ' => 'ꭺ', + 'Ꭻ' => 'ꭻ', + 'Ꭼ' => 'ꭼ', + 'Ꭽ' => 'ꭽ', + 'Ꭾ' => 'ꭾ', + 'Ꭿ' => 'ꭿ', + 'Ꮀ' => 'ꮀ', + 'Ꮁ' => 'ꮁ', + 'Ꮂ' => 'ꮂ', + 'Ꮃ' => 'ꮃ', + 'Ꮄ' => 'ꮄ', + 'Ꮅ' => 'ꮅ', + 'Ꮆ' => 'ꮆ', + 'Ꮇ' => 'ꮇ', + 'Ꮈ' => 'ꮈ', + 'Ꮉ' => 'ꮉ', + 'Ꮊ' => 'ꮊ', + 'Ꮋ' => 'ꮋ', + 'Ꮌ' => 'ꮌ', + 'Ꮍ' => 'ꮍ', + 'Ꮎ' => 'ꮎ', + 'Ꮏ' => 'ꮏ', + 'Ꮐ' => 'ꮐ', + 'Ꮑ' => 'ꮑ', + 'Ꮒ' => 'ꮒ', + 'Ꮓ' => 'ꮓ', + 'Ꮔ' => 'ꮔ', + 'Ꮕ' => 'ꮕ', + 'Ꮖ' => 'ꮖ', + 'Ꮗ' => 'ꮗ', + 'Ꮘ' => 'ꮘ', + 'Ꮙ' => 'ꮙ', + 'Ꮚ' => 'ꮚ', + 'Ꮛ' => 'ꮛ', + 'Ꮜ' => 'ꮜ', + 'Ꮝ' => 'ꮝ', + 'Ꮞ' => 'ꮞ', + 'Ꮟ' => 'ꮟ', + 'Ꮠ' => 'ꮠ', + 'Ꮡ' => 'ꮡ', + 'Ꮢ' => 'ꮢ', + 'Ꮣ' => 'ꮣ', + 'Ꮤ' => 'ꮤ', + 'Ꮥ' => 'ꮥ', + 'Ꮦ' => 'ꮦ', + 'Ꮧ' => 'ꮧ', + 'Ꮨ' => 'ꮨ', + 'Ꮩ' => 'ꮩ', + 'Ꮪ' => 'ꮪ', + 'Ꮫ' => 'ꮫ', + 'Ꮬ' => 'ꮬ', + 'Ꮭ' => 'ꮭ', + 'Ꮮ' => 'ꮮ', + 'Ꮯ' => 'ꮯ', + 'Ꮰ' => 'ꮰ', + 'Ꮱ' => 'ꮱ', + 'Ꮲ' => 'ꮲ', + 'Ꮳ' => 'ꮳ', + 'Ꮴ' => 'ꮴ', + 'Ꮵ' => 'ꮵ', + 'Ꮶ' => 'ꮶ', + 'Ꮷ' => 'ꮷ', + 'Ꮸ' => 'ꮸ', + 'Ꮹ' => 'ꮹ', + 'Ꮺ' => 'ꮺ', + 'Ꮻ' => 'ꮻ', + 'Ꮼ' => 'ꮼ', + 'Ꮽ' => 'ꮽ', + 'Ꮾ' => 'ꮾ', + 'Ꮿ' => 'ꮿ', + 'Ᏸ' => 'ᏸ', + 'Ᏹ' => 'ᏹ', + 'Ᏺ' => 'ᏺ', + 'Ᏻ' => 'ᏻ', + 'Ᏼ' => 'ᏼ', + 'Ᏽ' => 'ᏽ', + 'Ა' => 'ა', + 'Ბ' => 'ბ', + 'Გ' => 'გ', + 'Დ' => 'დ', + 'Ე' => 'ე', + 'Ვ' => 'ვ', + 'Ზ' => 'ზ', + 'Თ' => 'თ', + 'Ი' => 'ი', + 'Კ' => 'კ', + 'Ლ' => 'ლ', + 'Მ' => 'მ', + 'Ნ' => 'ნ', + 'Ო' => 'ო', + 'Პ' => 'პ', + 'Ჟ' => 'ჟ', + 'Რ' => 'რ', + 'Ს' => 'ს', + 'Ტ' => 'ტ', + 'Უ' => 'უ', + 'Ფ' => 'ფ', + 'Ქ' => 'ქ', + 'Ღ' => 'ღ', + 'Ყ' => 'ყ', + 'Შ' => 'შ', + 'Ჩ' => 'ჩ', + 'Ც' => 'ც', + 'Ძ' => 'ძ', + 'Წ' => 'წ', + 'Ჭ' => 'ჭ', + 'Ხ' => 'ხ', + 'Ჯ' => 'ჯ', + 'Ჰ' => 'ჰ', + 'Ჱ' => 'ჱ', + 'Ჲ' => 'ჲ', + 'Ჳ' => 'ჳ', + 'Ჴ' => 'ჴ', + 'Ჵ' => 'ჵ', + 'Ჶ' => 'ჶ', + 'Ჷ' => 'ჷ', + 'Ჸ' => 'ჸ', + 'Ჹ' => 'ჹ', + 'Ჺ' => 'ჺ', + 'Ჽ' => 'ჽ', + 'Ჾ' => 'ჾ', + 'Ჿ' => 'ჿ', + 'Ḁ' => 'ḁ', + 'Ḃ' => 'ḃ', + 'Ḅ' => 'ḅ', + 'Ḇ' => 'ḇ', + 'Ḉ' => 'ḉ', + 'Ḋ' => 'ḋ', + 'Ḍ' => 'ḍ', + 'Ḏ' => 'ḏ', + 'Ḑ' => 'ḑ', + 'Ḓ' => 'ḓ', + 'Ḕ' => 'ḕ', + 'Ḗ' => 'ḗ', + 'Ḙ' => 'ḙ', + 'Ḛ' => 'ḛ', + 'Ḝ' => 'ḝ', + 'Ḟ' => 'ḟ', + 'Ḡ' => 'ḡ', + 'Ḣ' => 'ḣ', + 'Ḥ' => 'ḥ', + 'Ḧ' => 'ḧ', + 'Ḩ' => 'ḩ', + 'Ḫ' => 'ḫ', + 'Ḭ' => 'ḭ', + 'Ḯ' => 'ḯ', + 'Ḱ' => 'ḱ', + 'Ḳ' => 'ḳ', + 'Ḵ' => 'ḵ', + 'Ḷ' => 'ḷ', + 'Ḹ' => 'ḹ', + 'Ḻ' => 'ḻ', + 'Ḽ' => 'ḽ', + 'Ḿ' => 'ḿ', + 'Ṁ' => 'ṁ', + 'Ṃ' => 'ṃ', + 'Ṅ' => 'ṅ', + 'Ṇ' => 'ṇ', + 'Ṉ' => 'ṉ', + 'Ṋ' => 'ṋ', + 'Ṍ' => 'ṍ', + 'Ṏ' => 'ṏ', + 'Ṑ' => 'ṑ', + 'Ṓ' => 'ṓ', + 'Ṕ' => 'ṕ', + 'Ṗ' => 'ṗ', + 'Ṙ' => 'ṙ', + 'Ṛ' => 'ṛ', + 'Ṝ' => 'ṝ', + 'Ṟ' => 'ṟ', + 'Ṡ' => 'ṡ', + 'Ṣ' => 'ṣ', + 'Ṥ' => 'ṥ', + 'Ṧ' => 'ṧ', + 'Ṩ' => 'ṩ', + 'Ṫ' => 'ṫ', + 'Ṭ' => 'ṭ', + 'Ṯ' => 'ṯ', + 'Ṱ' => 'ṱ', + 'Ṳ' => 'ṳ', + 'Ṵ' => 'ṵ', + 'Ṷ' => 'ṷ', + 'Ṹ' => 'ṹ', + 'Ṻ' => 'ṻ', + 'Ṽ' => 'ṽ', + 'Ṿ' => 'ṿ', + 'Ẁ' => 'ẁ', + 'Ẃ' => 'ẃ', + 'Ẅ' => 'ẅ', + 'Ẇ' => 'ẇ', + 'Ẉ' => 'ẉ', + 'Ẋ' => 'ẋ', + 'Ẍ' => 'ẍ', + 'Ẏ' => 'ẏ', + 'Ẑ' => 'ẑ', + 'Ẓ' => 'ẓ', + 'Ẕ' => 'ẕ', + 'ẞ' => 'ß', + 'Ạ' => 'ạ', + 'Ả' => 'ả', + 'Ấ' => 'ấ', + 'Ầ' => 'ầ', + 'Ẩ' => 'ẩ', + 'Ẫ' => 'ẫ', + 'Ậ' => 'ậ', + 'Ắ' => 'ắ', + 'Ằ' => 'ằ', + 'Ẳ' => 'ẳ', + 'Ẵ' => 'ẵ', + 'Ặ' => 'ặ', + 'Ẹ' => 'ẹ', + 'Ẻ' => 'ẻ', + 'Ẽ' => 'ẽ', + 'Ế' => 'ế', + 'Ề' => 'ề', + 'Ể' => 'ể', + 'Ễ' => 'ễ', + 'Ệ' => 'ệ', + 'Ỉ' => 'ỉ', + 'Ị' => 'ị', + 'Ọ' => 'ọ', + 'Ỏ' => 'ỏ', + 'Ố' => 'ố', + 'Ồ' => 'ồ', + 'Ổ' => 'ổ', + 'Ỗ' => 'ỗ', + 'Ộ' => 'ộ', + 'Ớ' => 'ớ', + 'Ờ' => 'ờ', + 'Ở' => 'ở', + 'Ỡ' => 'ỡ', + 'Ợ' => 'ợ', + 'Ụ' => 'ụ', + 'Ủ' => 'ủ', + 'Ứ' => 'ứ', + 'Ừ' => 'ừ', + 'Ử' => 'ử', + 'Ữ' => 'ữ', + 'Ự' => 'ự', + 'Ỳ' => 'ỳ', + 'Ỵ' => 'ỵ', + 'Ỷ' => 'ỷ', + 'Ỹ' => 'ỹ', + 'Ỻ' => 'ỻ', + 'Ỽ' => 'ỽ', + 'Ỿ' => 'ỿ', + 'Ἀ' => 'ἀ', + 'Ἁ' => 'ἁ', + 'Ἂ' => 'ἂ', + 'Ἃ' => 'ἃ', + 'Ἄ' => 'ἄ', + 'Ἅ' => 'ἅ', + 'Ἆ' => 'ἆ', + 'Ἇ' => 'ἇ', + 'Ἐ' => 'ἐ', + 'Ἑ' => 'ἑ', + 'Ἒ' => 'ἒ', + 'Ἓ' => 'ἓ', + 'Ἔ' => 'ἔ', + 'Ἕ' => 'ἕ', + 'Ἠ' => 'ἠ', + 'Ἡ' => 'ἡ', + 'Ἢ' => 'ἢ', + 'Ἣ' => 'ἣ', + 'Ἤ' => 'ἤ', + 'Ἥ' => 'ἥ', + 'Ἦ' => 'ἦ', + 'Ἧ' => 'ἧ', + 'Ἰ' => 'ἰ', + 'Ἱ' => 'ἱ', + 'Ἲ' => 'ἲ', + 'Ἳ' => 'ἳ', + 'Ἴ' => 'ἴ', + 'Ἵ' => 'ἵ', + 'Ἶ' => 'ἶ', + 'Ἷ' => 'ἷ', + 'Ὀ' => 'ὀ', + 'Ὁ' => 'ὁ', + 'Ὂ' => 'ὂ', + 'Ὃ' => 'ὃ', + 'Ὄ' => 'ὄ', + 'Ὅ' => 'ὅ', + 'Ὑ' => 'ὑ', + 'Ὓ' => 'ὓ', + 'Ὕ' => 'ὕ', + 'Ὗ' => 'ὗ', + 'Ὠ' => 'ὠ', + 'Ὡ' => 'ὡ', + 'Ὢ' => 'ὢ', + 'Ὣ' => 'ὣ', + 'Ὤ' => 'ὤ', + 'Ὥ' => 'ὥ', + 'Ὦ' => 'ὦ', + 'Ὧ' => 'ὧ', + 'ᾈ' => 'ᾀ', + 'ᾉ' => 'ᾁ', + 'ᾊ' => 'ᾂ', + 'ᾋ' => 'ᾃ', + 'ᾌ' => 'ᾄ', + 'ᾍ' => 'ᾅ', + 'ᾎ' => 'ᾆ', + 'ᾏ' => 'ᾇ', + 'ᾘ' => 'ᾐ', + 'ᾙ' => 'ᾑ', + 'ᾚ' => 'ᾒ', + 'ᾛ' => 'ᾓ', + 'ᾜ' => 'ᾔ', + 'ᾝ' => 'ᾕ', + 'ᾞ' => 'ᾖ', + 'ᾟ' => 'ᾗ', + 'ᾨ' => 'ᾠ', + 'ᾩ' => 'ᾡ', + 'ᾪ' => 'ᾢ', + 'ᾫ' => 'ᾣ', + 'ᾬ' => 'ᾤ', + 'ᾭ' => 'ᾥ', + 'ᾮ' => 'ᾦ', + 'ᾯ' => 'ᾧ', + 'Ᾰ' => 'ᾰ', + 'Ᾱ' => 'ᾱ', + 'Ὰ' => 'ὰ', + 'Ά' => 'ά', + 'ᾼ' => 'ᾳ', + 'Ὲ' => 'ὲ', + 'Έ' => 'έ', + 'Ὴ' => 'ὴ', + 'Ή' => 'ή', + 'ῌ' => 'ῃ', + 'Ῐ' => 'ῐ', + 'Ῑ' => 'ῑ', + 'Ὶ' => 'ὶ', + 'Ί' => 'ί', + 'Ῠ' => 'ῠ', + 'Ῡ' => 'ῡ', + 'Ὺ' => 'ὺ', + 'Ύ' => 'ύ', + 'Ῥ' => 'ῥ', + 'Ὸ' => 'ὸ', + 'Ό' => 'ό', + 'Ὼ' => 'ὼ', + 'Ώ' => 'ώ', + 'ῼ' => 'ῳ', + 'Ω' => 'ω', + 'K' => 'k', + 'Å' => 'å', + 'Ⅎ' => 'ⅎ', + 'Ⅰ' => 'ⅰ', + 'Ⅱ' => 'ⅱ', + 'Ⅲ' => 'ⅲ', + 'Ⅳ' => 'ⅳ', + 'Ⅴ' => 'ⅴ', + 'Ⅵ' => 'ⅵ', + 'Ⅶ' => 'ⅶ', + 'Ⅷ' => 'ⅷ', + 'Ⅸ' => 'ⅸ', + 'Ⅹ' => 'ⅹ', + 'Ⅺ' => 'ⅺ', + 'Ⅻ' => 'ⅻ', + 'Ⅼ' => 'ⅼ', + 'Ⅽ' => 'ⅽ', + 'Ⅾ' => 'ⅾ', + 'Ⅿ' => 'ⅿ', + 'Ↄ' => 'ↄ', + 'Ⓐ' => 'ⓐ', + 'Ⓑ' => 'ⓑ', + 'Ⓒ' => 'ⓒ', + 'Ⓓ' => 'ⓓ', + 'Ⓔ' => 'ⓔ', + 'Ⓕ' => 'ⓕ', + 'Ⓖ' => 'ⓖ', + 'Ⓗ' => 'ⓗ', + 'Ⓘ' => 'ⓘ', + 'Ⓙ' => 'ⓙ', + 'Ⓚ' => 'ⓚ', + 'Ⓛ' => 'ⓛ', + 'Ⓜ' => 'ⓜ', + 'Ⓝ' => 'ⓝ', + 'Ⓞ' => 'ⓞ', + 'Ⓟ' => 'ⓟ', + 'Ⓠ' => 'ⓠ', + 'Ⓡ' => 'ⓡ', + 'Ⓢ' => 'ⓢ', + 'Ⓣ' => 'ⓣ', + 'Ⓤ' => 'ⓤ', + 'Ⓥ' => 'ⓥ', + 'Ⓦ' => 'ⓦ', + 'Ⓧ' => 'ⓧ', + 'Ⓨ' => 'ⓨ', + 'Ⓩ' => 'ⓩ', + 'Ⰰ' => 'ⰰ', + 'Ⰱ' => 'ⰱ', + 'Ⰲ' => 'ⰲ', + 'Ⰳ' => 'ⰳ', + 'Ⰴ' => 'ⰴ', + 'Ⰵ' => 'ⰵ', + 'Ⰶ' => 'ⰶ', + 'Ⰷ' => 'ⰷ', + 'Ⰸ' => 'ⰸ', + 'Ⰹ' => 'ⰹ', + 'Ⰺ' => 'ⰺ', + 'Ⰻ' => 'ⰻ', + 'Ⰼ' => 'ⰼ', + 'Ⰽ' => 'ⰽ', + 'Ⰾ' => 'ⰾ', + 'Ⰿ' => 'ⰿ', + 'Ⱀ' => 'ⱀ', + 'Ⱁ' => 'ⱁ', + 'Ⱂ' => 'ⱂ', + 'Ⱃ' => 'ⱃ', + 'Ⱄ' => 'ⱄ', + 'Ⱅ' => 'ⱅ', + 'Ⱆ' => 'ⱆ', + 'Ⱇ' => 'ⱇ', + 'Ⱈ' => 'ⱈ', + 'Ⱉ' => 'ⱉ', + 'Ⱊ' => 'ⱊ', + 'Ⱋ' => 'ⱋ', + 'Ⱌ' => 'ⱌ', + 'Ⱍ' => 'ⱍ', + 'Ⱎ' => 'ⱎ', + 'Ⱏ' => 'ⱏ', + 'Ⱐ' => 'ⱐ', + 'Ⱑ' => 'ⱑ', + 'Ⱒ' => 'ⱒ', + 'Ⱓ' => 'ⱓ', + 'Ⱔ' => 'ⱔ', + 'Ⱕ' => 'ⱕ', + 'Ⱖ' => 'ⱖ', + 'Ⱗ' => 'ⱗ', + 'Ⱘ' => 'ⱘ', + 'Ⱙ' => 'ⱙ', + 'Ⱚ' => 'ⱚ', + 'Ⱛ' => 'ⱛ', + 'Ⱜ' => 'ⱜ', + 'Ⱝ' => 'ⱝ', + 'Ⱞ' => 'ⱞ', + 'Ⱡ' => 'ⱡ', + 'Ɫ' => 'ɫ', + 'Ᵽ' => 'ᵽ', + 'Ɽ' => 'ɽ', + 'Ⱨ' => 'ⱨ', + 'Ⱪ' => 'ⱪ', + 'Ⱬ' => 'ⱬ', + 'Ɑ' => 'ɑ', + 'Ɱ' => 'ɱ', + 'Ɐ' => 'ɐ', + 'Ɒ' => 'ɒ', + 'Ⱳ' => 'ⱳ', + 'Ⱶ' => 'ⱶ', + 'Ȿ' => 'ȿ', + 'Ɀ' => 'ɀ', + 'Ⲁ' => 'ⲁ', + 'Ⲃ' => 'ⲃ', + 'Ⲅ' => 'ⲅ', + 'Ⲇ' => 'ⲇ', + 'Ⲉ' => 'ⲉ', + 'Ⲋ' => 'ⲋ', + 'Ⲍ' => 'ⲍ', + 'Ⲏ' => 'ⲏ', + 'Ⲑ' => 'ⲑ', + 'Ⲓ' => 'ⲓ', + 'Ⲕ' => 'ⲕ', + 'Ⲗ' => 'ⲗ', + 'Ⲙ' => 'ⲙ', + 'Ⲛ' => 'ⲛ', + 'Ⲝ' => 'ⲝ', + 'Ⲟ' => 'ⲟ', + 'Ⲡ' => 'ⲡ', + 'Ⲣ' => 'ⲣ', + 'Ⲥ' => 'ⲥ', + 'Ⲧ' => 'ⲧ', + 'Ⲩ' => 'ⲩ', + 'Ⲫ' => 'ⲫ', + 'Ⲭ' => 'ⲭ', + 'Ⲯ' => 'ⲯ', + 'Ⲱ' => 'ⲱ', + 'Ⲳ' => 'ⲳ', + 'Ⲵ' => 'ⲵ', + 'Ⲷ' => 'ⲷ', + 'Ⲹ' => 'ⲹ', + 'Ⲻ' => 'ⲻ', + 'Ⲽ' => 'ⲽ', + 'Ⲿ' => 'ⲿ', + 'Ⳁ' => 'ⳁ', + 'Ⳃ' => 'ⳃ', + 'Ⳅ' => 'ⳅ', + 'Ⳇ' => 'ⳇ', + 'Ⳉ' => 'ⳉ', + 'Ⳋ' => 'ⳋ', + 'Ⳍ' => 'ⳍ', + 'Ⳏ' => 'ⳏ', + 'Ⳑ' => 'ⳑ', + 'Ⳓ' => 'ⳓ', + 'Ⳕ' => 'ⳕ', + 'Ⳗ' => 'ⳗ', + 'Ⳙ' => 'ⳙ', + 'Ⳛ' => 'ⳛ', + 'Ⳝ' => 'ⳝ', + 'Ⳟ' => 'ⳟ', + 'Ⳡ' => 'ⳡ', + 'Ⳣ' => 'ⳣ', + 'Ⳬ' => 'ⳬ', + 'Ⳮ' => 'ⳮ', + 'Ⳳ' => 'ⳳ', + 'Ꙁ' => 'ꙁ', + 'Ꙃ' => 'ꙃ', + 'Ꙅ' => 'ꙅ', + 'Ꙇ' => 'ꙇ', + 'Ꙉ' => 'ꙉ', + 'Ꙋ' => 'ꙋ', + 'Ꙍ' => 'ꙍ', + 'Ꙏ' => 'ꙏ', + 'Ꙑ' => 'ꙑ', + 'Ꙓ' => 'ꙓ', + 'Ꙕ' => 'ꙕ', + 'Ꙗ' => 'ꙗ', + 'Ꙙ' => 'ꙙ', + 'Ꙛ' => 'ꙛ', + 'Ꙝ' => 'ꙝ', + 'Ꙟ' => 'ꙟ', + 'Ꙡ' => 'ꙡ', + 'Ꙣ' => 'ꙣ', + 'Ꙥ' => 'ꙥ', + 'Ꙧ' => 'ꙧ', + 'Ꙩ' => 'ꙩ', + 'Ꙫ' => 'ꙫ', + 'Ꙭ' => 'ꙭ', + 'Ꚁ' => 'ꚁ', + 'Ꚃ' => 'ꚃ', + 'Ꚅ' => 'ꚅ', + 'Ꚇ' => 'ꚇ', + 'Ꚉ' => 'ꚉ', + 'Ꚋ' => 'ꚋ', + 'Ꚍ' => 'ꚍ', + 'Ꚏ' => 'ꚏ', + 'Ꚑ' => 'ꚑ', + 'Ꚓ' => 'ꚓ', + 'Ꚕ' => 'ꚕ', + 'Ꚗ' => 'ꚗ', + 'Ꚙ' => 'ꚙ', + 'Ꚛ' => 'ꚛ', + 'Ꜣ' => 'ꜣ', + 'Ꜥ' => 'ꜥ', + 'Ꜧ' => 'ꜧ', + 'Ꜩ' => 'ꜩ', + 'Ꜫ' => 'ꜫ', + 'Ꜭ' => 'ꜭ', + 'Ꜯ' => 'ꜯ', + 'Ꜳ' => 'ꜳ', + 'Ꜵ' => 'ꜵ', + 'Ꜷ' => 'ꜷ', + 'Ꜹ' => 'ꜹ', + 'Ꜻ' => 'ꜻ', + 'Ꜽ' => 'ꜽ', + 'Ꜿ' => 'ꜿ', + 'Ꝁ' => 'ꝁ', + 'Ꝃ' => 'ꝃ', + 'Ꝅ' => 'ꝅ', + 'Ꝇ' => 'ꝇ', + 'Ꝉ' => 'ꝉ', + 'Ꝋ' => 'ꝋ', + 'Ꝍ' => 'ꝍ', + 'Ꝏ' => 'ꝏ', + 'Ꝑ' => 'ꝑ', + 'Ꝓ' => 'ꝓ', + 'Ꝕ' => 'ꝕ', + 'Ꝗ' => 'ꝗ', + 'Ꝙ' => 'ꝙ', + 'Ꝛ' => 'ꝛ', + 'Ꝝ' => 'ꝝ', + 'Ꝟ' => 'ꝟ', + 'Ꝡ' => 'ꝡ', + 'Ꝣ' => 'ꝣ', + 'Ꝥ' => 'ꝥ', + 'Ꝧ' => 'ꝧ', + 'Ꝩ' => 'ꝩ', + 'Ꝫ' => 'ꝫ', + 'Ꝭ' => 'ꝭ', + 'Ꝯ' => 'ꝯ', + 'Ꝺ' => 'ꝺ', + 'Ꝼ' => 'ꝼ', + 'Ᵹ' => 'ᵹ', + 'Ꝿ' => 'ꝿ', + 'Ꞁ' => 'ꞁ', + 'Ꞃ' => 'ꞃ', + 'Ꞅ' => 'ꞅ', + 'Ꞇ' => 'ꞇ', + 'Ꞌ' => 'ꞌ', + 'Ɥ' => 'ɥ', + 'Ꞑ' => 'ꞑ', + 'Ꞓ' => 'ꞓ', + 'Ꞗ' => 'ꞗ', + 'Ꞙ' => 'ꞙ', + 'Ꞛ' => 'ꞛ', + 'Ꞝ' => 'ꞝ', + 'Ꞟ' => 'ꞟ', + 'Ꞡ' => 'ꞡ', + 'Ꞣ' => 'ꞣ', + 'Ꞥ' => 'ꞥ', + 'Ꞧ' => 'ꞧ', + 'Ꞩ' => 'ꞩ', + 'Ɦ' => 'ɦ', + 'Ɜ' => 'ɜ', + 'Ɡ' => 'ɡ', + 'Ɬ' => 'ɬ', + 'Ɪ' => 'ɪ', + 'Ʞ' => 'ʞ', + 'Ʇ' => 'ʇ', + 'Ʝ' => 'ʝ', + 'Ꭓ' => 'ꭓ', + 'Ꞵ' => 'ꞵ', + 'Ꞷ' => 'ꞷ', + 'Ꞹ' => 'ꞹ', + 'Ꞻ' => 'ꞻ', + 'Ꞽ' => 'ꞽ', + 'Ꞿ' => 'ꞿ', + 'Ꟃ' => 'ꟃ', + 'Ꞔ' => 'ꞔ', + 'Ʂ' => 'ʂ', + 'Ᶎ' => 'ᶎ', + 'Ꟈ' => 'ꟈ', + 'Ꟊ' => 'ꟊ', + 'Ꟶ' => 'ꟶ', + 'A' => 'a', + 'B' => 'b', + 'C' => 'c', + 'D' => 'd', + 'E' => 'e', + 'F' => 'f', + 'G' => 'g', + 'H' => 'h', + 'I' => 'i', + 'J' => 'j', + 'K' => 'k', + 'L' => 'l', + 'M' => 'm', + 'N' => 'n', + 'O' => 'o', + 'P' => 'p', + 'Q' => 'q', + 'R' => 'r', + 'S' => 's', + 'T' => 't', + 'U' => 'u', + 'V' => 'v', + 'W' => 'w', + 'X' => 'x', + 'Y' => 'y', + 'Z' => 'z', + '𐐀' => '𐐨', + '𐐁' => '𐐩', + '𐐂' => '𐐪', + '𐐃' => '𐐫', + '𐐄' => '𐐬', + '𐐅' => '𐐭', + '𐐆' => '𐐮', + '𐐇' => '𐐯', + '𐐈' => '𐐰', + '𐐉' => '𐐱', + '𐐊' => '𐐲', + '𐐋' => '𐐳', + '𐐌' => '𐐴', + '𐐍' => '𐐵', + '𐐎' => '𐐶', + '𐐏' => '𐐷', + '𐐐' => '𐐸', + '𐐑' => '𐐹', + '𐐒' => '𐐺', + '𐐓' => '𐐻', + '𐐔' => '𐐼', + '𐐕' => '𐐽', + '𐐖' => '𐐾', + '𐐗' => '𐐿', + '𐐘' => '𐑀', + '𐐙' => '𐑁', + '𐐚' => '𐑂', + '𐐛' => '𐑃', + '𐐜' => '𐑄', + '𐐝' => '𐑅', + '𐐞' => '𐑆', + '𐐟' => '𐑇', + '𐐠' => '𐑈', + '𐐡' => '𐑉', + '𐐢' => '𐑊', + '𐐣' => '𐑋', + '𐐤' => '𐑌', + '𐐥' => '𐑍', + '𐐦' => '𐑎', + '𐐧' => '𐑏', + '𐒰' => '𐓘', + '𐒱' => '𐓙', + '𐒲' => '𐓚', + '𐒳' => '𐓛', + '𐒴' => '𐓜', + '𐒵' => '𐓝', + '𐒶' => '𐓞', + '𐒷' => '𐓟', + '𐒸' => '𐓠', + '𐒹' => '𐓡', + '𐒺' => '𐓢', + '𐒻' => '𐓣', + '𐒼' => '𐓤', + '𐒽' => '𐓥', + '𐒾' => '𐓦', + '𐒿' => '𐓧', + '𐓀' => '𐓨', + '𐓁' => '𐓩', + '𐓂' => '𐓪', + '𐓃' => '𐓫', + '𐓄' => '𐓬', + '𐓅' => '𐓭', + '𐓆' => '𐓮', + '𐓇' => '𐓯', + '𐓈' => '𐓰', + '𐓉' => '𐓱', + '𐓊' => '𐓲', + '𐓋' => '𐓳', + '𐓌' => '𐓴', + '𐓍' => '𐓵', + '𐓎' => '𐓶', + '𐓏' => '𐓷', + '𐓐' => '𐓸', + '𐓑' => '𐓹', + '𐓒' => '𐓺', + '𐓓' => '𐓻', + '𐲀' => '𐳀', + '𐲁' => '𐳁', + '𐲂' => '𐳂', + '𐲃' => '𐳃', + '𐲄' => '𐳄', + '𐲅' => '𐳅', + '𐲆' => '𐳆', + '𐲇' => '𐳇', + '𐲈' => '𐳈', + '𐲉' => '𐳉', + '𐲊' => '𐳊', + '𐲋' => '𐳋', + '𐲌' => '𐳌', + '𐲍' => '𐳍', + '𐲎' => '𐳎', + '𐲏' => '𐳏', + '𐲐' => '𐳐', + '𐲑' => '𐳑', + '𐲒' => '𐳒', + '𐲓' => '𐳓', + '𐲔' => '𐳔', + '𐲕' => '𐳕', + '𐲖' => '𐳖', + '𐲗' => '𐳗', + '𐲘' => '𐳘', + '𐲙' => '𐳙', + '𐲚' => '𐳚', + '𐲛' => '𐳛', + '𐲜' => '𐳜', + '𐲝' => '𐳝', + '𐲞' => '𐳞', + '𐲟' => '𐳟', + '𐲠' => '𐳠', + '𐲡' => '𐳡', + '𐲢' => '𐳢', + '𐲣' => '𐳣', + '𐲤' => '𐳤', + '𐲥' => '𐳥', + '𐲦' => '𐳦', + '𐲧' => '𐳧', + '𐲨' => '𐳨', + '𐲩' => '𐳩', + '𐲪' => '𐳪', + '𐲫' => '𐳫', + '𐲬' => '𐳬', + '𐲭' => '𐳭', + '𐲮' => '𐳮', + '𐲯' => '𐳯', + '𐲰' => '𐳰', + '𐲱' => '𐳱', + '𐲲' => '𐳲', + '𑢠' => '𑣀', + '𑢡' => '𑣁', + '𑢢' => '𑣂', + '𑢣' => '𑣃', + '𑢤' => '𑣄', + '𑢥' => '𑣅', + '𑢦' => '𑣆', + '𑢧' => '𑣇', + '𑢨' => '𑣈', + '𑢩' => '𑣉', + '𑢪' => '𑣊', + '𑢫' => '𑣋', + '𑢬' => '𑣌', + '𑢭' => '𑣍', + '𑢮' => '𑣎', + '𑢯' => '𑣏', + '𑢰' => '𑣐', + '𑢱' => '𑣑', + '𑢲' => '𑣒', + '𑢳' => '𑣓', + '𑢴' => '𑣔', + '𑢵' => '𑣕', + '𑢶' => '𑣖', + '𑢷' => '𑣗', + '𑢸' => '𑣘', + '𑢹' => '𑣙', + '𑢺' => '𑣚', + '𑢻' => '𑣛', + '𑢼' => '𑣜', + '𑢽' => '𑣝', + '𑢾' => '𑣞', + '𑢿' => '𑣟', + '𖹀' => '𖹠', + '𖹁' => '𖹡', + '𖹂' => '𖹢', + '𖹃' => '𖹣', + '𖹄' => '𖹤', + '𖹅' => '𖹥', + '𖹆' => '𖹦', + '𖹇' => '𖹧', + '𖹈' => '𖹨', + '𖹉' => '𖹩', + '𖹊' => '𖹪', + '𖹋' => '𖹫', + '𖹌' => '𖹬', + '𖹍' => '𖹭', + '𖹎' => '𖹮', + '𖹏' => '𖹯', + '𖹐' => '𖹰', + '𖹑' => '𖹱', + '𖹒' => '𖹲', + '𖹓' => '𖹳', + '𖹔' => '𖹴', + '𖹕' => '𖹵', + '𖹖' => '𖹶', + '𖹗' => '𖹷', + '𖹘' => '𖹸', + '𖹙' => '𖹹', + '𖹚' => '𖹺', + '𖹛' => '𖹻', + '𖹜' => '𖹼', + '𖹝' => '𖹽', + '𖹞' => '𖹾', + '𖹟' => '𖹿', + '𞤀' => '𞤢', + '𞤁' => '𞤣', + '𞤂' => '𞤤', + '𞤃' => '𞤥', + '𞤄' => '𞤦', + '𞤅' => '𞤧', + '𞤆' => '𞤨', + '𞤇' => '𞤩', + '𞤈' => '𞤪', + '𞤉' => '𞤫', + '𞤊' => '𞤬', + '𞤋' => '𞤭', + '𞤌' => '𞤮', + '𞤍' => '𞤯', + '𞤎' => '𞤰', + '𞤏' => '𞤱', + '𞤐' => '𞤲', + '𞤑' => '𞤳', + '𞤒' => '𞤴', + '𞤓' => '𞤵', + '𞤔' => '𞤶', + '𞤕' => '𞤷', + '𞤖' => '𞤸', + '𞤗' => '𞤹', + '𞤘' => '𞤺', + '𞤙' => '𞤻', + '𞤚' => '𞤼', + '𞤛' => '𞤽', + '𞤜' => '𞤾', + '𞤝' => '𞤿', + '𞤞' => '𞥀', + '𞤟' => '𞥁', + '𞤠' => '𞥂', + '𞤡' => '𞥃', +); diff --git a/vendor/symfony/polyfill-mbstring/Resources/unidata/titleCaseRegexp.php b/vendor/symfony/polyfill-mbstring/Resources/unidata/titleCaseRegexp.php new file mode 100644 index 000000000..2a8f6e73b --- /dev/null +++ b/vendor/symfony/polyfill-mbstring/Resources/unidata/titleCaseRegexp.php @@ -0,0 +1,5 @@ + 'A', + 'b' => 'B', + 'c' => 'C', + 'd' => 'D', + 'e' => 'E', + 'f' => 'F', + 'g' => 'G', + 'h' => 'H', + 'i' => 'I', + 'j' => 'J', + 'k' => 'K', + 'l' => 'L', + 'm' => 'M', + 'n' => 'N', + 'o' => 'O', + 'p' => 'P', + 'q' => 'Q', + 'r' => 'R', + 's' => 'S', + 't' => 'T', + 'u' => 'U', + 'v' => 'V', + 'w' => 'W', + 'x' => 'X', + 'y' => 'Y', + 'z' => 'Z', + 'µ' => 'Μ', + 'à' => 'À', + 'á' => 'Á', + 'â' => 'Â', + 'ã' => 'Ã', + 'ä' => 'Ä', + 'å' => 'Å', + 'æ' => 'Æ', + 'ç' => 'Ç', + 'è' => 'È', + 'é' => 'É', + 'ê' => 'Ê', + 'ë' => 'Ë', + 'ì' => 'Ì', + 'í' => 'Í', + 'î' => 'Î', + 'ï' => 'Ï', + 'ð' => 'Ð', + 'ñ' => 'Ñ', + 'ò' => 'Ò', + 'ó' => 'Ó', + 'ô' => 'Ô', + 'õ' => 'Õ', + 'ö' => 'Ö', + 'ø' => 'Ø', + 'ù' => 'Ù', + 'ú' => 'Ú', + 'û' => 'Û', + 'ü' => 'Ü', + 'ý' => 'Ý', + 'þ' => 'Þ', + 'ÿ' => 'Ÿ', + 'ā' => 'Ā', + 'ă' => 'Ă', + 'ą' => 'Ą', + 'ć' => 'Ć', + 'ĉ' => 'Ĉ', + 'ċ' => 'Ċ', + 'č' => 'Č', + 'ď' => 'Ď', + 'đ' => 'Đ', + 'ē' => 'Ē', + 'ĕ' => 'Ĕ', + 'ė' => 'Ė', + 'ę' => 'Ę', + 'ě' => 'Ě', + 'ĝ' => 'Ĝ', + 'ğ' => 'Ğ', + 'ġ' => 'Ġ', + 'ģ' => 'Ģ', + 'ĥ' => 'Ĥ', + 'ħ' => 'Ħ', + 'ĩ' => 'Ĩ', + 'ī' => 'Ī', + 'ĭ' => 'Ĭ', + 'į' => 'Į', + 'ı' => 'I', + 'ij' => 'IJ', + 'ĵ' => 'Ĵ', + 'ķ' => 'Ķ', + 'ĺ' => 'Ĺ', + 'ļ' => 'Ļ', + 'ľ' => 'Ľ', + 'ŀ' => 'Ŀ', + 'ł' => 'Ł', + 'ń' => 'Ń', + 'ņ' => 'Ņ', + 'ň' => 'Ň', + 'ŋ' => 'Ŋ', + 'ō' => 'Ō', + 'ŏ' => 'Ŏ', + 'ő' => 'Ő', + 'œ' => 'Œ', + 'ŕ' => 'Ŕ', + 'ŗ' => 'Ŗ', + 'ř' => 'Ř', + 'ś' => 'Ś', + 'ŝ' => 'Ŝ', + 'ş' => 'Ş', + 'š' => 'Š', + 'ţ' => 'Ţ', + 'ť' => 'Ť', + 'ŧ' => 'Ŧ', + 'ũ' => 'Ũ', + 'ū' => 'Ū', + 'ŭ' => 'Ŭ', + 'ů' => 'Ů', + 'ű' => 'Ű', + 'ų' => 'Ų', + 'ŵ' => 'Ŵ', + 'ŷ' => 'Ŷ', + 'ź' => 'Ź', + 'ż' => 'Ż', + 'ž' => 'Ž', + 'ſ' => 'S', + 'ƀ' => 'Ƀ', + 'ƃ' => 'Ƃ', + 'ƅ' => 'Ƅ', + 'ƈ' => 'Ƈ', + 'ƌ' => 'Ƌ', + 'ƒ' => 'Ƒ', + 'ƕ' => 'Ƕ', + 'ƙ' => 'Ƙ', + 'ƚ' => 'Ƚ', + 'ƞ' => 'Ƞ', + 'ơ' => 'Ơ', + 'ƣ' => 'Ƣ', + 'ƥ' => 'Ƥ', + 'ƨ' => 'Ƨ', + 'ƭ' => 'Ƭ', + 'ư' => 'Ư', + 'ƴ' => 'Ƴ', + 'ƶ' => 'Ƶ', + 'ƹ' => 'Ƹ', + 'ƽ' => 'Ƽ', + 'ƿ' => 'Ƿ', + 'Dž' => 'DŽ', + 'dž' => 'DŽ', + 'Lj' => 'LJ', + 'lj' => 'LJ', + 'Nj' => 'NJ', + 'nj' => 'NJ', + 'ǎ' => 'Ǎ', + 'ǐ' => 'Ǐ', + 'ǒ' => 'Ǒ', + 'ǔ' => 'Ǔ', + 'ǖ' => 'Ǖ', + 'ǘ' => 'Ǘ', + 'ǚ' => 'Ǚ', + 'ǜ' => 'Ǜ', + 'ǝ' => 'Ǝ', + 'ǟ' => 'Ǟ', + 'ǡ' => 'Ǡ', + 'ǣ' => 'Ǣ', + 'ǥ' => 'Ǥ', + 'ǧ' => 'Ǧ', + 'ǩ' => 'Ǩ', + 'ǫ' => 'Ǫ', + 'ǭ' => 'Ǭ', + 'ǯ' => 'Ǯ', + 'Dz' => 'DZ', + 'dz' => 'DZ', + 'ǵ' => 'Ǵ', + 'ǹ' => 'Ǹ', + 'ǻ' => 'Ǻ', + 'ǽ' => 'Ǽ', + 'ǿ' => 'Ǿ', + 'ȁ' => 'Ȁ', + 'ȃ' => 'Ȃ', + 'ȅ' => 'Ȅ', + 'ȇ' => 'Ȇ', + 'ȉ' => 'Ȉ', + 'ȋ' => 'Ȋ', + 'ȍ' => 'Ȍ', + 'ȏ' => 'Ȏ', + 'ȑ' => 'Ȑ', + 'ȓ' => 'Ȓ', + 'ȕ' => 'Ȕ', + 'ȗ' => 'Ȗ', + 'ș' => 'Ș', + 'ț' => 'Ț', + 'ȝ' => 'Ȝ', + 'ȟ' => 'Ȟ', + 'ȣ' => 'Ȣ', + 'ȥ' => 'Ȥ', + 'ȧ' => 'Ȧ', + 'ȩ' => 'Ȩ', + 'ȫ' => 'Ȫ', + 'ȭ' => 'Ȭ', + 'ȯ' => 'Ȯ', + 'ȱ' => 'Ȱ', + 'ȳ' => 'Ȳ', + 'ȼ' => 'Ȼ', + 'ȿ' => 'Ȿ', + 'ɀ' => 'Ɀ', + 'ɂ' => 'Ɂ', + 'ɇ' => 'Ɇ', + 'ɉ' => 'Ɉ', + 'ɋ' => 'Ɋ', + 'ɍ' => 'Ɍ', + 'ɏ' => 'Ɏ', + 'ɐ' => 'Ɐ', + 'ɑ' => 'Ɑ', + 'ɒ' => 'Ɒ', + 'ɓ' => 'Ɓ', + 'ɔ' => 'Ɔ', + 'ɖ' => 'Ɖ', + 'ɗ' => 'Ɗ', + 'ə' => 'Ə', + 'ɛ' => 'Ɛ', + 'ɜ' => 'Ɜ', + 'ɠ' => 'Ɠ', + 'ɡ' => 'Ɡ', + 'ɣ' => 'Ɣ', + 'ɥ' => 'Ɥ', + 'ɦ' => 'Ɦ', + 'ɨ' => 'Ɨ', + 'ɩ' => 'Ɩ', + 'ɪ' => 'Ɪ', + 'ɫ' => 'Ɫ', + 'ɬ' => 'Ɬ', + 'ɯ' => 'Ɯ', + 'ɱ' => 'Ɱ', + 'ɲ' => 'Ɲ', + 'ɵ' => 'Ɵ', + 'ɽ' => 'Ɽ', + 'ʀ' => 'Ʀ', + 'ʂ' => 'Ʂ', + 'ʃ' => 'Ʃ', + 'ʇ' => 'Ʇ', + 'ʈ' => 'Ʈ', + 'ʉ' => 'Ʉ', + 'ʊ' => 'Ʊ', + 'ʋ' => 'Ʋ', + 'ʌ' => 'Ʌ', + 'ʒ' => 'Ʒ', + 'ʝ' => 'Ʝ', + 'ʞ' => 'Ʞ', + 'ͅ' => 'Ι', + 'ͱ' => 'Ͱ', + 'ͳ' => 'Ͳ', + 'ͷ' => 'Ͷ', + 'ͻ' => 'Ͻ', + 'ͼ' => 'Ͼ', + 'ͽ' => 'Ͽ', + 'ά' => 'Ά', + 'έ' => 'Έ', + 'ή' => 'Ή', + 'ί' => 'Ί', + 'α' => 'Α', + 'β' => 'Β', + 'γ' => 'Γ', + 'δ' => 'Δ', + 'ε' => 'Ε', + 'ζ' => 'Ζ', + 'η' => 'Η', + 'θ' => 'Θ', + 'ι' => 'Ι', + 'κ' => 'Κ', + 'λ' => 'Λ', + 'μ' => 'Μ', + 'ν' => 'Ν', + 'ξ' => 'Ξ', + 'ο' => 'Ο', + 'π' => 'Π', + 'ρ' => 'Ρ', + 'ς' => 'Σ', + 'σ' => 'Σ', + 'τ' => 'Τ', + 'υ' => 'Υ', + 'φ' => 'Φ', + 'χ' => 'Χ', + 'ψ' => 'Ψ', + 'ω' => 'Ω', + 'ϊ' => 'Ϊ', + 'ϋ' => 'Ϋ', + 'ό' => 'Ό', + 'ύ' => 'Ύ', + 'ώ' => 'Ώ', + 'ϐ' => 'Β', + 'ϑ' => 'Θ', + 'ϕ' => 'Φ', + 'ϖ' => 'Π', + 'ϗ' => 'Ϗ', + 'ϙ' => 'Ϙ', + 'ϛ' => 'Ϛ', + 'ϝ' => 'Ϝ', + 'ϟ' => 'Ϟ', + 'ϡ' => 'Ϡ', + 'ϣ' => 'Ϣ', + 'ϥ' => 'Ϥ', + 'ϧ' => 'Ϧ', + 'ϩ' => 'Ϩ', + 'ϫ' => 'Ϫ', + 'ϭ' => 'Ϭ', + 'ϯ' => 'Ϯ', + 'ϰ' => 'Κ', + 'ϱ' => 'Ρ', + 'ϲ' => 'Ϲ', + 'ϳ' => 'Ϳ', + 'ϵ' => 'Ε', + 'ϸ' => 'Ϸ', + 'ϻ' => 'Ϻ', + 'а' => 'А', + 'б' => 'Б', + 'в' => 'В', + 'г' => 'Г', + 'д' => 'Д', + 'е' => 'Е', + 'ж' => 'Ж', + 'з' => 'З', + 'и' => 'И', + 'й' => 'Й', + 'к' => 'К', + 'л' => 'Л', + 'м' => 'М', + 'н' => 'Н', + 'о' => 'О', + 'п' => 'П', + 'р' => 'Р', + 'с' => 'С', + 'т' => 'Т', + 'у' => 'У', + 'ф' => 'Ф', + 'х' => 'Х', + 'ц' => 'Ц', + 'ч' => 'Ч', + 'ш' => 'Ш', + 'щ' => 'Щ', + 'ъ' => 'Ъ', + 'ы' => 'Ы', + 'ь' => 'Ь', + 'э' => 'Э', + 'ю' => 'Ю', + 'я' => 'Я', + 'ѐ' => 'Ѐ', + 'ё' => 'Ё', + 'ђ' => 'Ђ', + 'ѓ' => 'Ѓ', + 'є' => 'Є', + 'ѕ' => 'Ѕ', + 'і' => 'І', + 'ї' => 'Ї', + 'ј' => 'Ј', + 'љ' => 'Љ', + 'њ' => 'Њ', + 'ћ' => 'Ћ', + 'ќ' => 'Ќ', + 'ѝ' => 'Ѝ', + 'ў' => 'Ў', + 'џ' => 'Џ', + 'ѡ' => 'Ѡ', + 'ѣ' => 'Ѣ', + 'ѥ' => 'Ѥ', + 'ѧ' => 'Ѧ', + 'ѩ' => 'Ѩ', + 'ѫ' => 'Ѫ', + 'ѭ' => 'Ѭ', + 'ѯ' => 'Ѯ', + 'ѱ' => 'Ѱ', + 'ѳ' => 'Ѳ', + 'ѵ' => 'Ѵ', + 'ѷ' => 'Ѷ', + 'ѹ' => 'Ѹ', + 'ѻ' => 'Ѻ', + 'ѽ' => 'Ѽ', + 'ѿ' => 'Ѿ', + 'ҁ' => 'Ҁ', + 'ҋ' => 'Ҋ', + 'ҍ' => 'Ҍ', + 'ҏ' => 'Ҏ', + 'ґ' => 'Ґ', + 'ғ' => 'Ғ', + 'ҕ' => 'Ҕ', + 'җ' => 'Җ', + 'ҙ' => 'Ҙ', + 'қ' => 'Қ', + 'ҝ' => 'Ҝ', + 'ҟ' => 'Ҟ', + 'ҡ' => 'Ҡ', + 'ң' => 'Ң', + 'ҥ' => 'Ҥ', + 'ҧ' => 'Ҧ', + 'ҩ' => 'Ҩ', + 'ҫ' => 'Ҫ', + 'ҭ' => 'Ҭ', + 'ү' => 'Ү', + 'ұ' => 'Ұ', + 'ҳ' => 'Ҳ', + 'ҵ' => 'Ҵ', + 'ҷ' => 'Ҷ', + 'ҹ' => 'Ҹ', + 'һ' => 'Һ', + 'ҽ' => 'Ҽ', + 'ҿ' => 'Ҿ', + 'ӂ' => 'Ӂ', + 'ӄ' => 'Ӄ', + 'ӆ' => 'Ӆ', + 'ӈ' => 'Ӈ', + 'ӊ' => 'Ӊ', + 'ӌ' => 'Ӌ', + 'ӎ' => 'Ӎ', + 'ӏ' => 'Ӏ', + 'ӑ' => 'Ӑ', + 'ӓ' => 'Ӓ', + 'ӕ' => 'Ӕ', + 'ӗ' => 'Ӗ', + 'ә' => 'Ә', + 'ӛ' => 'Ӛ', + 'ӝ' => 'Ӝ', + 'ӟ' => 'Ӟ', + 'ӡ' => 'Ӡ', + 'ӣ' => 'Ӣ', + 'ӥ' => 'Ӥ', + 'ӧ' => 'Ӧ', + 'ө' => 'Ө', + 'ӫ' => 'Ӫ', + 'ӭ' => 'Ӭ', + 'ӯ' => 'Ӯ', + 'ӱ' => 'Ӱ', + 'ӳ' => 'Ӳ', + 'ӵ' => 'Ӵ', + 'ӷ' => 'Ӷ', + 'ӹ' => 'Ӹ', + 'ӻ' => 'Ӻ', + 'ӽ' => 'Ӽ', + 'ӿ' => 'Ӿ', + 'ԁ' => 'Ԁ', + 'ԃ' => 'Ԃ', + 'ԅ' => 'Ԅ', + 'ԇ' => 'Ԇ', + 'ԉ' => 'Ԉ', + 'ԋ' => 'Ԋ', + 'ԍ' => 'Ԍ', + 'ԏ' => 'Ԏ', + 'ԑ' => 'Ԑ', + 'ԓ' => 'Ԓ', + 'ԕ' => 'Ԕ', + 'ԗ' => 'Ԗ', + 'ԙ' => 'Ԙ', + 'ԛ' => 'Ԛ', + 'ԝ' => 'Ԝ', + 'ԟ' => 'Ԟ', + 'ԡ' => 'Ԡ', + 'ԣ' => 'Ԣ', + 'ԥ' => 'Ԥ', + 'ԧ' => 'Ԧ', + 'ԩ' => 'Ԩ', + 'ԫ' => 'Ԫ', + 'ԭ' => 'Ԭ', + 'ԯ' => 'Ԯ', + 'ա' => 'Ա', + 'բ' => 'Բ', + 'գ' => 'Գ', + 'դ' => 'Դ', + 'ե' => 'Ե', + 'զ' => 'Զ', + 'է' => 'Է', + 'ը' => 'Ը', + 'թ' => 'Թ', + 'ժ' => 'Ժ', + 'ի' => 'Ի', + 'լ' => 'Լ', + 'խ' => 'Խ', + 'ծ' => 'Ծ', + 'կ' => 'Կ', + 'հ' => 'Հ', + 'ձ' => 'Ձ', + 'ղ' => 'Ղ', + 'ճ' => 'Ճ', + 'մ' => 'Մ', + 'յ' => 'Յ', + 'ն' => 'Ն', + 'շ' => 'Շ', + 'ո' => 'Ո', + 'չ' => 'Չ', + 'պ' => 'Պ', + 'ջ' => 'Ջ', + 'ռ' => 'Ռ', + 'ս' => 'Ս', + 'վ' => 'Վ', + 'տ' => 'Տ', + 'ր' => 'Ր', + 'ց' => 'Ց', + 'ւ' => 'Ւ', + 'փ' => 'Փ', + 'ք' => 'Ք', + 'օ' => 'Օ', + 'ֆ' => 'Ֆ', + 'ა' => 'Ა', + 'ბ' => 'Ბ', + 'გ' => 'Გ', + 'დ' => 'Დ', + 'ე' => 'Ე', + 'ვ' => 'Ვ', + 'ზ' => 'Ზ', + 'თ' => 'Თ', + 'ი' => 'Ი', + 'კ' => 'Კ', + 'ლ' => 'Ლ', + 'მ' => 'Მ', + 'ნ' => 'Ნ', + 'ო' => 'Ო', + 'პ' => 'Პ', + 'ჟ' => 'Ჟ', + 'რ' => 'Რ', + 'ს' => 'Ს', + 'ტ' => 'Ტ', + 'უ' => 'Უ', + 'ფ' => 'Ფ', + 'ქ' => 'Ქ', + 'ღ' => 'Ღ', + 'ყ' => 'Ყ', + 'შ' => 'Შ', + 'ჩ' => 'Ჩ', + 'ც' => 'Ც', + 'ძ' => 'Ძ', + 'წ' => 'Წ', + 'ჭ' => 'Ჭ', + 'ხ' => 'Ხ', + 'ჯ' => 'Ჯ', + 'ჰ' => 'Ჰ', + 'ჱ' => 'Ჱ', + 'ჲ' => 'Ჲ', + 'ჳ' => 'Ჳ', + 'ჴ' => 'Ჴ', + 'ჵ' => 'Ჵ', + 'ჶ' => 'Ჶ', + 'ჷ' => 'Ჷ', + 'ჸ' => 'Ჸ', + 'ჹ' => 'Ჹ', + 'ჺ' => 'Ჺ', + 'ჽ' => 'Ჽ', + 'ჾ' => 'Ჾ', + 'ჿ' => 'Ჿ', + 'ᏸ' => 'Ᏸ', + 'ᏹ' => 'Ᏹ', + 'ᏺ' => 'Ᏺ', + 'ᏻ' => 'Ᏻ', + 'ᏼ' => 'Ᏼ', + 'ᏽ' => 'Ᏽ', + 'ᲀ' => 'В', + 'ᲁ' => 'Д', + 'ᲂ' => 'О', + 'ᲃ' => 'С', + 'ᲄ' => 'Т', + 'ᲅ' => 'Т', + 'ᲆ' => 'Ъ', + 'ᲇ' => 'Ѣ', + 'ᲈ' => 'Ꙋ', + 'ᵹ' => 'Ᵹ', + 'ᵽ' => 'Ᵽ', + 'ᶎ' => 'Ᶎ', + 'ḁ' => 'Ḁ', + 'ḃ' => 'Ḃ', + 'ḅ' => 'Ḅ', + 'ḇ' => 'Ḇ', + 'ḉ' => 'Ḉ', + 'ḋ' => 'Ḋ', + 'ḍ' => 'Ḍ', + 'ḏ' => 'Ḏ', + 'ḑ' => 'Ḑ', + 'ḓ' => 'Ḓ', + 'ḕ' => 'Ḕ', + 'ḗ' => 'Ḗ', + 'ḙ' => 'Ḙ', + 'ḛ' => 'Ḛ', + 'ḝ' => 'Ḝ', + 'ḟ' => 'Ḟ', + 'ḡ' => 'Ḡ', + 'ḣ' => 'Ḣ', + 'ḥ' => 'Ḥ', + 'ḧ' => 'Ḧ', + 'ḩ' => 'Ḩ', + 'ḫ' => 'Ḫ', + 'ḭ' => 'Ḭ', + 'ḯ' => 'Ḯ', + 'ḱ' => 'Ḱ', + 'ḳ' => 'Ḳ', + 'ḵ' => 'Ḵ', + 'ḷ' => 'Ḷ', + 'ḹ' => 'Ḹ', + 'ḻ' => 'Ḻ', + 'ḽ' => 'Ḽ', + 'ḿ' => 'Ḿ', + 'ṁ' => 'Ṁ', + 'ṃ' => 'Ṃ', + 'ṅ' => 'Ṅ', + 'ṇ' => 'Ṇ', + 'ṉ' => 'Ṉ', + 'ṋ' => 'Ṋ', + 'ṍ' => 'Ṍ', + 'ṏ' => 'Ṏ', + 'ṑ' => 'Ṑ', + 'ṓ' => 'Ṓ', + 'ṕ' => 'Ṕ', + 'ṗ' => 'Ṗ', + 'ṙ' => 'Ṙ', + 'ṛ' => 'Ṛ', + 'ṝ' => 'Ṝ', + 'ṟ' => 'Ṟ', + 'ṡ' => 'Ṡ', + 'ṣ' => 'Ṣ', + 'ṥ' => 'Ṥ', + 'ṧ' => 'Ṧ', + 'ṩ' => 'Ṩ', + 'ṫ' => 'Ṫ', + 'ṭ' => 'Ṭ', + 'ṯ' => 'Ṯ', + 'ṱ' => 'Ṱ', + 'ṳ' => 'Ṳ', + 'ṵ' => 'Ṵ', + 'ṷ' => 'Ṷ', + 'ṹ' => 'Ṹ', + 'ṻ' => 'Ṻ', + 'ṽ' => 'Ṽ', + 'ṿ' => 'Ṿ', + 'ẁ' => 'Ẁ', + 'ẃ' => 'Ẃ', + 'ẅ' => 'Ẅ', + 'ẇ' => 'Ẇ', + 'ẉ' => 'Ẉ', + 'ẋ' => 'Ẋ', + 'ẍ' => 'Ẍ', + 'ẏ' => 'Ẏ', + 'ẑ' => 'Ẑ', + 'ẓ' => 'Ẓ', + 'ẕ' => 'Ẕ', + 'ẛ' => 'Ṡ', + 'ạ' => 'Ạ', + 'ả' => 'Ả', + 'ấ' => 'Ấ', + 'ầ' => 'Ầ', + 'ẩ' => 'Ẩ', + 'ẫ' => 'Ẫ', + 'ậ' => 'Ậ', + 'ắ' => 'Ắ', + 'ằ' => 'Ằ', + 'ẳ' => 'Ẳ', + 'ẵ' => 'Ẵ', + 'ặ' => 'Ặ', + 'ẹ' => 'Ẹ', + 'ẻ' => 'Ẻ', + 'ẽ' => 'Ẽ', + 'ế' => 'Ế', + 'ề' => 'Ề', + 'ể' => 'Ể', + 'ễ' => 'Ễ', + 'ệ' => 'Ệ', + 'ỉ' => 'Ỉ', + 'ị' => 'Ị', + 'ọ' => 'Ọ', + 'ỏ' => 'Ỏ', + 'ố' => 'Ố', + 'ồ' => 'Ồ', + 'ổ' => 'Ổ', + 'ỗ' => 'Ỗ', + 'ộ' => 'Ộ', + 'ớ' => 'Ớ', + 'ờ' => 'Ờ', + 'ở' => 'Ở', + 'ỡ' => 'Ỡ', + 'ợ' => 'Ợ', + 'ụ' => 'Ụ', + 'ủ' => 'Ủ', + 'ứ' => 'Ứ', + 'ừ' => 'Ừ', + 'ử' => 'Ử', + 'ữ' => 'Ữ', + 'ự' => 'Ự', + 'ỳ' => 'Ỳ', + 'ỵ' => 'Ỵ', + 'ỷ' => 'Ỷ', + 'ỹ' => 'Ỹ', + 'ỻ' => 'Ỻ', + 'ỽ' => 'Ỽ', + 'ỿ' => 'Ỿ', + 'ἀ' => 'Ἀ', + 'ἁ' => 'Ἁ', + 'ἂ' => 'Ἂ', + 'ἃ' => 'Ἃ', + 'ἄ' => 'Ἄ', + 'ἅ' => 'Ἅ', + 'ἆ' => 'Ἆ', + 'ἇ' => 'Ἇ', + 'ἐ' => 'Ἐ', + 'ἑ' => 'Ἑ', + 'ἒ' => 'Ἒ', + 'ἓ' => 'Ἓ', + 'ἔ' => 'Ἔ', + 'ἕ' => 'Ἕ', + 'ἠ' => 'Ἠ', + 'ἡ' => 'Ἡ', + 'ἢ' => 'Ἢ', + 'ἣ' => 'Ἣ', + 'ἤ' => 'Ἤ', + 'ἥ' => 'Ἥ', + 'ἦ' => 'Ἦ', + 'ἧ' => 'Ἧ', + 'ἰ' => 'Ἰ', + 'ἱ' => 'Ἱ', + 'ἲ' => 'Ἲ', + 'ἳ' => 'Ἳ', + 'ἴ' => 'Ἴ', + 'ἵ' => 'Ἵ', + 'ἶ' => 'Ἶ', + 'ἷ' => 'Ἷ', + 'ὀ' => 'Ὀ', + 'ὁ' => 'Ὁ', + 'ὂ' => 'Ὂ', + 'ὃ' => 'Ὃ', + 'ὄ' => 'Ὄ', + 'ὅ' => 'Ὅ', + 'ὑ' => 'Ὑ', + 'ὓ' => 'Ὓ', + 'ὕ' => 'Ὕ', + 'ὗ' => 'Ὗ', + 'ὠ' => 'Ὠ', + 'ὡ' => 'Ὡ', + 'ὢ' => 'Ὢ', + 'ὣ' => 'Ὣ', + 'ὤ' => 'Ὤ', + 'ὥ' => 'Ὥ', + 'ὦ' => 'Ὦ', + 'ὧ' => 'Ὧ', + 'ὰ' => 'Ὰ', + 'ά' => 'Ά', + 'ὲ' => 'Ὲ', + 'έ' => 'Έ', + 'ὴ' => 'Ὴ', + 'ή' => 'Ή', + 'ὶ' => 'Ὶ', + 'ί' => 'Ί', + 'ὸ' => 'Ὸ', + 'ό' => 'Ό', + 'ὺ' => 'Ὺ', + 'ύ' => 'Ύ', + 'ὼ' => 'Ὼ', + 'ώ' => 'Ώ', + 'ᾀ' => 'ἈΙ', + 'ᾁ' => 'ἉΙ', + 'ᾂ' => 'ἊΙ', + 'ᾃ' => 'ἋΙ', + 'ᾄ' => 'ἌΙ', + 'ᾅ' => 'ἍΙ', + 'ᾆ' => 'ἎΙ', + 'ᾇ' => 'ἏΙ', + 'ᾐ' => 'ἨΙ', + 'ᾑ' => 'ἩΙ', + 'ᾒ' => 'ἪΙ', + 'ᾓ' => 'ἫΙ', + 'ᾔ' => 'ἬΙ', + 'ᾕ' => 'ἭΙ', + 'ᾖ' => 'ἮΙ', + 'ᾗ' => 'ἯΙ', + 'ᾠ' => 'ὨΙ', + 'ᾡ' => 'ὩΙ', + 'ᾢ' => 'ὪΙ', + 'ᾣ' => 'ὫΙ', + 'ᾤ' => 'ὬΙ', + 'ᾥ' => 'ὭΙ', + 'ᾦ' => 'ὮΙ', + 'ᾧ' => 'ὯΙ', + 'ᾰ' => 'Ᾰ', + 'ᾱ' => 'Ᾱ', + 'ᾳ' => 'ΑΙ', + 'ι' => 'Ι', + 'ῃ' => 'ΗΙ', + 'ῐ' => 'Ῐ', + 'ῑ' => 'Ῑ', + 'ῠ' => 'Ῠ', + 'ῡ' => 'Ῡ', + 'ῥ' => 'Ῥ', + 'ῳ' => 'ΩΙ', + 'ⅎ' => 'Ⅎ', + 'ⅰ' => 'Ⅰ', + 'ⅱ' => 'Ⅱ', + 'ⅲ' => 'Ⅲ', + 'ⅳ' => 'Ⅳ', + 'ⅴ' => 'Ⅴ', + 'ⅵ' => 'Ⅵ', + 'ⅶ' => 'Ⅶ', + 'ⅷ' => 'Ⅷ', + 'ⅸ' => 'Ⅸ', + 'ⅹ' => 'Ⅹ', + 'ⅺ' => 'Ⅺ', + 'ⅻ' => 'Ⅻ', + 'ⅼ' => 'Ⅼ', + 'ⅽ' => 'Ⅽ', + 'ⅾ' => 'Ⅾ', + 'ⅿ' => 'Ⅿ', + 'ↄ' => 'Ↄ', + 'ⓐ' => 'Ⓐ', + 'ⓑ' => 'Ⓑ', + 'ⓒ' => 'Ⓒ', + 'ⓓ' => 'Ⓓ', + 'ⓔ' => 'Ⓔ', + 'ⓕ' => 'Ⓕ', + 'ⓖ' => 'Ⓖ', + 'ⓗ' => 'Ⓗ', + 'ⓘ' => 'Ⓘ', + 'ⓙ' => 'Ⓙ', + 'ⓚ' => 'Ⓚ', + 'ⓛ' => 'Ⓛ', + 'ⓜ' => 'Ⓜ', + 'ⓝ' => 'Ⓝ', + 'ⓞ' => 'Ⓞ', + 'ⓟ' => 'Ⓟ', + 'ⓠ' => 'Ⓠ', + 'ⓡ' => 'Ⓡ', + 'ⓢ' => 'Ⓢ', + 'ⓣ' => 'Ⓣ', + 'ⓤ' => 'Ⓤ', + 'ⓥ' => 'Ⓥ', + 'ⓦ' => 'Ⓦ', + 'ⓧ' => 'Ⓧ', + 'ⓨ' => 'Ⓨ', + 'ⓩ' => 'Ⓩ', + 'ⰰ' => 'Ⰰ', + 'ⰱ' => 'Ⰱ', + 'ⰲ' => 'Ⰲ', + 'ⰳ' => 'Ⰳ', + 'ⰴ' => 'Ⰴ', + 'ⰵ' => 'Ⰵ', + 'ⰶ' => 'Ⰶ', + 'ⰷ' => 'Ⰷ', + 'ⰸ' => 'Ⰸ', + 'ⰹ' => 'Ⰹ', + 'ⰺ' => 'Ⰺ', + 'ⰻ' => 'Ⰻ', + 'ⰼ' => 'Ⰼ', + 'ⰽ' => 'Ⰽ', + 'ⰾ' => 'Ⰾ', + 'ⰿ' => 'Ⰿ', + 'ⱀ' => 'Ⱀ', + 'ⱁ' => 'Ⱁ', + 'ⱂ' => 'Ⱂ', + 'ⱃ' => 'Ⱃ', + 'ⱄ' => 'Ⱄ', + 'ⱅ' => 'Ⱅ', + 'ⱆ' => 'Ⱆ', + 'ⱇ' => 'Ⱇ', + 'ⱈ' => 'Ⱈ', + 'ⱉ' => 'Ⱉ', + 'ⱊ' => 'Ⱊ', + 'ⱋ' => 'Ⱋ', + 'ⱌ' => 'Ⱌ', + 'ⱍ' => 'Ⱍ', + 'ⱎ' => 'Ⱎ', + 'ⱏ' => 'Ⱏ', + 'ⱐ' => 'Ⱐ', + 'ⱑ' => 'Ⱑ', + 'ⱒ' => 'Ⱒ', + 'ⱓ' => 'Ⱓ', + 'ⱔ' => 'Ⱔ', + 'ⱕ' => 'Ⱕ', + 'ⱖ' => 'Ⱖ', + 'ⱗ' => 'Ⱗ', + 'ⱘ' => 'Ⱘ', + 'ⱙ' => 'Ⱙ', + 'ⱚ' => 'Ⱚ', + 'ⱛ' => 'Ⱛ', + 'ⱜ' => 'Ⱜ', + 'ⱝ' => 'Ⱝ', + 'ⱞ' => 'Ⱞ', + 'ⱡ' => 'Ⱡ', + 'ⱥ' => 'Ⱥ', + 'ⱦ' => 'Ⱦ', + 'ⱨ' => 'Ⱨ', + 'ⱪ' => 'Ⱪ', + 'ⱬ' => 'Ⱬ', + 'ⱳ' => 'Ⱳ', + 'ⱶ' => 'Ⱶ', + 'ⲁ' => 'Ⲁ', + 'ⲃ' => 'Ⲃ', + 'ⲅ' => 'Ⲅ', + 'ⲇ' => 'Ⲇ', + 'ⲉ' => 'Ⲉ', + 'ⲋ' => 'Ⲋ', + 'ⲍ' => 'Ⲍ', + 'ⲏ' => 'Ⲏ', + 'ⲑ' => 'Ⲑ', + 'ⲓ' => 'Ⲓ', + 'ⲕ' => 'Ⲕ', + 'ⲗ' => 'Ⲗ', + 'ⲙ' => 'Ⲙ', + 'ⲛ' => 'Ⲛ', + 'ⲝ' => 'Ⲝ', + 'ⲟ' => 'Ⲟ', + 'ⲡ' => 'Ⲡ', + 'ⲣ' => 'Ⲣ', + 'ⲥ' => 'Ⲥ', + 'ⲧ' => 'Ⲧ', + 'ⲩ' => 'Ⲩ', + 'ⲫ' => 'Ⲫ', + 'ⲭ' => 'Ⲭ', + 'ⲯ' => 'Ⲯ', + 'ⲱ' => 'Ⲱ', + 'ⲳ' => 'Ⲳ', + 'ⲵ' => 'Ⲵ', + 'ⲷ' => 'Ⲷ', + 'ⲹ' => 'Ⲹ', + 'ⲻ' => 'Ⲻ', + 'ⲽ' => 'Ⲽ', + 'ⲿ' => 'Ⲿ', + 'ⳁ' => 'Ⳁ', + 'ⳃ' => 'Ⳃ', + 'ⳅ' => 'Ⳅ', + 'ⳇ' => 'Ⳇ', + 'ⳉ' => 'Ⳉ', + 'ⳋ' => 'Ⳋ', + 'ⳍ' => 'Ⳍ', + 'ⳏ' => 'Ⳏ', + 'ⳑ' => 'Ⳑ', + 'ⳓ' => 'Ⳓ', + 'ⳕ' => 'Ⳕ', + 'ⳗ' => 'Ⳗ', + 'ⳙ' => 'Ⳙ', + 'ⳛ' => 'Ⳛ', + 'ⳝ' => 'Ⳝ', + 'ⳟ' => 'Ⳟ', + 'ⳡ' => 'Ⳡ', + 'ⳣ' => 'Ⳣ', + 'ⳬ' => 'Ⳬ', + 'ⳮ' => 'Ⳮ', + 'ⳳ' => 'Ⳳ', + 'ⴀ' => 'Ⴀ', + 'ⴁ' => 'Ⴁ', + 'ⴂ' => 'Ⴂ', + 'ⴃ' => 'Ⴃ', + 'ⴄ' => 'Ⴄ', + 'ⴅ' => 'Ⴅ', + 'ⴆ' => 'Ⴆ', + 'ⴇ' => 'Ⴇ', + 'ⴈ' => 'Ⴈ', + 'ⴉ' => 'Ⴉ', + 'ⴊ' => 'Ⴊ', + 'ⴋ' => 'Ⴋ', + 'ⴌ' => 'Ⴌ', + 'ⴍ' => 'Ⴍ', + 'ⴎ' => 'Ⴎ', + 'ⴏ' => 'Ⴏ', + 'ⴐ' => 'Ⴐ', + 'ⴑ' => 'Ⴑ', + 'ⴒ' => 'Ⴒ', + 'ⴓ' => 'Ⴓ', + 'ⴔ' => 'Ⴔ', + 'ⴕ' => 'Ⴕ', + 'ⴖ' => 'Ⴖ', + 'ⴗ' => 'Ⴗ', + 'ⴘ' => 'Ⴘ', + 'ⴙ' => 'Ⴙ', + 'ⴚ' => 'Ⴚ', + 'ⴛ' => 'Ⴛ', + 'ⴜ' => 'Ⴜ', + 'ⴝ' => 'Ⴝ', + 'ⴞ' => 'Ⴞ', + 'ⴟ' => 'Ⴟ', + 'ⴠ' => 'Ⴠ', + 'ⴡ' => 'Ⴡ', + 'ⴢ' => 'Ⴢ', + 'ⴣ' => 'Ⴣ', + 'ⴤ' => 'Ⴤ', + 'ⴥ' => 'Ⴥ', + 'ⴧ' => 'Ⴧ', + 'ⴭ' => 'Ⴭ', + 'ꙁ' => 'Ꙁ', + 'ꙃ' => 'Ꙃ', + 'ꙅ' => 'Ꙅ', + 'ꙇ' => 'Ꙇ', + 'ꙉ' => 'Ꙉ', + 'ꙋ' => 'Ꙋ', + 'ꙍ' => 'Ꙍ', + 'ꙏ' => 'Ꙏ', + 'ꙑ' => 'Ꙑ', + 'ꙓ' => 'Ꙓ', + 'ꙕ' => 'Ꙕ', + 'ꙗ' => 'Ꙗ', + 'ꙙ' => 'Ꙙ', + 'ꙛ' => 'Ꙛ', + 'ꙝ' => 'Ꙝ', + 'ꙟ' => 'Ꙟ', + 'ꙡ' => 'Ꙡ', + 'ꙣ' => 'Ꙣ', + 'ꙥ' => 'Ꙥ', + 'ꙧ' => 'Ꙧ', + 'ꙩ' => 'Ꙩ', + 'ꙫ' => 'Ꙫ', + 'ꙭ' => 'Ꙭ', + 'ꚁ' => 'Ꚁ', + 'ꚃ' => 'Ꚃ', + 'ꚅ' => 'Ꚅ', + 'ꚇ' => 'Ꚇ', + 'ꚉ' => 'Ꚉ', + 'ꚋ' => 'Ꚋ', + 'ꚍ' => 'Ꚍ', + 'ꚏ' => 'Ꚏ', + 'ꚑ' => 'Ꚑ', + 'ꚓ' => 'Ꚓ', + 'ꚕ' => 'Ꚕ', + 'ꚗ' => 'Ꚗ', + 'ꚙ' => 'Ꚙ', + 'ꚛ' => 'Ꚛ', + 'ꜣ' => 'Ꜣ', + 'ꜥ' => 'Ꜥ', + 'ꜧ' => 'Ꜧ', + 'ꜩ' => 'Ꜩ', + 'ꜫ' => 'Ꜫ', + 'ꜭ' => 'Ꜭ', + 'ꜯ' => 'Ꜯ', + 'ꜳ' => 'Ꜳ', + 'ꜵ' => 'Ꜵ', + 'ꜷ' => 'Ꜷ', + 'ꜹ' => 'Ꜹ', + 'ꜻ' => 'Ꜻ', + 'ꜽ' => 'Ꜽ', + 'ꜿ' => 'Ꜿ', + 'ꝁ' => 'Ꝁ', + 'ꝃ' => 'Ꝃ', + 'ꝅ' => 'Ꝅ', + 'ꝇ' => 'Ꝇ', + 'ꝉ' => 'Ꝉ', + 'ꝋ' => 'Ꝋ', + 'ꝍ' => 'Ꝍ', + 'ꝏ' => 'Ꝏ', + 'ꝑ' => 'Ꝑ', + 'ꝓ' => 'Ꝓ', + 'ꝕ' => 'Ꝕ', + 'ꝗ' => 'Ꝗ', + 'ꝙ' => 'Ꝙ', + 'ꝛ' => 'Ꝛ', + 'ꝝ' => 'Ꝝ', + 'ꝟ' => 'Ꝟ', + 'ꝡ' => 'Ꝡ', + 'ꝣ' => 'Ꝣ', + 'ꝥ' => 'Ꝥ', + 'ꝧ' => 'Ꝧ', + 'ꝩ' => 'Ꝩ', + 'ꝫ' => 'Ꝫ', + 'ꝭ' => 'Ꝭ', + 'ꝯ' => 'Ꝯ', + 'ꝺ' => 'Ꝺ', + 'ꝼ' => 'Ꝼ', + 'ꝿ' => 'Ꝿ', + 'ꞁ' => 'Ꞁ', + 'ꞃ' => 'Ꞃ', + 'ꞅ' => 'Ꞅ', + 'ꞇ' => 'Ꞇ', + 'ꞌ' => 'Ꞌ', + 'ꞑ' => 'Ꞑ', + 'ꞓ' => 'Ꞓ', + 'ꞔ' => 'Ꞔ', + 'ꞗ' => 'Ꞗ', + 'ꞙ' => 'Ꞙ', + 'ꞛ' => 'Ꞛ', + 'ꞝ' => 'Ꞝ', + 'ꞟ' => 'Ꞟ', + 'ꞡ' => 'Ꞡ', + 'ꞣ' => 'Ꞣ', + 'ꞥ' => 'Ꞥ', + 'ꞧ' => 'Ꞧ', + 'ꞩ' => 'Ꞩ', + 'ꞵ' => 'Ꞵ', + 'ꞷ' => 'Ꞷ', + 'ꞹ' => 'Ꞹ', + 'ꞻ' => 'Ꞻ', + 'ꞽ' => 'Ꞽ', + 'ꞿ' => 'Ꞿ', + 'ꟃ' => 'Ꟃ', + 'ꟈ' => 'Ꟈ', + 'ꟊ' => 'Ꟊ', + 'ꟶ' => 'Ꟶ', + 'ꭓ' => 'Ꭓ', + 'ꭰ' => 'Ꭰ', + 'ꭱ' => 'Ꭱ', + 'ꭲ' => 'Ꭲ', + 'ꭳ' => 'Ꭳ', + 'ꭴ' => 'Ꭴ', + 'ꭵ' => 'Ꭵ', + 'ꭶ' => 'Ꭶ', + 'ꭷ' => 'Ꭷ', + 'ꭸ' => 'Ꭸ', + 'ꭹ' => 'Ꭹ', + 'ꭺ' => 'Ꭺ', + 'ꭻ' => 'Ꭻ', + 'ꭼ' => 'Ꭼ', + 'ꭽ' => 'Ꭽ', + 'ꭾ' => 'Ꭾ', + 'ꭿ' => 'Ꭿ', + 'ꮀ' => 'Ꮀ', + 'ꮁ' => 'Ꮁ', + 'ꮂ' => 'Ꮂ', + 'ꮃ' => 'Ꮃ', + 'ꮄ' => 'Ꮄ', + 'ꮅ' => 'Ꮅ', + 'ꮆ' => 'Ꮆ', + 'ꮇ' => 'Ꮇ', + 'ꮈ' => 'Ꮈ', + 'ꮉ' => 'Ꮉ', + 'ꮊ' => 'Ꮊ', + 'ꮋ' => 'Ꮋ', + 'ꮌ' => 'Ꮌ', + 'ꮍ' => 'Ꮍ', + 'ꮎ' => 'Ꮎ', + 'ꮏ' => 'Ꮏ', + 'ꮐ' => 'Ꮐ', + 'ꮑ' => 'Ꮑ', + 'ꮒ' => 'Ꮒ', + 'ꮓ' => 'Ꮓ', + 'ꮔ' => 'Ꮔ', + 'ꮕ' => 'Ꮕ', + 'ꮖ' => 'Ꮖ', + 'ꮗ' => 'Ꮗ', + 'ꮘ' => 'Ꮘ', + 'ꮙ' => 'Ꮙ', + 'ꮚ' => 'Ꮚ', + 'ꮛ' => 'Ꮛ', + 'ꮜ' => 'Ꮜ', + 'ꮝ' => 'Ꮝ', + 'ꮞ' => 'Ꮞ', + 'ꮟ' => 'Ꮟ', + 'ꮠ' => 'Ꮠ', + 'ꮡ' => 'Ꮡ', + 'ꮢ' => 'Ꮢ', + 'ꮣ' => 'Ꮣ', + 'ꮤ' => 'Ꮤ', + 'ꮥ' => 'Ꮥ', + 'ꮦ' => 'Ꮦ', + 'ꮧ' => 'Ꮧ', + 'ꮨ' => 'Ꮨ', + 'ꮩ' => 'Ꮩ', + 'ꮪ' => 'Ꮪ', + 'ꮫ' => 'Ꮫ', + 'ꮬ' => 'Ꮬ', + 'ꮭ' => 'Ꮭ', + 'ꮮ' => 'Ꮮ', + 'ꮯ' => 'Ꮯ', + 'ꮰ' => 'Ꮰ', + 'ꮱ' => 'Ꮱ', + 'ꮲ' => 'Ꮲ', + 'ꮳ' => 'Ꮳ', + 'ꮴ' => 'Ꮴ', + 'ꮵ' => 'Ꮵ', + 'ꮶ' => 'Ꮶ', + 'ꮷ' => 'Ꮷ', + 'ꮸ' => 'Ꮸ', + 'ꮹ' => 'Ꮹ', + 'ꮺ' => 'Ꮺ', + 'ꮻ' => 'Ꮻ', + 'ꮼ' => 'Ꮼ', + 'ꮽ' => 'Ꮽ', + 'ꮾ' => 'Ꮾ', + 'ꮿ' => 'Ꮿ', + 'a' => 'A', + 'b' => 'B', + 'c' => 'C', + 'd' => 'D', + 'e' => 'E', + 'f' => 'F', + 'g' => 'G', + 'h' => 'H', + 'i' => 'I', + 'j' => 'J', + 'k' => 'K', + 'l' => 'L', + 'm' => 'M', + 'n' => 'N', + 'o' => 'O', + 'p' => 'P', + 'q' => 'Q', + 'r' => 'R', + 's' => 'S', + 't' => 'T', + 'u' => 'U', + 'v' => 'V', + 'w' => 'W', + 'x' => 'X', + 'y' => 'Y', + 'z' => 'Z', + '𐐨' => '𐐀', + '𐐩' => '𐐁', + '𐐪' => '𐐂', + '𐐫' => '𐐃', + '𐐬' => '𐐄', + '𐐭' => '𐐅', + '𐐮' => '𐐆', + '𐐯' => '𐐇', + '𐐰' => '𐐈', + '𐐱' => '𐐉', + '𐐲' => '𐐊', + '𐐳' => '𐐋', + '𐐴' => '𐐌', + '𐐵' => '𐐍', + '𐐶' => '𐐎', + '𐐷' => '𐐏', + '𐐸' => '𐐐', + '𐐹' => '𐐑', + '𐐺' => '𐐒', + '𐐻' => '𐐓', + '𐐼' => '𐐔', + '𐐽' => '𐐕', + '𐐾' => '𐐖', + '𐐿' => '𐐗', + '𐑀' => '𐐘', + '𐑁' => '𐐙', + '𐑂' => '𐐚', + '𐑃' => '𐐛', + '𐑄' => '𐐜', + '𐑅' => '𐐝', + '𐑆' => '𐐞', + '𐑇' => '𐐟', + '𐑈' => '𐐠', + '𐑉' => '𐐡', + '𐑊' => '𐐢', + '𐑋' => '𐐣', + '𐑌' => '𐐤', + '𐑍' => '𐐥', + '𐑎' => '𐐦', + '𐑏' => '𐐧', + '𐓘' => '𐒰', + '𐓙' => '𐒱', + '𐓚' => '𐒲', + '𐓛' => '𐒳', + '𐓜' => '𐒴', + '𐓝' => '𐒵', + '𐓞' => '𐒶', + '𐓟' => '𐒷', + '𐓠' => '𐒸', + '𐓡' => '𐒹', + '𐓢' => '𐒺', + '𐓣' => '𐒻', + '𐓤' => '𐒼', + '𐓥' => '𐒽', + '𐓦' => '𐒾', + '𐓧' => '𐒿', + '𐓨' => '𐓀', + '𐓩' => '𐓁', + '𐓪' => '𐓂', + '𐓫' => '𐓃', + '𐓬' => '𐓄', + '𐓭' => '𐓅', + '𐓮' => '𐓆', + '𐓯' => '𐓇', + '𐓰' => '𐓈', + '𐓱' => '𐓉', + '𐓲' => '𐓊', + '𐓳' => '𐓋', + '𐓴' => '𐓌', + '𐓵' => '𐓍', + '𐓶' => '𐓎', + '𐓷' => '𐓏', + '𐓸' => '𐓐', + '𐓹' => '𐓑', + '𐓺' => '𐓒', + '𐓻' => '𐓓', + '𐳀' => '𐲀', + '𐳁' => '𐲁', + '𐳂' => '𐲂', + '𐳃' => '𐲃', + '𐳄' => '𐲄', + '𐳅' => '𐲅', + '𐳆' => '𐲆', + '𐳇' => '𐲇', + '𐳈' => '𐲈', + '𐳉' => '𐲉', + '𐳊' => '𐲊', + '𐳋' => '𐲋', + '𐳌' => '𐲌', + '𐳍' => '𐲍', + '𐳎' => '𐲎', + '𐳏' => '𐲏', + '𐳐' => '𐲐', + '𐳑' => '𐲑', + '𐳒' => '𐲒', + '𐳓' => '𐲓', + '𐳔' => '𐲔', + '𐳕' => '𐲕', + '𐳖' => '𐲖', + '𐳗' => '𐲗', + '𐳘' => '𐲘', + '𐳙' => '𐲙', + '𐳚' => '𐲚', + '𐳛' => '𐲛', + '𐳜' => '𐲜', + '𐳝' => '𐲝', + '𐳞' => '𐲞', + '𐳟' => '𐲟', + '𐳠' => '𐲠', + '𐳡' => '𐲡', + '𐳢' => '𐲢', + '𐳣' => '𐲣', + '𐳤' => '𐲤', + '𐳥' => '𐲥', + '𐳦' => '𐲦', + '𐳧' => '𐲧', + '𐳨' => '𐲨', + '𐳩' => '𐲩', + '𐳪' => '𐲪', + '𐳫' => '𐲫', + '𐳬' => '𐲬', + '𐳭' => '𐲭', + '𐳮' => '𐲮', + '𐳯' => '𐲯', + '𐳰' => '𐲰', + '𐳱' => '𐲱', + '𐳲' => '𐲲', + '𑣀' => '𑢠', + '𑣁' => '𑢡', + '𑣂' => '𑢢', + '𑣃' => '𑢣', + '𑣄' => '𑢤', + '𑣅' => '𑢥', + '𑣆' => '𑢦', + '𑣇' => '𑢧', + '𑣈' => '𑢨', + '𑣉' => '𑢩', + '𑣊' => '𑢪', + '𑣋' => '𑢫', + '𑣌' => '𑢬', + '𑣍' => '𑢭', + '𑣎' => '𑢮', + '𑣏' => '𑢯', + '𑣐' => '𑢰', + '𑣑' => '𑢱', + '𑣒' => '𑢲', + '𑣓' => '𑢳', + '𑣔' => '𑢴', + '𑣕' => '𑢵', + '𑣖' => '𑢶', + '𑣗' => '𑢷', + '𑣘' => '𑢸', + '𑣙' => '𑢹', + '𑣚' => '𑢺', + '𑣛' => '𑢻', + '𑣜' => '𑢼', + '𑣝' => '𑢽', + '𑣞' => '𑢾', + '𑣟' => '𑢿', + '𖹠' => '𖹀', + '𖹡' => '𖹁', + '𖹢' => '𖹂', + '𖹣' => '𖹃', + '𖹤' => '𖹄', + '𖹥' => '𖹅', + '𖹦' => '𖹆', + '𖹧' => '𖹇', + '𖹨' => '𖹈', + '𖹩' => '𖹉', + '𖹪' => '𖹊', + '𖹫' => '𖹋', + '𖹬' => '𖹌', + '𖹭' => '𖹍', + '𖹮' => '𖹎', + '𖹯' => '𖹏', + '𖹰' => '𖹐', + '𖹱' => '𖹑', + '𖹲' => '𖹒', + '𖹳' => '𖹓', + '𖹴' => '𖹔', + '𖹵' => '𖹕', + '𖹶' => '𖹖', + '𖹷' => '𖹗', + '𖹸' => '𖹘', + '𖹹' => '𖹙', + '𖹺' => '𖹚', + '𖹻' => '𖹛', + '𖹼' => '𖹜', + '𖹽' => '𖹝', + '𖹾' => '𖹞', + '𖹿' => '𖹟', + '𞤢' => '𞤀', + '𞤣' => '𞤁', + '𞤤' => '𞤂', + '𞤥' => '𞤃', + '𞤦' => '𞤄', + '𞤧' => '𞤅', + '𞤨' => '𞤆', + '𞤩' => '𞤇', + '𞤪' => '𞤈', + '𞤫' => '𞤉', + '𞤬' => '𞤊', + '𞤭' => '𞤋', + '𞤮' => '𞤌', + '𞤯' => '𞤍', + '𞤰' => '𞤎', + '𞤱' => '𞤏', + '𞤲' => '𞤐', + '𞤳' => '𞤑', + '𞤴' => '𞤒', + '𞤵' => '𞤓', + '𞤶' => '𞤔', + '𞤷' => '𞤕', + '𞤸' => '𞤖', + '𞤹' => '𞤗', + '𞤺' => '𞤘', + '𞤻' => '𞤙', + '𞤼' => '𞤚', + '𞤽' => '𞤛', + '𞤾' => '𞤜', + '𞤿' => '𞤝', + '𞥀' => '𞤞', + '𞥁' => '𞤟', + '𞥂' => '𞤠', + '𞥃' => '𞤡', + 'ß' => 'SS', + 'ff' => 'FF', + 'fi' => 'FI', + 'fl' => 'FL', + 'ffi' => 'FFI', + 'ffl' => 'FFL', + 'ſt' => 'ST', + 'st' => 'ST', + 'և' => 'ԵՒ', + 'ﬓ' => 'ՄՆ', + 'ﬔ' => 'ՄԵ', + 'ﬕ' => 'ՄԻ', + 'ﬖ' => 'ՎՆ', + 'ﬗ' => 'ՄԽ', + 'ʼn' => 'ʼN', + 'ΐ' => 'Ϊ́', + 'ΰ' => 'Ϋ́', + 'ǰ' => 'J̌', + 'ẖ' => 'H̱', + 'ẗ' => 'T̈', + 'ẘ' => 'W̊', + 'ẙ' => 'Y̊', + 'ẚ' => 'Aʾ', + 'ὐ' => 'Υ̓', + 'ὒ' => 'Υ̓̀', + 'ὔ' => 'Υ̓́', + 'ὖ' => 'Υ̓͂', + 'ᾶ' => 'Α͂', + 'ῆ' => 'Η͂', + 'ῒ' => 'Ϊ̀', + 'ΐ' => 'Ϊ́', + 'ῖ' => 'Ι͂', + 'ῗ' => 'Ϊ͂', + 'ῢ' => 'Ϋ̀', + 'ΰ' => 'Ϋ́', + 'ῤ' => 'Ρ̓', + 'ῦ' => 'Υ͂', + 'ῧ' => 'Ϋ͂', + 'ῶ' => 'Ω͂', + 'ᾈ' => 'ἈΙ', + 'ᾉ' => 'ἉΙ', + 'ᾊ' => 'ἊΙ', + 'ᾋ' => 'ἋΙ', + 'ᾌ' => 'ἌΙ', + 'ᾍ' => 'ἍΙ', + 'ᾎ' => 'ἎΙ', + 'ᾏ' => 'ἏΙ', + 'ᾘ' => 'ἨΙ', + 'ᾙ' => 'ἩΙ', + 'ᾚ' => 'ἪΙ', + 'ᾛ' => 'ἫΙ', + 'ᾜ' => 'ἬΙ', + 'ᾝ' => 'ἭΙ', + 'ᾞ' => 'ἮΙ', + 'ᾟ' => 'ἯΙ', + 'ᾨ' => 'ὨΙ', + 'ᾩ' => 'ὩΙ', + 'ᾪ' => 'ὪΙ', + 'ᾫ' => 'ὫΙ', + 'ᾬ' => 'ὬΙ', + 'ᾭ' => 'ὭΙ', + 'ᾮ' => 'ὮΙ', + 'ᾯ' => 'ὯΙ', + 'ᾼ' => 'ΑΙ', + 'ῌ' => 'ΗΙ', + 'ῼ' => 'ΩΙ', + 'ᾲ' => 'ᾺΙ', + 'ᾴ' => 'ΆΙ', + 'ῂ' => 'ῊΙ', + 'ῄ' => 'ΉΙ', + 'ῲ' => 'ῺΙ', + 'ῴ' => 'ΏΙ', + 'ᾷ' => 'Α͂Ι', + 'ῇ' => 'Η͂Ι', + 'ῷ' => 'Ω͂Ι', +); diff --git a/vendor/symfony/polyfill-mbstring/bootstrap.php b/vendor/symfony/polyfill-mbstring/bootstrap.php new file mode 100644 index 000000000..1fedd1f7c --- /dev/null +++ b/vendor/symfony/polyfill-mbstring/bootstrap.php @@ -0,0 +1,147 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Mbstring as p; + +if (\PHP_VERSION_ID >= 80000) { + return require __DIR__.'/bootstrap80.php'; +} + +if (!function_exists('mb_convert_encoding')) { + function mb_convert_encoding($string, $to_encoding, $from_encoding = null) { return p\Mbstring::mb_convert_encoding($string, $to_encoding, $from_encoding); } +} +if (!function_exists('mb_decode_mimeheader')) { + function mb_decode_mimeheader($string) { return p\Mbstring::mb_decode_mimeheader($string); } +} +if (!function_exists('mb_encode_mimeheader')) { + function mb_encode_mimeheader($string, $charset = null, $transfer_encoding = null, $newline = "\r\n", $indent = 0) { return p\Mbstring::mb_encode_mimeheader($string, $charset, $transfer_encoding, $newline, $indent); } +} +if (!function_exists('mb_decode_numericentity')) { + function mb_decode_numericentity($string, $map, $encoding = null) { return p\Mbstring::mb_decode_numericentity($string, $map, $encoding); } +} +if (!function_exists('mb_encode_numericentity')) { + function mb_encode_numericentity($string, $map, $encoding = null, $hex = false) { return p\Mbstring::mb_encode_numericentity($string, $map, $encoding, $hex); } +} +if (!function_exists('mb_convert_case')) { + function mb_convert_case($string, $mode, $encoding = null) { return p\Mbstring::mb_convert_case($string, $mode, $encoding); } +} +if (!function_exists('mb_internal_encoding')) { + function mb_internal_encoding($encoding = null) { return p\Mbstring::mb_internal_encoding($encoding); } +} +if (!function_exists('mb_language')) { + function mb_language($language = null) { return p\Mbstring::mb_language($language); } +} +if (!function_exists('mb_list_encodings')) { + function mb_list_encodings() { return p\Mbstring::mb_list_encodings(); } +} +if (!function_exists('mb_encoding_aliases')) { + function mb_encoding_aliases($encoding) { return p\Mbstring::mb_encoding_aliases($encoding); } +} +if (!function_exists('mb_check_encoding')) { + function mb_check_encoding($value = null, $encoding = null) { return p\Mbstring::mb_check_encoding($value, $encoding); } +} +if (!function_exists('mb_detect_encoding')) { + function mb_detect_encoding($string, $encodings = null, $strict = false) { return p\Mbstring::mb_detect_encoding($string, $encodings, $strict); } +} +if (!function_exists('mb_detect_order')) { + function mb_detect_order($encoding = null) { return p\Mbstring::mb_detect_order($encoding); } +} +if (!function_exists('mb_parse_str')) { + function mb_parse_str($string, &$result = []) { parse_str($string, $result); return (bool) $result; } +} +if (!function_exists('mb_strlen')) { + function mb_strlen($string, $encoding = null) { return p\Mbstring::mb_strlen($string, $encoding); } +} +if (!function_exists('mb_strpos')) { + function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strpos($haystack, $needle, $offset, $encoding); } +} +if (!function_exists('mb_strtolower')) { + function mb_strtolower($string, $encoding = null) { return p\Mbstring::mb_strtolower($string, $encoding); } +} +if (!function_exists('mb_strtoupper')) { + function mb_strtoupper($string, $encoding = null) { return p\Mbstring::mb_strtoupper($string, $encoding); } +} +if (!function_exists('mb_substitute_character')) { + function mb_substitute_character($substitute_character = null) { return p\Mbstring::mb_substitute_character($substitute_character); } +} +if (!function_exists('mb_substr')) { + function mb_substr($string, $start, $length = 2147483647, $encoding = null) { return p\Mbstring::mb_substr($string, $start, $length, $encoding); } +} +if (!function_exists('mb_stripos')) { + function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_stripos($haystack, $needle, $offset, $encoding); } +} +if (!function_exists('mb_stristr')) { + function mb_stristr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_stristr($haystack, $needle, $before_needle, $encoding); } +} +if (!function_exists('mb_strrchr')) { + function mb_strrchr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strrchr($haystack, $needle, $before_needle, $encoding); } +} +if (!function_exists('mb_strrichr')) { + function mb_strrichr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strrichr($haystack, $needle, $before_needle, $encoding); } +} +if (!function_exists('mb_strripos')) { + function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strripos($haystack, $needle, $offset, $encoding); } +} +if (!function_exists('mb_strrpos')) { + function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strrpos($haystack, $needle, $offset, $encoding); } +} +if (!function_exists('mb_strstr')) { + function mb_strstr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strstr($haystack, $needle, $before_needle, $encoding); } +} +if (!function_exists('mb_get_info')) { + function mb_get_info($type = 'all') { return p\Mbstring::mb_get_info($type); } +} +if (!function_exists('mb_http_output')) { + function mb_http_output($encoding = null) { return p\Mbstring::mb_http_output($encoding); } +} +if (!function_exists('mb_strwidth')) { + function mb_strwidth($string, $encoding = null) { return p\Mbstring::mb_strwidth($string, $encoding); } +} +if (!function_exists('mb_substr_count')) { + function mb_substr_count($haystack, $needle, $encoding = null) { return p\Mbstring::mb_substr_count($haystack, $needle, $encoding); } +} +if (!function_exists('mb_output_handler')) { + function mb_output_handler($string, $status) { return p\Mbstring::mb_output_handler($string, $status); } +} +if (!function_exists('mb_http_input')) { + function mb_http_input($type = null) { return p\Mbstring::mb_http_input($type); } +} + +if (!function_exists('mb_convert_variables')) { + function mb_convert_variables($to_encoding, $from_encoding, &...$vars) { return p\Mbstring::mb_convert_variables($to_encoding, $from_encoding, ...$vars); } +} + +if (!function_exists('mb_ord')) { + function mb_ord($string, $encoding = null) { return p\Mbstring::mb_ord($string, $encoding); } +} +if (!function_exists('mb_chr')) { + function mb_chr($codepoint, $encoding = null) { return p\Mbstring::mb_chr($codepoint, $encoding); } +} +if (!function_exists('mb_scrub')) { + function mb_scrub($string, $encoding = null) { $encoding = null === $encoding ? mb_internal_encoding() : $encoding; return mb_convert_encoding($string, $encoding, $encoding); } +} +if (!function_exists('mb_str_split')) { + function mb_str_split($string, $length = 1, $encoding = null) { return p\Mbstring::mb_str_split($string, $length, $encoding); } +} + +if (extension_loaded('mbstring')) { + return; +} + +if (!defined('MB_CASE_UPPER')) { + define('MB_CASE_UPPER', 0); +} +if (!defined('MB_CASE_LOWER')) { + define('MB_CASE_LOWER', 1); +} +if (!defined('MB_CASE_TITLE')) { + define('MB_CASE_TITLE', 2); +} diff --git a/vendor/symfony/polyfill-mbstring/bootstrap80.php b/vendor/symfony/polyfill-mbstring/bootstrap80.php new file mode 100644 index 000000000..82f5ac4d0 --- /dev/null +++ b/vendor/symfony/polyfill-mbstring/bootstrap80.php @@ -0,0 +1,143 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Mbstring as p; + +if (!function_exists('mb_convert_encoding')) { + function mb_convert_encoding(array|string|null $string, ?string $to_encoding, array|string|null $from_encoding = null): array|string|false { return p\Mbstring::mb_convert_encoding($string ?? '', (string) $to_encoding, $from_encoding); } +} +if (!function_exists('mb_decode_mimeheader')) { + function mb_decode_mimeheader(?string $string): string { return p\Mbstring::mb_decode_mimeheader((string) $string); } +} +if (!function_exists('mb_encode_mimeheader')) { + function mb_encode_mimeheader(?string $string, ?string $charset = null, ?string $transfer_encoding = null, ?string $newline = "\r\n", ?int $indent = 0): string { return p\Mbstring::mb_encode_mimeheader((string) $string, $charset, $transfer_encoding, (string) $newline, (int) $indent); } +} +if (!function_exists('mb_decode_numericentity')) { + function mb_decode_numericentity(?string $string, array $map, ?string $encoding = null): string { return p\Mbstring::mb_decode_numericentity((string) $string, $map, $encoding); } +} +if (!function_exists('mb_encode_numericentity')) { + function mb_encode_numericentity(?string $string, array $map, ?string $encoding = null, ?bool $hex = false): string { return p\Mbstring::mb_encode_numericentity((string) $string, $map, $encoding, (bool) $hex); } +} +if (!function_exists('mb_convert_case')) { + function mb_convert_case(?string $string, ?int $mode, ?string $encoding = null): string { return p\Mbstring::mb_convert_case((string) $string, (int) $mode, $encoding); } +} +if (!function_exists('mb_internal_encoding')) { + function mb_internal_encoding(?string $encoding = null): string|bool { return p\Mbstring::mb_internal_encoding($encoding); } +} +if (!function_exists('mb_language')) { + function mb_language(?string $language = null): string|bool { return p\Mbstring::mb_language($language); } +} +if (!function_exists('mb_list_encodings')) { + function mb_list_encodings(): array { return p\Mbstring::mb_list_encodings(); } +} +if (!function_exists('mb_encoding_aliases')) { + function mb_encoding_aliases(?string $encoding): array { return p\Mbstring::mb_encoding_aliases((string) $encoding); } +} +if (!function_exists('mb_check_encoding')) { + function mb_check_encoding(array|string|null $value = null, ?string $encoding = null): bool { return p\Mbstring::mb_check_encoding($value, $encoding); } +} +if (!function_exists('mb_detect_encoding')) { + function mb_detect_encoding(?string $string, array|string|null $encodings = null, ?bool $strict = false): string|false { return p\Mbstring::mb_detect_encoding((string) $string, $encodings, (bool) $strict); } +} +if (!function_exists('mb_detect_order')) { + function mb_detect_order(array|string|null $encoding = null): array|bool { return p\Mbstring::mb_detect_order($encoding); } +} +if (!function_exists('mb_parse_str')) { + function mb_parse_str(?string $string, &$result = []): bool { parse_str((string) $string, $result); return (bool) $result; } +} +if (!function_exists('mb_strlen')) { + function mb_strlen(?string $string, ?string $encoding = null): int { return p\Mbstring::mb_strlen((string) $string, $encoding); } +} +if (!function_exists('mb_strpos')) { + function mb_strpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strpos((string) $haystack, (string) $needle, (int) $offset, $encoding); } +} +if (!function_exists('mb_strtolower')) { + function mb_strtolower(?string $string, ?string $encoding = null): string { return p\Mbstring::mb_strtolower((string) $string, $encoding); } +} +if (!function_exists('mb_strtoupper')) { + function mb_strtoupper(?string $string, ?string $encoding = null): string { return p\Mbstring::mb_strtoupper((string) $string, $encoding); } +} +if (!function_exists('mb_substitute_character')) { + function mb_substitute_character(string|int|null $substitute_character = null): string|int|bool { return p\Mbstring::mb_substitute_character($substitute_character); } +} +if (!function_exists('mb_substr')) { + function mb_substr(?string $string, ?int $start, ?int $length = null, ?string $encoding = null): string { return p\Mbstring::mb_substr((string) $string, (int) $start, $length, $encoding); } +} +if (!function_exists('mb_stripos')) { + function mb_stripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_stripos((string) $haystack, (string) $needle, (int) $offset, $encoding); } +} +if (!function_exists('mb_stristr')) { + function mb_stristr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_stristr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } +} +if (!function_exists('mb_strrchr')) { + function mb_strrchr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strrchr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } +} +if (!function_exists('mb_strrichr')) { + function mb_strrichr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strrichr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } +} +if (!function_exists('mb_strripos')) { + function mb_strripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strripos((string) $haystack, (string) $needle, (int) $offset, $encoding); } +} +if (!function_exists('mb_strrpos')) { + function mb_strrpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strrpos((string) $haystack, (string) $needle, (int) $offset, $encoding); } +} +if (!function_exists('mb_strstr')) { + function mb_strstr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strstr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } +} +if (!function_exists('mb_get_info')) { + function mb_get_info(?string $type = 'all'): array|string|int|false { return p\Mbstring::mb_get_info((string) $type); } +} +if (!function_exists('mb_http_output')) { + function mb_http_output(?string $encoding = null): string|bool { return p\Mbstring::mb_http_output($encoding); } +} +if (!function_exists('mb_strwidth')) { + function mb_strwidth(?string $string, ?string $encoding = null): int { return p\Mbstring::mb_strwidth((string) $string, $encoding); } +} +if (!function_exists('mb_substr_count')) { + function mb_substr_count(?string $haystack, ?string $needle, ?string $encoding = null): int { return p\Mbstring::mb_substr_count((string) $haystack, (string) $needle, $encoding); } +} +if (!function_exists('mb_output_handler')) { + function mb_output_handler(?string $string, ?int $status): string { return p\Mbstring::mb_output_handler((string) $string, (int) $status); } +} +if (!function_exists('mb_http_input')) { + function mb_http_input(?string $type = null): array|string|false { return p\Mbstring::mb_http_input($type); } +} + +if (!function_exists('mb_convert_variables')) { + function mb_convert_variables(?string $to_encoding, array|string|null $from_encoding, mixed &$var, mixed &...$vars): string|false { return p\Mbstring::mb_convert_variables((string) $to_encoding, $from_encoding ?? '', $var, ...$vars); } +} + +if (!function_exists('mb_ord')) { + function mb_ord(?string $string, ?string $encoding = null): int|false { return p\Mbstring::mb_ord((string) $string, $encoding); } +} +if (!function_exists('mb_chr')) { + function mb_chr(?int $codepoint, ?string $encoding = null): string|false { return p\Mbstring::mb_chr((int) $codepoint, $encoding); } +} +if (!function_exists('mb_scrub')) { + function mb_scrub(?string $string, ?string $encoding = null): string { $encoding ??= mb_internal_encoding(); return mb_convert_encoding((string) $string, $encoding, $encoding); } +} +if (!function_exists('mb_str_split')) { + function mb_str_split(?string $string, ?int $length = 1, ?string $encoding = null): array { return p\Mbstring::mb_str_split((string) $string, (int) $length, $encoding); } +} + +if (extension_loaded('mbstring')) { + return; +} + +if (!defined('MB_CASE_UPPER')) { + define('MB_CASE_UPPER', 0); +} +if (!defined('MB_CASE_LOWER')) { + define('MB_CASE_LOWER', 1); +} +if (!defined('MB_CASE_TITLE')) { + define('MB_CASE_TITLE', 2); +} diff --git a/vendor/symfony/polyfill-mbstring/composer.json b/vendor/symfony/polyfill-mbstring/composer.json new file mode 100644 index 000000000..2ed7a7435 --- /dev/null +++ b/vendor/symfony/polyfill-mbstring/composer.json @@ -0,0 +1,38 @@ +{ + "name": "symfony/polyfill-mbstring", + "type": "library", + "description": "Symfony polyfill for the Mbstring extension", + "keywords": ["polyfill", "shim", "compatibility", "portable", "mbstring"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.1" + }, + "autoload": { + "psr-4": { "Symfony\\Polyfill\\Mbstring\\": "" }, + "files": [ "bootstrap.php" ] + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + } +} diff --git a/vendor/symfony/polyfill-php72/LICENSE b/vendor/symfony/polyfill-php72/LICENSE new file mode 100644 index 000000000..4cd8bdd30 --- /dev/null +++ b/vendor/symfony/polyfill-php72/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015-2019 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/polyfill-php72/Php72.php b/vendor/symfony/polyfill-php72/Php72.php new file mode 100644 index 000000000..5e20d5bf8 --- /dev/null +++ b/vendor/symfony/polyfill-php72/Php72.php @@ -0,0 +1,217 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Php72; + +/** + * @author Nicolas Grekas + * @author Dariusz Rumiński + * + * @internal + */ +final class Php72 +{ + private static $hashMask; + + public static function utf8_encode($s) + { + $s .= $s; + $len = \strlen($s); + + for ($i = $len >> 1, $j = 0; $i < $len; ++$i, ++$j) { + switch (true) { + case $s[$i] < "\x80": $s[$j] = $s[$i]; break; + case $s[$i] < "\xC0": $s[$j] = "\xC2"; $s[++$j] = $s[$i]; break; + default: $s[$j] = "\xC3"; $s[++$j] = \chr(\ord($s[$i]) - 64); break; + } + } + + return substr($s, 0, $j); + } + + public static function utf8_decode($s) + { + $s = (string) $s; + $len = \strlen($s); + + for ($i = 0, $j = 0; $i < $len; ++$i, ++$j) { + switch ($s[$i] & "\xF0") { + case "\xC0": + case "\xD0": + $c = (\ord($s[$i] & "\x1F") << 6) | \ord($s[++$i] & "\x3F"); + $s[$j] = $c < 256 ? \chr($c) : '?'; + break; + + case "\xF0": + ++$i; + // no break + + case "\xE0": + $s[$j] = '?'; + $i += 2; + break; + + default: + $s[$j] = $s[$i]; + } + } + + return substr($s, 0, $j); + } + + public static function php_os_family() + { + if ('\\' === \DIRECTORY_SEPARATOR) { + return 'Windows'; + } + + $map = [ + 'Darwin' => 'Darwin', + 'DragonFly' => 'BSD', + 'FreeBSD' => 'BSD', + 'NetBSD' => 'BSD', + 'OpenBSD' => 'BSD', + 'Linux' => 'Linux', + 'SunOS' => 'Solaris', + ]; + + return isset($map[\PHP_OS]) ? $map[\PHP_OS] : 'Unknown'; + } + + public static function spl_object_id($object) + { + if (null === self::$hashMask) { + self::initHashMask(); + } + if (null === $hash = spl_object_hash($object)) { + return; + } + + // On 32-bit systems, PHP_INT_SIZE is 4, + return self::$hashMask ^ hexdec(substr($hash, 16 - (\PHP_INT_SIZE * 2 - 1), (\PHP_INT_SIZE * 2 - 1))); + } + + public static function sapi_windows_vt100_support($stream, $enable = null) + { + if (!\is_resource($stream)) { + trigger_error('sapi_windows_vt100_support() expects parameter 1 to be resource, '.\gettype($stream).' given', \E_USER_WARNING); + + return false; + } + + $meta = stream_get_meta_data($stream); + + if ('STDIO' !== $meta['stream_type']) { + trigger_error('sapi_windows_vt100_support() was not able to analyze the specified stream', \E_USER_WARNING); + + return false; + } + + // We cannot actually disable vt100 support if it is set + if (false === $enable || !self::stream_isatty($stream)) { + return false; + } + + // The native function does not apply to stdin + $meta = array_map('strtolower', $meta); + $stdin = 'php://stdin' === $meta['uri'] || 'php://fd/0' === $meta['uri']; + + return !$stdin + && (false !== getenv('ANSICON') + || 'ON' === getenv('ConEmuANSI') + || 'xterm' === getenv('TERM') + || 'Hyper' === getenv('TERM_PROGRAM')); + } + + public static function stream_isatty($stream) + { + if (!\is_resource($stream)) { + trigger_error('stream_isatty() expects parameter 1 to be resource, '.\gettype($stream).' given', \E_USER_WARNING); + + return false; + } + + if ('\\' === \DIRECTORY_SEPARATOR) { + $stat = @fstat($stream); + // Check if formatted mode is S_IFCHR + return $stat ? 0020000 === ($stat['mode'] & 0170000) : false; + } + + return \function_exists('posix_isatty') && @posix_isatty($stream); + } + + private static function initHashMask() + { + $obj = (object) []; + self::$hashMask = -1; + + // check if we are nested in an output buffering handler to prevent a fatal error with ob_start() below + $obFuncs = ['ob_clean', 'ob_end_clean', 'ob_flush', 'ob_end_flush', 'ob_get_contents', 'ob_get_flush']; + foreach (debug_backtrace(\PHP_VERSION_ID >= 50400 ? \DEBUG_BACKTRACE_IGNORE_ARGS : false) as $frame) { + if (isset($frame['function'][0]) && !isset($frame['class']) && 'o' === $frame['function'][0] && \in_array($frame['function'], $obFuncs)) { + $frame['line'] = 0; + break; + } + } + if (!empty($frame['line'])) { + ob_start(); + debug_zval_dump($obj); + self::$hashMask = (int) substr(ob_get_clean(), 17); + } + + self::$hashMask ^= hexdec(substr(spl_object_hash($obj), 16 - (\PHP_INT_SIZE * 2 - 1), (\PHP_INT_SIZE * 2 - 1))); + } + + public static function mb_chr($code, $encoding = null) + { + if (0x80 > $code %= 0x200000) { + $s = \chr($code); + } elseif (0x800 > $code) { + $s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F); + } elseif (0x10000 > $code) { + $s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F); + } else { + $s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F); + } + + if ('UTF-8' !== $encoding = $encoding ?? mb_internal_encoding()) { + $s = mb_convert_encoding($s, $encoding, 'UTF-8'); + } + + return $s; + } + + public static function mb_ord($s, $encoding = null) + { + if (null === $encoding) { + $s = mb_convert_encoding($s, 'UTF-8'); + } elseif ('UTF-8' !== $encoding) { + $s = mb_convert_encoding($s, 'UTF-8', $encoding); + } + + if (1 === \strlen($s)) { + return \ord($s); + } + + $code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0; + if (0xF0 <= $code) { + return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80; + } + if (0xE0 <= $code) { + return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80; + } + if (0xC0 <= $code) { + return (($code - 0xC0) << 6) + $s[2] - 0x80; + } + + return $code; + } +} diff --git a/vendor/symfony/polyfill-php72/README.md b/vendor/symfony/polyfill-php72/README.md new file mode 100644 index 000000000..59dec8a23 --- /dev/null +++ b/vendor/symfony/polyfill-php72/README.md @@ -0,0 +1,28 @@ +Symfony Polyfill / Php72 +======================== + +This component provides functions added to PHP 7.2 core: + +- [`spl_object_id`](https://php.net/spl_object_id) +- [`stream_isatty`](https://php.net/stream_isatty) + +On Windows only: + +- [`sapi_windows_vt100_support`](https://php.net/sapi_windows_vt100_support) + +Moved to core since 7.2 (was in the optional XML extension earlier): + +- [`utf8_encode`](https://php.net/utf8_encode) +- [`utf8_decode`](https://php.net/utf8_decode) + +Also, it provides constants added to PHP 7.2: +- [`PHP_FLOAT_*`](https://php.net/reserved.constants#constant.php-float-dig) +- [`PHP_OS_FAMILY`](https://php.net/reserved.constants#constant.php-os-family) + +More information can be found in the +[main Polyfill README](https://github.com/symfony/polyfill/blob/master/README.md). + +License +======= + +This library is released under the [MIT license](LICENSE). diff --git a/vendor/symfony/polyfill-php72/bootstrap.php b/vendor/symfony/polyfill-php72/bootstrap.php new file mode 100644 index 000000000..b5c92d4c7 --- /dev/null +++ b/vendor/symfony/polyfill-php72/bootstrap.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Php72 as p; + +if (\PHP_VERSION_ID >= 70200) { + return; +} + +if (!defined('PHP_FLOAT_DIG')) { + define('PHP_FLOAT_DIG', 15); +} +if (!defined('PHP_FLOAT_EPSILON')) { + define('PHP_FLOAT_EPSILON', 2.2204460492503E-16); +} +if (!defined('PHP_FLOAT_MIN')) { + define('PHP_FLOAT_MIN', 2.2250738585072E-308); +} +if (!defined('PHP_FLOAT_MAX')) { + define('PHP_FLOAT_MAX', 1.7976931348623157E+308); +} +if (!defined('PHP_OS_FAMILY')) { + define('PHP_OS_FAMILY', p\Php72::php_os_family()); +} + +if ('\\' === \DIRECTORY_SEPARATOR && !function_exists('sapi_windows_vt100_support')) { + function sapi_windows_vt100_support($stream, $enable = null) { return p\Php72::sapi_windows_vt100_support($stream, $enable); } +} +if (!function_exists('stream_isatty')) { + function stream_isatty($stream) { return p\Php72::stream_isatty($stream); } +} +if (!function_exists('utf8_encode')) { + function utf8_encode($string) { return p\Php72::utf8_encode($string); } +} +if (!function_exists('utf8_decode')) { + function utf8_decode($string) { return p\Php72::utf8_decode($string); } +} +if (!function_exists('spl_object_id')) { + function spl_object_id($object) { return p\Php72::spl_object_id($object); } +} +if (!function_exists('mb_ord')) { + function mb_ord($string, $encoding = null) { return p\Php72::mb_ord($string, $encoding); } +} +if (!function_exists('mb_chr')) { + function mb_chr($codepoint, $encoding = null) { return p\Php72::mb_chr($codepoint, $encoding); } +} +if (!function_exists('mb_scrub')) { + function mb_scrub($string, $encoding = null) { $encoding = null === $encoding ? mb_internal_encoding() : $encoding; return mb_convert_encoding($string, $encoding, $encoding); } +} diff --git a/vendor/symfony/polyfill-php72/composer.json b/vendor/symfony/polyfill-php72/composer.json new file mode 100644 index 000000000..c96c84477 --- /dev/null +++ b/vendor/symfony/polyfill-php72/composer.json @@ -0,0 +1,35 @@ +{ + "name": "symfony/polyfill-php72", + "type": "library", + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "keywords": ["polyfill", "shim", "compatibility", "portable"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.1" + }, + "autoload": { + "psr-4": { "Symfony\\Polyfill\\Php72\\": "" }, + "files": [ "bootstrap.php" ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + } +} diff --git a/vendor/symfony/polyfill-php80/LICENSE b/vendor/symfony/polyfill-php80/LICENSE new file mode 100644 index 000000000..5593b1d84 --- /dev/null +++ b/vendor/symfony/polyfill-php80/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2020 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/polyfill-php80/Php80.php b/vendor/symfony/polyfill-php80/Php80.php new file mode 100644 index 000000000..5fef51184 --- /dev/null +++ b/vendor/symfony/polyfill-php80/Php80.php @@ -0,0 +1,105 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Php80; + +/** + * @author Ion Bazan + * @author Nico Oelgart + * @author Nicolas Grekas + * + * @internal + */ +final class Php80 +{ + public static function fdiv(float $dividend, float $divisor): float + { + return @($dividend / $divisor); + } + + public static function get_debug_type($value): string + { + switch (true) { + case null === $value: return 'null'; + case \is_bool($value): return 'bool'; + case \is_string($value): return 'string'; + case \is_array($value): return 'array'; + case \is_int($value): return 'int'; + case \is_float($value): return 'float'; + case \is_object($value): break; + case $value instanceof \__PHP_Incomplete_Class: return '__PHP_Incomplete_Class'; + default: + if (null === $type = @get_resource_type($value)) { + return 'unknown'; + } + + if ('Unknown' === $type) { + $type = 'closed'; + } + + return "resource ($type)"; + } + + $class = \get_class($value); + + if (false === strpos($class, '@')) { + return $class; + } + + return (get_parent_class($class) ?: key(class_implements($class)) ?: 'class').'@anonymous'; + } + + public static function get_resource_id($res): int + { + if (!\is_resource($res) && null === @get_resource_type($res)) { + throw new \TypeError(sprintf('Argument 1 passed to get_resource_id() must be of the type resource, %s given', get_debug_type($res))); + } + + return (int) $res; + } + + public static function preg_last_error_msg(): string + { + switch (preg_last_error()) { + case \PREG_INTERNAL_ERROR: + return 'Internal error'; + case \PREG_BAD_UTF8_ERROR: + return 'Malformed UTF-8 characters, possibly incorrectly encoded'; + case \PREG_BAD_UTF8_OFFSET_ERROR: + return 'The offset did not correspond to the beginning of a valid UTF-8 code point'; + case \PREG_BACKTRACK_LIMIT_ERROR: + return 'Backtrack limit exhausted'; + case \PREG_RECURSION_LIMIT_ERROR: + return 'Recursion limit exhausted'; + case \PREG_JIT_STACKLIMIT_ERROR: + return 'JIT stack limit exhausted'; + case \PREG_NO_ERROR: + return 'No error'; + default: + return 'Unknown error'; + } + } + + public static function str_contains(string $haystack, string $needle): bool + { + return '' === $needle || false !== strpos($haystack, $needle); + } + + public static function str_starts_with(string $haystack, string $needle): bool + { + return 0 === strncmp($haystack, $needle, \strlen($needle)); + } + + public static function str_ends_with(string $haystack, string $needle): bool + { + return '' === $needle || ('' !== $haystack && 0 === substr_compare($haystack, $needle, -\strlen($needle))); + } +} diff --git a/vendor/symfony/polyfill-php80/README.md b/vendor/symfony/polyfill-php80/README.md new file mode 100644 index 000000000..eaa3050ab --- /dev/null +++ b/vendor/symfony/polyfill-php80/README.md @@ -0,0 +1,24 @@ +Symfony Polyfill / Php80 +======================== + +This component provides features added to PHP 8.0 core: + +- `Stringable` interface +- [`fdiv`](https://php.net/fdiv) +- `ValueError` class +- `UnhandledMatchError` class +- `FILTER_VALIDATE_BOOL` constant +- [`get_debug_type`](https://php.net/get_debug_type) +- [`preg_last_error_msg`](https://php.net/preg_last_error_msg) +- [`str_contains`](https://php.net/str_contains) +- [`str_starts_with`](https://php.net/str_starts_with) +- [`str_ends_with`](https://php.net/str_ends_with) +- [`get_resource_id`](https://php.net/get_resource_id) + +More information can be found in the +[main Polyfill README](https://github.com/symfony/polyfill/blob/master/README.md). + +License +======= + +This library is released under the [MIT license](LICENSE). diff --git a/vendor/symfony/polyfill-php80/Resources/stubs/Attribute.php b/vendor/symfony/polyfill-php80/Resources/stubs/Attribute.php new file mode 100644 index 000000000..7ea6d2772 --- /dev/null +++ b/vendor/symfony/polyfill-php80/Resources/stubs/Attribute.php @@ -0,0 +1,22 @@ +flags = $flags; + } +} diff --git a/vendor/symfony/polyfill-php80/Resources/stubs/Stringable.php b/vendor/symfony/polyfill-php80/Resources/stubs/Stringable.php new file mode 100644 index 000000000..77e037cb5 --- /dev/null +++ b/vendor/symfony/polyfill-php80/Resources/stubs/Stringable.php @@ -0,0 +1,11 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Php80 as p; + +if (\PHP_VERSION_ID >= 80000) { + return; +} + +if (!defined('FILTER_VALIDATE_BOOL') && defined('FILTER_VALIDATE_BOOLEAN')) { + define('FILTER_VALIDATE_BOOL', \FILTER_VALIDATE_BOOLEAN); +} + +if (!function_exists('fdiv')) { + function fdiv(float $num1, float $num2): float { return p\Php80::fdiv($num1, $num2); } +} +if (!function_exists('preg_last_error_msg')) { + function preg_last_error_msg(): string { return p\Php80::preg_last_error_msg(); } +} +if (!function_exists('str_contains')) { + function str_contains(string $haystack, string $needle): bool { return p\Php80::str_contains($haystack, $needle); } +} +if (!function_exists('str_starts_with')) { + function str_starts_with(string $haystack, string $needle): bool { return p\Php80::str_starts_with($haystack, $needle); } +} +if (!function_exists('str_ends_with')) { + function str_ends_with(string $haystack, string $needle): bool { return p\Php80::str_ends_with($haystack, $needle); } +} +if (!function_exists('get_debug_type')) { + function get_debug_type($value): string { return p\Php80::get_debug_type($value); } +} +if (!function_exists('get_resource_id')) { + function get_resource_id($resource): int { return p\Php80::get_resource_id($resource); } +} diff --git a/vendor/symfony/polyfill-php80/composer.json b/vendor/symfony/polyfill-php80/composer.json new file mode 100644 index 000000000..5fe679db3 --- /dev/null +++ b/vendor/symfony/polyfill-php80/composer.json @@ -0,0 +1,40 @@ +{ + "name": "symfony/polyfill-php80", + "type": "library", + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "keywords": ["polyfill", "shim", "compatibility", "portable"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.1" + }, + "autoload": { + "psr-4": { "Symfony\\Polyfill\\Php80\\": "" }, + "files": [ "bootstrap.php" ], + "classmap": [ "Resources/stubs" ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + } +} diff --git a/vendor/symfony/var-dumper/CHANGELOG.md b/vendor/symfony/var-dumper/CHANGELOG.md new file mode 100644 index 000000000..94b1c17d1 --- /dev/null +++ b/vendor/symfony/var-dumper/CHANGELOG.md @@ -0,0 +1,53 @@ +CHANGELOG +========= + +4.4.0 +----- + + * added `VarDumperTestTrait::setUpVarDumper()` and `VarDumperTestTrait::tearDownVarDumper()` + to configure casters & flags to use in tests + * added `ImagineCaster` and infrastructure to dump images + * added the stamps of a message after it is dispatched in `TraceableMessageBus` and `MessengerDataCollector` collected data + * added `UuidCaster` + * made all casters final + * added support for the `NO_COLOR` env var (https://no-color.org/) + +4.3.0 +----- + + * added `DsCaster` to support dumping the contents of data structures from the Ds extension + +4.2.0 +----- + + * support selecting the format to use by setting the environment variable `VAR_DUMPER_FORMAT` to `html` or `cli` + +4.1.0 +----- + + * added a `ServerDumper` to send serialized Data clones to a server + * added a `ServerDumpCommand` and `DumpServer` to run a server collecting + and displaying dumps on a single place with multiple formats support + * added `CliDescriptor` and `HtmlDescriptor` descriptors for `server:dump` CLI and HTML formats support + +4.0.0 +----- + + * support for passing `\ReflectionClass` instances to the `Caster::castObject()` + method has been dropped, pass class names as strings instead + * the `Data::getRawData()` method has been removed + * the `VarDumperTestTrait::assertDumpEquals()` method expects a 3rd `$filter = 0` + argument and moves `$message = ''` argument at 4th position. + * the `VarDumperTestTrait::assertDumpMatchesFormat()` method expects a 3rd `$filter = 0` + argument and moves `$message = ''` argument at 4th position. + +3.4.0 +----- + + * added `AbstractCloner::setMinDepth()` function to ensure minimum tree depth + * deprecated `MongoCaster` + +2.7.0 +----- + + * deprecated `Cloner\Data::getLimitedClone()`. Use `withMaxDepth`, `withMaxItemsPerDepth` or `withRefHandles` instead. diff --git a/vendor/symfony/var-dumper/Caster/AmqpCaster.php b/vendor/symfony/var-dumper/Caster/AmqpCaster.php new file mode 100644 index 000000000..60045ff7b --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/AmqpCaster.php @@ -0,0 +1,212 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts Amqp related classes to array representation. + * + * @author Grégoire Pineau + * + * @final since Symfony 4.4 + */ +class AmqpCaster +{ + private const FLAGS = [ + \AMQP_DURABLE => 'AMQP_DURABLE', + \AMQP_PASSIVE => 'AMQP_PASSIVE', + \AMQP_EXCLUSIVE => 'AMQP_EXCLUSIVE', + \AMQP_AUTODELETE => 'AMQP_AUTODELETE', + \AMQP_INTERNAL => 'AMQP_INTERNAL', + \AMQP_NOLOCAL => 'AMQP_NOLOCAL', + \AMQP_AUTOACK => 'AMQP_AUTOACK', + \AMQP_IFEMPTY => 'AMQP_IFEMPTY', + \AMQP_IFUNUSED => 'AMQP_IFUNUSED', + \AMQP_MANDATORY => 'AMQP_MANDATORY', + \AMQP_IMMEDIATE => 'AMQP_IMMEDIATE', + \AMQP_MULTIPLE => 'AMQP_MULTIPLE', + \AMQP_NOWAIT => 'AMQP_NOWAIT', + \AMQP_REQUEUE => 'AMQP_REQUEUE', + ]; + + private const EXCHANGE_TYPES = [ + \AMQP_EX_TYPE_DIRECT => 'AMQP_EX_TYPE_DIRECT', + \AMQP_EX_TYPE_FANOUT => 'AMQP_EX_TYPE_FANOUT', + \AMQP_EX_TYPE_TOPIC => 'AMQP_EX_TYPE_TOPIC', + \AMQP_EX_TYPE_HEADERS => 'AMQP_EX_TYPE_HEADERS', + ]; + + public static function castConnection(\AMQPConnection $c, array $a, Stub $stub, $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + + $a += [ + $prefix.'is_connected' => $c->isConnected(), + ]; + + // Recent version of the extension already expose private properties + if (isset($a["\x00AMQPConnection\x00login"])) { + return $a; + } + + // BC layer in the amqp lib + if (method_exists($c, 'getReadTimeout')) { + $timeout = $c->getReadTimeout(); + } else { + $timeout = $c->getTimeout(); + } + + $a += [ + $prefix.'is_connected' => $c->isConnected(), + $prefix.'login' => $c->getLogin(), + $prefix.'password' => $c->getPassword(), + $prefix.'host' => $c->getHost(), + $prefix.'vhost' => $c->getVhost(), + $prefix.'port' => $c->getPort(), + $prefix.'read_timeout' => $timeout, + ]; + + return $a; + } + + public static function castChannel(\AMQPChannel $c, array $a, Stub $stub, $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + + $a += [ + $prefix.'is_connected' => $c->isConnected(), + $prefix.'channel_id' => $c->getChannelId(), + ]; + + // Recent version of the extension already expose private properties + if (isset($a["\x00AMQPChannel\x00connection"])) { + return $a; + } + + $a += [ + $prefix.'connection' => $c->getConnection(), + $prefix.'prefetch_size' => $c->getPrefetchSize(), + $prefix.'prefetch_count' => $c->getPrefetchCount(), + ]; + + return $a; + } + + public static function castQueue(\AMQPQueue $c, array $a, Stub $stub, $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + + $a += [ + $prefix.'flags' => self::extractFlags($c->getFlags()), + ]; + + // Recent version of the extension already expose private properties + if (isset($a["\x00AMQPQueue\x00name"])) { + return $a; + } + + $a += [ + $prefix.'connection' => $c->getConnection(), + $prefix.'channel' => $c->getChannel(), + $prefix.'name' => $c->getName(), + $prefix.'arguments' => $c->getArguments(), + ]; + + return $a; + } + + public static function castExchange(\AMQPExchange $c, array $a, Stub $stub, $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + + $a += [ + $prefix.'flags' => self::extractFlags($c->getFlags()), + ]; + + $type = isset(self::EXCHANGE_TYPES[$c->getType()]) ? new ConstStub(self::EXCHANGE_TYPES[$c->getType()], $c->getType()) : $c->getType(); + + // Recent version of the extension already expose private properties + if (isset($a["\x00AMQPExchange\x00name"])) { + $a["\x00AMQPExchange\x00type"] = $type; + + return $a; + } + + $a += [ + $prefix.'connection' => $c->getConnection(), + $prefix.'channel' => $c->getChannel(), + $prefix.'name' => $c->getName(), + $prefix.'type' => $type, + $prefix.'arguments' => $c->getArguments(), + ]; + + return $a; + } + + public static function castEnvelope(\AMQPEnvelope $c, array $a, Stub $stub, $isNested, $filter = 0) + { + $prefix = Caster::PREFIX_VIRTUAL; + + $deliveryMode = new ConstStub($c->getDeliveryMode().(2 === $c->getDeliveryMode() ? ' (persistent)' : ' (non-persistent)'), $c->getDeliveryMode()); + + // Recent version of the extension already expose private properties + if (isset($a["\x00AMQPEnvelope\x00body"])) { + $a["\0AMQPEnvelope\0delivery_mode"] = $deliveryMode; + + return $a; + } + + if (!($filter & Caster::EXCLUDE_VERBOSE)) { + $a += [$prefix.'body' => $c->getBody()]; + } + + $a += [ + $prefix.'delivery_tag' => $c->getDeliveryTag(), + $prefix.'is_redelivery' => $c->isRedelivery(), + $prefix.'exchange_name' => $c->getExchangeName(), + $prefix.'routing_key' => $c->getRoutingKey(), + $prefix.'content_type' => $c->getContentType(), + $prefix.'content_encoding' => $c->getContentEncoding(), + $prefix.'headers' => $c->getHeaders(), + $prefix.'delivery_mode' => $deliveryMode, + $prefix.'priority' => $c->getPriority(), + $prefix.'correlation_id' => $c->getCorrelationId(), + $prefix.'reply_to' => $c->getReplyTo(), + $prefix.'expiration' => $c->getExpiration(), + $prefix.'message_id' => $c->getMessageId(), + $prefix.'timestamp' => $c->getTimeStamp(), + $prefix.'type' => $c->getType(), + $prefix.'user_id' => $c->getUserId(), + $prefix.'app_id' => $c->getAppId(), + ]; + + return $a; + } + + private static function extractFlags(int $flags): ConstStub + { + $flagsArray = []; + + foreach (self::FLAGS as $value => $name) { + if ($flags & $value) { + $flagsArray[] = $name; + } + } + + if (!$flagsArray) { + $flagsArray = ['AMQP_NOPARAM']; + } + + return new ConstStub(implode('|', $flagsArray), $flags); + } +} diff --git a/vendor/symfony/var-dumper/Caster/ArgsStub.php b/vendor/symfony/var-dumper/Caster/ArgsStub.php new file mode 100644 index 000000000..f8b485bd4 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/ArgsStub.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Represents a list of function arguments. + * + * @author Nicolas Grekas + */ +class ArgsStub extends EnumStub +{ + private static $parameters = []; + + public function __construct(array $args, string $function, ?string $class) + { + [$variadic, $params] = self::getParameters($function, $class); + + $values = []; + foreach ($args as $k => $v) { + $values[$k] = !is_scalar($v) && !$v instanceof Stub ? new CutStub($v) : $v; + } + if (null === $params) { + parent::__construct($values, false); + + return; + } + if (\count($values) < \count($params)) { + $params = \array_slice($params, 0, \count($values)); + } elseif (\count($values) > \count($params)) { + $values[] = new EnumStub(array_splice($values, \count($params)), false); + $params[] = $variadic; + } + if (['...'] === $params) { + $this->dumpKeys = false; + $this->value = $values[0]->value; + } else { + $this->value = array_combine($params, $values); + } + } + + private static function getParameters(string $function, ?string $class): array + { + if (isset(self::$parameters[$k = $class.'::'.$function])) { + return self::$parameters[$k]; + } + + try { + $r = null !== $class ? new \ReflectionMethod($class, $function) : new \ReflectionFunction($function); + } catch (\ReflectionException $e) { + return [null, null]; + } + + $variadic = '...'; + $params = []; + foreach ($r->getParameters() as $v) { + $k = '$'.$v->name; + if ($v->isPassedByReference()) { + $k = '&'.$k; + } + if ($v->isVariadic()) { + $variadic .= $k; + } else { + $params[] = $k; + } + } + + return self::$parameters[$k] = [$variadic, $params]; + } +} diff --git a/vendor/symfony/var-dumper/Caster/Caster.php b/vendor/symfony/var-dumper/Caster/Caster.php new file mode 100644 index 000000000..d35f3230b --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/Caster.php @@ -0,0 +1,175 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Helper for filtering out properties in casters. + * + * @author Nicolas Grekas + * + * @final + */ +class Caster +{ + public const EXCLUDE_VERBOSE = 1; + public const EXCLUDE_VIRTUAL = 2; + public const EXCLUDE_DYNAMIC = 4; + public const EXCLUDE_PUBLIC = 8; + public const EXCLUDE_PROTECTED = 16; + public const EXCLUDE_PRIVATE = 32; + public const EXCLUDE_NULL = 64; + public const EXCLUDE_EMPTY = 128; + public const EXCLUDE_NOT_IMPORTANT = 256; + public const EXCLUDE_STRICT = 512; + + public const PREFIX_VIRTUAL = "\0~\0"; + public const PREFIX_DYNAMIC = "\0+\0"; + public const PREFIX_PROTECTED = "\0*\0"; + + /** + * Casts objects to arrays and adds the dynamic property prefix. + * + * @param object $obj The object to cast + * @param bool $hasDebugInfo Whether the __debugInfo method exists on $obj or not + * + * @return array The array-cast of the object, with prefixed dynamic properties + */ + public static function castObject($obj, string $class, bool $hasDebugInfo = false, string $debugClass = null): array + { + if ($hasDebugInfo) { + try { + $debugInfo = $obj->__debugInfo(); + } catch (\Exception $e) { + // ignore failing __debugInfo() + $hasDebugInfo = false; + } + } + + $a = $obj instanceof \Closure ? [] : (array) $obj; + + if ($obj instanceof \__PHP_Incomplete_Class) { + return $a; + } + + if ($a) { + static $publicProperties = []; + $debugClass = $debugClass ?? get_debug_type($obj); + + $i = 0; + $prefixedKeys = []; + foreach ($a as $k => $v) { + if (isset($k[0]) ? "\0" !== $k[0] : \PHP_VERSION_ID >= 70200) { + if (!isset($publicProperties[$class])) { + foreach ((new \ReflectionClass($class))->getProperties(\ReflectionProperty::IS_PUBLIC) as $prop) { + $publicProperties[$class][$prop->name] = true; + } + } + if (!isset($publicProperties[$class][$k])) { + $prefixedKeys[$i] = self::PREFIX_DYNAMIC.$k; + } + } elseif ($debugClass !== $class && 1 === strpos($k, $class)) { + $prefixedKeys[$i] = "\0".$debugClass.strrchr($k, "\0"); + } + ++$i; + } + if ($prefixedKeys) { + $keys = array_keys($a); + foreach ($prefixedKeys as $i => $k) { + $keys[$i] = $k; + } + $a = array_combine($keys, $a); + } + } + + if ($hasDebugInfo && \is_array($debugInfo)) { + foreach ($debugInfo as $k => $v) { + if (!isset($k[0]) || "\0" !== $k[0]) { + if (\array_key_exists(self::PREFIX_DYNAMIC.$k, $a)) { + continue; + } + $k = self::PREFIX_VIRTUAL.$k; + } + + unset($a[$k]); + $a[$k] = $v; + } + } + + return $a; + } + + /** + * Filters out the specified properties. + * + * By default, a single match in the $filter bit field filters properties out, following an "or" logic. + * When EXCLUDE_STRICT is set, an "and" logic is applied: all bits must match for a property to be removed. + * + * @param array $a The array containing the properties to filter + * @param int $filter A bit field of Caster::EXCLUDE_* constants specifying which properties to filter out + * @param string[] $listedProperties List of properties to exclude when Caster::EXCLUDE_VERBOSE is set, and to preserve when Caster::EXCLUDE_NOT_IMPORTANT is set + * @param int &$count Set to the number of removed properties + * + * @return array The filtered array + */ + public static function filter(array $a, int $filter, array $listedProperties = [], ?int &$count = 0): array + { + $count = 0; + + foreach ($a as $k => $v) { + $type = self::EXCLUDE_STRICT & $filter; + + if (null === $v) { + $type |= self::EXCLUDE_NULL & $filter; + $type |= self::EXCLUDE_EMPTY & $filter; + } elseif (false === $v || '' === $v || '0' === $v || 0 === $v || 0.0 === $v || [] === $v) { + $type |= self::EXCLUDE_EMPTY & $filter; + } + if ((self::EXCLUDE_NOT_IMPORTANT & $filter) && !\in_array($k, $listedProperties, true)) { + $type |= self::EXCLUDE_NOT_IMPORTANT; + } + if ((self::EXCLUDE_VERBOSE & $filter) && \in_array($k, $listedProperties, true)) { + $type |= self::EXCLUDE_VERBOSE; + } + + if (!isset($k[1]) || "\0" !== $k[0]) { + $type |= self::EXCLUDE_PUBLIC & $filter; + } elseif ('~' === $k[1]) { + $type |= self::EXCLUDE_VIRTUAL & $filter; + } elseif ('+' === $k[1]) { + $type |= self::EXCLUDE_DYNAMIC & $filter; + } elseif ('*' === $k[1]) { + $type |= self::EXCLUDE_PROTECTED & $filter; + } else { + $type |= self::EXCLUDE_PRIVATE & $filter; + } + + if ((self::EXCLUDE_STRICT & $filter) ? $type === $filter : $type) { + unset($a[$k]); + ++$count; + } + } + + return $a; + } + + public static function castPhpIncompleteClass(\__PHP_Incomplete_Class $c, array $a, Stub $stub, bool $isNested): array + { + if (isset($a['__PHP_Incomplete_Class_Name'])) { + $stub->class .= '('.$a['__PHP_Incomplete_Class_Name'].')'; + unset($a['__PHP_Incomplete_Class_Name']); + } + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Caster/ClassStub.php b/vendor/symfony/var-dumper/Caster/ClassStub.php new file mode 100644 index 000000000..612a7ca2d --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/ClassStub.php @@ -0,0 +1,106 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Represents a PHP class identifier. + * + * @author Nicolas Grekas + */ +class ClassStub extends ConstStub +{ + /** + * @param string $identifier A PHP identifier, e.g. a class, method, interface, etc. name + * @param callable $callable The callable targeted by the identifier when it is ambiguous or not a real PHP identifier + */ + public function __construct(string $identifier, $callable = null) + { + $this->value = $identifier; + + try { + if (null !== $callable) { + if ($callable instanceof \Closure) { + $r = new \ReflectionFunction($callable); + } elseif (\is_object($callable)) { + $r = [$callable, '__invoke']; + } elseif (\is_array($callable)) { + $r = $callable; + } elseif (false !== $i = strpos($callable, '::')) { + $r = [substr($callable, 0, $i), substr($callable, 2 + $i)]; + } else { + $r = new \ReflectionFunction($callable); + } + } elseif (0 < $i = strpos($identifier, '::') ?: strpos($identifier, '->')) { + $r = [substr($identifier, 0, $i), substr($identifier, 2 + $i)]; + } else { + $r = new \ReflectionClass($identifier); + } + + if (\is_array($r)) { + try { + $r = new \ReflectionMethod($r[0], $r[1]); + } catch (\ReflectionException $e) { + $r = new \ReflectionClass($r[0]); + } + } + + if (false !== strpos($identifier, "@anonymous\0")) { + $this->value = $identifier = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)[0-9a-fA-F]++/', function ($m) { + return class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0]; + }, $identifier); + } + + if (null !== $callable && $r instanceof \ReflectionFunctionAbstract) { + $s = ReflectionCaster::castFunctionAbstract($r, [], new Stub(), true, Caster::EXCLUDE_VERBOSE); + $s = ReflectionCaster::getSignature($s); + + if ('()' === substr($identifier, -2)) { + $this->value = substr_replace($identifier, $s, -2); + } else { + $this->value .= $s; + } + } + } catch (\ReflectionException $e) { + return; + } finally { + if (0 < $i = strrpos($this->value, '\\')) { + $this->attr['ellipsis'] = \strlen($this->value) - $i; + $this->attr['ellipsis-type'] = 'class'; + $this->attr['ellipsis-tail'] = 1; + } + } + + if ($f = $r->getFileName()) { + $this->attr['file'] = $f; + $this->attr['line'] = $r->getStartLine(); + } + } + + public static function wrapCallable($callable) + { + if (\is_object($callable) || !\is_callable($callable)) { + return $callable; + } + + if (!\is_array($callable)) { + $callable = new static($callable, $callable); + } elseif (\is_string($callable[0])) { + $callable[0] = new static($callable[0], $callable); + } else { + $callable[1] = new static($callable[1], $callable); + } + + return $callable; + } +} diff --git a/vendor/symfony/var-dumper/Caster/ConstStub.php b/vendor/symfony/var-dumper/Caster/ConstStub.php new file mode 100644 index 000000000..8b0179745 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/ConstStub.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Represents a PHP constant and its value. + * + * @author Nicolas Grekas + */ +class ConstStub extends Stub +{ + public function __construct(string $name, $value = null) + { + $this->class = $name; + $this->value = 1 < \func_num_args() ? $value : $name; + } + + /** + * @return string + */ + public function __toString() + { + return (string) $this->value; + } +} diff --git a/vendor/symfony/var-dumper/Caster/CutArrayStub.php b/vendor/symfony/var-dumper/Caster/CutArrayStub.php new file mode 100644 index 000000000..0e4fb363d --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/CutArrayStub.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +/** + * Represents a cut array. + * + * @author Nicolas Grekas + */ +class CutArrayStub extends CutStub +{ + public $preservedSubset; + + public function __construct(array $value, array $preservedKeys) + { + parent::__construct($value); + + $this->preservedSubset = array_intersect_key($value, array_flip($preservedKeys)); + $this->cut -= \count($this->preservedSubset); + } +} diff --git a/vendor/symfony/var-dumper/Caster/CutStub.php b/vendor/symfony/var-dumper/Caster/CutStub.php new file mode 100644 index 000000000..464c6dbd1 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/CutStub.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Represents the main properties of a PHP variable, pre-casted by a caster. + * + * @author Nicolas Grekas + */ +class CutStub extends Stub +{ + public function __construct($value) + { + $this->value = $value; + + switch (\gettype($value)) { + case 'object': + $this->type = self::TYPE_OBJECT; + $this->class = \get_class($value); + + if ($value instanceof \Closure) { + ReflectionCaster::castClosure($value, [], $this, true, Caster::EXCLUDE_VERBOSE); + } + + $this->cut = -1; + break; + + case 'array': + $this->type = self::TYPE_ARRAY; + $this->class = self::ARRAY_ASSOC; + $this->cut = $this->value = \count($value); + break; + + case 'resource': + case 'unknown type': + case 'resource (closed)': + $this->type = self::TYPE_RESOURCE; + $this->handle = (int) $value; + if ('Unknown' === $this->class = @get_resource_type($value)) { + $this->class = 'Closed'; + } + $this->cut = -1; + break; + + case 'string': + $this->type = self::TYPE_STRING; + $this->class = preg_match('//u', $value) ? self::STRING_UTF8 : self::STRING_BINARY; + $this->cut = self::STRING_BINARY === $this->class ? \strlen($value) : mb_strlen($value, 'UTF-8'); + $this->value = ''; + break; + } + } +} diff --git a/vendor/symfony/var-dumper/Caster/DOMCaster.php b/vendor/symfony/var-dumper/Caster/DOMCaster.php new file mode 100644 index 000000000..5f2b9cd11 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/DOMCaster.php @@ -0,0 +1,304 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts DOM related classes to array representation. + * + * @author Nicolas Grekas + * + * @final since Symfony 4.4 + */ +class DOMCaster +{ + private const ERROR_CODES = [ + \DOM_PHP_ERR => 'DOM_PHP_ERR', + \DOM_INDEX_SIZE_ERR => 'DOM_INDEX_SIZE_ERR', + \DOMSTRING_SIZE_ERR => 'DOMSTRING_SIZE_ERR', + \DOM_HIERARCHY_REQUEST_ERR => 'DOM_HIERARCHY_REQUEST_ERR', + \DOM_WRONG_DOCUMENT_ERR => 'DOM_WRONG_DOCUMENT_ERR', + \DOM_INVALID_CHARACTER_ERR => 'DOM_INVALID_CHARACTER_ERR', + \DOM_NO_DATA_ALLOWED_ERR => 'DOM_NO_DATA_ALLOWED_ERR', + \DOM_NO_MODIFICATION_ALLOWED_ERR => 'DOM_NO_MODIFICATION_ALLOWED_ERR', + \DOM_NOT_FOUND_ERR => 'DOM_NOT_FOUND_ERR', + \DOM_NOT_SUPPORTED_ERR => 'DOM_NOT_SUPPORTED_ERR', + \DOM_INUSE_ATTRIBUTE_ERR => 'DOM_INUSE_ATTRIBUTE_ERR', + \DOM_INVALID_STATE_ERR => 'DOM_INVALID_STATE_ERR', + \DOM_SYNTAX_ERR => 'DOM_SYNTAX_ERR', + \DOM_INVALID_MODIFICATION_ERR => 'DOM_INVALID_MODIFICATION_ERR', + \DOM_NAMESPACE_ERR => 'DOM_NAMESPACE_ERR', + \DOM_INVALID_ACCESS_ERR => 'DOM_INVALID_ACCESS_ERR', + \DOM_VALIDATION_ERR => 'DOM_VALIDATION_ERR', + ]; + + private const NODE_TYPES = [ + \XML_ELEMENT_NODE => 'XML_ELEMENT_NODE', + \XML_ATTRIBUTE_NODE => 'XML_ATTRIBUTE_NODE', + \XML_TEXT_NODE => 'XML_TEXT_NODE', + \XML_CDATA_SECTION_NODE => 'XML_CDATA_SECTION_NODE', + \XML_ENTITY_REF_NODE => 'XML_ENTITY_REF_NODE', + \XML_ENTITY_NODE => 'XML_ENTITY_NODE', + \XML_PI_NODE => 'XML_PI_NODE', + \XML_COMMENT_NODE => 'XML_COMMENT_NODE', + \XML_DOCUMENT_NODE => 'XML_DOCUMENT_NODE', + \XML_DOCUMENT_TYPE_NODE => 'XML_DOCUMENT_TYPE_NODE', + \XML_DOCUMENT_FRAG_NODE => 'XML_DOCUMENT_FRAG_NODE', + \XML_NOTATION_NODE => 'XML_NOTATION_NODE', + \XML_HTML_DOCUMENT_NODE => 'XML_HTML_DOCUMENT_NODE', + \XML_DTD_NODE => 'XML_DTD_NODE', + \XML_ELEMENT_DECL_NODE => 'XML_ELEMENT_DECL_NODE', + \XML_ATTRIBUTE_DECL_NODE => 'XML_ATTRIBUTE_DECL_NODE', + \XML_ENTITY_DECL_NODE => 'XML_ENTITY_DECL_NODE', + \XML_NAMESPACE_DECL_NODE => 'XML_NAMESPACE_DECL_NODE', + ]; + + public static function castException(\DOMException $e, array $a, Stub $stub, $isNested) + { + $k = Caster::PREFIX_PROTECTED.'code'; + if (isset($a[$k], self::ERROR_CODES[$a[$k]])) { + $a[$k] = new ConstStub(self::ERROR_CODES[$a[$k]], $a[$k]); + } + + return $a; + } + + public static function castLength($dom, array $a, Stub $stub, $isNested) + { + $a += [ + 'length' => $dom->length, + ]; + + return $a; + } + + public static function castImplementation($dom, array $a, Stub $stub, $isNested) + { + $a += [ + Caster::PREFIX_VIRTUAL.'Core' => '1.0', + Caster::PREFIX_VIRTUAL.'XML' => '2.0', + ]; + + return $a; + } + + public static function castNode(\DOMNode $dom, array $a, Stub $stub, $isNested) + { + $a += [ + 'nodeName' => $dom->nodeName, + 'nodeValue' => new CutStub($dom->nodeValue), + 'nodeType' => new ConstStub(self::NODE_TYPES[$dom->nodeType], $dom->nodeType), + 'parentNode' => new CutStub($dom->parentNode), + 'childNodes' => $dom->childNodes, + 'firstChild' => new CutStub($dom->firstChild), + 'lastChild' => new CutStub($dom->lastChild), + 'previousSibling' => new CutStub($dom->previousSibling), + 'nextSibling' => new CutStub($dom->nextSibling), + 'attributes' => $dom->attributes, + 'ownerDocument' => new CutStub($dom->ownerDocument), + 'namespaceURI' => $dom->namespaceURI, + 'prefix' => $dom->prefix, + 'localName' => $dom->localName, + 'baseURI' => $dom->baseURI ? new LinkStub($dom->baseURI) : $dom->baseURI, + 'textContent' => new CutStub($dom->textContent), + ]; + + return $a; + } + + public static function castNameSpaceNode(\DOMNameSpaceNode $dom, array $a, Stub $stub, $isNested) + { + $a += [ + 'nodeName' => $dom->nodeName, + 'nodeValue' => new CutStub($dom->nodeValue), + 'nodeType' => new ConstStub(self::NODE_TYPES[$dom->nodeType], $dom->nodeType), + 'prefix' => $dom->prefix, + 'localName' => $dom->localName, + 'namespaceURI' => $dom->namespaceURI, + 'ownerDocument' => new CutStub($dom->ownerDocument), + 'parentNode' => new CutStub($dom->parentNode), + ]; + + return $a; + } + + public static function castDocument(\DOMDocument $dom, array $a, Stub $stub, $isNested, $filter = 0) + { + $a += [ + 'doctype' => $dom->doctype, + 'implementation' => $dom->implementation, + 'documentElement' => new CutStub($dom->documentElement), + 'actualEncoding' => $dom->actualEncoding, + 'encoding' => $dom->encoding, + 'xmlEncoding' => $dom->xmlEncoding, + 'standalone' => $dom->standalone, + 'xmlStandalone' => $dom->xmlStandalone, + 'version' => $dom->version, + 'xmlVersion' => $dom->xmlVersion, + 'strictErrorChecking' => $dom->strictErrorChecking, + 'documentURI' => $dom->documentURI ? new LinkStub($dom->documentURI) : $dom->documentURI, + 'config' => $dom->config, + 'formatOutput' => $dom->formatOutput, + 'validateOnParse' => $dom->validateOnParse, + 'resolveExternals' => $dom->resolveExternals, + 'preserveWhiteSpace' => $dom->preserveWhiteSpace, + 'recover' => $dom->recover, + 'substituteEntities' => $dom->substituteEntities, + ]; + + if (!($filter & Caster::EXCLUDE_VERBOSE)) { + $formatOutput = $dom->formatOutput; + $dom->formatOutput = true; + $a += [Caster::PREFIX_VIRTUAL.'xml' => $dom->saveXML()]; + $dom->formatOutput = $formatOutput; + } + + return $a; + } + + public static function castCharacterData(\DOMCharacterData $dom, array $a, Stub $stub, $isNested) + { + $a += [ + 'data' => $dom->data, + 'length' => $dom->length, + ]; + + return $a; + } + + public static function castAttr(\DOMAttr $dom, array $a, Stub $stub, $isNested) + { + $a += [ + 'name' => $dom->name, + 'specified' => $dom->specified, + 'value' => $dom->value, + 'ownerElement' => $dom->ownerElement, + 'schemaTypeInfo' => $dom->schemaTypeInfo, + ]; + + return $a; + } + + public static function castElement(\DOMElement $dom, array $a, Stub $stub, $isNested) + { + $a += [ + 'tagName' => $dom->tagName, + 'schemaTypeInfo' => $dom->schemaTypeInfo, + ]; + + return $a; + } + + public static function castText(\DOMText $dom, array $a, Stub $stub, $isNested) + { + $a += [ + 'wholeText' => $dom->wholeText, + ]; + + return $a; + } + + public static function castTypeinfo(\DOMTypeinfo $dom, array $a, Stub $stub, $isNested) + { + $a += [ + 'typeName' => $dom->typeName, + 'typeNamespace' => $dom->typeNamespace, + ]; + + return $a; + } + + public static function castDomError(\DOMDomError $dom, array $a, Stub $stub, $isNested) + { + $a += [ + 'severity' => $dom->severity, + 'message' => $dom->message, + 'type' => $dom->type, + 'relatedException' => $dom->relatedException, + 'related_data' => $dom->related_data, + 'location' => $dom->location, + ]; + + return $a; + } + + public static function castLocator(\DOMLocator $dom, array $a, Stub $stub, $isNested) + { + $a += [ + 'lineNumber' => $dom->lineNumber, + 'columnNumber' => $dom->columnNumber, + 'offset' => $dom->offset, + 'relatedNode' => $dom->relatedNode, + 'uri' => $dom->uri ? new LinkStub($dom->uri, $dom->lineNumber) : $dom->uri, + ]; + + return $a; + } + + public static function castDocumentType(\DOMDocumentType $dom, array $a, Stub $stub, $isNested) + { + $a += [ + 'name' => $dom->name, + 'entities' => $dom->entities, + 'notations' => $dom->notations, + 'publicId' => $dom->publicId, + 'systemId' => $dom->systemId, + 'internalSubset' => $dom->internalSubset, + ]; + + return $a; + } + + public static function castNotation(\DOMNotation $dom, array $a, Stub $stub, $isNested) + { + $a += [ + 'publicId' => $dom->publicId, + 'systemId' => $dom->systemId, + ]; + + return $a; + } + + public static function castEntity(\DOMEntity $dom, array $a, Stub $stub, $isNested) + { + $a += [ + 'publicId' => $dom->publicId, + 'systemId' => $dom->systemId, + 'notationName' => $dom->notationName, + 'actualEncoding' => $dom->actualEncoding, + 'encoding' => $dom->encoding, + 'version' => $dom->version, + ]; + + return $a; + } + + public static function castProcessingInstruction(\DOMProcessingInstruction $dom, array $a, Stub $stub, $isNested) + { + $a += [ + 'target' => $dom->target, + 'data' => $dom->data, + ]; + + return $a; + } + + public static function castXPath(\DOMXPath $dom, array $a, Stub $stub, $isNested) + { + $a += [ + 'document' => $dom->document, + ]; + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Caster/DateCaster.php b/vendor/symfony/var-dumper/Caster/DateCaster.php new file mode 100644 index 000000000..171fbde55 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/DateCaster.php @@ -0,0 +1,128 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts DateTimeInterface related classes to array representation. + * + * @author Dany Maillard + * + * @final since Symfony 4.4 + */ +class DateCaster +{ + private const PERIOD_LIMIT = 3; + + public static function castDateTime(\DateTimeInterface $d, array $a, Stub $stub, $isNested, $filter) + { + $prefix = Caster::PREFIX_VIRTUAL; + $location = $d->getTimezone()->getLocation(); + $fromNow = (new \DateTime())->diff($d); + + $title = $d->format('l, F j, Y') + ."\n".self::formatInterval($fromNow).' from now' + .($location ? ($d->format('I') ? "\nDST On" : "\nDST Off") : '') + ; + + unset( + $a[Caster::PREFIX_DYNAMIC.'date'], + $a[Caster::PREFIX_DYNAMIC.'timezone'], + $a[Caster::PREFIX_DYNAMIC.'timezone_type'] + ); + $a[$prefix.'date'] = new ConstStub(self::formatDateTime($d, $location ? ' e (P)' : ' P'), $title); + + $stub->class .= $d->format(' @U'); + + return $a; + } + + public static function castInterval(\DateInterval $interval, array $a, Stub $stub, $isNested, $filter) + { + $now = new \DateTimeImmutable(); + $numberOfSeconds = $now->add($interval)->getTimestamp() - $now->getTimestamp(); + $title = number_format($numberOfSeconds, 0, '.', ' ').'s'; + + $i = [Caster::PREFIX_VIRTUAL.'interval' => new ConstStub(self::formatInterval($interval), $title)]; + + return $filter & Caster::EXCLUDE_VERBOSE ? $i : $i + $a; + } + + private static function formatInterval(\DateInterval $i): string + { + $format = '%R '; + + if (0 === $i->y && 0 === $i->m && ($i->h >= 24 || $i->i >= 60 || $i->s >= 60)) { + $i = date_diff($d = new \DateTime(), date_add(clone $d, $i)); // recalculate carry over points + $format .= 0 < $i->days ? '%ad ' : ''; + } else { + $format .= ($i->y ? '%yy ' : '').($i->m ? '%mm ' : '').($i->d ? '%dd ' : ''); + } + + $format .= $i->h || $i->i || $i->s || $i->f ? '%H:%I:'.self::formatSeconds($i->s, substr($i->f, 2)) : ''; + $format = '%R ' === $format ? '0s' : $format; + + return $i->format(rtrim($format)); + } + + public static function castTimeZone(\DateTimeZone $timeZone, array $a, Stub $stub, $isNested, $filter) + { + $location = $timeZone->getLocation(); + $formatted = (new \DateTime('now', $timeZone))->format($location ? 'e (P)' : 'P'); + $title = $location && \extension_loaded('intl') ? \Locale::getDisplayRegion('-'.$location['country_code']) : ''; + + $z = [Caster::PREFIX_VIRTUAL.'timezone' => new ConstStub($formatted, $title)]; + + return $filter & Caster::EXCLUDE_VERBOSE ? $z : $z + $a; + } + + public static function castPeriod(\DatePeriod $p, array $a, Stub $stub, $isNested, $filter) + { + $dates = []; + if (\PHP_VERSION_ID >= 70107) { // see https://bugs.php.net/74639 + foreach (clone $p as $i => $d) { + if (self::PERIOD_LIMIT === $i) { + $now = new \DateTimeImmutable('now', new \DateTimeZone('UTC')); + $dates[] = sprintf('%s more', ($end = $p->getEndDate()) + ? ceil(($end->format('U.u') - $d->format('U.u')) / ((int) $now->add($p->getDateInterval())->format('U.u') - (int) $now->format('U.u'))) + : $p->recurrences - $i + ); + break; + } + $dates[] = sprintf('%s) %s', $i + 1, self::formatDateTime($d)); + } + } + + $period = sprintf( + 'every %s, from %s (%s) %s', + self::formatInterval($p->getDateInterval()), + self::formatDateTime($p->getStartDate()), + $p->include_start_date ? 'included' : 'excluded', + ($end = $p->getEndDate()) ? 'to '.self::formatDateTime($end) : 'recurring '.$p->recurrences.' time/s' + ); + + $p = [Caster::PREFIX_VIRTUAL.'period' => new ConstStub($period, implode("\n", $dates))]; + + return $filter & Caster::EXCLUDE_VERBOSE ? $p : $p + $a; + } + + private static function formatDateTime(\DateTimeInterface $d, string $extra = ''): string + { + return $d->format('Y-m-d H:i:'.self::formatSeconds($d->format('s'), $d->format('u')).$extra); + } + + private static function formatSeconds(string $s, string $us): string + { + return sprintf('%02d.%s', $s, 0 === ($len = \strlen($t = rtrim($us, '0'))) ? '0' : ($len <= 3 ? str_pad($t, 3, '0') : $us)); + } +} diff --git a/vendor/symfony/var-dumper/Caster/DoctrineCaster.php b/vendor/symfony/var-dumper/Caster/DoctrineCaster.php new file mode 100644 index 000000000..7409508b0 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/DoctrineCaster.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Doctrine\Common\Proxy\Proxy as CommonProxy; +use Doctrine\ORM\PersistentCollection; +use Doctrine\ORM\Proxy\Proxy as OrmProxy; +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts Doctrine related classes to array representation. + * + * @author Nicolas Grekas + * + * @final since Symfony 4.4 + */ +class DoctrineCaster +{ + public static function castCommonProxy(CommonProxy $proxy, array $a, Stub $stub, $isNested) + { + foreach (['__cloner__', '__initializer__'] as $k) { + if (\array_key_exists($k, $a)) { + unset($a[$k]); + ++$stub->cut; + } + } + + return $a; + } + + public static function castOrmProxy(OrmProxy $proxy, array $a, Stub $stub, $isNested) + { + foreach (['_entityPersister', '_identifier'] as $k) { + if (\array_key_exists($k = "\0Doctrine\\ORM\\Proxy\\Proxy\0".$k, $a)) { + unset($a[$k]); + ++$stub->cut; + } + } + + return $a; + } + + public static function castPersistentCollection(PersistentCollection $coll, array $a, Stub $stub, $isNested) + { + foreach (['snapshot', 'association', 'typeClass'] as $k) { + if (\array_key_exists($k = "\0Doctrine\\ORM\\PersistentCollection\0".$k, $a)) { + $a[$k] = new CutStub($a[$k]); + } + } + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Caster/DsCaster.php b/vendor/symfony/var-dumper/Caster/DsCaster.php new file mode 100644 index 000000000..11423c9b2 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/DsCaster.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Ds\Collection; +use Ds\Map; +use Ds\Pair; +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts Ds extension classes to array representation. + * + * @author Jáchym Toušek + * + * @final since Symfony 4.4 + */ +class DsCaster +{ + public static function castCollection(Collection $c, array $a, Stub $stub, bool $isNested): array + { + $a[Caster::PREFIX_VIRTUAL.'count'] = $c->count(); + $a[Caster::PREFIX_VIRTUAL.'capacity'] = $c->capacity(); + + if (!$c instanceof Map) { + $a += $c->toArray(); + } + + return $a; + } + + public static function castMap(Map $c, array $a, Stub $stub, bool $isNested): array + { + foreach ($c as $k => $v) { + $a[] = new DsPairStub($k, $v); + } + + return $a; + } + + public static function castPair(Pair $c, array $a, Stub $stub, bool $isNested): array + { + foreach ($c->toArray() as $k => $v) { + $a[Caster::PREFIX_VIRTUAL.$k] = $v; + } + + return $a; + } + + public static function castPairStub(DsPairStub $c, array $a, Stub $stub, bool $isNested): array + { + if ($isNested) { + $stub->class = Pair::class; + $stub->value = null; + $stub->handle = 0; + + $a = $c->value; + } + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Caster/DsPairStub.php b/vendor/symfony/var-dumper/Caster/DsPairStub.php new file mode 100644 index 000000000..a1dcc1561 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/DsPairStub.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * @author Nicolas Grekas + */ +class DsPairStub extends Stub +{ + public function __construct($key, $value) + { + $this->value = [ + Caster::PREFIX_VIRTUAL.'key' => $key, + Caster::PREFIX_VIRTUAL.'value' => $value, + ]; + } +} diff --git a/vendor/symfony/var-dumper/Caster/EnumStub.php b/vendor/symfony/var-dumper/Caster/EnumStub.php new file mode 100644 index 000000000..7a4e98a21 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/EnumStub.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Represents an enumeration of values. + * + * @author Nicolas Grekas + */ +class EnumStub extends Stub +{ + public $dumpKeys = true; + + public function __construct(array $values, bool $dumpKeys = true) + { + $this->value = $values; + $this->dumpKeys = $dumpKeys; + } +} diff --git a/vendor/symfony/var-dumper/Caster/ExceptionCaster.php b/vendor/symfony/var-dumper/Caster/ExceptionCaster.php new file mode 100644 index 000000000..3ea17526c --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/ExceptionCaster.php @@ -0,0 +1,382 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\ErrorHandler\Exception\SilencedErrorContext; +use Symfony\Component\VarDumper\Cloner\Stub; +use Symfony\Component\VarDumper\Exception\ThrowingCasterException; + +/** + * Casts common Exception classes to array representation. + * + * @author Nicolas Grekas + * + * @final since Symfony 4.4 + */ +class ExceptionCaster +{ + public static $srcContext = 1; + public static $traceArgs = true; + public static $errorTypes = [ + \E_DEPRECATED => 'E_DEPRECATED', + \E_USER_DEPRECATED => 'E_USER_DEPRECATED', + \E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR', + \E_ERROR => 'E_ERROR', + \E_WARNING => 'E_WARNING', + \E_PARSE => 'E_PARSE', + \E_NOTICE => 'E_NOTICE', + \E_CORE_ERROR => 'E_CORE_ERROR', + \E_CORE_WARNING => 'E_CORE_WARNING', + \E_COMPILE_ERROR => 'E_COMPILE_ERROR', + \E_COMPILE_WARNING => 'E_COMPILE_WARNING', + \E_USER_ERROR => 'E_USER_ERROR', + \E_USER_WARNING => 'E_USER_WARNING', + \E_USER_NOTICE => 'E_USER_NOTICE', + \E_STRICT => 'E_STRICT', + ]; + + private static $framesCache = []; + + public static function castError(\Error $e, array $a, Stub $stub, $isNested, $filter = 0) + { + return self::filterExceptionArray($stub->class, $a, "\0Error\0", $filter); + } + + public static function castException(\Exception $e, array $a, Stub $stub, $isNested, $filter = 0) + { + return self::filterExceptionArray($stub->class, $a, "\0Exception\0", $filter); + } + + public static function castErrorException(\ErrorException $e, array $a, Stub $stub, $isNested) + { + if (isset($a[$s = Caster::PREFIX_PROTECTED.'severity'], self::$errorTypes[$a[$s]])) { + $a[$s] = new ConstStub(self::$errorTypes[$a[$s]], $a[$s]); + } + + return $a; + } + + public static function castThrowingCasterException(ThrowingCasterException $e, array $a, Stub $stub, $isNested) + { + $trace = Caster::PREFIX_VIRTUAL.'trace'; + $prefix = Caster::PREFIX_PROTECTED; + $xPrefix = "\0Exception\0"; + + if (isset($a[$xPrefix.'previous'], $a[$trace]) && $a[$xPrefix.'previous'] instanceof \Exception) { + $b = (array) $a[$xPrefix.'previous']; + $class = get_debug_type($a[$xPrefix.'previous']); + self::traceUnshift($b[$xPrefix.'trace'], $class, $b[$prefix.'file'], $b[$prefix.'line']); + $a[$trace] = new TraceStub($b[$xPrefix.'trace'], false, 0, -\count($a[$trace]->value)); + } + + unset($a[$xPrefix.'previous'], $a[$prefix.'code'], $a[$prefix.'file'], $a[$prefix.'line']); + + return $a; + } + + public static function castSilencedErrorContext(SilencedErrorContext $e, array $a, Stub $stub, $isNested) + { + $sPrefix = "\0".SilencedErrorContext::class."\0"; + + if (!isset($a[$s = $sPrefix.'severity'])) { + return $a; + } + + if (isset(self::$errorTypes[$a[$s]])) { + $a[$s] = new ConstStub(self::$errorTypes[$a[$s]], $a[$s]); + } + + $trace = [[ + 'file' => $a[$sPrefix.'file'], + 'line' => $a[$sPrefix.'line'], + ]]; + + if (isset($a[$sPrefix.'trace'])) { + $trace = array_merge($trace, $a[$sPrefix.'trace']); + } + + unset($a[$sPrefix.'file'], $a[$sPrefix.'line'], $a[$sPrefix.'trace']); + $a[Caster::PREFIX_VIRTUAL.'trace'] = new TraceStub($trace, self::$traceArgs); + + return $a; + } + + public static function castTraceStub(TraceStub $trace, array $a, Stub $stub, $isNested) + { + if (!$isNested) { + return $a; + } + $stub->class = ''; + $stub->handle = 0; + $frames = $trace->value; + $prefix = Caster::PREFIX_VIRTUAL; + + $a = []; + $j = \count($frames); + if (0 > $i = $trace->sliceOffset) { + $i = max(0, $j + $i); + } + if (!isset($trace->value[$i])) { + return []; + } + $lastCall = isset($frames[$i]['function']) ? (isset($frames[$i]['class']) ? $frames[0]['class'].$frames[$i]['type'] : '').$frames[$i]['function'].'()' : ''; + $frames[] = ['function' => '']; + $collapse = false; + + for ($j += $trace->numberingOffset - $i++; isset($frames[$i]); ++$i, --$j) { + $f = $frames[$i]; + $call = isset($f['function']) ? (isset($f['class']) ? $f['class'].$f['type'] : '').$f['function'] : '???'; + + $frame = new FrameStub( + [ + 'object' => $f['object'] ?? null, + 'class' => $f['class'] ?? null, + 'type' => $f['type'] ?? null, + 'function' => $f['function'] ?? null, + ] + $frames[$i - 1], + false, + true + ); + $f = self::castFrameStub($frame, [], $frame, true); + if (isset($f[$prefix.'src'])) { + foreach ($f[$prefix.'src']->value as $label => $frame) { + if (0 === strpos($label, "\0~collapse=0")) { + if ($collapse) { + $label = substr_replace($label, '1', 11, 1); + } else { + $collapse = true; + } + } + $label = substr_replace($label, "title=Stack level $j.&", 2, 0); + } + $f = $frames[$i - 1]; + if ($trace->keepArgs && !empty($f['args']) && $frame instanceof EnumStub) { + $frame->value['arguments'] = new ArgsStub($f['args'], $f['function'] ?? null, $f['class'] ?? null); + } + } elseif ('???' !== $lastCall) { + $label = new ClassStub($lastCall); + if (isset($label->attr['ellipsis'])) { + $label->attr['ellipsis'] += 2; + $label = substr_replace($prefix, "ellipsis-type=class&ellipsis={$label->attr['ellipsis']}&ellipsis-tail=1&title=Stack level $j.", 2, 0).$label->value.'()'; + } else { + $label = substr_replace($prefix, "title=Stack level $j.", 2, 0).$label->value.'()'; + } + } else { + $label = substr_replace($prefix, "title=Stack level $j.", 2, 0).$lastCall; + } + $a[substr_replace($label, sprintf('separator=%s&', $frame instanceof EnumStub ? ' ' : ':'), 2, 0)] = $frame; + + $lastCall = $call; + } + if (null !== $trace->sliceLength) { + $a = \array_slice($a, 0, $trace->sliceLength, true); + } + + return $a; + } + + public static function castFrameStub(FrameStub $frame, array $a, Stub $stub, $isNested) + { + if (!$isNested) { + return $a; + } + $f = $frame->value; + $prefix = Caster::PREFIX_VIRTUAL; + + if (isset($f['file'], $f['line'])) { + $cacheKey = $f; + unset($cacheKey['object'], $cacheKey['args']); + $cacheKey[] = self::$srcContext; + $cacheKey = implode('-', $cacheKey); + + if (isset(self::$framesCache[$cacheKey])) { + $a[$prefix.'src'] = self::$framesCache[$cacheKey]; + } else { + if (preg_match('/\((\d+)\)(?:\([\da-f]{32}\))? : (?:eval\(\)\'d code|runtime-created function)$/', $f['file'], $match)) { + $f['file'] = substr($f['file'], 0, -\strlen($match[0])); + $f['line'] = (int) $match[1]; + } + $src = $f['line']; + $srcKey = $f['file']; + $ellipsis = new LinkStub($srcKey, 0); + $srcAttr = 'collapse='.(int) $ellipsis->inVendor; + $ellipsisTail = $ellipsis->attr['ellipsis-tail'] ?? 0; + $ellipsis = $ellipsis->attr['ellipsis'] ?? 0; + + if (file_exists($f['file']) && 0 <= self::$srcContext) { + if (!empty($f['class']) && (is_subclass_of($f['class'], 'Twig\Template') || is_subclass_of($f['class'], 'Twig_Template')) && method_exists($f['class'], 'getDebugInfo')) { + $template = $f['object'] ?? unserialize(sprintf('O:%d:"%s":0:{}', \strlen($f['class']), $f['class'])); + + $ellipsis = 0; + $templateSrc = method_exists($template, 'getSourceContext') ? $template->getSourceContext()->getCode() : (method_exists($template, 'getSource') ? $template->getSource() : ''); + $templateInfo = $template->getDebugInfo(); + if (isset($templateInfo[$f['line']])) { + if (!method_exists($template, 'getSourceContext') || !file_exists($templatePath = $template->getSourceContext()->getPath())) { + $templatePath = null; + } + if ($templateSrc) { + $src = self::extractSource($templateSrc, $templateInfo[$f['line']], self::$srcContext, 'twig', $templatePath, $f); + $srcKey = ($templatePath ?: $template->getTemplateName()).':'.$templateInfo[$f['line']]; + } + } + } + if ($srcKey == $f['file']) { + $src = self::extractSource(file_get_contents($f['file']), $f['line'], self::$srcContext, 'php', $f['file'], $f); + $srcKey .= ':'.$f['line']; + if ($ellipsis) { + $ellipsis += 1 + \strlen($f['line']); + } + } + $srcAttr .= sprintf('&separator= &file=%s&line=%d', rawurlencode($f['file']), $f['line']); + } else { + $srcAttr .= '&separator=:'; + } + $srcAttr .= $ellipsis ? '&ellipsis-type=path&ellipsis='.$ellipsis.'&ellipsis-tail='.$ellipsisTail : ''; + self::$framesCache[$cacheKey] = $a[$prefix.'src'] = new EnumStub(["\0~$srcAttr\0$srcKey" => $src]); + } + } + + unset($a[$prefix.'args'], $a[$prefix.'line'], $a[$prefix.'file']); + if ($frame->inTraceStub) { + unset($a[$prefix.'class'], $a[$prefix.'type'], $a[$prefix.'function']); + } + foreach ($a as $k => $v) { + if (!$v) { + unset($a[$k]); + } + } + if ($frame->keepArgs && !empty($f['args'])) { + $a[$prefix.'arguments'] = new ArgsStub($f['args'], $f['function'], $f['class']); + } + + return $a; + } + + private static function filterExceptionArray(string $xClass, array $a, string $xPrefix, int $filter): array + { + if (isset($a[$xPrefix.'trace'])) { + $trace = $a[$xPrefix.'trace']; + unset($a[$xPrefix.'trace']); // Ensures the trace is always last + } else { + $trace = []; + } + + if (!($filter & Caster::EXCLUDE_VERBOSE) && $trace) { + if (isset($a[Caster::PREFIX_PROTECTED.'file'], $a[Caster::PREFIX_PROTECTED.'line'])) { + self::traceUnshift($trace, $xClass, $a[Caster::PREFIX_PROTECTED.'file'], $a[Caster::PREFIX_PROTECTED.'line']); + } + $a[Caster::PREFIX_VIRTUAL.'trace'] = new TraceStub($trace, self::$traceArgs); + } + if (empty($a[$xPrefix.'previous'])) { + unset($a[$xPrefix.'previous']); + } + unset($a[$xPrefix.'string'], $a[Caster::PREFIX_DYNAMIC.'xdebug_message'], $a[Caster::PREFIX_DYNAMIC.'__destructorException']); + + if (isset($a[Caster::PREFIX_PROTECTED.'message']) && false !== strpos($a[Caster::PREFIX_PROTECTED.'message'], "@anonymous\0")) { + $a[Caster::PREFIX_PROTECTED.'message'] = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)[0-9a-fA-F]++/', function ($m) { + return class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0]; + }, $a[Caster::PREFIX_PROTECTED.'message']); + } + + if (isset($a[Caster::PREFIX_PROTECTED.'file'], $a[Caster::PREFIX_PROTECTED.'line'])) { + $a[Caster::PREFIX_PROTECTED.'file'] = new LinkStub($a[Caster::PREFIX_PROTECTED.'file'], $a[Caster::PREFIX_PROTECTED.'line']); + } + + return $a; + } + + private static function traceUnshift(array &$trace, ?string $class, string $file, int $line): void + { + if (isset($trace[0]['file'], $trace[0]['line']) && $trace[0]['file'] === $file && $trace[0]['line'] === $line) { + return; + } + array_unshift($trace, [ + 'function' => $class ? 'new '.$class : null, + 'file' => $file, + 'line' => $line, + ]); + } + + private static function extractSource(string $srcLines, int $line, int $srcContext, string $lang, ?string $file, array $frame): EnumStub + { + $srcLines = explode("\n", $srcLines); + $src = []; + + for ($i = $line - 1 - $srcContext; $i <= $line - 1 + $srcContext; ++$i) { + $src[] = ($srcLines[$i] ?? '')."\n"; + } + + if ($frame['function'] ?? false) { + $stub = new CutStub(new \stdClass()); + $stub->class = (isset($frame['class']) ? $frame['class'].$frame['type'] : '').$frame['function']; + $stub->type = Stub::TYPE_OBJECT; + $stub->attr['cut_hash'] = true; + $stub->attr['file'] = $frame['file']; + $stub->attr['line'] = $frame['line']; + + try { + $caller = isset($frame['class']) ? new \ReflectionMethod($frame['class'], $frame['function']) : new \ReflectionFunction($frame['function']); + $stub->class .= ReflectionCaster::getSignature(ReflectionCaster::castFunctionAbstract($caller, [], $stub, true, Caster::EXCLUDE_VERBOSE)); + + if ($f = $caller->getFileName()) { + $stub->attr['file'] = $f; + $stub->attr['line'] = $caller->getStartLine(); + } + } catch (\ReflectionException $e) { + // ignore fake class/function + } + + $srcLines = ["\0~separator=\0" => $stub]; + } else { + $stub = null; + $srcLines = []; + } + + $ltrim = 0; + do { + $pad = null; + for ($i = $srcContext << 1; $i >= 0; --$i) { + if (isset($src[$i][$ltrim]) && "\r" !== ($c = $src[$i][$ltrim]) && "\n" !== $c) { + if (null === $pad) { + $pad = $c; + } + if ((' ' !== $c && "\t" !== $c) || $pad !== $c) { + break; + } + } + } + ++$ltrim; + } while (0 > $i && null !== $pad); + + --$ltrim; + + foreach ($src as $i => $c) { + if ($ltrim) { + $c = isset($c[$ltrim]) && "\r" !== $c[$ltrim] ? substr($c, $ltrim) : ltrim($c, " \t"); + } + $c = substr($c, 0, -1); + if ($i !== $srcContext) { + $c = new ConstStub('default', $c); + } else { + $c = new ConstStub($c, $stub ? 'in '.$stub->class : ''); + if (null !== $file) { + $c->attr['file'] = $file; + $c->attr['line'] = $line; + } + } + $c->attr['lang'] = $lang; + $srcLines[sprintf("\0~separator=› &%d\0", $i + $line - $srcContext)] = $c; + } + + return new EnumStub($srcLines); + } +} diff --git a/vendor/symfony/var-dumper/Caster/FrameStub.php b/vendor/symfony/var-dumper/Caster/FrameStub.php new file mode 100644 index 000000000..878675528 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/FrameStub.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +/** + * Represents a single backtrace frame as returned by debug_backtrace() or Exception->getTrace(). + * + * @author Nicolas Grekas + */ +class FrameStub extends EnumStub +{ + public $keepArgs; + public $inTraceStub; + + public function __construct(array $frame, bool $keepArgs = true, bool $inTraceStub = false) + { + $this->value = $frame; + $this->keepArgs = $keepArgs; + $this->inTraceStub = $inTraceStub; + } +} diff --git a/vendor/symfony/var-dumper/Caster/GmpCaster.php b/vendor/symfony/var-dumper/Caster/GmpCaster.php new file mode 100644 index 000000000..2b20e15dc --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/GmpCaster.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts GMP objects to array representation. + * + * @author Hamza Amrouche + * @author Nicolas Grekas + * + * @final since Symfony 4.4 + */ +class GmpCaster +{ + public static function castGmp(\GMP $gmp, array $a, Stub $stub, $isNested, $filter): array + { + $a[Caster::PREFIX_VIRTUAL.'value'] = new ConstStub(gmp_strval($gmp), gmp_strval($gmp)); + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Caster/ImagineCaster.php b/vendor/symfony/var-dumper/Caster/ImagineCaster.php new file mode 100644 index 000000000..d1289da33 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/ImagineCaster.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Imagine\Image\ImageInterface; +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * @author Grégoire Pineau + */ +final class ImagineCaster +{ + public static function castImage(ImageInterface $c, array $a, Stub $stub, bool $isNested): array + { + $imgData = $c->get('png'); + if (\strlen($imgData) > 1 * 1000 * 1000) { + $a += [ + Caster::PREFIX_VIRTUAL.'image' => new ConstStub($c->getSize()), + ]; + } else { + $a += [ + Caster::PREFIX_VIRTUAL.'image' => new ImgStub($imgData, 'image/png', $c->getSize()), + ]; + } + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Caster/ImgStub.php b/vendor/symfony/var-dumper/Caster/ImgStub.php new file mode 100644 index 000000000..05789fe33 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/ImgStub.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +/** + * @author Grégoire Pineau + */ +class ImgStub extends ConstStub +{ + public function __construct(string $data, string $contentType, string $size) + { + $this->value = ''; + $this->attr['img-data'] = $data; + $this->attr['img-size'] = $size; + $this->attr['content-type'] = $contentType; + } +} diff --git a/vendor/symfony/var-dumper/Caster/IntlCaster.php b/vendor/symfony/var-dumper/Caster/IntlCaster.php new file mode 100644 index 000000000..d7099cb18 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/IntlCaster.php @@ -0,0 +1,172 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * @author Nicolas Grekas + * @author Jan Schädlich + * + * @final since Symfony 4.4 + */ +class IntlCaster +{ + public static function castMessageFormatter(\MessageFormatter $c, array $a, Stub $stub, $isNested) + { + $a += [ + Caster::PREFIX_VIRTUAL.'locale' => $c->getLocale(), + Caster::PREFIX_VIRTUAL.'pattern' => $c->getPattern(), + ]; + + return self::castError($c, $a); + } + + public static function castNumberFormatter(\NumberFormatter $c, array $a, Stub $stub, $isNested, $filter = 0) + { + $a += [ + Caster::PREFIX_VIRTUAL.'locale' => $c->getLocale(), + Caster::PREFIX_VIRTUAL.'pattern' => $c->getPattern(), + ]; + + if ($filter & Caster::EXCLUDE_VERBOSE) { + $stub->cut += 3; + + return self::castError($c, $a); + } + + $a += [ + Caster::PREFIX_VIRTUAL.'attributes' => new EnumStub( + [ + 'PARSE_INT_ONLY' => $c->getAttribute(\NumberFormatter::PARSE_INT_ONLY), + 'GROUPING_USED' => $c->getAttribute(\NumberFormatter::GROUPING_USED), + 'DECIMAL_ALWAYS_SHOWN' => $c->getAttribute(\NumberFormatter::DECIMAL_ALWAYS_SHOWN), + 'MAX_INTEGER_DIGITS' => $c->getAttribute(\NumberFormatter::MAX_INTEGER_DIGITS), + 'MIN_INTEGER_DIGITS' => $c->getAttribute(\NumberFormatter::MIN_INTEGER_DIGITS), + 'INTEGER_DIGITS' => $c->getAttribute(\NumberFormatter::INTEGER_DIGITS), + 'MAX_FRACTION_DIGITS' => $c->getAttribute(\NumberFormatter::MAX_FRACTION_DIGITS), + 'MIN_FRACTION_DIGITS' => $c->getAttribute(\NumberFormatter::MIN_FRACTION_DIGITS), + 'FRACTION_DIGITS' => $c->getAttribute(\NumberFormatter::FRACTION_DIGITS), + 'MULTIPLIER' => $c->getAttribute(\NumberFormatter::MULTIPLIER), + 'GROUPING_SIZE' => $c->getAttribute(\NumberFormatter::GROUPING_SIZE), + 'ROUNDING_MODE' => $c->getAttribute(\NumberFormatter::ROUNDING_MODE), + 'ROUNDING_INCREMENT' => $c->getAttribute(\NumberFormatter::ROUNDING_INCREMENT), + 'FORMAT_WIDTH' => $c->getAttribute(\NumberFormatter::FORMAT_WIDTH), + 'PADDING_POSITION' => $c->getAttribute(\NumberFormatter::PADDING_POSITION), + 'SECONDARY_GROUPING_SIZE' => $c->getAttribute(\NumberFormatter::SECONDARY_GROUPING_SIZE), + 'SIGNIFICANT_DIGITS_USED' => $c->getAttribute(\NumberFormatter::SIGNIFICANT_DIGITS_USED), + 'MIN_SIGNIFICANT_DIGITS' => $c->getAttribute(\NumberFormatter::MIN_SIGNIFICANT_DIGITS), + 'MAX_SIGNIFICANT_DIGITS' => $c->getAttribute(\NumberFormatter::MAX_SIGNIFICANT_DIGITS), + 'LENIENT_PARSE' => $c->getAttribute(\NumberFormatter::LENIENT_PARSE), + ] + ), + Caster::PREFIX_VIRTUAL.'text_attributes' => new EnumStub( + [ + 'POSITIVE_PREFIX' => $c->getTextAttribute(\NumberFormatter::POSITIVE_PREFIX), + 'POSITIVE_SUFFIX' => $c->getTextAttribute(\NumberFormatter::POSITIVE_SUFFIX), + 'NEGATIVE_PREFIX' => $c->getTextAttribute(\NumberFormatter::NEGATIVE_PREFIX), + 'NEGATIVE_SUFFIX' => $c->getTextAttribute(\NumberFormatter::NEGATIVE_SUFFIX), + 'PADDING_CHARACTER' => $c->getTextAttribute(\NumberFormatter::PADDING_CHARACTER), + 'CURRENCY_CODE' => $c->getTextAttribute(\NumberFormatter::CURRENCY_CODE), + 'DEFAULT_RULESET' => $c->getTextAttribute(\NumberFormatter::DEFAULT_RULESET), + 'PUBLIC_RULESETS' => $c->getTextAttribute(\NumberFormatter::PUBLIC_RULESETS), + ] + ), + Caster::PREFIX_VIRTUAL.'symbols' => new EnumStub( + [ + 'DECIMAL_SEPARATOR_SYMBOL' => $c->getSymbol(\NumberFormatter::DECIMAL_SEPARATOR_SYMBOL), + 'GROUPING_SEPARATOR_SYMBOL' => $c->getSymbol(\NumberFormatter::GROUPING_SEPARATOR_SYMBOL), + 'PATTERN_SEPARATOR_SYMBOL' => $c->getSymbol(\NumberFormatter::PATTERN_SEPARATOR_SYMBOL), + 'PERCENT_SYMBOL' => $c->getSymbol(\NumberFormatter::PERCENT_SYMBOL), + 'ZERO_DIGIT_SYMBOL' => $c->getSymbol(\NumberFormatter::ZERO_DIGIT_SYMBOL), + 'DIGIT_SYMBOL' => $c->getSymbol(\NumberFormatter::DIGIT_SYMBOL), + 'MINUS_SIGN_SYMBOL' => $c->getSymbol(\NumberFormatter::MINUS_SIGN_SYMBOL), + 'PLUS_SIGN_SYMBOL' => $c->getSymbol(\NumberFormatter::PLUS_SIGN_SYMBOL), + 'CURRENCY_SYMBOL' => $c->getSymbol(\NumberFormatter::CURRENCY_SYMBOL), + 'INTL_CURRENCY_SYMBOL' => $c->getSymbol(\NumberFormatter::INTL_CURRENCY_SYMBOL), + 'MONETARY_SEPARATOR_SYMBOL' => $c->getSymbol(\NumberFormatter::MONETARY_SEPARATOR_SYMBOL), + 'EXPONENTIAL_SYMBOL' => $c->getSymbol(\NumberFormatter::EXPONENTIAL_SYMBOL), + 'PERMILL_SYMBOL' => $c->getSymbol(\NumberFormatter::PERMILL_SYMBOL), + 'PAD_ESCAPE_SYMBOL' => $c->getSymbol(\NumberFormatter::PAD_ESCAPE_SYMBOL), + 'INFINITY_SYMBOL' => $c->getSymbol(\NumberFormatter::INFINITY_SYMBOL), + 'NAN_SYMBOL' => $c->getSymbol(\NumberFormatter::NAN_SYMBOL), + 'SIGNIFICANT_DIGIT_SYMBOL' => $c->getSymbol(\NumberFormatter::SIGNIFICANT_DIGIT_SYMBOL), + 'MONETARY_GROUPING_SEPARATOR_SYMBOL' => $c->getSymbol(\NumberFormatter::MONETARY_GROUPING_SEPARATOR_SYMBOL), + ] + ), + ]; + + return self::castError($c, $a); + } + + public static function castIntlTimeZone(\IntlTimeZone $c, array $a, Stub $stub, $isNested) + { + $a += [ + Caster::PREFIX_VIRTUAL.'display_name' => $c->getDisplayName(), + Caster::PREFIX_VIRTUAL.'id' => $c->getID(), + Caster::PREFIX_VIRTUAL.'raw_offset' => $c->getRawOffset(), + ]; + + if ($c->useDaylightTime()) { + $a += [ + Caster::PREFIX_VIRTUAL.'dst_savings' => $c->getDSTSavings(), + ]; + } + + return self::castError($c, $a); + } + + public static function castIntlCalendar(\IntlCalendar $c, array $a, Stub $stub, $isNested, $filter = 0) + { + $a += [ + Caster::PREFIX_VIRTUAL.'type' => $c->getType(), + Caster::PREFIX_VIRTUAL.'first_day_of_week' => $c->getFirstDayOfWeek(), + Caster::PREFIX_VIRTUAL.'minimal_days_in_first_week' => $c->getMinimalDaysInFirstWeek(), + Caster::PREFIX_VIRTUAL.'repeated_wall_time_option' => $c->getRepeatedWallTimeOption(), + Caster::PREFIX_VIRTUAL.'skipped_wall_time_option' => $c->getSkippedWallTimeOption(), + Caster::PREFIX_VIRTUAL.'time' => $c->getTime(), + Caster::PREFIX_VIRTUAL.'in_daylight_time' => $c->inDaylightTime(), + Caster::PREFIX_VIRTUAL.'is_lenient' => $c->isLenient(), + Caster::PREFIX_VIRTUAL.'time_zone' => ($filter & Caster::EXCLUDE_VERBOSE) ? new CutStub($c->getTimeZone()) : $c->getTimeZone(), + ]; + + return self::castError($c, $a); + } + + public static function castIntlDateFormatter(\IntlDateFormatter $c, array $a, Stub $stub, $isNested, $filter = 0) + { + $a += [ + Caster::PREFIX_VIRTUAL.'locale' => $c->getLocale(), + Caster::PREFIX_VIRTUAL.'pattern' => $c->getPattern(), + Caster::PREFIX_VIRTUAL.'calendar' => $c->getCalendar(), + Caster::PREFIX_VIRTUAL.'time_zone_id' => $c->getTimeZoneId(), + Caster::PREFIX_VIRTUAL.'time_type' => $c->getTimeType(), + Caster::PREFIX_VIRTUAL.'date_type' => $c->getDateType(), + Caster::PREFIX_VIRTUAL.'calendar_object' => ($filter & Caster::EXCLUDE_VERBOSE) ? new CutStub($c->getCalendarObject()) : $c->getCalendarObject(), + Caster::PREFIX_VIRTUAL.'time_zone' => ($filter & Caster::EXCLUDE_VERBOSE) ? new CutStub($c->getTimeZone()) : $c->getTimeZone(), + ]; + + return self::castError($c, $a); + } + + private static function castError($c, array $a): array + { + if ($errorCode = $c->getErrorCode()) { + $a += [ + Caster::PREFIX_VIRTUAL.'error_code' => $errorCode, + Caster::PREFIX_VIRTUAL.'error_message' => $c->getErrorMessage(), + ]; + } + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Caster/LinkStub.php b/vendor/symfony/var-dumper/Caster/LinkStub.php new file mode 100644 index 000000000..6360716d7 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/LinkStub.php @@ -0,0 +1,108 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +/** + * Represents a file or a URL. + * + * @author Nicolas Grekas + */ +class LinkStub extends ConstStub +{ + public $inVendor = false; + + private static $vendorRoots; + private static $composerRoots; + + public function __construct($label, int $line = 0, $href = null) + { + $this->value = $label; + + if (null === $href) { + $href = $label; + } + if (!\is_string($href)) { + return; + } + if (0 === strpos($href, 'file://')) { + if ($href === $label) { + $label = substr($label, 7); + } + $href = substr($href, 7); + } elseif (false !== strpos($href, '://')) { + $this->attr['href'] = $href; + + return; + } + if (!file_exists($href)) { + return; + } + if ($line) { + $this->attr['line'] = $line; + } + if ($label !== $this->attr['file'] = realpath($href) ?: $href) { + return; + } + if ($composerRoot = $this->getComposerRoot($href, $this->inVendor)) { + $this->attr['ellipsis'] = \strlen($href) - \strlen($composerRoot) + 1; + $this->attr['ellipsis-type'] = 'path'; + $this->attr['ellipsis-tail'] = 1 + ($this->inVendor ? 2 + \strlen(implode('', \array_slice(explode(\DIRECTORY_SEPARATOR, substr($href, 1 - $this->attr['ellipsis'])), 0, 2))) : 0); + } elseif (3 < \count($ellipsis = explode(\DIRECTORY_SEPARATOR, $href))) { + $this->attr['ellipsis'] = 2 + \strlen(implode('', \array_slice($ellipsis, -2))); + $this->attr['ellipsis-type'] = 'path'; + $this->attr['ellipsis-tail'] = 1; + } + } + + private function getComposerRoot(string $file, bool &$inVendor) + { + if (null === self::$vendorRoots) { + self::$vendorRoots = []; + + foreach (get_declared_classes() as $class) { + if ('C' === $class[0] && 0 === strpos($class, 'ComposerAutoloaderInit')) { + $r = new \ReflectionClass($class); + $v = \dirname($r->getFileName(), 2); + if (file_exists($v.'/composer/installed.json')) { + self::$vendorRoots[] = $v.\DIRECTORY_SEPARATOR; + } + } + } + } + $inVendor = false; + + if (isset(self::$composerRoots[$dir = \dirname($file)])) { + return self::$composerRoots[$dir]; + } + + foreach (self::$vendorRoots as $root) { + if ($inVendor = 0 === strpos($file, $root)) { + return $root; + } + } + + $parent = $dir; + while (!@file_exists($parent.'/composer.json')) { + if (!@file_exists($parent)) { + // open_basedir restriction in effect + break; + } + if ($parent === \dirname($parent)) { + return self::$composerRoots[$dir] = false; + } + + $parent = \dirname($parent); + } + + return self::$composerRoots[$dir] = $parent.\DIRECTORY_SEPARATOR; + } +} diff --git a/vendor/symfony/var-dumper/Caster/MemcachedCaster.php b/vendor/symfony/var-dumper/Caster/MemcachedCaster.php new file mode 100644 index 000000000..942eecb11 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/MemcachedCaster.php @@ -0,0 +1,81 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * @author Jan Schädlich + * + * @final since Symfony 4.4 + */ +class MemcachedCaster +{ + private static $optionConstants; + private static $defaultOptions; + + public static function castMemcached(\Memcached $c, array $a, Stub $stub, $isNested) + { + $a += [ + Caster::PREFIX_VIRTUAL.'servers' => $c->getServerList(), + Caster::PREFIX_VIRTUAL.'options' => new EnumStub( + self::getNonDefaultOptions($c) + ), + ]; + + return $a; + } + + private static function getNonDefaultOptions(\Memcached $c): array + { + self::$defaultOptions = self::$defaultOptions ?? self::discoverDefaultOptions(); + self::$optionConstants = self::$optionConstants ?? self::getOptionConstants(); + + $nonDefaultOptions = []; + foreach (self::$optionConstants as $constantKey => $value) { + if (self::$defaultOptions[$constantKey] !== $option = $c->getOption($value)) { + $nonDefaultOptions[$constantKey] = $option; + } + } + + return $nonDefaultOptions; + } + + private static function discoverDefaultOptions(): array + { + $defaultMemcached = new \Memcached(); + $defaultMemcached->addServer('127.0.0.1', 11211); + + $defaultOptions = []; + self::$optionConstants = self::$optionConstants ?? self::getOptionConstants(); + + foreach (self::$optionConstants as $constantKey => $value) { + $defaultOptions[$constantKey] = $defaultMemcached->getOption($value); + } + + return $defaultOptions; + } + + private static function getOptionConstants(): array + { + $reflectedMemcached = new \ReflectionClass(\Memcached::class); + + $optionConstants = []; + foreach ($reflectedMemcached->getConstants() as $constantKey => $value) { + if (0 === strpos($constantKey, 'OPT_')) { + $optionConstants[$constantKey] = $value; + } + } + + return $optionConstants; + } +} diff --git a/vendor/symfony/var-dumper/Caster/PdoCaster.php b/vendor/symfony/var-dumper/Caster/PdoCaster.php new file mode 100644 index 000000000..47b0a62b7 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/PdoCaster.php @@ -0,0 +1,122 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts PDO related classes to array representation. + * + * @author Nicolas Grekas + * + * @final since Symfony 4.4 + */ +class PdoCaster +{ + private const PDO_ATTRIBUTES = [ + 'CASE' => [ + \PDO::CASE_LOWER => 'LOWER', + \PDO::CASE_NATURAL => 'NATURAL', + \PDO::CASE_UPPER => 'UPPER', + ], + 'ERRMODE' => [ + \PDO::ERRMODE_SILENT => 'SILENT', + \PDO::ERRMODE_WARNING => 'WARNING', + \PDO::ERRMODE_EXCEPTION => 'EXCEPTION', + ], + 'TIMEOUT', + 'PREFETCH', + 'AUTOCOMMIT', + 'PERSISTENT', + 'DRIVER_NAME', + 'SERVER_INFO', + 'ORACLE_NULLS' => [ + \PDO::NULL_NATURAL => 'NATURAL', + \PDO::NULL_EMPTY_STRING => 'EMPTY_STRING', + \PDO::NULL_TO_STRING => 'TO_STRING', + ], + 'CLIENT_VERSION', + 'SERVER_VERSION', + 'STATEMENT_CLASS', + 'EMULATE_PREPARES', + 'CONNECTION_STATUS', + 'STRINGIFY_FETCHES', + 'DEFAULT_FETCH_MODE' => [ + \PDO::FETCH_ASSOC => 'ASSOC', + \PDO::FETCH_BOTH => 'BOTH', + \PDO::FETCH_LAZY => 'LAZY', + \PDO::FETCH_NUM => 'NUM', + \PDO::FETCH_OBJ => 'OBJ', + ], + ]; + + public static function castPdo(\PDO $c, array $a, Stub $stub, $isNested) + { + $attr = []; + $errmode = $c->getAttribute(\PDO::ATTR_ERRMODE); + $c->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); + + foreach (self::PDO_ATTRIBUTES as $k => $v) { + if (!isset($k[0])) { + $k = $v; + $v = []; + } + + try { + $attr[$k] = 'ERRMODE' === $k ? $errmode : $c->getAttribute(\constant('PDO::ATTR_'.$k)); + if ($v && isset($v[$attr[$k]])) { + $attr[$k] = new ConstStub($v[$attr[$k]], $attr[$k]); + } + } catch (\Exception $e) { + } + } + if (isset($attr[$k = 'STATEMENT_CLASS'][1])) { + if ($attr[$k][1]) { + $attr[$k][1] = new ArgsStub($attr[$k][1], '__construct', $attr[$k][0]); + } + $attr[$k][0] = new ClassStub($attr[$k][0]); + } + + $prefix = Caster::PREFIX_VIRTUAL; + $a += [ + $prefix.'inTransaction' => method_exists($c, 'inTransaction'), + $prefix.'errorInfo' => $c->errorInfo(), + $prefix.'attributes' => new EnumStub($attr), + ]; + + if ($a[$prefix.'inTransaction']) { + $a[$prefix.'inTransaction'] = $c->inTransaction(); + } else { + unset($a[$prefix.'inTransaction']); + } + + if (!isset($a[$prefix.'errorInfo'][1], $a[$prefix.'errorInfo'][2])) { + unset($a[$prefix.'errorInfo']); + } + + $c->setAttribute(\PDO::ATTR_ERRMODE, $errmode); + + return $a; + } + + public static function castPdoStatement(\PDOStatement $c, array $a, Stub $stub, $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + $a[$prefix.'errorInfo'] = $c->errorInfo(); + + if (!isset($a[$prefix.'errorInfo'][1], $a[$prefix.'errorInfo'][2])) { + unset($a[$prefix.'errorInfo']); + } + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Caster/PgSqlCaster.php b/vendor/symfony/var-dumper/Caster/PgSqlCaster.php new file mode 100644 index 000000000..3097c5184 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/PgSqlCaster.php @@ -0,0 +1,156 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts pqsql resources to array representation. + * + * @author Nicolas Grekas + * + * @final since Symfony 4.4 + */ +class PgSqlCaster +{ + private const PARAM_CODES = [ + 'server_encoding', + 'client_encoding', + 'is_superuser', + 'session_authorization', + 'DateStyle', + 'TimeZone', + 'IntervalStyle', + 'integer_datetimes', + 'application_name', + 'standard_conforming_strings', + ]; + + private const TRANSACTION_STATUS = [ + \PGSQL_TRANSACTION_IDLE => 'PGSQL_TRANSACTION_IDLE', + \PGSQL_TRANSACTION_ACTIVE => 'PGSQL_TRANSACTION_ACTIVE', + \PGSQL_TRANSACTION_INTRANS => 'PGSQL_TRANSACTION_INTRANS', + \PGSQL_TRANSACTION_INERROR => 'PGSQL_TRANSACTION_INERROR', + \PGSQL_TRANSACTION_UNKNOWN => 'PGSQL_TRANSACTION_UNKNOWN', + ]; + + private const RESULT_STATUS = [ + \PGSQL_EMPTY_QUERY => 'PGSQL_EMPTY_QUERY', + \PGSQL_COMMAND_OK => 'PGSQL_COMMAND_OK', + \PGSQL_TUPLES_OK => 'PGSQL_TUPLES_OK', + \PGSQL_COPY_OUT => 'PGSQL_COPY_OUT', + \PGSQL_COPY_IN => 'PGSQL_COPY_IN', + \PGSQL_BAD_RESPONSE => 'PGSQL_BAD_RESPONSE', + \PGSQL_NONFATAL_ERROR => 'PGSQL_NONFATAL_ERROR', + \PGSQL_FATAL_ERROR => 'PGSQL_FATAL_ERROR', + ]; + + private const DIAG_CODES = [ + 'severity' => \PGSQL_DIAG_SEVERITY, + 'sqlstate' => \PGSQL_DIAG_SQLSTATE, + 'message' => \PGSQL_DIAG_MESSAGE_PRIMARY, + 'detail' => \PGSQL_DIAG_MESSAGE_DETAIL, + 'hint' => \PGSQL_DIAG_MESSAGE_HINT, + 'statement position' => \PGSQL_DIAG_STATEMENT_POSITION, + 'internal position' => \PGSQL_DIAG_INTERNAL_POSITION, + 'internal query' => \PGSQL_DIAG_INTERNAL_QUERY, + 'context' => \PGSQL_DIAG_CONTEXT, + 'file' => \PGSQL_DIAG_SOURCE_FILE, + 'line' => \PGSQL_DIAG_SOURCE_LINE, + 'function' => \PGSQL_DIAG_SOURCE_FUNCTION, + ]; + + public static function castLargeObject($lo, array $a, Stub $stub, $isNested) + { + $a['seek position'] = pg_lo_tell($lo); + + return $a; + } + + public static function castLink($link, array $a, Stub $stub, $isNested) + { + $a['status'] = pg_connection_status($link); + $a['status'] = new ConstStub(\PGSQL_CONNECTION_OK === $a['status'] ? 'PGSQL_CONNECTION_OK' : 'PGSQL_CONNECTION_BAD', $a['status']); + $a['busy'] = pg_connection_busy($link); + + $a['transaction'] = pg_transaction_status($link); + if (isset(self::TRANSACTION_STATUS[$a['transaction']])) { + $a['transaction'] = new ConstStub(self::TRANSACTION_STATUS[$a['transaction']], $a['transaction']); + } + + $a['pid'] = pg_get_pid($link); + $a['last error'] = pg_last_error($link); + $a['last notice'] = pg_last_notice($link); + $a['host'] = pg_host($link); + $a['port'] = pg_port($link); + $a['dbname'] = pg_dbname($link); + $a['options'] = pg_options($link); + $a['version'] = pg_version($link); + + foreach (self::PARAM_CODES as $v) { + if (false !== $s = pg_parameter_status($link, $v)) { + $a['param'][$v] = $s; + } + } + + $a['param']['client_encoding'] = pg_client_encoding($link); + $a['param'] = new EnumStub($a['param']); + + return $a; + } + + public static function castResult($result, array $a, Stub $stub, $isNested) + { + $a['num rows'] = pg_num_rows($result); + $a['status'] = pg_result_status($result); + if (isset(self::RESULT_STATUS[$a['status']])) { + $a['status'] = new ConstStub(self::RESULT_STATUS[$a['status']], $a['status']); + } + $a['command-completion tag'] = pg_result_status($result, \PGSQL_STATUS_STRING); + + if (-1 === $a['num rows']) { + foreach (self::DIAG_CODES as $k => $v) { + $a['error'][$k] = pg_result_error_field($result, $v); + } + } + + $a['affected rows'] = pg_affected_rows($result); + $a['last OID'] = pg_last_oid($result); + + $fields = pg_num_fields($result); + + for ($i = 0; $i < $fields; ++$i) { + $field = [ + 'name' => pg_field_name($result, $i), + 'table' => sprintf('%s (OID: %s)', pg_field_table($result, $i), pg_field_table($result, $i, true)), + 'type' => sprintf('%s (OID: %s)', pg_field_type($result, $i), pg_field_type_oid($result, $i)), + 'nullable' => (bool) pg_field_is_null($result, $i), + 'storage' => pg_field_size($result, $i).' bytes', + 'display' => pg_field_prtlen($result, $i).' chars', + ]; + if (' (OID: )' === $field['table']) { + $field['table'] = null; + } + if ('-1 bytes' === $field['storage']) { + $field['storage'] = 'variable size'; + } elseif ('1 bytes' === $field['storage']) { + $field['storage'] = '1 byte'; + } + if ('1 chars' === $field['display']) { + $field['display'] = '1 char'; + } + $a['fields'][] = new EnumStub($field); + } + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Caster/ProxyManagerCaster.php b/vendor/symfony/var-dumper/Caster/ProxyManagerCaster.php new file mode 100644 index 000000000..ec02f8137 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/ProxyManagerCaster.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use ProxyManager\Proxy\ProxyInterface; +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * @author Nicolas Grekas + * + * @final since Symfony 4.4 + */ +class ProxyManagerCaster +{ + public static function castProxy(ProxyInterface $c, array $a, Stub $stub, $isNested) + { + if ($parent = get_parent_class($c)) { + $stub->class .= ' - '.$parent; + } + $stub->class .= '@proxy'; + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Caster/RedisCaster.php b/vendor/symfony/var-dumper/Caster/RedisCaster.php new file mode 100644 index 000000000..bd877cb3e --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/RedisCaster.php @@ -0,0 +1,152 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts Redis class from ext-redis to array representation. + * + * @author Nicolas Grekas + * + * @final since Symfony 4.4 + */ +class RedisCaster +{ + private const SERIALIZERS = [ + \Redis::SERIALIZER_NONE => 'NONE', + \Redis::SERIALIZER_PHP => 'PHP', + 2 => 'IGBINARY', // Optional Redis::SERIALIZER_IGBINARY + ]; + + private const MODES = [ + \Redis::ATOMIC => 'ATOMIC', + \Redis::MULTI => 'MULTI', + \Redis::PIPELINE => 'PIPELINE', + ]; + + private const COMPRESSION_MODES = [ + 0 => 'NONE', // Redis::COMPRESSION_NONE + 1 => 'LZF', // Redis::COMPRESSION_LZF + ]; + + private const FAILOVER_OPTIONS = [ + \RedisCluster::FAILOVER_NONE => 'NONE', + \RedisCluster::FAILOVER_ERROR => 'ERROR', + \RedisCluster::FAILOVER_DISTRIBUTE => 'DISTRIBUTE', + \RedisCluster::FAILOVER_DISTRIBUTE_SLAVES => 'DISTRIBUTE_SLAVES', + ]; + + public static function castRedis(\Redis $c, array $a, Stub $stub, $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + + if (!$connected = $c->isConnected()) { + return $a + [ + $prefix.'isConnected' => $connected, + ]; + } + + $mode = $c->getMode(); + + return $a + [ + $prefix.'isConnected' => $connected, + $prefix.'host' => $c->getHost(), + $prefix.'port' => $c->getPort(), + $prefix.'auth' => $c->getAuth(), + $prefix.'mode' => isset(self::MODES[$mode]) ? new ConstStub(self::MODES[$mode], $mode) : $mode, + $prefix.'dbNum' => $c->getDbNum(), + $prefix.'timeout' => $c->getTimeout(), + $prefix.'lastError' => $c->getLastError(), + $prefix.'persistentId' => $c->getPersistentID(), + $prefix.'options' => self::getRedisOptions($c), + ]; + } + + public static function castRedisArray(\RedisArray $c, array $a, Stub $stub, $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + + return $a + [ + $prefix.'hosts' => $c->_hosts(), + $prefix.'function' => ClassStub::wrapCallable($c->_function()), + $prefix.'lastError' => $c->getLastError(), + $prefix.'options' => self::getRedisOptions($c), + ]; + } + + public static function castRedisCluster(\RedisCluster $c, array $a, Stub $stub, $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + $failover = $c->getOption(\RedisCluster::OPT_SLAVE_FAILOVER); + + $a += [ + $prefix.'_masters' => $c->_masters(), + $prefix.'_redir' => $c->_redir(), + $prefix.'mode' => new ConstStub($c->getMode() ? 'MULTI' : 'ATOMIC', $c->getMode()), + $prefix.'lastError' => $c->getLastError(), + $prefix.'options' => self::getRedisOptions($c, [ + 'SLAVE_FAILOVER' => isset(self::FAILOVER_OPTIONS[$failover]) ? new ConstStub(self::FAILOVER_OPTIONS[$failover], $failover) : $failover, + ]), + ]; + + return $a; + } + + /** + * @param \Redis|\RedisArray|\RedisCluster $redis + */ + private static function getRedisOptions($redis, array $options = []): EnumStub + { + $serializer = $redis->getOption(\Redis::OPT_SERIALIZER); + if (\is_array($serializer)) { + foreach ($serializer as &$v) { + if (isset(self::SERIALIZERS[$v])) { + $v = new ConstStub(self::SERIALIZERS[$v], $v); + } + } + } elseif (isset(self::SERIALIZERS[$serializer])) { + $serializer = new ConstStub(self::SERIALIZERS[$serializer], $serializer); + } + + $compression = \defined('Redis::OPT_COMPRESSION') ? $redis->getOption(\Redis::OPT_COMPRESSION) : 0; + if (\is_array($compression)) { + foreach ($compression as &$v) { + if (isset(self::COMPRESSION_MODES[$v])) { + $v = new ConstStub(self::COMPRESSION_MODES[$v], $v); + } + } + } elseif (isset(self::COMPRESSION_MODES[$compression])) { + $compression = new ConstStub(self::COMPRESSION_MODES[$compression], $compression); + } + + $retry = \defined('Redis::OPT_SCAN') ? $redis->getOption(\Redis::OPT_SCAN) : 0; + if (\is_array($retry)) { + foreach ($retry as &$v) { + $v = new ConstStub($v ? 'RETRY' : 'NORETRY', $v); + } + } else { + $retry = new ConstStub($retry ? 'RETRY' : 'NORETRY', $retry); + } + + $options += [ + 'TCP_KEEPALIVE' => \defined('Redis::OPT_TCP_KEEPALIVE') ? $redis->getOption(\Redis::OPT_TCP_KEEPALIVE) : 0, + 'READ_TIMEOUT' => $redis->getOption(\Redis::OPT_READ_TIMEOUT), + 'COMPRESSION' => $compression, + 'SERIALIZER' => $serializer, + 'PREFIX' => $redis->getOption(\Redis::OPT_PREFIX), + 'SCAN' => $retry, + ]; + + return new EnumStub($options); + } +} diff --git a/vendor/symfony/var-dumper/Caster/ReflectionCaster.php b/vendor/symfony/var-dumper/Caster/ReflectionCaster.php new file mode 100644 index 000000000..95c1dbf6f --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/ReflectionCaster.php @@ -0,0 +1,401 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts Reflector related classes to array representation. + * + * @author Nicolas Grekas + * + * @final since Symfony 4.4 + */ +class ReflectionCaster +{ + public const UNSET_CLOSURE_FILE_INFO = ['Closure' => __CLASS__.'::unsetClosureFileInfo']; + + private const EXTRA_MAP = [ + 'docComment' => 'getDocComment', + 'extension' => 'getExtensionName', + 'isDisabled' => 'isDisabled', + 'isDeprecated' => 'isDeprecated', + 'isInternal' => 'isInternal', + 'isUserDefined' => 'isUserDefined', + 'isGenerator' => 'isGenerator', + 'isVariadic' => 'isVariadic', + ]; + + public static function castClosure(\Closure $c, array $a, Stub $stub, $isNested, $filter = 0) + { + $prefix = Caster::PREFIX_VIRTUAL; + $c = new \ReflectionFunction($c); + + $a = static::castFunctionAbstract($c, $a, $stub, $isNested, $filter); + + if (false === strpos($c->name, '{closure}')) { + $stub->class = isset($a[$prefix.'class']) ? $a[$prefix.'class']->value.'::'.$c->name : $c->name; + unset($a[$prefix.'class']); + } + unset($a[$prefix.'extra']); + + $stub->class .= self::getSignature($a); + + if ($f = $c->getFileName()) { + $stub->attr['file'] = $f; + $stub->attr['line'] = $c->getStartLine(); + } + + unset($a[$prefix.'parameters']); + + if ($filter & Caster::EXCLUDE_VERBOSE) { + $stub->cut += ($c->getFileName() ? 2 : 0) + \count($a); + + return []; + } + + if ($f) { + $a[$prefix.'file'] = new LinkStub($f, $c->getStartLine()); + $a[$prefix.'line'] = $c->getStartLine().' to '.$c->getEndLine(); + } + + return $a; + } + + public static function unsetClosureFileInfo(\Closure $c, array $a) + { + unset($a[Caster::PREFIX_VIRTUAL.'file'], $a[Caster::PREFIX_VIRTUAL.'line']); + + return $a; + } + + public static function castGenerator(\Generator $c, array $a, Stub $stub, $isNested) + { + // Cannot create ReflectionGenerator based on a terminated Generator + try { + $reflectionGenerator = new \ReflectionGenerator($c); + } catch (\Exception $e) { + $a[Caster::PREFIX_VIRTUAL.'closed'] = true; + + return $a; + } + + return self::castReflectionGenerator($reflectionGenerator, $a, $stub, $isNested); + } + + public static function castType(\ReflectionType $c, array $a, Stub $stub, $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + + if ($c instanceof \ReflectionNamedType || \PHP_VERSION_ID < 80000) { + $a += [ + $prefix.'name' => $c instanceof \ReflectionNamedType ? $c->getName() : (string) $c, + $prefix.'allowsNull' => $c->allowsNull(), + $prefix.'isBuiltin' => $c->isBuiltin(), + ]; + } elseif ($c instanceof \ReflectionUnionType) { + $a[$prefix.'allowsNull'] = $c->allowsNull(); + self::addMap($a, $c, [ + 'types' => 'getTypes', + ]); + } else { + $a[$prefix.'allowsNull'] = $c->allowsNull(); + } + + return $a; + } + + public static function castReflectionGenerator(\ReflectionGenerator $c, array $a, Stub $stub, $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + + if ($c->getThis()) { + $a[$prefix.'this'] = new CutStub($c->getThis()); + } + $function = $c->getFunction(); + $frame = [ + 'class' => $function->class ?? null, + 'type' => isset($function->class) ? ($function->isStatic() ? '::' : '->') : null, + 'function' => $function->name, + 'file' => $c->getExecutingFile(), + 'line' => $c->getExecutingLine(), + ]; + if ($trace = $c->getTrace(\DEBUG_BACKTRACE_IGNORE_ARGS)) { + $function = new \ReflectionGenerator($c->getExecutingGenerator()); + array_unshift($trace, [ + 'function' => 'yield', + 'file' => $function->getExecutingFile(), + 'line' => $function->getExecutingLine() - 1, + ]); + $trace[] = $frame; + $a[$prefix.'trace'] = new TraceStub($trace, false, 0, -1, -1); + } else { + $function = new FrameStub($frame, false, true); + $function = ExceptionCaster::castFrameStub($function, [], $function, true); + $a[$prefix.'executing'] = $function[$prefix.'src']; + } + + $a[Caster::PREFIX_VIRTUAL.'closed'] = false; + + return $a; + } + + public static function castClass(\ReflectionClass $c, array $a, Stub $stub, $isNested, $filter = 0) + { + $prefix = Caster::PREFIX_VIRTUAL; + + if ($n = \Reflection::getModifierNames($c->getModifiers())) { + $a[$prefix.'modifiers'] = implode(' ', $n); + } + + self::addMap($a, $c, [ + 'extends' => 'getParentClass', + 'implements' => 'getInterfaceNames', + 'constants' => 'getConstants', + ]); + + foreach ($c->getProperties() as $n) { + $a[$prefix.'properties'][$n->name] = $n; + } + + foreach ($c->getMethods() as $n) { + $a[$prefix.'methods'][$n->name] = $n; + } + + if (!($filter & Caster::EXCLUDE_VERBOSE) && !$isNested) { + self::addExtra($a, $c); + } + + return $a; + } + + public static function castFunctionAbstract(\ReflectionFunctionAbstract $c, array $a, Stub $stub, $isNested, $filter = 0) + { + $prefix = Caster::PREFIX_VIRTUAL; + + self::addMap($a, $c, [ + 'returnsReference' => 'returnsReference', + 'returnType' => 'getReturnType', + 'class' => 'getClosureScopeClass', + 'this' => 'getClosureThis', + ]); + + if (isset($a[$prefix.'returnType'])) { + $v = $a[$prefix.'returnType']; + $v = $v instanceof \ReflectionNamedType ? $v->getName() : (string) $v; + $a[$prefix.'returnType'] = new ClassStub($a[$prefix.'returnType'] instanceof \ReflectionNamedType && $a[$prefix.'returnType']->allowsNull() && 'mixed' !== $v ? '?'.$v : $v, [class_exists($v, false) || interface_exists($v, false) || trait_exists($v, false) ? $v : '', '']); + } + if (isset($a[$prefix.'class'])) { + $a[$prefix.'class'] = new ClassStub($a[$prefix.'class']); + } + if (isset($a[$prefix.'this'])) { + $a[$prefix.'this'] = new CutStub($a[$prefix.'this']); + } + + foreach ($c->getParameters() as $v) { + $k = '$'.$v->name; + if ($v->isVariadic()) { + $k = '...'.$k; + } + if ($v->isPassedByReference()) { + $k = '&'.$k; + } + $a[$prefix.'parameters'][$k] = $v; + } + if (isset($a[$prefix.'parameters'])) { + $a[$prefix.'parameters'] = new EnumStub($a[$prefix.'parameters']); + } + + if (!($filter & Caster::EXCLUDE_VERBOSE) && $v = $c->getStaticVariables()) { + foreach ($v as $k => &$v) { + if (\is_object($v)) { + $a[$prefix.'use']['$'.$k] = new CutStub($v); + } else { + $a[$prefix.'use']['$'.$k] = &$v; + } + } + unset($v); + $a[$prefix.'use'] = new EnumStub($a[$prefix.'use']); + } + + if (!($filter & Caster::EXCLUDE_VERBOSE) && !$isNested) { + self::addExtra($a, $c); + } + + return $a; + } + + public static function castMethod(\ReflectionMethod $c, array $a, Stub $stub, $isNested) + { + $a[Caster::PREFIX_VIRTUAL.'modifiers'] = implode(' ', \Reflection::getModifierNames($c->getModifiers())); + + return $a; + } + + public static function castParameter(\ReflectionParameter $c, array $a, Stub $stub, $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + + self::addMap($a, $c, [ + 'position' => 'getPosition', + 'isVariadic' => 'isVariadic', + 'byReference' => 'isPassedByReference', + 'allowsNull' => 'allowsNull', + ]); + + if ($v = $c->getType()) { + $a[$prefix.'typeHint'] = $v instanceof \ReflectionNamedType ? $v->getName() : (string) $v; + } + + if (isset($a[$prefix.'typeHint'])) { + $v = $a[$prefix.'typeHint']; + $a[$prefix.'typeHint'] = new ClassStub($v, [class_exists($v, false) || interface_exists($v, false) || trait_exists($v, false) ? $v : '', '']); + } else { + unset($a[$prefix.'allowsNull']); + } + + try { + $a[$prefix.'default'] = $v = $c->getDefaultValue(); + if ($c->isDefaultValueConstant()) { + $a[$prefix.'default'] = new ConstStub($c->getDefaultValueConstantName(), $v); + } + if (null === $v) { + unset($a[$prefix.'allowsNull']); + } + } catch (\ReflectionException $e) { + } + + return $a; + } + + public static function castProperty(\ReflectionProperty $c, array $a, Stub $stub, $isNested) + { + $a[Caster::PREFIX_VIRTUAL.'modifiers'] = implode(' ', \Reflection::getModifierNames($c->getModifiers())); + self::addExtra($a, $c); + + return $a; + } + + public static function castReference(\ReflectionReference $c, array $a, Stub $stub, $isNested) + { + $a[Caster::PREFIX_VIRTUAL.'id'] = $c->getId(); + + return $a; + } + + public static function castExtension(\ReflectionExtension $c, array $a, Stub $stub, $isNested) + { + self::addMap($a, $c, [ + 'version' => 'getVersion', + 'dependencies' => 'getDependencies', + 'iniEntries' => 'getIniEntries', + 'isPersistent' => 'isPersistent', + 'isTemporary' => 'isTemporary', + 'constants' => 'getConstants', + 'functions' => 'getFunctions', + 'classes' => 'getClasses', + ]); + + return $a; + } + + public static function castZendExtension(\ReflectionZendExtension $c, array $a, Stub $stub, $isNested) + { + self::addMap($a, $c, [ + 'version' => 'getVersion', + 'author' => 'getAuthor', + 'copyright' => 'getCopyright', + 'url' => 'getURL', + ]); + + return $a; + } + + public static function getSignature(array $a) + { + $prefix = Caster::PREFIX_VIRTUAL; + $signature = ''; + + if (isset($a[$prefix.'parameters'])) { + foreach ($a[$prefix.'parameters']->value as $k => $param) { + $signature .= ', '; + if ($type = $param->getType()) { + if (!$type instanceof \ReflectionNamedType) { + $signature .= $type.' '; + } else { + if (!$param->isOptional() && $param->allowsNull() && 'mixed' !== $type->getName()) { + $signature .= '?'; + } + $signature .= substr(strrchr('\\'.$type->getName(), '\\'), 1).' '; + } + } + $signature .= $k; + + if (!$param->isDefaultValueAvailable()) { + continue; + } + $v = $param->getDefaultValue(); + $signature .= ' = '; + + if ($param->isDefaultValueConstant()) { + $signature .= substr(strrchr('\\'.$param->getDefaultValueConstantName(), '\\'), 1); + } elseif (null === $v) { + $signature .= 'null'; + } elseif (\is_array($v)) { + $signature .= $v ? '[…'.\count($v).']' : '[]'; + } elseif (\is_string($v)) { + $signature .= 10 > \strlen($v) && false === strpos($v, '\\') ? "'{$v}'" : "'…".\strlen($v)."'"; + } elseif (\is_bool($v)) { + $signature .= $v ? 'true' : 'false'; + } else { + $signature .= $v; + } + } + } + $signature = (empty($a[$prefix.'returnsReference']) ? '' : '&').'('.substr($signature, 2).')'; + + if (isset($a[$prefix.'returnType'])) { + $signature .= ': '.substr(strrchr('\\'.$a[$prefix.'returnType'], '\\'), 1); + } + + return $signature; + } + + private static function addExtra(array &$a, \Reflector $c) + { + $x = isset($a[Caster::PREFIX_VIRTUAL.'extra']) ? $a[Caster::PREFIX_VIRTUAL.'extra']->value : []; + + if (method_exists($c, 'getFileName') && $m = $c->getFileName()) { + $x['file'] = new LinkStub($m, $c->getStartLine()); + $x['line'] = $c->getStartLine().' to '.$c->getEndLine(); + } + + self::addMap($x, $c, self::EXTRA_MAP, ''); + + if ($x) { + $a[Caster::PREFIX_VIRTUAL.'extra'] = new EnumStub($x); + } + } + + private static function addMap(array &$a, $c, array $map, string $prefix = Caster::PREFIX_VIRTUAL) + { + foreach ($map as $k => $m) { + if (\PHP_VERSION_ID >= 80000 && 'isDisabled' === $k) { + continue; + } + + if (method_exists($c, $m) && false !== ($m = $c->$m()) && null !== $m) { + $a[$prefix.$k] = $m instanceof \Reflector ? $m->name : $m; + } + } + } +} diff --git a/vendor/symfony/var-dumper/Caster/ResourceCaster.php b/vendor/symfony/var-dumper/Caster/ResourceCaster.php new file mode 100644 index 000000000..5a7c42852 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/ResourceCaster.php @@ -0,0 +1,105 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts common resource types to array representation. + * + * @author Nicolas Grekas + * + * @final since Symfony 4.4 + */ +class ResourceCaster +{ + /** + * @param \CurlHandle|resource $h + * + * @return array + */ + public static function castCurl($h, array $a, Stub $stub, $isNested) + { + return curl_getinfo($h); + } + + public static function castDba($dba, array $a, Stub $stub, $isNested) + { + $list = dba_list(); + $a['file'] = $list[(int) $dba]; + + return $a; + } + + public static function castProcess($process, array $a, Stub $stub, $isNested) + { + return proc_get_status($process); + } + + public static function castStream($stream, array $a, Stub $stub, $isNested) + { + $a = stream_get_meta_data($stream) + static::castStreamContext($stream, $a, $stub, $isNested); + if (isset($a['uri'])) { + $a['uri'] = new LinkStub($a['uri']); + } + + return $a; + } + + public static function castStreamContext($stream, array $a, Stub $stub, $isNested) + { + return @stream_context_get_params($stream) ?: $a; + } + + public static function castGd($gd, array $a, Stub $stub, $isNested) + { + $a['size'] = imagesx($gd).'x'.imagesy($gd); + $a['trueColor'] = imageistruecolor($gd); + + return $a; + } + + public static function castMysqlLink($h, array $a, Stub $stub, $isNested) + { + $a['host'] = mysql_get_host_info($h); + $a['protocol'] = mysql_get_proto_info($h); + $a['server'] = mysql_get_server_info($h); + + return $a; + } + + public static function castOpensslX509($h, array $a, Stub $stub, $isNested) + { + $stub->cut = -1; + $info = openssl_x509_parse($h, false); + + $pin = openssl_pkey_get_public($h); + $pin = openssl_pkey_get_details($pin)['key']; + $pin = \array_slice(explode("\n", $pin), 1, -2); + $pin = base64_decode(implode('', $pin)); + $pin = base64_encode(hash('sha256', $pin, true)); + + $a += [ + 'subject' => new EnumStub(array_intersect_key($info['subject'], ['organizationName' => true, 'commonName' => true])), + 'issuer' => new EnumStub(array_intersect_key($info['issuer'], ['organizationName' => true, 'commonName' => true])), + 'expiry' => new ConstStub(date(\DateTime::ISO8601, $info['validTo_time_t']), $info['validTo_time_t']), + 'fingerprint' => new EnumStub([ + 'md5' => new ConstStub(wordwrap(strtoupper(openssl_x509_fingerprint($h, 'md5')), 2, ':', true)), + 'sha1' => new ConstStub(wordwrap(strtoupper(openssl_x509_fingerprint($h, 'sha1')), 2, ':', true)), + 'sha256' => new ConstStub(wordwrap(strtoupper(openssl_x509_fingerprint($h, 'sha256')), 2, ':', true)), + 'pin-sha256' => new ConstStub($pin), + ]), + ]; + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Caster/SplCaster.php b/vendor/symfony/var-dumper/Caster/SplCaster.php new file mode 100644 index 000000000..5abc51a9f --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/SplCaster.php @@ -0,0 +1,245 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts SPL related classes to array representation. + * + * @author Nicolas Grekas + * + * @final since Symfony 4.4 + */ +class SplCaster +{ + private const SPL_FILE_OBJECT_FLAGS = [ + \SplFileObject::DROP_NEW_LINE => 'DROP_NEW_LINE', + \SplFileObject::READ_AHEAD => 'READ_AHEAD', + \SplFileObject::SKIP_EMPTY => 'SKIP_EMPTY', + \SplFileObject::READ_CSV => 'READ_CSV', + ]; + + public static function castArrayObject(\ArrayObject $c, array $a, Stub $stub, $isNested) + { + return self::castSplArray($c, $a, $stub, $isNested); + } + + public static function castArrayIterator(\ArrayIterator $c, array $a, Stub $stub, $isNested) + { + return self::castSplArray($c, $a, $stub, $isNested); + } + + public static function castHeap(\Iterator $c, array $a, Stub $stub, $isNested) + { + $a += [ + Caster::PREFIX_VIRTUAL.'heap' => iterator_to_array(clone $c), + ]; + + return $a; + } + + public static function castDoublyLinkedList(\SplDoublyLinkedList $c, array $a, Stub $stub, $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + $mode = $c->getIteratorMode(); + $c->setIteratorMode(\SplDoublyLinkedList::IT_MODE_KEEP | $mode & ~\SplDoublyLinkedList::IT_MODE_DELETE); + + $a += [ + $prefix.'mode' => new ConstStub((($mode & \SplDoublyLinkedList::IT_MODE_LIFO) ? 'IT_MODE_LIFO' : 'IT_MODE_FIFO').' | '.(($mode & \SplDoublyLinkedList::IT_MODE_DELETE) ? 'IT_MODE_DELETE' : 'IT_MODE_KEEP'), $mode), + $prefix.'dllist' => iterator_to_array($c), + ]; + $c->setIteratorMode($mode); + + return $a; + } + + public static function castFileInfo(\SplFileInfo $c, array $a, Stub $stub, $isNested) + { + static $map = [ + 'path' => 'getPath', + 'filename' => 'getFilename', + 'basename' => 'getBasename', + 'pathname' => 'getPathname', + 'extension' => 'getExtension', + 'realPath' => 'getRealPath', + 'aTime' => 'getATime', + 'mTime' => 'getMTime', + 'cTime' => 'getCTime', + 'inode' => 'getInode', + 'size' => 'getSize', + 'perms' => 'getPerms', + 'owner' => 'getOwner', + 'group' => 'getGroup', + 'type' => 'getType', + 'writable' => 'isWritable', + 'readable' => 'isReadable', + 'executable' => 'isExecutable', + 'file' => 'isFile', + 'dir' => 'isDir', + 'link' => 'isLink', + 'linkTarget' => 'getLinkTarget', + ]; + + $prefix = Caster::PREFIX_VIRTUAL; + unset($a["\0SplFileInfo\0fileName"]); + unset($a["\0SplFileInfo\0pathName"]); + + if (\PHP_VERSION_ID < 80000) { + if (false === $c->getPathname()) { + $a[$prefix.'⚠'] = 'The parent constructor was not called: the object is in an invalid state'; + + return $a; + } + } else { + try { + $c->isReadable(); + } catch (\RuntimeException $e) { + if ('Object not initialized' !== $e->getMessage()) { + throw $e; + } + + $a[$prefix.'⚠'] = 'The parent constructor was not called: the object is in an invalid state'; + + return $a; + } catch (\Error $e) { + if ('Object not initialized' !== $e->getMessage()) { + throw $e; + } + + $a[$prefix.'⚠'] = 'The parent constructor was not called: the object is in an invalid state'; + + return $a; + } + } + + foreach ($map as $key => $accessor) { + try { + $a[$prefix.$key] = $c->$accessor(); + } catch (\Exception $e) { + } + } + + if (isset($a[$prefix.'realPath'])) { + $a[$prefix.'realPath'] = new LinkStub($a[$prefix.'realPath']); + } + + if (isset($a[$prefix.'perms'])) { + $a[$prefix.'perms'] = new ConstStub(sprintf('0%o', $a[$prefix.'perms']), $a[$prefix.'perms']); + } + + static $mapDate = ['aTime', 'mTime', 'cTime']; + foreach ($mapDate as $key) { + if (isset($a[$prefix.$key])) { + $a[$prefix.$key] = new ConstStub(date('Y-m-d H:i:s', $a[$prefix.$key]), $a[$prefix.$key]); + } + } + + return $a; + } + + public static function castFileObject(\SplFileObject $c, array $a, Stub $stub, $isNested) + { + static $map = [ + 'csvControl' => 'getCsvControl', + 'flags' => 'getFlags', + 'maxLineLen' => 'getMaxLineLen', + 'fstat' => 'fstat', + 'eof' => 'eof', + 'key' => 'key', + ]; + + $prefix = Caster::PREFIX_VIRTUAL; + + foreach ($map as $key => $accessor) { + try { + $a[$prefix.$key] = $c->$accessor(); + } catch (\Exception $e) { + } + } + + if (isset($a[$prefix.'flags'])) { + $flagsArray = []; + foreach (self::SPL_FILE_OBJECT_FLAGS as $value => $name) { + if ($a[$prefix.'flags'] & $value) { + $flagsArray[] = $name; + } + } + $a[$prefix.'flags'] = new ConstStub(implode('|', $flagsArray), $a[$prefix.'flags']); + } + + if (isset($a[$prefix.'fstat'])) { + $a[$prefix.'fstat'] = new CutArrayStub($a[$prefix.'fstat'], ['dev', 'ino', 'nlink', 'rdev', 'blksize', 'blocks']); + } + + return $a; + } + + public static function castObjectStorage(\SplObjectStorage $c, array $a, Stub $stub, $isNested) + { + $storage = []; + unset($a[Caster::PREFIX_DYNAMIC."\0gcdata"]); // Don't hit https://bugs.php.net/65967 + unset($a["\0SplObjectStorage\0storage"]); + + $clone = clone $c; + foreach ($clone as $obj) { + $storage[] = [ + 'object' => $obj, + 'info' => $clone->getInfo(), + ]; + } + + $a += [ + Caster::PREFIX_VIRTUAL.'storage' => $storage, + ]; + + return $a; + } + + public static function castOuterIterator(\OuterIterator $c, array $a, Stub $stub, $isNested) + { + $a[Caster::PREFIX_VIRTUAL.'innerIterator'] = $c->getInnerIterator(); + + return $a; + } + + public static function castWeakReference(\WeakReference $c, array $a, Stub $stub, $isNested) + { + $a[Caster::PREFIX_VIRTUAL.'object'] = $c->get(); + + return $a; + } + + private static function castSplArray($c, array $a, Stub $stub, bool $isNested): array + { + $prefix = Caster::PREFIX_VIRTUAL; + $flags = $c->getFlags(); + + if (!($flags & \ArrayObject::STD_PROP_LIST)) { + $c->setFlags(\ArrayObject::STD_PROP_LIST); + $a = Caster::castObject($c, \get_class($c), method_exists($c, '__debugInfo'), $stub->class); + $c->setFlags($flags); + } + if (\PHP_VERSION_ID < 70400) { + $a[$prefix.'storage'] = $c->getArrayCopy(); + } + $a += [ + $prefix.'flag::STD_PROP_LIST' => (bool) ($flags & \ArrayObject::STD_PROP_LIST), + $prefix.'flag::ARRAY_AS_PROPS' => (bool) ($flags & \ArrayObject::ARRAY_AS_PROPS), + ]; + if ($c instanceof \ArrayObject) { + $a[$prefix.'iteratorClass'] = new ClassStub($c->getIteratorClass()); + } + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Caster/StubCaster.php b/vendor/symfony/var-dumper/Caster/StubCaster.php new file mode 100644 index 000000000..b6332fb74 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/StubCaster.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts a caster's Stub. + * + * @author Nicolas Grekas + * + * @final since Symfony 4.4 + */ +class StubCaster +{ + public static function castStub(Stub $c, array $a, Stub $stub, $isNested) + { + if ($isNested) { + $stub->type = $c->type; + $stub->class = $c->class; + $stub->value = $c->value; + $stub->handle = $c->handle; + $stub->cut = $c->cut; + $stub->attr = $c->attr; + + if (Stub::TYPE_REF === $c->type && !$c->class && \is_string($c->value) && !preg_match('//u', $c->value)) { + $stub->type = Stub::TYPE_STRING; + $stub->class = Stub::STRING_BINARY; + } + + $a = []; + } + + return $a; + } + + public static function castCutArray(CutArrayStub $c, array $a, Stub $stub, $isNested) + { + return $isNested ? $c->preservedSubset : $a; + } + + public static function cutInternals($obj, array $a, Stub $stub, $isNested) + { + if ($isNested) { + $stub->cut += \count($a); + + return []; + } + + return $a; + } + + public static function castEnum(EnumStub $c, array $a, Stub $stub, $isNested) + { + if ($isNested) { + $stub->class = $c->dumpKeys ? '' : null; + $stub->handle = 0; + $stub->value = null; + $stub->cut = $c->cut; + $stub->attr = $c->attr; + + $a = []; + + if ($c->value) { + foreach (array_keys($c->value) as $k) { + $keys[] = !isset($k[0]) || "\0" !== $k[0] ? Caster::PREFIX_VIRTUAL.$k : $k; + } + // Preserve references with array_combine() + $a = array_combine($keys, $c->value); + } + } + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Caster/SymfonyCaster.php b/vendor/symfony/var-dumper/Caster/SymfonyCaster.php new file mode 100644 index 000000000..06f213ef0 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/SymfonyCaster.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * @final since Symfony 4.4 + */ +class SymfonyCaster +{ + private const REQUEST_GETTERS = [ + 'pathInfo' => 'getPathInfo', + 'requestUri' => 'getRequestUri', + 'baseUrl' => 'getBaseUrl', + 'basePath' => 'getBasePath', + 'method' => 'getMethod', + 'format' => 'getRequestFormat', + ]; + + public static function castRequest(Request $request, array $a, Stub $stub, $isNested) + { + $clone = null; + + foreach (self::REQUEST_GETTERS as $prop => $getter) { + $key = Caster::PREFIX_PROTECTED.$prop; + if (\array_key_exists($key, $a) && null === $a[$key]) { + if (null === $clone) { + $clone = clone $request; + } + $a[Caster::PREFIX_VIRTUAL.$prop] = $clone->{$getter}(); + } + } + + return $a; + } + + public static function castHttpClient($client, array $a, Stub $stub, $isNested) + { + $multiKey = sprintf("\0%s\0multi", \get_class($client)); + if (isset($a[$multiKey])) { + $a[$multiKey] = new CutStub($a[$multiKey]); + } + + return $a; + } + + public static function castHttpClientResponse($response, array $a, Stub $stub, $isNested) + { + $stub->cut += \count($a); + $a = []; + + foreach ($response->getInfo() as $k => $v) { + $a[Caster::PREFIX_VIRTUAL.$k] = $v; + } + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Caster/TraceStub.php b/vendor/symfony/var-dumper/Caster/TraceStub.php new file mode 100644 index 000000000..5eea1c876 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/TraceStub.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Represents a backtrace as returned by debug_backtrace() or Exception->getTrace(). + * + * @author Nicolas Grekas + */ +class TraceStub extends Stub +{ + public $keepArgs; + public $sliceOffset; + public $sliceLength; + public $numberingOffset; + + public function __construct(array $trace, bool $keepArgs = true, int $sliceOffset = 0, int $sliceLength = null, int $numberingOffset = 0) + { + $this->value = $trace; + $this->keepArgs = $keepArgs; + $this->sliceOffset = $sliceOffset; + $this->sliceLength = $sliceLength; + $this->numberingOffset = $numberingOffset; + } +} diff --git a/vendor/symfony/var-dumper/Caster/UuidCaster.php b/vendor/symfony/var-dumper/Caster/UuidCaster.php new file mode 100644 index 000000000..b10277457 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/UuidCaster.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Ramsey\Uuid\UuidInterface; +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * @author Grégoire Pineau + */ +final class UuidCaster +{ + public static function castRamseyUuid(UuidInterface $c, array $a, Stub $stub, bool $isNested): array + { + $a += [ + Caster::PREFIX_VIRTUAL.'uuid' => (string) $c, + ]; + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Caster/XmlReaderCaster.php b/vendor/symfony/var-dumper/Caster/XmlReaderCaster.php new file mode 100644 index 000000000..19bf6a3d5 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/XmlReaderCaster.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts XmlReader class to array representation. + * + * @author Baptiste Clavié + * + * @final since Symfony 4.4 + */ +class XmlReaderCaster +{ + private const NODE_TYPES = [ + \XMLReader::NONE => 'NONE', + \XMLReader::ELEMENT => 'ELEMENT', + \XMLReader::ATTRIBUTE => 'ATTRIBUTE', + \XMLReader::TEXT => 'TEXT', + \XMLReader::CDATA => 'CDATA', + \XMLReader::ENTITY_REF => 'ENTITY_REF', + \XMLReader::ENTITY => 'ENTITY', + \XMLReader::PI => 'PI (Processing Instruction)', + \XMLReader::COMMENT => 'COMMENT', + \XMLReader::DOC => 'DOC', + \XMLReader::DOC_TYPE => 'DOC_TYPE', + \XMLReader::DOC_FRAGMENT => 'DOC_FRAGMENT', + \XMLReader::NOTATION => 'NOTATION', + \XMLReader::WHITESPACE => 'WHITESPACE', + \XMLReader::SIGNIFICANT_WHITESPACE => 'SIGNIFICANT_WHITESPACE', + \XMLReader::END_ELEMENT => 'END_ELEMENT', + \XMLReader::END_ENTITY => 'END_ENTITY', + \XMLReader::XML_DECLARATION => 'XML_DECLARATION', + ]; + + public static function castXmlReader(\XMLReader $reader, array $a, Stub $stub, $isNested) + { + $props = Caster::PREFIX_VIRTUAL.'parserProperties'; + $info = [ + 'localName' => $reader->localName, + 'prefix' => $reader->prefix, + 'nodeType' => new ConstStub(self::NODE_TYPES[$reader->nodeType], $reader->nodeType), + 'depth' => $reader->depth, + 'isDefault' => $reader->isDefault, + 'isEmptyElement' => \XMLReader::NONE === $reader->nodeType ? null : $reader->isEmptyElement, + 'xmlLang' => $reader->xmlLang, + 'attributeCount' => $reader->attributeCount, + 'value' => $reader->value, + 'namespaceURI' => $reader->namespaceURI, + 'baseURI' => $reader->baseURI ? new LinkStub($reader->baseURI) : $reader->baseURI, + $props => [ + 'LOADDTD' => $reader->getParserProperty(\XMLReader::LOADDTD), + 'DEFAULTATTRS' => $reader->getParserProperty(\XMLReader::DEFAULTATTRS), + 'VALIDATE' => $reader->getParserProperty(\XMLReader::VALIDATE), + 'SUBST_ENTITIES' => $reader->getParserProperty(\XMLReader::SUBST_ENTITIES), + ], + ]; + + if ($info[$props] = Caster::filter($info[$props], Caster::EXCLUDE_EMPTY, [], $count)) { + $info[$props] = new EnumStub($info[$props]); + $info[$props]->cut = $count; + } + + $info = Caster::filter($info, Caster::EXCLUDE_EMPTY, [], $count); + // +2 because hasValue and hasAttributes are always filtered + $stub->cut += $count + 2; + + return $a + $info; + } +} diff --git a/vendor/symfony/var-dumper/Caster/XmlResourceCaster.php b/vendor/symfony/var-dumper/Caster/XmlResourceCaster.php new file mode 100644 index 000000000..455fc065b --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/XmlResourceCaster.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts XML resources to array representation. + * + * @author Nicolas Grekas + * + * @final since Symfony 4.4 + */ +class XmlResourceCaster +{ + private const XML_ERRORS = [ + \XML_ERROR_NONE => 'XML_ERROR_NONE', + \XML_ERROR_NO_MEMORY => 'XML_ERROR_NO_MEMORY', + \XML_ERROR_SYNTAX => 'XML_ERROR_SYNTAX', + \XML_ERROR_NO_ELEMENTS => 'XML_ERROR_NO_ELEMENTS', + \XML_ERROR_INVALID_TOKEN => 'XML_ERROR_INVALID_TOKEN', + \XML_ERROR_UNCLOSED_TOKEN => 'XML_ERROR_UNCLOSED_TOKEN', + \XML_ERROR_PARTIAL_CHAR => 'XML_ERROR_PARTIAL_CHAR', + \XML_ERROR_TAG_MISMATCH => 'XML_ERROR_TAG_MISMATCH', + \XML_ERROR_DUPLICATE_ATTRIBUTE => 'XML_ERROR_DUPLICATE_ATTRIBUTE', + \XML_ERROR_JUNK_AFTER_DOC_ELEMENT => 'XML_ERROR_JUNK_AFTER_DOC_ELEMENT', + \XML_ERROR_PARAM_ENTITY_REF => 'XML_ERROR_PARAM_ENTITY_REF', + \XML_ERROR_UNDEFINED_ENTITY => 'XML_ERROR_UNDEFINED_ENTITY', + \XML_ERROR_RECURSIVE_ENTITY_REF => 'XML_ERROR_RECURSIVE_ENTITY_REF', + \XML_ERROR_ASYNC_ENTITY => 'XML_ERROR_ASYNC_ENTITY', + \XML_ERROR_BAD_CHAR_REF => 'XML_ERROR_BAD_CHAR_REF', + \XML_ERROR_BINARY_ENTITY_REF => 'XML_ERROR_BINARY_ENTITY_REF', + \XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF => 'XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF', + \XML_ERROR_MISPLACED_XML_PI => 'XML_ERROR_MISPLACED_XML_PI', + \XML_ERROR_UNKNOWN_ENCODING => 'XML_ERROR_UNKNOWN_ENCODING', + \XML_ERROR_INCORRECT_ENCODING => 'XML_ERROR_INCORRECT_ENCODING', + \XML_ERROR_UNCLOSED_CDATA_SECTION => 'XML_ERROR_UNCLOSED_CDATA_SECTION', + \XML_ERROR_EXTERNAL_ENTITY_HANDLING => 'XML_ERROR_EXTERNAL_ENTITY_HANDLING', + ]; + + public static function castXml($h, array $a, Stub $stub, $isNested) + { + $a['current_byte_index'] = xml_get_current_byte_index($h); + $a['current_column_number'] = xml_get_current_column_number($h); + $a['current_line_number'] = xml_get_current_line_number($h); + $a['error_code'] = xml_get_error_code($h); + + if (isset(self::XML_ERRORS[$a['error_code']])) { + $a['error_code'] = new ConstStub(self::XML_ERRORS[$a['error_code']], $a['error_code']); + } + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Cloner/AbstractCloner.php b/vendor/symfony/var-dumper/Cloner/AbstractCloner.php new file mode 100644 index 000000000..178237905 --- /dev/null +++ b/vendor/symfony/var-dumper/Cloner/AbstractCloner.php @@ -0,0 +1,375 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Cloner; + +use Symfony\Component\VarDumper\Caster\Caster; +use Symfony\Component\VarDumper\Exception\ThrowingCasterException; + +/** + * AbstractCloner implements a generic caster mechanism for objects and resources. + * + * @author Nicolas Grekas + */ +abstract class AbstractCloner implements ClonerInterface +{ + public static $defaultCasters = [ + '__PHP_Incomplete_Class' => ['Symfony\Component\VarDumper\Caster\Caster', 'castPhpIncompleteClass'], + + 'Symfony\Component\VarDumper\Caster\CutStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castStub'], + 'Symfony\Component\VarDumper\Caster\CutArrayStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castCutArray'], + 'Symfony\Component\VarDumper\Caster\ConstStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castStub'], + 'Symfony\Component\VarDumper\Caster\EnumStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castEnum'], + + 'Closure' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castClosure'], + 'Generator' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castGenerator'], + 'ReflectionType' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castType'], + 'ReflectionGenerator' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castReflectionGenerator'], + 'ReflectionClass' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castClass'], + 'ReflectionFunctionAbstract' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castFunctionAbstract'], + 'ReflectionMethod' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castMethod'], + 'ReflectionParameter' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castParameter'], + 'ReflectionProperty' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castProperty'], + 'ReflectionReference' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castReference'], + 'ReflectionExtension' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castExtension'], + 'ReflectionZendExtension' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castZendExtension'], + + 'Doctrine\Common\Persistence\ObjectManager' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], + 'Doctrine\Common\Proxy\Proxy' => ['Symfony\Component\VarDumper\Caster\DoctrineCaster', 'castCommonProxy'], + 'Doctrine\ORM\Proxy\Proxy' => ['Symfony\Component\VarDumper\Caster\DoctrineCaster', 'castOrmProxy'], + 'Doctrine\ORM\PersistentCollection' => ['Symfony\Component\VarDumper\Caster\DoctrineCaster', 'castPersistentCollection'], + 'Doctrine\Persistence\ObjectManager' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], + + 'DOMException' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castException'], + 'DOMStringList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], + 'DOMNameList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], + 'DOMImplementation' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castImplementation'], + 'DOMImplementationList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], + 'DOMNode' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNode'], + 'DOMNameSpaceNode' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNameSpaceNode'], + 'DOMDocument' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castDocument'], + 'DOMNodeList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], + 'DOMNamedNodeMap' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], + 'DOMCharacterData' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castCharacterData'], + 'DOMAttr' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castAttr'], + 'DOMElement' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castElement'], + 'DOMText' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castText'], + 'DOMTypeinfo' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castTypeinfo'], + 'DOMDomError' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castDomError'], + 'DOMLocator' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLocator'], + 'DOMDocumentType' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castDocumentType'], + 'DOMNotation' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNotation'], + 'DOMEntity' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castEntity'], + 'DOMProcessingInstruction' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castProcessingInstruction'], + 'DOMXPath' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castXPath'], + + 'XMLReader' => ['Symfony\Component\VarDumper\Caster\XmlReaderCaster', 'castXmlReader'], + + 'ErrorException' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castErrorException'], + 'Exception' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castException'], + 'Error' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castError'], + 'Symfony\Component\DependencyInjection\ContainerInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], + 'Symfony\Component\EventDispatcher\EventDispatcherInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], + 'Symfony\Component\HttpClient\CurlHttpClient' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClient'], + 'Symfony\Component\HttpClient\NativeHttpClient' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClient'], + 'Symfony\Component\HttpClient\Response\CurlResponse' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClientResponse'], + 'Symfony\Component\HttpClient\Response\NativeResponse' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClientResponse'], + 'Symfony\Component\HttpFoundation\Request' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castRequest'], + 'Symfony\Component\VarDumper\Exception\ThrowingCasterException' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castThrowingCasterException'], + 'Symfony\Component\VarDumper\Caster\TraceStub' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castTraceStub'], + 'Symfony\Component\VarDumper\Caster\FrameStub' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castFrameStub'], + 'Symfony\Component\VarDumper\Cloner\AbstractCloner' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], + 'Symfony\Component\ErrorHandler\Exception\SilencedErrorContext' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castSilencedErrorContext'], + + 'Imagine\Image\ImageInterface' => ['Symfony\Component\VarDumper\Caster\ImagineCaster', 'castImage'], + + 'Ramsey\Uuid\UuidInterface' => ['Symfony\Component\VarDumper\Caster\UuidCaster', 'castRamseyUuid'], + + 'ProxyManager\Proxy\ProxyInterface' => ['Symfony\Component\VarDumper\Caster\ProxyManagerCaster', 'castProxy'], + 'PHPUnit_Framework_MockObject_MockObject' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], + 'PHPUnit\Framework\MockObject\MockObject' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], + 'PHPUnit\Framework\MockObject\Stub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], + 'Prophecy\Prophecy\ProphecySubjectInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], + 'Mockery\MockInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], + + 'PDO' => ['Symfony\Component\VarDumper\Caster\PdoCaster', 'castPdo'], + 'PDOStatement' => ['Symfony\Component\VarDumper\Caster\PdoCaster', 'castPdoStatement'], + + 'AMQPConnection' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castConnection'], + 'AMQPChannel' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castChannel'], + 'AMQPQueue' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castQueue'], + 'AMQPExchange' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castExchange'], + 'AMQPEnvelope' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castEnvelope'], + + 'ArrayObject' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castArrayObject'], + 'ArrayIterator' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castArrayIterator'], + 'SplDoublyLinkedList' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castDoublyLinkedList'], + 'SplFileInfo' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castFileInfo'], + 'SplFileObject' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castFileObject'], + 'SplHeap' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castHeap'], + 'SplObjectStorage' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castObjectStorage'], + 'SplPriorityQueue' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castHeap'], + 'OuterIterator' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castOuterIterator'], + 'WeakReference' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castWeakReference'], + + 'Redis' => ['Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedis'], + 'RedisArray' => ['Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedisArray'], + 'RedisCluster' => ['Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedisCluster'], + + 'DateTimeInterface' => ['Symfony\Component\VarDumper\Caster\DateCaster', 'castDateTime'], + 'DateInterval' => ['Symfony\Component\VarDumper\Caster\DateCaster', 'castInterval'], + 'DateTimeZone' => ['Symfony\Component\VarDumper\Caster\DateCaster', 'castTimeZone'], + 'DatePeriod' => ['Symfony\Component\VarDumper\Caster\DateCaster', 'castPeriod'], + + 'GMP' => ['Symfony\Component\VarDumper\Caster\GmpCaster', 'castGmp'], + + 'MessageFormatter' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castMessageFormatter'], + 'NumberFormatter' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castNumberFormatter'], + 'IntlTimeZone' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castIntlTimeZone'], + 'IntlCalendar' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castIntlCalendar'], + 'IntlDateFormatter' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castIntlDateFormatter'], + + 'Memcached' => ['Symfony\Component\VarDumper\Caster\MemcachedCaster', 'castMemcached'], + + 'Ds\Collection' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castCollection'], + 'Ds\Map' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castMap'], + 'Ds\Pair' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castPair'], + 'Symfony\Component\VarDumper\Caster\DsPairStub' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castPairStub'], + + 'CurlHandle' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castCurl'], + ':curl' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castCurl'], + + ':dba' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castDba'], + ':dba persistent' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castDba'], + + 'GdImage' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castGd'], + ':gd' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castGd'], + + ':mysql link' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castMysqlLink'], + ':pgsql large object' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLargeObject'], + ':pgsql link' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLink'], + ':pgsql link persistent' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLink'], + ':pgsql result' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castResult'], + ':process' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castProcess'], + ':stream' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStream'], + + 'OpenSSLCertificate' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castOpensslX509'], + ':OpenSSL X.509' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castOpensslX509'], + + ':persistent stream' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStream'], + ':stream-context' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStreamContext'], + + 'XmlParser' => ['Symfony\Component\VarDumper\Caster\XmlResourceCaster', 'castXml'], + ':xml' => ['Symfony\Component\VarDumper\Caster\XmlResourceCaster', 'castXml'], + ]; + + protected $maxItems = 2500; + protected $maxString = -1; + protected $minDepth = 1; + + private $casters = []; + private $prevErrorHandler; + private $classInfo = []; + private $filter = 0; + + /** + * @param callable[]|null $casters A map of casters + * + * @see addCasters + */ + public function __construct(array $casters = null) + { + if (null === $casters) { + $casters = static::$defaultCasters; + } + $this->addCasters($casters); + } + + /** + * Adds casters for resources and objects. + * + * Maps resources or objects types to a callback. + * Types are in the key, with a callable caster for value. + * Resource types are to be prefixed with a `:`, + * see e.g. static::$defaultCasters. + * + * @param callable[] $casters A map of casters + */ + public function addCasters(array $casters) + { + foreach ($casters as $type => $callback) { + $this->casters[$type][] = $callback; + } + } + + /** + * Sets the maximum number of items to clone past the minimum depth in nested structures. + * + * @param int $maxItems + */ + public function setMaxItems($maxItems) + { + $this->maxItems = (int) $maxItems; + } + + /** + * Sets the maximum cloned length for strings. + * + * @param int $maxString + */ + public function setMaxString($maxString) + { + $this->maxString = (int) $maxString; + } + + /** + * Sets the minimum tree depth where we are guaranteed to clone all the items. After this + * depth is reached, only setMaxItems items will be cloned. + * + * @param int $minDepth + */ + public function setMinDepth($minDepth) + { + $this->minDepth = (int) $minDepth; + } + + /** + * Clones a PHP variable. + * + * @param mixed $var Any PHP variable + * @param int $filter A bit field of Caster::EXCLUDE_* constants + * + * @return Data The cloned variable represented by a Data object + */ + public function cloneVar($var, $filter = 0) + { + $this->prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = []) { + if (\E_RECOVERABLE_ERROR === $type || \E_USER_ERROR === $type) { + // Cloner never dies + throw new \ErrorException($msg, 0, $type, $file, $line); + } + + if ($this->prevErrorHandler) { + return ($this->prevErrorHandler)($type, $msg, $file, $line, $context); + } + + return false; + }); + $this->filter = $filter; + + if ($gc = gc_enabled()) { + gc_disable(); + } + try { + return new Data($this->doClone($var)); + } finally { + if ($gc) { + gc_enable(); + } + restore_error_handler(); + $this->prevErrorHandler = null; + } + } + + /** + * Effectively clones the PHP variable. + * + * @param mixed $var Any PHP variable + * + * @return array The cloned variable represented in an array + */ + abstract protected function doClone($var); + + /** + * Casts an object to an array representation. + * + * @param bool $isNested True if the object is nested in the dumped structure + * + * @return array The object casted as array + */ + protected function castObject(Stub $stub, $isNested) + { + $obj = $stub->value; + $class = $stub->class; + + if (\PHP_VERSION_ID < 80000 ? "\0" === ($class[15] ?? null) : false !== strpos($class, "@anonymous\0")) { + $stub->class = get_debug_type($obj); + } + if (isset($this->classInfo[$class])) { + [$i, $parents, $hasDebugInfo, $fileInfo] = $this->classInfo[$class]; + } else { + $i = 2; + $parents = [$class]; + $hasDebugInfo = method_exists($class, '__debugInfo'); + + foreach (class_parents($class) as $p) { + $parents[] = $p; + ++$i; + } + foreach (class_implements($class) as $p) { + $parents[] = $p; + ++$i; + } + $parents[] = '*'; + + $r = new \ReflectionClass($class); + $fileInfo = $r->isInternal() || $r->isSubclassOf(Stub::class) ? [] : [ + 'file' => $r->getFileName(), + 'line' => $r->getStartLine(), + ]; + + $this->classInfo[$class] = [$i, $parents, $hasDebugInfo, $fileInfo]; + } + + $stub->attr += $fileInfo; + $a = Caster::castObject($obj, $class, $hasDebugInfo, $stub->class); + + try { + while ($i--) { + if (!empty($this->casters[$p = $parents[$i]])) { + foreach ($this->casters[$p] as $callback) { + $a = $callback($obj, $a, $stub, $isNested, $this->filter); + } + } + } + } catch (\Exception $e) { + $a = [(Stub::TYPE_OBJECT === $stub->type ? Caster::PREFIX_VIRTUAL : '').'⚠' => new ThrowingCasterException($e)] + $a; + } + + return $a; + } + + /** + * Casts a resource to an array representation. + * + * @param bool $isNested True if the object is nested in the dumped structure + * + * @return array The resource casted as array + */ + protected function castResource(Stub $stub, $isNested) + { + $a = []; + $res = $stub->value; + $type = $stub->class; + + try { + if (!empty($this->casters[':'.$type])) { + foreach ($this->casters[':'.$type] as $callback) { + $a = $callback($res, $a, $stub, $isNested, $this->filter); + } + } + } catch (\Exception $e) { + $a = [(Stub::TYPE_OBJECT === $stub->type ? Caster::PREFIX_VIRTUAL : '').'⚠' => new ThrowingCasterException($e)] + $a; + } + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Cloner/ClonerInterface.php b/vendor/symfony/var-dumper/Cloner/ClonerInterface.php new file mode 100644 index 000000000..7ed287a2d --- /dev/null +++ b/vendor/symfony/var-dumper/Cloner/ClonerInterface.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Cloner; + +/** + * @author Nicolas Grekas + */ +interface ClonerInterface +{ + /** + * Clones a PHP variable. + * + * @param mixed $var Any PHP variable + * + * @return Data The cloned variable represented by a Data object + */ + public function cloneVar($var); +} diff --git a/vendor/symfony/var-dumper/Cloner/Cursor.php b/vendor/symfony/var-dumper/Cloner/Cursor.php new file mode 100644 index 000000000..1fd796d67 --- /dev/null +++ b/vendor/symfony/var-dumper/Cloner/Cursor.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Cloner; + +/** + * Represents the current state of a dumper while dumping. + * + * @author Nicolas Grekas + */ +class Cursor +{ + public const HASH_INDEXED = Stub::ARRAY_INDEXED; + public const HASH_ASSOC = Stub::ARRAY_ASSOC; + public const HASH_OBJECT = Stub::TYPE_OBJECT; + public const HASH_RESOURCE = Stub::TYPE_RESOURCE; + + public $depth = 0; + public $refIndex = 0; + public $softRefTo = 0; + public $softRefCount = 0; + public $softRefHandle = 0; + public $hardRefTo = 0; + public $hardRefCount = 0; + public $hardRefHandle = 0; + public $hashType; + public $hashKey; + public $hashKeyIsBinary; + public $hashIndex = 0; + public $hashLength = 0; + public $hashCut = 0; + public $stop = false; + public $attr = []; + public $skipChildren = false; +} diff --git a/vendor/symfony/var-dumper/Cloner/Data.php b/vendor/symfony/var-dumper/Cloner/Data.php new file mode 100644 index 000000000..21adb2364 --- /dev/null +++ b/vendor/symfony/var-dumper/Cloner/Data.php @@ -0,0 +1,455 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Cloner; + +use Symfony\Component\VarDumper\Caster\Caster; +use Symfony\Component\VarDumper\Dumper\ContextProvider\SourceContextProvider; + +/** + * @author Nicolas Grekas + */ +class Data implements \ArrayAccess, \Countable, \IteratorAggregate +{ + private $data; + private $position = 0; + private $key = 0; + private $maxDepth = 20; + private $maxItemsPerDepth = -1; + private $useRefHandles = -1; + private $context = []; + + /** + * @param array $data An array as returned by ClonerInterface::cloneVar() + */ + public function __construct(array $data) + { + $this->data = $data; + } + + /** + * @return string|null The type of the value + */ + public function getType() + { + $item = $this->data[$this->position][$this->key]; + + if ($item instanceof Stub && Stub::TYPE_REF === $item->type && !$item->position) { + $item = $item->value; + } + if (!$item instanceof Stub) { + return \gettype($item); + } + if (Stub::TYPE_STRING === $item->type) { + return 'string'; + } + if (Stub::TYPE_ARRAY === $item->type) { + return 'array'; + } + if (Stub::TYPE_OBJECT === $item->type) { + return $item->class; + } + if (Stub::TYPE_RESOURCE === $item->type) { + return $item->class.' resource'; + } + + return null; + } + + /** + * @param array|bool $recursive Whether values should be resolved recursively or not + * + * @return string|int|float|bool|array|Data[]|null A native representation of the original value + */ + public function getValue($recursive = false) + { + $item = $this->data[$this->position][$this->key]; + + if ($item instanceof Stub && Stub::TYPE_REF === $item->type && !$item->position) { + $item = $item->value; + } + if (!($item = $this->getStub($item)) instanceof Stub) { + return $item; + } + if (Stub::TYPE_STRING === $item->type) { + return $item->value; + } + + $children = $item->position ? $this->data[$item->position] : []; + + foreach ($children as $k => $v) { + if ($recursive && !($v = $this->getStub($v)) instanceof Stub) { + continue; + } + $children[$k] = clone $this; + $children[$k]->key = $k; + $children[$k]->position = $item->position; + + if ($recursive) { + if (Stub::TYPE_REF === $v->type && ($v = $this->getStub($v->value)) instanceof Stub) { + $recursive = (array) $recursive; + if (isset($recursive[$v->position])) { + continue; + } + $recursive[$v->position] = true; + } + $children[$k] = $children[$k]->getValue($recursive); + } + } + + return $children; + } + + /** + * @return int + */ + public function count() + { + return \count($this->getValue()); + } + + /** + * @return \Traversable + */ + public function getIterator() + { + if (!\is_array($value = $this->getValue())) { + throw new \LogicException(sprintf('"%s" object holds non-iterable type "%s".', self::class, \gettype($value))); + } + + yield from $value; + } + + public function __get($key) + { + if (null !== $data = $this->seek($key)) { + $item = $this->getStub($data->data[$data->position][$data->key]); + + return $item instanceof Stub || [] === $item ? $data : $item; + } + + return null; + } + + /** + * @return bool + */ + public function __isset($key) + { + return null !== $this->seek($key); + } + + /** + * @return bool + */ + public function offsetExists($key) + { + return $this->__isset($key); + } + + public function offsetGet($key) + { + return $this->__get($key); + } + + public function offsetSet($key, $value) + { + throw new \BadMethodCallException(self::class.' objects are immutable.'); + } + + public function offsetUnset($key) + { + throw new \BadMethodCallException(self::class.' objects are immutable.'); + } + + /** + * @return string + */ + public function __toString() + { + $value = $this->getValue(); + + if (!\is_array($value)) { + return (string) $value; + } + + return sprintf('%s (count=%d)', $this->getType(), \count($value)); + } + + /** + * Returns a depth limited clone of $this. + * + * @param int $maxDepth The max dumped depth level + * + * @return static + */ + public function withMaxDepth($maxDepth) + { + $data = clone $this; + $data->maxDepth = (int) $maxDepth; + + return $data; + } + + /** + * Limits the number of elements per depth level. + * + * @param int $maxItemsPerDepth The max number of items dumped per depth level + * + * @return static + */ + public function withMaxItemsPerDepth($maxItemsPerDepth) + { + $data = clone $this; + $data->maxItemsPerDepth = (int) $maxItemsPerDepth; + + return $data; + } + + /** + * Enables/disables objects' identifiers tracking. + * + * @param bool $useRefHandles False to hide global ref. handles + * + * @return static + */ + public function withRefHandles($useRefHandles) + { + $data = clone $this; + $data->useRefHandles = $useRefHandles ? -1 : 0; + + return $data; + } + + /** + * @return static + */ + public function withContext(array $context) + { + $data = clone $this; + $data->context = $context; + + return $data; + } + + /** + * Seeks to a specific key in nested data structures. + * + * @param string|int $key The key to seek to + * + * @return static|null Null if the key is not set + */ + public function seek($key) + { + $item = $this->data[$this->position][$this->key]; + + if ($item instanceof Stub && Stub::TYPE_REF === $item->type && !$item->position) { + $item = $item->value; + } + if (!($item = $this->getStub($item)) instanceof Stub || !$item->position) { + return null; + } + $keys = [$key]; + + switch ($item->type) { + case Stub::TYPE_OBJECT: + $keys[] = Caster::PREFIX_DYNAMIC.$key; + $keys[] = Caster::PREFIX_PROTECTED.$key; + $keys[] = Caster::PREFIX_VIRTUAL.$key; + $keys[] = "\0$item->class\0$key"; + // no break + case Stub::TYPE_ARRAY: + case Stub::TYPE_RESOURCE: + break; + default: + return null; + } + + $data = null; + $children = $this->data[$item->position]; + + foreach ($keys as $key) { + if (isset($children[$key]) || \array_key_exists($key, $children)) { + $data = clone $this; + $data->key = $key; + $data->position = $item->position; + break; + } + } + + return $data; + } + + /** + * Dumps data with a DumperInterface dumper. + */ + public function dump(DumperInterface $dumper) + { + $refs = [0]; + $cursor = new Cursor(); + + if ($cursor->attr = $this->context[SourceContextProvider::class] ?? []) { + $cursor->attr['if_links'] = true; + $cursor->hashType = -1; + $dumper->dumpScalar($cursor, 'default', '^'); + $cursor->attr = ['if_links' => true]; + $dumper->dumpScalar($cursor, 'default', ' '); + $cursor->hashType = 0; + } + + $this->dumpItem($dumper, $cursor, $refs, $this->data[$this->position][$this->key]); + } + + /** + * Depth-first dumping of items. + * + * @param mixed $item A Stub object or the original value being dumped + */ + private function dumpItem(DumperInterface $dumper, Cursor $cursor, array &$refs, $item) + { + $cursor->refIndex = 0; + $cursor->softRefTo = $cursor->softRefHandle = $cursor->softRefCount = 0; + $cursor->hardRefTo = $cursor->hardRefHandle = $cursor->hardRefCount = 0; + $firstSeen = true; + + if (!$item instanceof Stub) { + $cursor->attr = []; + $type = \gettype($item); + if ($item && 'array' === $type) { + $item = $this->getStub($item); + } + } elseif (Stub::TYPE_REF === $item->type) { + if ($item->handle) { + if (!isset($refs[$r = $item->handle - (\PHP_INT_MAX >> 1)])) { + $cursor->refIndex = $refs[$r] = $cursor->refIndex ?: ++$refs[0]; + } else { + $firstSeen = false; + } + $cursor->hardRefTo = $refs[$r]; + $cursor->hardRefHandle = $this->useRefHandles & $item->handle; + $cursor->hardRefCount = 0 < $item->handle ? $item->refCount : 0; + } + $cursor->attr = $item->attr; + $type = $item->class ?: \gettype($item->value); + $item = $this->getStub($item->value); + } + if ($item instanceof Stub) { + if ($item->refCount) { + if (!isset($refs[$r = $item->handle])) { + $cursor->refIndex = $refs[$r] = $cursor->refIndex ?: ++$refs[0]; + } else { + $firstSeen = false; + } + $cursor->softRefTo = $refs[$r]; + } + $cursor->softRefHandle = $this->useRefHandles & $item->handle; + $cursor->softRefCount = $item->refCount; + $cursor->attr = $item->attr; + $cut = $item->cut; + + if ($item->position && $firstSeen) { + $children = $this->data[$item->position]; + + if ($cursor->stop) { + if ($cut >= 0) { + $cut += \count($children); + } + $children = []; + } + } else { + $children = []; + } + switch ($item->type) { + case Stub::TYPE_STRING: + $dumper->dumpString($cursor, $item->value, Stub::STRING_BINARY === $item->class, $cut); + break; + + case Stub::TYPE_ARRAY: + $item = clone $item; + $item->type = $item->class; + $item->class = $item->value; + // no break + case Stub::TYPE_OBJECT: + case Stub::TYPE_RESOURCE: + $withChildren = $children && $cursor->depth !== $this->maxDepth && $this->maxItemsPerDepth; + $dumper->enterHash($cursor, $item->type, $item->class, $withChildren); + if ($withChildren) { + if ($cursor->skipChildren) { + $withChildren = false; + $cut = -1; + } else { + $cut = $this->dumpChildren($dumper, $cursor, $refs, $children, $cut, $item->type, null !== $item->class); + } + } elseif ($children && 0 <= $cut) { + $cut += \count($children); + } + $cursor->skipChildren = false; + $dumper->leaveHash($cursor, $item->type, $item->class, $withChildren, $cut); + break; + + default: + throw new \RuntimeException(sprintf('Unexpected Stub type: "%s".', $item->type)); + } + } elseif ('array' === $type) { + $dumper->enterHash($cursor, Cursor::HASH_INDEXED, 0, false); + $dumper->leaveHash($cursor, Cursor::HASH_INDEXED, 0, false, 0); + } elseif ('string' === $type) { + $dumper->dumpString($cursor, $item, false, 0); + } else { + $dumper->dumpScalar($cursor, $type, $item); + } + } + + /** + * Dumps children of hash structures. + * + * @return int The final number of removed items + */ + private function dumpChildren(DumperInterface $dumper, Cursor $parentCursor, array &$refs, array $children, int $hashCut, int $hashType, bool $dumpKeys): int + { + $cursor = clone $parentCursor; + ++$cursor->depth; + $cursor->hashType = $hashType; + $cursor->hashIndex = 0; + $cursor->hashLength = \count($children); + $cursor->hashCut = $hashCut; + foreach ($children as $key => $child) { + $cursor->hashKeyIsBinary = isset($key[0]) && !preg_match('//u', $key); + $cursor->hashKey = $dumpKeys ? $key : null; + $this->dumpItem($dumper, $cursor, $refs, $child); + if (++$cursor->hashIndex === $this->maxItemsPerDepth || $cursor->stop) { + $parentCursor->stop = true; + + return $hashCut >= 0 ? $hashCut + $cursor->hashLength - $cursor->hashIndex : $hashCut; + } + } + + return $hashCut; + } + + private function getStub($item) + { + if (!$item || !\is_array($item)) { + return $item; + } + + $stub = new Stub(); + $stub->type = Stub::TYPE_ARRAY; + foreach ($item as $stub->class => $stub->position) { + } + if (isset($item[0])) { + $stub->cut = $item[0]; + } + $stub->value = $stub->cut + ($stub->position ? \count($this->data[$stub->position]) : 0); + + return $stub; + } +} diff --git a/vendor/symfony/var-dumper/Cloner/DumperInterface.php b/vendor/symfony/var-dumper/Cloner/DumperInterface.php new file mode 100644 index 000000000..ec8ef2727 --- /dev/null +++ b/vendor/symfony/var-dumper/Cloner/DumperInterface.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Cloner; + +/** + * DumperInterface used by Data objects. + * + * @author Nicolas Grekas + */ +interface DumperInterface +{ + /** + * Dumps a scalar value. + * + * @param string $type The PHP type of the value being dumped + * @param string|int|float|bool $value The scalar value being dumped + */ + public function dumpScalar(Cursor $cursor, $type, $value); + + /** + * Dumps a string. + * + * @param string $str The string being dumped + * @param bool $bin Whether $str is UTF-8 or binary encoded + * @param int $cut The number of characters $str has been cut by + */ + public function dumpString(Cursor $cursor, $str, $bin, $cut); + + /** + * Dumps while entering an hash. + * + * @param int $type A Cursor::HASH_* const for the type of hash + * @param string|int $class The object class, resource type or array count + * @param bool $hasChild When the dump of the hash has child item + */ + public function enterHash(Cursor $cursor, $type, $class, $hasChild); + + /** + * Dumps while leaving an hash. + * + * @param int $type A Cursor::HASH_* const for the type of hash + * @param string|int $class The object class, resource type or array count + * @param bool $hasChild When the dump of the hash has child item + * @param int $cut The number of items the hash has been cut by + */ + public function leaveHash(Cursor $cursor, $type, $class, $hasChild, $cut); +} diff --git a/vendor/symfony/var-dumper/Cloner/Stub.php b/vendor/symfony/var-dumper/Cloner/Stub.php new file mode 100644 index 000000000..073c56efb --- /dev/null +++ b/vendor/symfony/var-dumper/Cloner/Stub.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Cloner; + +/** + * Represents the main properties of a PHP variable. + * + * @author Nicolas Grekas + */ +class Stub +{ + public const TYPE_REF = 1; + public const TYPE_STRING = 2; + public const TYPE_ARRAY = 3; + public const TYPE_OBJECT = 4; + public const TYPE_RESOURCE = 5; + + public const STRING_BINARY = 1; + public const STRING_UTF8 = 2; + + public const ARRAY_ASSOC = 1; + public const ARRAY_INDEXED = 2; + + public $type = self::TYPE_REF; + public $class = ''; + public $value; + public $cut = 0; + public $handle = 0; + public $refCount = 0; + public $position = 0; + public $attr = []; + + private static $defaultProperties = []; + + /** + * @internal + */ + public function __sleep(): array + { + $properties = []; + + if (!isset(self::$defaultProperties[$c = static::class])) { + self::$defaultProperties[$c] = get_class_vars($c); + + foreach ((new \ReflectionClass($c))->getStaticProperties() as $k => $v) { + unset(self::$defaultProperties[$c][$k]); + } + } + + foreach (self::$defaultProperties[$c] as $k => $v) { + if ($this->$k !== $v) { + $properties[] = $k; + } + } + + return $properties; + } +} diff --git a/vendor/symfony/var-dumper/Cloner/VarCloner.php b/vendor/symfony/var-dumper/Cloner/VarCloner.php new file mode 100644 index 000000000..6a9002137 --- /dev/null +++ b/vendor/symfony/var-dumper/Cloner/VarCloner.php @@ -0,0 +1,307 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Cloner; + +/** + * @author Nicolas Grekas + */ +class VarCloner extends AbstractCloner +{ + private static $gid; + private static $arrayCache = []; + + /** + * {@inheritdoc} + */ + protected function doClone($var) + { + $len = 1; // Length of $queue + $pos = 0; // Number of cloned items past the minimum depth + $refsCounter = 0; // Hard references counter + $queue = [[$var]]; // This breadth-first queue is the return value + $indexedArrays = []; // Map of queue indexes that hold numerically indexed arrays + $hardRefs = []; // Map of original zval ids to stub objects + $objRefs = []; // Map of original object handles to their stub object counterpart + $objects = []; // Keep a ref to objects to ensure their handle cannot be reused while cloning + $resRefs = []; // Map of original resource handles to their stub object counterpart + $values = []; // Map of stub objects' ids to original values + $maxItems = $this->maxItems; + $maxString = $this->maxString; + $minDepth = $this->minDepth; + $currentDepth = 0; // Current tree depth + $currentDepthFinalIndex = 0; // Final $queue index for current tree depth + $minimumDepthReached = 0 === $minDepth; // Becomes true when minimum tree depth has been reached + $cookie = (object) []; // Unique object used to detect hard references + $a = null; // Array cast for nested structures + $stub = null; // Stub capturing the main properties of an original item value + // or null if the original value is used directly + + if (!$gid = self::$gid) { + $gid = self::$gid = md5(random_bytes(6)); // Unique string used to detect the special $GLOBALS variable + } + $arrayStub = new Stub(); + $arrayStub->type = Stub::TYPE_ARRAY; + $fromObjCast = false; + + for ($i = 0; $i < $len; ++$i) { + // Detect when we move on to the next tree depth + if ($i > $currentDepthFinalIndex) { + ++$currentDepth; + $currentDepthFinalIndex = $len - 1; + if ($currentDepth >= $minDepth) { + $minimumDepthReached = true; + } + } + + $refs = $vals = $queue[$i]; + if (\PHP_VERSION_ID < 70200 && empty($indexedArrays[$i])) { + // see https://wiki.php.net/rfc/convert_numeric_keys_in_object_array_casts + foreach ($vals as $k => $v) { + if (\is_int($k)) { + continue; + } + foreach ([$k => true] as $gk => $gv) { + } + if ($gk !== $k) { + $fromObjCast = true; + $refs = $vals = array_values($queue[$i]); + break; + } + } + } + foreach ($vals as $k => $v) { + // $v is the original value or a stub object in case of hard references + + if (\PHP_VERSION_ID >= 70400) { + $zvalIsRef = null !== \ReflectionReference::fromArrayElement($vals, $k); + } else { + $refs[$k] = $cookie; + $zvalIsRef = $vals[$k] === $cookie; + } + + if ($zvalIsRef) { + $vals[$k] = &$stub; // Break hard references to make $queue completely + unset($stub); // independent from the original structure + if ($v instanceof Stub && isset($hardRefs[spl_object_id($v)])) { + $vals[$k] = $refs[$k] = $v; + if ($v->value instanceof Stub && (Stub::TYPE_OBJECT === $v->value->type || Stub::TYPE_RESOURCE === $v->value->type)) { + ++$v->value->refCount; + } + ++$v->refCount; + continue; + } + $refs[$k] = $vals[$k] = new Stub(); + $refs[$k]->value = $v; + $h = spl_object_id($refs[$k]); + $hardRefs[$h] = &$refs[$k]; + $values[$h] = $v; + $vals[$k]->handle = ++$refsCounter; + } + // Create $stub when the original value $v can not be used directly + // If $v is a nested structure, put that structure in array $a + switch (true) { + case null === $v: + case \is_bool($v): + case \is_int($v): + case \is_float($v): + continue 2; + case \is_string($v): + if ('' === $v) { + continue 2; + } + if (!preg_match('//u', $v)) { + $stub = new Stub(); + $stub->type = Stub::TYPE_STRING; + $stub->class = Stub::STRING_BINARY; + if (0 <= $maxString && 0 < $cut = \strlen($v) - $maxString) { + $stub->cut = $cut; + $stub->value = substr($v, 0, -$cut); + } else { + $stub->value = $v; + } + } elseif (0 <= $maxString && isset($v[1 + ($maxString >> 2)]) && 0 < $cut = mb_strlen($v, 'UTF-8') - $maxString) { + $stub = new Stub(); + $stub->type = Stub::TYPE_STRING; + $stub->class = Stub::STRING_UTF8; + $stub->cut = $cut; + $stub->value = mb_substr($v, 0, $maxString, 'UTF-8'); + } else { + continue 2; + } + $a = null; + break; + + case \is_array($v): + if (!$v) { + continue 2; + } + $stub = $arrayStub; + $stub->class = Stub::ARRAY_INDEXED; + + $j = -1; + foreach ($v as $gk => $gv) { + if ($gk !== ++$j) { + $stub->class = Stub::ARRAY_ASSOC; + break; + } + } + $a = $v; + + if (Stub::ARRAY_ASSOC === $stub->class) { + // Copies of $GLOBALS have very strange behavior, + // let's detect them with some black magic + if (\PHP_VERSION_ID < 80100 && ($a[$gid] = true) && isset($v[$gid])) { + unset($v[$gid]); + $a = []; + foreach ($v as $gk => &$gv) { + if ($v === $gv) { + unset($v); + $v = new Stub(); + $v->value = [$v->cut = \count($gv), Stub::TYPE_ARRAY => 0]; + $v->handle = -1; + $gv = &$hardRefs[spl_object_id($v)]; + $gv = $v; + } + + $a[$gk] = &$gv; + } + unset($gv); + } else { + $a = $v; + } + } elseif (\PHP_VERSION_ID < 70200) { + $indexedArrays[$len] = true; + } + break; + + case \is_object($v): + case $v instanceof \__PHP_Incomplete_Class: + if (empty($objRefs[$h = spl_object_id($v)])) { + $stub = new Stub(); + $stub->type = Stub::TYPE_OBJECT; + $stub->class = \get_class($v); + $stub->value = $v; + $stub->handle = $h; + $a = $this->castObject($stub, 0 < $i); + if ($v !== $stub->value) { + if (Stub::TYPE_OBJECT !== $stub->type || null === $stub->value) { + break; + } + $stub->handle = $h = spl_object_id($stub->value); + } + $stub->value = null; + if (0 <= $maxItems && $maxItems <= $pos && $minimumDepthReached) { + $stub->cut = \count($a); + $a = null; + } + } + if (empty($objRefs[$h])) { + $objRefs[$h] = $stub; + $objects[] = $v; + } else { + $stub = $objRefs[$h]; + ++$stub->refCount; + $a = null; + } + break; + + default: // resource + if (empty($resRefs[$h = (int) $v])) { + $stub = new Stub(); + $stub->type = Stub::TYPE_RESOURCE; + if ('Unknown' === $stub->class = @get_resource_type($v)) { + $stub->class = 'Closed'; + } + $stub->value = $v; + $stub->handle = $h; + $a = $this->castResource($stub, 0 < $i); + $stub->value = null; + if (0 <= $maxItems && $maxItems <= $pos && $minimumDepthReached) { + $stub->cut = \count($a); + $a = null; + } + } + if (empty($resRefs[$h])) { + $resRefs[$h] = $stub; + } else { + $stub = $resRefs[$h]; + ++$stub->refCount; + $a = null; + } + break; + } + + if ($a) { + if (!$minimumDepthReached || 0 > $maxItems) { + $queue[$len] = $a; + $stub->position = $len++; + } elseif ($pos < $maxItems) { + if ($maxItems < $pos += \count($a)) { + $a = \array_slice($a, 0, $maxItems - $pos, true); + if ($stub->cut >= 0) { + $stub->cut += $pos - $maxItems; + } + } + $queue[$len] = $a; + $stub->position = $len++; + } elseif ($stub->cut >= 0) { + $stub->cut += \count($a); + $stub->position = 0; + } + } + + if ($arrayStub === $stub) { + if ($arrayStub->cut) { + $stub = [$arrayStub->cut, $arrayStub->class => $arrayStub->position]; + $arrayStub->cut = 0; + } elseif (isset(self::$arrayCache[$arrayStub->class][$arrayStub->position])) { + $stub = self::$arrayCache[$arrayStub->class][$arrayStub->position]; + } else { + self::$arrayCache[$arrayStub->class][$arrayStub->position] = $stub = [$arrayStub->class => $arrayStub->position]; + } + } + + if ($zvalIsRef) { + $refs[$k]->value = $stub; + } else { + $vals[$k] = $stub; + } + } + + if ($fromObjCast) { + $fromObjCast = false; + $refs = $vals; + $vals = []; + $j = -1; + foreach ($queue[$i] as $k => $v) { + foreach ([$k => true] as $gk => $gv) { + } + if ($gk !== $k) { + $vals = (object) $vals; + $vals->{$k} = $refs[++$j]; + $vals = (array) $vals; + } else { + $vals[$k] = $refs[++$j]; + } + } + } + + $queue[$i] = $vals; + } + + foreach ($values as $h => $v) { + $hardRefs[$h] = $v; + } + + return $queue; + } +} diff --git a/vendor/symfony/var-dumper/Command/Descriptor/CliDescriptor.php b/vendor/symfony/var-dumper/Command/Descriptor/CliDescriptor.php new file mode 100644 index 000000000..7d9ec0e7e --- /dev/null +++ b/vendor/symfony/var-dumper/Command/Descriptor/CliDescriptor.php @@ -0,0 +1,88 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Command\Descriptor; + +use Symfony\Component\Console\Formatter\OutputFormatterStyle; +use Symfony\Component\Console\Input\ArrayInput; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\VarDumper\Cloner\Data; +use Symfony\Component\VarDumper\Dumper\CliDumper; + +/** + * Describe collected data clones for cli output. + * + * @author Maxime Steinhausser + * + * @final + */ +class CliDescriptor implements DumpDescriptorInterface +{ + private $dumper; + private $lastIdentifier; + private $supportsHref; + + public function __construct(CliDumper $dumper) + { + $this->dumper = $dumper; + $this->supportsHref = method_exists(OutputFormatterStyle::class, 'setHref'); + } + + public function describe(OutputInterface $output, Data $data, array $context, int $clientId): void + { + $io = $output instanceof SymfonyStyle ? $output : new SymfonyStyle(new ArrayInput([]), $output); + $this->dumper->setColors($output->isDecorated()); + + $rows = [['date', date('r', (int) $context['timestamp'])]]; + $lastIdentifier = $this->lastIdentifier; + $this->lastIdentifier = $clientId; + + $section = "Received from client #$clientId"; + if (isset($context['request'])) { + $request = $context['request']; + $this->lastIdentifier = $request['identifier']; + $section = sprintf('%s %s', $request['method'], $request['uri']); + if ($controller = $request['controller']) { + $rows[] = ['controller', rtrim($this->dumper->dump($controller, true), "\n")]; + } + } elseif (isset($context['cli'])) { + $this->lastIdentifier = $context['cli']['identifier']; + $section = '$ '.$context['cli']['command_line']; + } + + if ($this->lastIdentifier !== $lastIdentifier) { + $io->section($section); + } + + if (isset($context['source'])) { + $source = $context['source']; + $sourceInfo = sprintf('%s on line %d', $source['name'], $source['line']); + $fileLink = $source['file_link'] ?? null; + if ($this->supportsHref && $fileLink) { + $sourceInfo = sprintf('%s', $fileLink, $sourceInfo); + } + $rows[] = ['source', $sourceInfo]; + $file = $source['file_relative'] ?? $source['file']; + $rows[] = ['file', $file]; + } + + $io->table([], $rows); + + if (!$this->supportsHref && isset($fileLink)) { + $io->writeln(['Open source in your IDE/browser:', $fileLink]); + $io->newLine(); + } + + $this->dumper->dump($data); + $io->newLine(); + } +} diff --git a/vendor/symfony/var-dumper/Command/Descriptor/DumpDescriptorInterface.php b/vendor/symfony/var-dumper/Command/Descriptor/DumpDescriptorInterface.php new file mode 100644 index 000000000..267d27bfa --- /dev/null +++ b/vendor/symfony/var-dumper/Command/Descriptor/DumpDescriptorInterface.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Command\Descriptor; + +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\VarDumper\Cloner\Data; + +/** + * @author Maxime Steinhausser + */ +interface DumpDescriptorInterface +{ + public function describe(OutputInterface $output, Data $data, array $context, int $clientId): void; +} diff --git a/vendor/symfony/var-dumper/Command/Descriptor/HtmlDescriptor.php b/vendor/symfony/var-dumper/Command/Descriptor/HtmlDescriptor.php new file mode 100644 index 000000000..636b61828 --- /dev/null +++ b/vendor/symfony/var-dumper/Command/Descriptor/HtmlDescriptor.php @@ -0,0 +1,119 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Command\Descriptor; + +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\VarDumper\Cloner\Data; +use Symfony\Component\VarDumper\Dumper\HtmlDumper; + +/** + * Describe collected data clones for html output. + * + * @author Maxime Steinhausser + * + * @final + */ +class HtmlDescriptor implements DumpDescriptorInterface +{ + private $dumper; + private $initialized = false; + + public function __construct(HtmlDumper $dumper) + { + $this->dumper = $dumper; + } + + public function describe(OutputInterface $output, Data $data, array $context, int $clientId): void + { + if (!$this->initialized) { + $styles = file_get_contents(__DIR__.'/../../Resources/css/htmlDescriptor.css'); + $scripts = file_get_contents(__DIR__.'/../../Resources/js/htmlDescriptor.js'); + $output->writeln(""); + $this->initialized = true; + } + + $title = '-'; + if (isset($context['request'])) { + $request = $context['request']; + $controller = "{$this->dumper->dump($request['controller'], true, ['maxDepth' => 0])}"; + $title = sprintf('%s %s', $request['method'], $uri = $request['uri'], $uri); + $dedupIdentifier = $request['identifier']; + } elseif (isset($context['cli'])) { + $title = '$ '.$context['cli']['command_line']; + $dedupIdentifier = $context['cli']['identifier']; + } else { + $dedupIdentifier = uniqid('', true); + } + + $sourceDescription = ''; + if (isset($context['source'])) { + $source = $context['source']; + $projectDir = $source['project_dir'] ?? null; + $sourceDescription = sprintf('%s on line %d', $source['name'], $source['line']); + if (isset($source['file_link'])) { + $sourceDescription = sprintf('%s', $source['file_link'], $sourceDescription); + } + } + + $isoDate = $this->extractDate($context, 'c'); + $tags = array_filter([ + 'controller' => $controller ?? null, + 'project dir' => $projectDir ?? null, + ]); + + $output->writeln(<< +
+
+

$title

+ +
+ {$this->renderTags($tags)} +
+
+

+ $sourceDescription +

+ {$this->dumper->dump($data, true)} +
+ +HTML + ); + } + + private function extractDate(array $context, string $format = 'r'): string + { + return date($format, (int) $context['timestamp']); + } + + private function renderTags(array $tags): string + { + if (!$tags) { + return ''; + } + + $renderedTags = ''; + foreach ($tags as $key => $value) { + $renderedTags .= sprintf('
  • %s%s
  • ', $key, $value); + } + + return << +
      + $renderedTags +
    + +HTML; + } +} diff --git a/vendor/symfony/var-dumper/Command/ServerDumpCommand.php b/vendor/symfony/var-dumper/Command/ServerDumpCommand.php new file mode 100644 index 000000000..b66301b52 --- /dev/null +++ b/vendor/symfony/var-dumper/Command/ServerDumpCommand.php @@ -0,0 +1,101 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Command; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Exception\InvalidArgumentException; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\VarDumper\Cloner\Data; +use Symfony\Component\VarDumper\Command\Descriptor\CliDescriptor; +use Symfony\Component\VarDumper\Command\Descriptor\DumpDescriptorInterface; +use Symfony\Component\VarDumper\Command\Descriptor\HtmlDescriptor; +use Symfony\Component\VarDumper\Dumper\CliDumper; +use Symfony\Component\VarDumper\Dumper\HtmlDumper; +use Symfony\Component\VarDumper\Server\DumpServer; + +/** + * Starts a dump server to collect and output dumps on a single place with multiple formats support. + * + * @author Maxime Steinhausser + * + * @final + */ +class ServerDumpCommand extends Command +{ + protected static $defaultName = 'server:dump'; + + private $server; + + /** @var DumpDescriptorInterface[] */ + private $descriptors; + + public function __construct(DumpServer $server, array $descriptors = []) + { + $this->server = $server; + $this->descriptors = $descriptors + [ + 'cli' => new CliDescriptor(new CliDumper()), + 'html' => new HtmlDescriptor(new HtmlDumper()), + ]; + + parent::__construct(); + } + + protected function configure() + { + $availableFormats = implode(', ', array_keys($this->descriptors)); + + $this + ->addOption('format', null, InputOption::VALUE_REQUIRED, sprintf('The output format (%s)', $availableFormats), 'cli') + ->setDescription('Start a dump server that collects and displays dumps in a single place') + ->setHelp(<<<'EOF' +%command.name% starts a dump server that collects and displays +dumps in a single place for debugging you application: + + php %command.full_name% + +You can consult dumped data in HTML format in your browser by providing the --format=html option +and redirecting the output to a file: + + php %command.full_name% --format="html" > dump.html + +EOF + ) + ; + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $io = new SymfonyStyle($input, $output); + $format = $input->getOption('format'); + + if (!$descriptor = $this->descriptors[$format] ?? null) { + throw new InvalidArgumentException(sprintf('Unsupported format "%s".', $format)); + } + + $errorIo = $io->getErrorStyle(); + $errorIo->title('Symfony Var Dumper Server'); + + $this->server->start(); + + $errorIo->success(sprintf('Server listening on %s', $this->server->getHost())); + $errorIo->comment('Quit the server with CONTROL-C.'); + + $this->server->listen(function (Data $data, array $context, int $clientId) use ($descriptor, $io) { + $descriptor->describe($io, $data, $context, $clientId); + }); + + return 0; + } +} diff --git a/vendor/symfony/var-dumper/Dumper/AbstractDumper.php b/vendor/symfony/var-dumper/Dumper/AbstractDumper.php new file mode 100644 index 000000000..eea56b599 --- /dev/null +++ b/vendor/symfony/var-dumper/Dumper/AbstractDumper.php @@ -0,0 +1,212 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Dumper; + +use Symfony\Component\VarDumper\Cloner\Data; +use Symfony\Component\VarDumper\Cloner\DumperInterface; + +/** + * Abstract mechanism for dumping a Data object. + * + * @author Nicolas Grekas + */ +abstract class AbstractDumper implements DataDumperInterface, DumperInterface +{ + public const DUMP_LIGHT_ARRAY = 1; + public const DUMP_STRING_LENGTH = 2; + public const DUMP_COMMA_SEPARATOR = 4; + public const DUMP_TRAILING_COMMA = 8; + + public static $defaultOutput = 'php://output'; + + protected $line = ''; + protected $lineDumper; + protected $outputStream; + protected $decimalPoint; // This is locale dependent + protected $indentPad = ' '; + protected $flags; + + private $charset = ''; + + /** + * @param callable|resource|string|null $output A line dumper callable, an opened stream or an output path, defaults to static::$defaultOutput + * @param string|null $charset The default character encoding to use for non-UTF8 strings + * @param int $flags A bit field of static::DUMP_* constants to fine tune dumps representation + */ + public function __construct($output = null, string $charset = null, int $flags = 0) + { + $this->flags = $flags; + $this->setCharset($charset ?: ini_get('php.output_encoding') ?: ini_get('default_charset') ?: 'UTF-8'); + $this->decimalPoint = localeconv(); + $this->decimalPoint = $this->decimalPoint['decimal_point']; + $this->setOutput($output ?: static::$defaultOutput); + if (!$output && \is_string(static::$defaultOutput)) { + static::$defaultOutput = $this->outputStream; + } + } + + /** + * Sets the output destination of the dumps. + * + * @param callable|resource|string $output A line dumper callable, an opened stream or an output path + * + * @return callable|resource|string The previous output destination + */ + public function setOutput($output) + { + $prev = null !== $this->outputStream ? $this->outputStream : $this->lineDumper; + + if (\is_callable($output)) { + $this->outputStream = null; + $this->lineDumper = $output; + } else { + if (\is_string($output)) { + $output = fopen($output, 'w'); + } + $this->outputStream = $output; + $this->lineDumper = [$this, 'echoLine']; + } + + return $prev; + } + + /** + * Sets the default character encoding to use for non-UTF8 strings. + * + * @param string $charset The default character encoding to use for non-UTF8 strings + * + * @return string The previous charset + */ + public function setCharset($charset) + { + $prev = $this->charset; + + $charset = strtoupper($charset); + $charset = null === $charset || 'UTF-8' === $charset || 'UTF8' === $charset ? 'CP1252' : $charset; + + $this->charset = $charset; + + return $prev; + } + + /** + * Sets the indentation pad string. + * + * @param string $pad A string that will be prepended to dumped lines, repeated by nesting level + * + * @return string The previous indent pad + */ + public function setIndentPad($pad) + { + $prev = $this->indentPad; + $this->indentPad = $pad; + + return $prev; + } + + /** + * Dumps a Data object. + * + * @param callable|resource|string|true|null $output A line dumper callable, an opened stream, an output path or true to return the dump + * + * @return string|null The dump as string when $output is true + */ + public function dump(Data $data, $output = null) + { + $this->decimalPoint = localeconv(); + $this->decimalPoint = $this->decimalPoint['decimal_point']; + + if ($locale = $this->flags & (self::DUMP_COMMA_SEPARATOR | self::DUMP_TRAILING_COMMA) ? setlocale(\LC_NUMERIC, 0) : null) { + setlocale(\LC_NUMERIC, 'C'); + } + + if ($returnDump = true === $output) { + $output = fopen('php://memory', 'r+'); + } + if ($output) { + $prevOutput = $this->setOutput($output); + } + try { + $data->dump($this); + $this->dumpLine(-1); + + if ($returnDump) { + $result = stream_get_contents($output, -1, 0); + fclose($output); + + return $result; + } + } finally { + if ($output) { + $this->setOutput($prevOutput); + } + if ($locale) { + setlocale(\LC_NUMERIC, $locale); + } + } + + return null; + } + + /** + * Dumps the current line. + * + * @param int $depth The recursive depth in the dumped structure for the line being dumped, + * or -1 to signal the end-of-dump to the line dumper callable + */ + protected function dumpLine($depth) + { + ($this->lineDumper)($this->line, $depth, $this->indentPad); + $this->line = ''; + } + + /** + * Generic line dumper callback. + * + * @param string $line The line to write + * @param int $depth The recursive depth in the dumped structure + * @param string $indentPad The line indent pad + */ + protected function echoLine($line, $depth, $indentPad) + { + if (-1 !== $depth) { + fwrite($this->outputStream, str_repeat($indentPad, $depth).$line."\n"); + } + } + + /** + * Converts a non-UTF-8 string to UTF-8. + * + * @param string|null $s The non-UTF-8 string to convert + * + * @return string|null The string converted to UTF-8 + */ + protected function utf8Encode($s) + { + if (null === $s || preg_match('//u', $s)) { + return $s; + } + + if (!\function_exists('iconv')) { + throw new \RuntimeException('Unable to convert a non-UTF-8 string to UTF-8: required function iconv() does not exist. You should install ext-iconv or symfony/polyfill-iconv.'); + } + + if (false !== $c = @iconv($this->charset, 'UTF-8', $s)) { + return $c; + } + if ('CP1252' !== $this->charset && false !== $c = @iconv('CP1252', 'UTF-8', $s)) { + return $c; + } + + return iconv('CP850', 'UTF-8', $s); + } +} diff --git a/vendor/symfony/var-dumper/Dumper/CliDumper.php b/vendor/symfony/var-dumper/Dumper/CliDumper.php new file mode 100644 index 000000000..55484b0b0 --- /dev/null +++ b/vendor/symfony/var-dumper/Dumper/CliDumper.php @@ -0,0 +1,655 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Dumper; + +use Symfony\Component\VarDumper\Cloner\Cursor; +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * CliDumper dumps variables for command line output. + * + * @author Nicolas Grekas + */ +class CliDumper extends AbstractDumper +{ + public static $defaultColors; + public static $defaultOutput = 'php://stdout'; + + protected $colors; + protected $maxStringWidth = 0; + protected $styles = [ + // See http://en.wikipedia.org/wiki/ANSI_escape_code#graphics + 'default' => '0;38;5;208', + 'num' => '1;38;5;38', + 'const' => '1;38;5;208', + 'str' => '1;38;5;113', + 'note' => '38;5;38', + 'ref' => '38;5;247', + 'public' => '', + 'protected' => '', + 'private' => '', + 'meta' => '38;5;170', + 'key' => '38;5;113', + 'index' => '38;5;38', + ]; + + protected static $controlCharsRx = '/[\x00-\x1F\x7F]+/'; + protected static $controlCharsMap = [ + "\t" => '\t', + "\n" => '\n', + "\v" => '\v', + "\f" => '\f', + "\r" => '\r', + "\033" => '\e', + ]; + + protected $collapseNextHash = false; + protected $expandNextHash = false; + + private $displayOptions = [ + 'fileLinkFormat' => null, + ]; + + private $handlesHrefGracefully; + + /** + * {@inheritdoc} + */ + public function __construct($output = null, string $charset = null, int $flags = 0) + { + parent::__construct($output, $charset, $flags); + + if ('\\' === \DIRECTORY_SEPARATOR && !$this->isWindowsTrueColor()) { + // Use only the base 16 xterm colors when using ANSICON or standard Windows 10 CLI + $this->setStyles([ + 'default' => '31', + 'num' => '1;34', + 'const' => '1;31', + 'str' => '1;32', + 'note' => '34', + 'ref' => '1;30', + 'meta' => '35', + 'key' => '32', + 'index' => '34', + ]); + } + + $this->displayOptions['fileLinkFormat'] = ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format') ?: 'file://%f#L%l'; + } + + /** + * Enables/disables colored output. + * + * @param bool $colors + */ + public function setColors($colors) + { + $this->colors = (bool) $colors; + } + + /** + * Sets the maximum number of characters per line for dumped strings. + * + * @param int $maxStringWidth + */ + public function setMaxStringWidth($maxStringWidth) + { + $this->maxStringWidth = (int) $maxStringWidth; + } + + /** + * Configures styles. + * + * @param array $styles A map of style names to style definitions + */ + public function setStyles(array $styles) + { + $this->styles = $styles + $this->styles; + } + + /** + * Configures display options. + * + * @param array $displayOptions A map of display options to customize the behavior + */ + public function setDisplayOptions(array $displayOptions) + { + $this->displayOptions = $displayOptions + $this->displayOptions; + } + + /** + * {@inheritdoc} + */ + public function dumpScalar(Cursor $cursor, $type, $value) + { + $this->dumpKey($cursor); + + $style = 'const'; + $attr = $cursor->attr; + + switch ($type) { + case 'default': + $style = 'default'; + break; + + case 'integer': + $style = 'num'; + break; + + case 'double': + $style = 'num'; + + switch (true) { + case \INF === $value: $value = 'INF'; break; + case -\INF === $value: $value = '-INF'; break; + case is_nan($value): $value = 'NAN'; break; + default: + $value = (string) $value; + if (false === strpos($value, $this->decimalPoint)) { + $value .= $this->decimalPoint.'0'; + } + break; + } + break; + + case 'NULL': + $value = 'null'; + break; + + case 'boolean': + $value = $value ? 'true' : 'false'; + break; + + default: + $attr += ['value' => $this->utf8Encode($value)]; + $value = $this->utf8Encode($type); + break; + } + + $this->line .= $this->style($style, $value, $attr); + + $this->endValue($cursor); + } + + /** + * {@inheritdoc} + */ + public function dumpString(Cursor $cursor, $str, $bin, $cut) + { + $this->dumpKey($cursor); + $attr = $cursor->attr; + + if ($bin) { + $str = $this->utf8Encode($str); + } + if ('' === $str) { + $this->line .= '""'; + $this->endValue($cursor); + } else { + $attr += [ + 'length' => 0 <= $cut ? mb_strlen($str, 'UTF-8') + $cut : 0, + 'binary' => $bin, + ]; + $str = explode("\n", $str); + if (isset($str[1]) && !isset($str[2]) && !isset($str[1][0])) { + unset($str[1]); + $str[0] .= "\n"; + } + $m = \count($str) - 1; + $i = $lineCut = 0; + + if (self::DUMP_STRING_LENGTH & $this->flags) { + $this->line .= '('.$attr['length'].') '; + } + if ($bin) { + $this->line .= 'b'; + } + + if ($m) { + $this->line .= '"""'; + $this->dumpLine($cursor->depth); + } else { + $this->line .= '"'; + } + + foreach ($str as $str) { + if ($i < $m) { + $str .= "\n"; + } + if (0 < $this->maxStringWidth && $this->maxStringWidth < $len = mb_strlen($str, 'UTF-8')) { + $str = mb_substr($str, 0, $this->maxStringWidth, 'UTF-8'); + $lineCut = $len - $this->maxStringWidth; + } + if ($m && 0 < $cursor->depth) { + $this->line .= $this->indentPad; + } + if ('' !== $str) { + $this->line .= $this->style('str', $str, $attr); + } + if ($i++ == $m) { + if ($m) { + if ('' !== $str) { + $this->dumpLine($cursor->depth); + if (0 < $cursor->depth) { + $this->line .= $this->indentPad; + } + } + $this->line .= '"""'; + } else { + $this->line .= '"'; + } + if ($cut < 0) { + $this->line .= '…'; + $lineCut = 0; + } elseif ($cut) { + $lineCut += $cut; + } + } + if ($lineCut) { + $this->line .= '…'.$lineCut; + $lineCut = 0; + } + + if ($i > $m) { + $this->endValue($cursor); + } else { + $this->dumpLine($cursor->depth); + } + } + } + } + + /** + * {@inheritdoc} + */ + public function enterHash(Cursor $cursor, $type, $class, $hasChild) + { + if (null === $this->colors) { + $this->colors = $this->supportsColors(); + } + + $this->dumpKey($cursor); + $attr = $cursor->attr; + + if ($this->collapseNextHash) { + $cursor->skipChildren = true; + $this->collapseNextHash = $hasChild = false; + } + + $class = $this->utf8Encode($class); + if (Cursor::HASH_OBJECT === $type) { + $prefix = $class && 'stdClass' !== $class ? $this->style('note', $class, $attr).(empty($attr['cut_hash']) ? ' {' : '') : '{'; + } elseif (Cursor::HASH_RESOURCE === $type) { + $prefix = $this->style('note', $class.' resource', $attr).($hasChild ? ' {' : ' '); + } else { + $prefix = $class && !(self::DUMP_LIGHT_ARRAY & $this->flags) ? $this->style('note', 'array:'.$class).' [' : '['; + } + + if (($cursor->softRefCount || 0 < $cursor->softRefHandle) && empty($attr['cut_hash'])) { + $prefix .= $this->style('ref', (Cursor::HASH_RESOURCE === $type ? '@' : '#').(0 < $cursor->softRefHandle ? $cursor->softRefHandle : $cursor->softRefTo), ['count' => $cursor->softRefCount]); + } elseif ($cursor->hardRefTo && !$cursor->refIndex && $class) { + $prefix .= $this->style('ref', '&'.$cursor->hardRefTo, ['count' => $cursor->hardRefCount]); + } elseif (!$hasChild && Cursor::HASH_RESOURCE === $type) { + $prefix = substr($prefix, 0, -1); + } + + $this->line .= $prefix; + + if ($hasChild) { + $this->dumpLine($cursor->depth); + } + } + + /** + * {@inheritdoc} + */ + public function leaveHash(Cursor $cursor, $type, $class, $hasChild, $cut) + { + if (empty($cursor->attr['cut_hash'])) { + $this->dumpEllipsis($cursor, $hasChild, $cut); + $this->line .= Cursor::HASH_OBJECT === $type ? '}' : (Cursor::HASH_RESOURCE !== $type ? ']' : ($hasChild ? '}' : '')); + } + + $this->endValue($cursor); + } + + /** + * Dumps an ellipsis for cut children. + * + * @param bool $hasChild When the dump of the hash has child item + * @param int $cut The number of items the hash has been cut by + */ + protected function dumpEllipsis(Cursor $cursor, $hasChild, $cut) + { + if ($cut) { + $this->line .= ' …'; + if (0 < $cut) { + $this->line .= $cut; + } + if ($hasChild) { + $this->dumpLine($cursor->depth + 1); + } + } + } + + /** + * Dumps a key in a hash structure. + */ + protected function dumpKey(Cursor $cursor) + { + if (null !== $key = $cursor->hashKey) { + if ($cursor->hashKeyIsBinary) { + $key = $this->utf8Encode($key); + } + $attr = ['binary' => $cursor->hashKeyIsBinary]; + $bin = $cursor->hashKeyIsBinary ? 'b' : ''; + $style = 'key'; + switch ($cursor->hashType) { + default: + case Cursor::HASH_INDEXED: + if (self::DUMP_LIGHT_ARRAY & $this->flags) { + break; + } + $style = 'index'; + // no break + case Cursor::HASH_ASSOC: + if (\is_int($key)) { + $this->line .= $this->style($style, $key).' => '; + } else { + $this->line .= $bin.'"'.$this->style($style, $key).'" => '; + } + break; + + case Cursor::HASH_RESOURCE: + $key = "\0~\0".$key; + // no break + case Cursor::HASH_OBJECT: + if (!isset($key[0]) || "\0" !== $key[0]) { + $this->line .= '+'.$bin.$this->style('public', $key).': '; + } elseif (0 < strpos($key, "\0", 1)) { + $key = explode("\0", substr($key, 1), 2); + + switch ($key[0][0]) { + case '+': // User inserted keys + $attr['dynamic'] = true; + $this->line .= '+'.$bin.'"'.$this->style('public', $key[1], $attr).'": '; + break 2; + case '~': + $style = 'meta'; + if (isset($key[0][1])) { + parse_str(substr($key[0], 1), $attr); + $attr += ['binary' => $cursor->hashKeyIsBinary]; + } + break; + case '*': + $style = 'protected'; + $bin = '#'.$bin; + break; + default: + $attr['class'] = $key[0]; + $style = 'private'; + $bin = '-'.$bin; + break; + } + + if (isset($attr['collapse'])) { + if ($attr['collapse']) { + $this->collapseNextHash = true; + } else { + $this->expandNextHash = true; + } + } + + $this->line .= $bin.$this->style($style, $key[1], $attr).($attr['separator'] ?? ': '); + } else { + // This case should not happen + $this->line .= '-'.$bin.'"'.$this->style('private', $key, ['class' => '']).'": '; + } + break; + } + + if ($cursor->hardRefTo) { + $this->line .= $this->style('ref', '&'.($cursor->hardRefCount ? $cursor->hardRefTo : ''), ['count' => $cursor->hardRefCount]).' '; + } + } + } + + /** + * Decorates a value with some style. + * + * @param string $style The type of style being applied + * @param string $value The value being styled + * @param array $attr Optional context information + * + * @return string The value with style decoration + */ + protected function style($style, $value, $attr = []) + { + if (null === $this->colors) { + $this->colors = $this->supportsColors(); + } + + if (null === $this->handlesHrefGracefully) { + $this->handlesHrefGracefully = 'JetBrains-JediTerm' !== getenv('TERMINAL_EMULATOR') + && (!getenv('KONSOLE_VERSION') || (int) getenv('KONSOLE_VERSION') > 201100); + } + + if (isset($attr['ellipsis'], $attr['ellipsis-type'])) { + $prefix = substr($value, 0, -$attr['ellipsis']); + if ('cli' === \PHP_SAPI && 'path' === $attr['ellipsis-type'] && isset($_SERVER[$pwd = '\\' === \DIRECTORY_SEPARATOR ? 'CD' : 'PWD']) && 0 === strpos($prefix, $_SERVER[$pwd])) { + $prefix = '.'.substr($prefix, \strlen($_SERVER[$pwd])); + } + if (!empty($attr['ellipsis-tail'])) { + $prefix .= substr($value, -$attr['ellipsis'], $attr['ellipsis-tail']); + $value = substr($value, -$attr['ellipsis'] + $attr['ellipsis-tail']); + } else { + $value = substr($value, -$attr['ellipsis']); + } + + $value = $this->style('default', $prefix).$this->style($style, $value); + + goto href; + } + + $map = static::$controlCharsMap; + $startCchr = $this->colors ? "\033[m\033[{$this->styles['default']}m" : ''; + $endCchr = $this->colors ? "\033[m\033[{$this->styles[$style]}m" : ''; + $value = preg_replace_callback(static::$controlCharsRx, function ($c) use ($map, $startCchr, $endCchr) { + $s = $startCchr; + $c = $c[$i = 0]; + do { + $s .= $map[$c[$i]] ?? sprintf('\x%02X', \ord($c[$i])); + } while (isset($c[++$i])); + + return $s.$endCchr; + }, $value, -1, $cchrCount); + + if ($this->colors) { + if ($cchrCount && "\033" === $value[0]) { + $value = substr($value, \strlen($startCchr)); + } else { + $value = "\033[{$this->styles[$style]}m".$value; + } + if ($cchrCount && $endCchr === substr($value, -\strlen($endCchr))) { + $value = substr($value, 0, -\strlen($endCchr)); + } else { + $value .= "\033[{$this->styles['default']}m"; + } + } + + href: + if ($this->colors && $this->handlesHrefGracefully) { + if (isset($attr['file']) && $href = $this->getSourceLink($attr['file'], $attr['line'] ?? 0)) { + if ('note' === $style) { + $value .= "\033]8;;{$href}\033\\^\033]8;;\033\\"; + } else { + $attr['href'] = $href; + } + } + if (isset($attr['href'])) { + $value = "\033]8;;{$attr['href']}\033\\{$value}\033]8;;\033\\"; + } + } elseif ($attr['if_links'] ?? false) { + return ''; + } + + return $value; + } + + /** + * @return bool Tells if the current output stream supports ANSI colors or not + */ + protected function supportsColors() + { + if ($this->outputStream !== static::$defaultOutput) { + return $this->hasColorSupport($this->outputStream); + } + if (null !== static::$defaultColors) { + return static::$defaultColors; + } + if (isset($_SERVER['argv'][1])) { + $colors = $_SERVER['argv']; + $i = \count($colors); + while (--$i > 0) { + if (isset($colors[$i][5])) { + switch ($colors[$i]) { + case '--ansi': + case '--color': + case '--color=yes': + case '--color=force': + case '--color=always': + return static::$defaultColors = true; + + case '--no-ansi': + case '--color=no': + case '--color=none': + case '--color=never': + return static::$defaultColors = false; + } + } + } + } + + $h = stream_get_meta_data($this->outputStream) + ['wrapper_type' => null]; + $h = 'Output' === $h['stream_type'] && 'PHP' === $h['wrapper_type'] ? fopen('php://stdout', 'w') : $this->outputStream; + + return static::$defaultColors = $this->hasColorSupport($h); + } + + /** + * {@inheritdoc} + */ + protected function dumpLine($depth, $endOfValue = false) + { + if ($this->colors) { + $this->line = sprintf("\033[%sm%s\033[m", $this->styles['default'], $this->line); + } + parent::dumpLine($depth); + } + + protected function endValue(Cursor $cursor) + { + if (-1 === $cursor->hashType) { + return; + } + + if (Stub::ARRAY_INDEXED === $cursor->hashType || Stub::ARRAY_ASSOC === $cursor->hashType) { + if (self::DUMP_TRAILING_COMMA & $this->flags && 0 < $cursor->depth) { + $this->line .= ','; + } elseif (self::DUMP_COMMA_SEPARATOR & $this->flags && 1 < $cursor->hashLength - $cursor->hashIndex) { + $this->line .= ','; + } + } + + $this->dumpLine($cursor->depth, true); + } + + /** + * Returns true if the stream supports colorization. + * + * Reference: Composer\XdebugHandler\Process::supportsColor + * https://github.com/composer/xdebug-handler + * + * @param mixed $stream A CLI output stream + */ + private function hasColorSupport($stream): bool + { + if (!\is_resource($stream) || 'stream' !== get_resource_type($stream)) { + return false; + } + + // Follow https://no-color.org/ + if (isset($_SERVER['NO_COLOR']) || false !== getenv('NO_COLOR')) { + return false; + } + + if ('Hyper' === getenv('TERM_PROGRAM')) { + return true; + } + + if (\DIRECTORY_SEPARATOR === '\\') { + return (\function_exists('sapi_windows_vt100_support') + && @sapi_windows_vt100_support($stream)) + || false !== getenv('ANSICON') + || 'ON' === getenv('ConEmuANSI') + || 'xterm' === getenv('TERM'); + } + + if (\function_exists('stream_isatty')) { + return @stream_isatty($stream); + } + + if (\function_exists('posix_isatty')) { + return @posix_isatty($stream); + } + + $stat = @fstat($stream); + // Check if formatted mode is S_IFCHR + return $stat ? 0020000 === ($stat['mode'] & 0170000) : false; + } + + /** + * Returns true if the Windows terminal supports true color. + * + * Note that this does not check an output stream, but relies on environment + * variables from known implementations, or a PHP and Windows version that + * supports true color. + */ + private function isWindowsTrueColor(): bool + { + $result = 183 <= getenv('ANSICON_VER') + || 'ON' === getenv('ConEmuANSI') + || 'xterm' === getenv('TERM') + || 'Hyper' === getenv('TERM_PROGRAM'); + + if (!$result && \PHP_VERSION_ID >= 70200) { + $version = sprintf( + '%s.%s.%s', + PHP_WINDOWS_VERSION_MAJOR, + PHP_WINDOWS_VERSION_MINOR, + PHP_WINDOWS_VERSION_BUILD + ); + $result = $version >= '10.0.15063'; + } + + return $result; + } + + private function getSourceLink(string $file, int $line) + { + if ($fmt = $this->displayOptions['fileLinkFormat']) { + return \is_string($fmt) ? strtr($fmt, ['%f' => $file, '%l' => $line]) : ($fmt->format($file, $line) ?: 'file://'.$file.'#L'.$line); + } + + return false; + } +} diff --git a/vendor/symfony/var-dumper/Dumper/ContextProvider/CliContextProvider.php b/vendor/symfony/var-dumper/Dumper/ContextProvider/CliContextProvider.php new file mode 100644 index 000000000..38f878971 --- /dev/null +++ b/vendor/symfony/var-dumper/Dumper/ContextProvider/CliContextProvider.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Dumper\ContextProvider; + +/** + * Tries to provide context on CLI. + * + * @author Maxime Steinhausser + */ +final class CliContextProvider implements ContextProviderInterface +{ + public function getContext(): ?array + { + if ('cli' !== \PHP_SAPI) { + return null; + } + + return [ + 'command_line' => $commandLine = implode(' ', $_SERVER['argv'] ?? []), + 'identifier' => hash('crc32b', $commandLine.$_SERVER['REQUEST_TIME_FLOAT']), + ]; + } +} diff --git a/vendor/symfony/var-dumper/Dumper/ContextProvider/ContextProviderInterface.php b/vendor/symfony/var-dumper/Dumper/ContextProvider/ContextProviderInterface.php new file mode 100644 index 000000000..38ef3b0f1 --- /dev/null +++ b/vendor/symfony/var-dumper/Dumper/ContextProvider/ContextProviderInterface.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Dumper\ContextProvider; + +/** + * Interface to provide contextual data about dump data clones sent to a server. + * + * @author Maxime Steinhausser + */ +interface ContextProviderInterface +{ + /** + * @return array|null Context data or null if unable to provide any context + */ + public function getContext(): ?array; +} diff --git a/vendor/symfony/var-dumper/Dumper/ContextProvider/RequestContextProvider.php b/vendor/symfony/var-dumper/Dumper/ContextProvider/RequestContextProvider.php new file mode 100644 index 000000000..3684a4753 --- /dev/null +++ b/vendor/symfony/var-dumper/Dumper/ContextProvider/RequestContextProvider.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Dumper\ContextProvider; + +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\VarDumper\Caster\ReflectionCaster; +use Symfony\Component\VarDumper\Cloner\VarCloner; + +/** + * Tries to provide context from a request. + * + * @author Maxime Steinhausser + */ +final class RequestContextProvider implements ContextProviderInterface +{ + private $requestStack; + private $cloner; + + public function __construct(RequestStack $requestStack) + { + $this->requestStack = $requestStack; + $this->cloner = new VarCloner(); + $this->cloner->setMaxItems(0); + $this->cloner->addCasters(ReflectionCaster::UNSET_CLOSURE_FILE_INFO); + } + + public function getContext(): ?array + { + if (null === $request = $this->requestStack->getCurrentRequest()) { + return null; + } + + $controller = $request->attributes->get('_controller'); + + return [ + 'uri' => $request->getUri(), + 'method' => $request->getMethod(), + 'controller' => $controller ? $this->cloner->cloneVar($controller) : $controller, + 'identifier' => spl_object_hash($request), + ]; + } +} diff --git a/vendor/symfony/var-dumper/Dumper/ContextProvider/SourceContextProvider.php b/vendor/symfony/var-dumper/Dumper/ContextProvider/SourceContextProvider.php new file mode 100644 index 000000000..c3cd3221a --- /dev/null +++ b/vendor/symfony/var-dumper/Dumper/ContextProvider/SourceContextProvider.php @@ -0,0 +1,126 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Dumper\ContextProvider; + +use Symfony\Component\HttpKernel\Debug\FileLinkFormatter; +use Symfony\Component\VarDumper\Cloner\VarCloner; +use Symfony\Component\VarDumper\Dumper\HtmlDumper; +use Symfony\Component\VarDumper\VarDumper; +use Twig\Template; + +/** + * Tries to provide context from sources (class name, file, line, code excerpt, ...). + * + * @author Nicolas Grekas + * @author Maxime Steinhausser + */ +final class SourceContextProvider implements ContextProviderInterface +{ + private $limit; + private $charset; + private $projectDir; + private $fileLinkFormatter; + + public function __construct(string $charset = null, string $projectDir = null, FileLinkFormatter $fileLinkFormatter = null, int $limit = 9) + { + $this->charset = $charset; + $this->projectDir = $projectDir; + $this->fileLinkFormatter = $fileLinkFormatter; + $this->limit = $limit; + } + + public function getContext(): ?array + { + $trace = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT | \DEBUG_BACKTRACE_IGNORE_ARGS, $this->limit); + + $file = $trace[1]['file']; + $line = $trace[1]['line']; + $name = false; + $fileExcerpt = false; + + for ($i = 2; $i < $this->limit; ++$i) { + if (isset($trace[$i]['class'], $trace[$i]['function']) + && 'dump' === $trace[$i]['function'] + && VarDumper::class === $trace[$i]['class'] + ) { + $file = $trace[$i]['file'] ?? $file; + $line = $trace[$i]['line'] ?? $line; + + while (++$i < $this->limit) { + if (isset($trace[$i]['function'], $trace[$i]['file']) && empty($trace[$i]['class']) && 0 !== strpos($trace[$i]['function'], 'call_user_func')) { + $file = $trace[$i]['file']; + $line = $trace[$i]['line']; + + break; + } elseif (isset($trace[$i]['object']) && $trace[$i]['object'] instanceof Template) { + $template = $trace[$i]['object']; + $name = $template->getTemplateName(); + $src = method_exists($template, 'getSourceContext') ? $template->getSourceContext()->getCode() : (method_exists($template, 'getSource') ? $template->getSource() : false); + $info = $template->getDebugInfo(); + if (isset($info[$trace[$i - 1]['line']])) { + $line = $info[$trace[$i - 1]['line']]; + $file = method_exists($template, 'getSourceContext') ? $template->getSourceContext()->getPath() : null; + + if ($src) { + $src = explode("\n", $src); + $fileExcerpt = []; + + for ($i = max($line - 3, 1), $max = min($line + 3, \count($src)); $i <= $max; ++$i) { + $fileExcerpt[] = ''.$this->htmlEncode($src[$i - 1]).''; + } + + $fileExcerpt = '
      '.implode("\n", $fileExcerpt).'
    '; + } + } + break; + } + } + break; + } + } + + if (false === $name) { + $name = str_replace('\\', '/', $file); + $name = substr($name, strrpos($name, '/') + 1); + } + + $context = ['name' => $name, 'file' => $file, 'line' => $line]; + $context['file_excerpt'] = $fileExcerpt; + + if (null !== $this->projectDir) { + $context['project_dir'] = $this->projectDir; + if (0 === strpos($file, $this->projectDir)) { + $context['file_relative'] = ltrim(substr($file, \strlen($this->projectDir)), \DIRECTORY_SEPARATOR); + } + } + + if ($this->fileLinkFormatter && $fileLink = $this->fileLinkFormatter->format($context['file'], $context['line'])) { + $context['file_link'] = $fileLink; + } + + return $context; + } + + private function htmlEncode(string $s): string + { + $html = ''; + + $dumper = new HtmlDumper(function ($line) use (&$html) { $html .= $line; }, $this->charset); + $dumper->setDumpHeader(''); + $dumper->setDumpBoundaries('', ''); + + $cloner = new VarCloner(); + $dumper->dump($cloner->cloneVar($s)); + + return substr(strip_tags($html), 1, -1); + } +} diff --git a/vendor/symfony/var-dumper/Dumper/ContextualizedDumper.php b/vendor/symfony/var-dumper/Dumper/ContextualizedDumper.php new file mode 100644 index 000000000..76384176e --- /dev/null +++ b/vendor/symfony/var-dumper/Dumper/ContextualizedDumper.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Dumper; + +use Symfony\Component\VarDumper\Cloner\Data; +use Symfony\Component\VarDumper\Dumper\ContextProvider\ContextProviderInterface; + +/** + * @author Kévin Thérage + */ +class ContextualizedDumper implements DataDumperInterface +{ + private $wrappedDumper; + private $contextProviders; + + /** + * @param ContextProviderInterface[] $contextProviders + */ + public function __construct(DataDumperInterface $wrappedDumper, array $contextProviders) + { + $this->wrappedDumper = $wrappedDumper; + $this->contextProviders = $contextProviders; + } + + public function dump(Data $data) + { + $context = []; + foreach ($this->contextProviders as $contextProvider) { + $context[\get_class($contextProvider)] = $contextProvider->getContext(); + } + + $this->wrappedDumper->dump($data->withContext($context)); + } +} diff --git a/vendor/symfony/var-dumper/Dumper/DataDumperInterface.php b/vendor/symfony/var-dumper/Dumper/DataDumperInterface.php new file mode 100644 index 000000000..b173bccf3 --- /dev/null +++ b/vendor/symfony/var-dumper/Dumper/DataDumperInterface.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Dumper; + +use Symfony\Component\VarDumper\Cloner\Data; + +/** + * DataDumperInterface for dumping Data objects. + * + * @author Nicolas Grekas + */ +interface DataDumperInterface +{ + public function dump(Data $data); +} diff --git a/vendor/symfony/var-dumper/Dumper/HtmlDumper.php b/vendor/symfony/var-dumper/Dumper/HtmlDumper.php new file mode 100644 index 000000000..6b205a737 --- /dev/null +++ b/vendor/symfony/var-dumper/Dumper/HtmlDumper.php @@ -0,0 +1,1004 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Dumper; + +use Symfony\Component\VarDumper\Cloner\Cursor; +use Symfony\Component\VarDumper\Cloner\Data; + +/** + * HtmlDumper dumps variables as HTML. + * + * @author Nicolas Grekas + */ +class HtmlDumper extends CliDumper +{ + public static $defaultOutput = 'php://output'; + + protected static $themes = [ + 'dark' => [ + 'default' => 'background-color:#18171B; color:#FF8400; line-height:1.2em; font:12px Menlo, Monaco, Consolas, monospace; word-wrap: break-word; white-space: pre-wrap; position:relative; z-index:99999; word-break: break-all', + 'num' => 'font-weight:bold; color:#1299DA', + 'const' => 'font-weight:bold', + 'str' => 'font-weight:bold; color:#56DB3A', + 'note' => 'color:#1299DA', + 'ref' => 'color:#A0A0A0', + 'public' => 'color:#FFFFFF', + 'protected' => 'color:#FFFFFF', + 'private' => 'color:#FFFFFF', + 'meta' => 'color:#B729D9', + 'key' => 'color:#56DB3A', + 'index' => 'color:#1299DA', + 'ellipsis' => 'color:#FF8400', + 'ns' => 'user-select:none;', + ], + 'light' => [ + 'default' => 'background:none; color:#CC7832; line-height:1.2em; font:12px Menlo, Monaco, Consolas, monospace; word-wrap: break-word; white-space: pre-wrap; position:relative; z-index:99999; word-break: break-all', + 'num' => 'font-weight:bold; color:#1299DA', + 'const' => 'font-weight:bold', + 'str' => 'font-weight:bold; color:#629755;', + 'note' => 'color:#6897BB', + 'ref' => 'color:#6E6E6E', + 'public' => 'color:#262626', + 'protected' => 'color:#262626', + 'private' => 'color:#262626', + 'meta' => 'color:#B729D9', + 'key' => 'color:#789339', + 'index' => 'color:#1299DA', + 'ellipsis' => 'color:#CC7832', + 'ns' => 'user-select:none;', + ], + ]; + + protected $dumpHeader; + protected $dumpPrefix = '
    ';
    +    protected $dumpSuffix = '
    '; + protected $dumpId = 'sf-dump'; + protected $colors = true; + protected $headerIsDumped = false; + protected $lastDepth = -1; + protected $styles; + + private $displayOptions = [ + 'maxDepth' => 1, + 'maxStringLength' => 160, + 'fileLinkFormat' => null, + ]; + private $extraDisplayOptions = []; + + /** + * {@inheritdoc} + */ + public function __construct($output = null, string $charset = null, int $flags = 0) + { + AbstractDumper::__construct($output, $charset, $flags); + $this->dumpId = 'sf-dump-'.mt_rand(); + $this->displayOptions['fileLinkFormat'] = ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format'); + $this->styles = static::$themes['dark'] ?? self::$themes['dark']; + } + + /** + * {@inheritdoc} + */ + public function setStyles(array $styles) + { + $this->headerIsDumped = false; + $this->styles = $styles + $this->styles; + } + + public function setTheme(string $themeName) + { + if (!isset(static::$themes[$themeName])) { + throw new \InvalidArgumentException(sprintf('Theme "%s" does not exist in class "%s".', $themeName, static::class)); + } + + $this->setStyles(static::$themes[$themeName]); + } + + /** + * Configures display options. + * + * @param array $displayOptions A map of display options to customize the behavior + */ + public function setDisplayOptions(array $displayOptions) + { + $this->headerIsDumped = false; + $this->displayOptions = $displayOptions + $this->displayOptions; + } + + /** + * Sets an HTML header that will be dumped once in the output stream. + * + * @param string $header An HTML string + */ + public function setDumpHeader($header) + { + $this->dumpHeader = $header; + } + + /** + * Sets an HTML prefix and suffix that will encapse every single dump. + * + * @param string $prefix The prepended HTML string + * @param string $suffix The appended HTML string + */ + public function setDumpBoundaries($prefix, $suffix) + { + $this->dumpPrefix = $prefix; + $this->dumpSuffix = $suffix; + } + + /** + * {@inheritdoc} + */ + public function dump(Data $data, $output = null, array $extraDisplayOptions = []) + { + $this->extraDisplayOptions = $extraDisplayOptions; + $result = parent::dump($data, $output); + $this->dumpId = 'sf-dump-'.mt_rand(); + + return $result; + } + + /** + * Dumps the HTML header. + */ + protected function getDumpHeader() + { + $this->headerIsDumped = null !== $this->outputStream ? $this->outputStream : $this->lineDumper; + + if (null !== $this->dumpHeader) { + return $this->dumpHeader; + } + + $line = str_replace('{$options}', json_encode($this->displayOptions, \JSON_FORCE_OBJECT), <<<'EOHTML' +'.$this->dumpHeader; + } + + /** + * {@inheritdoc} + */ + public function dumpString(Cursor $cursor, $str, $bin, $cut) + { + if ('' === $str && isset($cursor->attr['img-data'], $cursor->attr['content-type'])) { + $this->dumpKey($cursor); + $this->line .= $this->style('default', $cursor->attr['img-size'] ?? '', []).' '; + $this->endValue($cursor); + $this->line .= $this->indentPad; + $this->line .= sprintf('', $cursor->attr['content-type'], base64_encode($cursor->attr['img-data'])); + $this->endValue($cursor); + } else { + parent::dumpString($cursor, $str, $bin, $cut); + } + } + + /** + * {@inheritdoc} + */ + public function enterHash(Cursor $cursor, $type, $class, $hasChild) + { + if (Cursor::HASH_OBJECT === $type) { + $cursor->attr['depth'] = $cursor->depth; + } + parent::enterHash($cursor, $type, $class, false); + + if ($cursor->skipChildren) { + $cursor->skipChildren = false; + $eol = ' class=sf-dump-compact>'; + } elseif ($this->expandNextHash) { + $this->expandNextHash = false; + $eol = ' class=sf-dump-expanded>'; + } else { + $eol = '>'; + } + + if ($hasChild) { + $this->line .= 'refIndex) { + $r = Cursor::HASH_OBJECT !== $type ? 1 - (Cursor::HASH_RESOURCE !== $type) : 2; + $r .= $r && 0 < $cursor->softRefHandle ? $cursor->softRefHandle : $cursor->refIndex; + + $this->line .= sprintf(' id=%s-ref%s', $this->dumpId, $r); + } + $this->line .= $eol; + $this->dumpLine($cursor->depth); + } + } + + /** + * {@inheritdoc} + */ + public function leaveHash(Cursor $cursor, $type, $class, $hasChild, $cut) + { + $this->dumpEllipsis($cursor, $hasChild, $cut); + if ($hasChild) { + $this->line .= ''; + } + parent::leaveHash($cursor, $type, $class, $hasChild, 0); + } + + /** + * {@inheritdoc} + */ + protected function style($style, $value, $attr = []) + { + if ('' === $value) { + return ''; + } + + $v = esc($value); + + if ('ref' === $style) { + if (empty($attr['count'])) { + return sprintf('%s', $v); + } + $r = ('#' !== $v[0] ? 1 - ('@' !== $v[0]) : 2).substr($value, 1); + + return sprintf('%s', $this->dumpId, $r, 1 + $attr['count'], $v); + } + + if ('const' === $style && isset($attr['value'])) { + $style .= sprintf(' title="%s"', esc(is_scalar($attr['value']) ? $attr['value'] : json_encode($attr['value']))); + } elseif ('public' === $style) { + $style .= sprintf(' title="%s"', empty($attr['dynamic']) ? 'Public property' : 'Runtime added dynamic property'); + } elseif ('str' === $style && 1 < $attr['length']) { + $style .= sprintf(' title="%d%s characters"', $attr['length'], $attr['binary'] ? ' binary or non-UTF-8' : ''); + } elseif ('note' === $style && 0 < ($attr['depth'] ?? 0) && false !== $c = strrpos($value, '\\')) { + $style .= ' title=""'; + $attr += [ + 'ellipsis' => \strlen($value) - $c, + 'ellipsis-type' => 'note', + 'ellipsis-tail' => 1, + ]; + } elseif ('protected' === $style) { + $style .= ' title="Protected property"'; + } elseif ('meta' === $style && isset($attr['title'])) { + $style .= sprintf(' title="%s"', esc($this->utf8Encode($attr['title']))); + } elseif ('private' === $style) { + $style .= sprintf(' title="Private property defined in class: `%s`"', esc($this->utf8Encode($attr['class']))); + } + $map = static::$controlCharsMap; + + if (isset($attr['ellipsis'])) { + $class = 'sf-dump-ellipsis'; + if (isset($attr['ellipsis-type'])) { + $class = sprintf('"%s sf-dump-ellipsis-%s"', $class, $attr['ellipsis-type']); + } + $label = esc(substr($value, -$attr['ellipsis'])); + $style = str_replace(' title="', " title=\"$v\n", $style); + $v = sprintf('%s', $class, substr($v, 0, -\strlen($label))); + + if (!empty($attr['ellipsis-tail'])) { + $tail = \strlen(esc(substr($value, -$attr['ellipsis'], $attr['ellipsis-tail']))); + $v .= sprintf('%s%s', $class, substr($label, 0, $tail), substr($label, $tail)); + } else { + $v .= $label; + } + } + + $v = "".preg_replace_callback(static::$controlCharsRx, function ($c) use ($map) { + $s = $b = ''; + }, $v).''; + + if (isset($attr['file']) && $href = $this->getSourceLink($attr['file'], $attr['line'] ?? 0)) { + $attr['href'] = $href; + } + if (isset($attr['href'])) { + $target = isset($attr['file']) ? '' : ' target="_blank"'; + $v = sprintf('%s', esc($this->utf8Encode($attr['href'])), $target, $v); + } + if (isset($attr['lang'])) { + $v = sprintf('%s', esc($attr['lang']), $v); + } + + return $v; + } + + /** + * {@inheritdoc} + */ + protected function dumpLine($depth, $endOfValue = false) + { + if (-1 === $this->lastDepth) { + $this->line = sprintf($this->dumpPrefix, $this->dumpId, $this->indentPad).$this->line; + } + if ($this->headerIsDumped !== (null !== $this->outputStream ? $this->outputStream : $this->lineDumper)) { + $this->line = $this->getDumpHeader().$this->line; + } + + if (-1 === $depth) { + $args = ['"'.$this->dumpId.'"']; + if ($this->extraDisplayOptions) { + $args[] = json_encode($this->extraDisplayOptions, \JSON_FORCE_OBJECT); + } + // Replace is for BC + $this->line .= sprintf(str_replace('"%s"', '%s', $this->dumpSuffix), implode(', ', $args)); + } + $this->lastDepth = $depth; + + $this->line = mb_convert_encoding($this->line, 'HTML-ENTITIES', 'UTF-8'); + + if (-1 === $depth) { + AbstractDumper::dumpLine(0); + } + AbstractDumper::dumpLine($depth); + } + + private function getSourceLink(string $file, int $line) + { + $options = $this->extraDisplayOptions + $this->displayOptions; + + if ($fmt = $options['fileLinkFormat']) { + return \is_string($fmt) ? strtr($fmt, ['%f' => $file, '%l' => $line]) : $fmt->format($file, $line); + } + + return false; + } +} + +function esc($str) +{ + return htmlspecialchars($str, \ENT_QUOTES, 'UTF-8'); +} diff --git a/vendor/symfony/var-dumper/Dumper/ServerDumper.php b/vendor/symfony/var-dumper/Dumper/ServerDumper.php new file mode 100644 index 000000000..94795bf6d --- /dev/null +++ b/vendor/symfony/var-dumper/Dumper/ServerDumper.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Dumper; + +use Symfony\Component\VarDumper\Cloner\Data; +use Symfony\Component\VarDumper\Dumper\ContextProvider\ContextProviderInterface; +use Symfony\Component\VarDumper\Server\Connection; + +/** + * ServerDumper forwards serialized Data clones to a server. + * + * @author Maxime Steinhausser + */ +class ServerDumper implements DataDumperInterface +{ + private $connection; + private $wrappedDumper; + + /** + * @param string $host The server host + * @param DataDumperInterface|null $wrappedDumper A wrapped instance used whenever we failed contacting the server + * @param ContextProviderInterface[] $contextProviders Context providers indexed by context name + */ + public function __construct(string $host, DataDumperInterface $wrappedDumper = null, array $contextProviders = []) + { + $this->connection = new Connection($host, $contextProviders); + $this->wrappedDumper = $wrappedDumper; + } + + public function getContextProviders(): array + { + return $this->connection->getContextProviders(); + } + + /** + * {@inheritdoc} + */ + public function dump(Data $data) + { + if (!$this->connection->write($data) && $this->wrappedDumper) { + $this->wrappedDumper->dump($data); + } + } +} diff --git a/vendor/symfony/var-dumper/Exception/ThrowingCasterException.php b/vendor/symfony/var-dumper/Exception/ThrowingCasterException.php new file mode 100644 index 000000000..122f0d358 --- /dev/null +++ b/vendor/symfony/var-dumper/Exception/ThrowingCasterException.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Exception; + +/** + * @author Nicolas Grekas + */ +class ThrowingCasterException extends \Exception +{ + /** + * @param \Throwable $prev The exception thrown from the caster + */ + public function __construct(\Throwable $prev) + { + parent::__construct('Unexpected '.\get_class($prev).' thrown from a caster: '.$prev->getMessage(), 0, $prev); + } +} diff --git a/vendor/symfony/var-dumper/LICENSE b/vendor/symfony/var-dumper/LICENSE new file mode 100644 index 000000000..c1f0aac1c --- /dev/null +++ b/vendor/symfony/var-dumper/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2014-2021 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/var-dumper/README.md b/vendor/symfony/var-dumper/README.md new file mode 100644 index 000000000..bdac24477 --- /dev/null +++ b/vendor/symfony/var-dumper/README.md @@ -0,0 +1,15 @@ +VarDumper Component +=================== + +The VarDumper component provides mechanisms for walking through any arbitrary +PHP variable. It provides a better `dump()` function that you can use instead +of `var_dump`. + +Resources +--------- + + * [Documentation](https://symfony.com/doc/current/components/var_dumper/introduction.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/vendor/symfony/var-dumper/Resources/bin/var-dump-server b/vendor/symfony/var-dumper/Resources/bin/var-dump-server new file mode 100755 index 000000000..98c813a06 --- /dev/null +++ b/vendor/symfony/var-dumper/Resources/bin/var-dump-server @@ -0,0 +1,63 @@ +#!/usr/bin/env php + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Starts a dump server to collect and output dumps on a single place with multiple formats support. + * + * @author Maxime Steinhausser + */ + +use Psr\Log\LoggerInterface; +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Input\ArgvInput; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Logger\ConsoleLogger; +use Symfony\Component\Console\Output\ConsoleOutput; +use Symfony\Component\VarDumper\Command\ServerDumpCommand; +use Symfony\Component\VarDumper\Server\DumpServer; + +function includeIfExists(string $file): bool +{ + return file_exists($file) && include $file; +} + +if ( + !includeIfExists(__DIR__ . '/../../../../autoload.php') && + !includeIfExists(__DIR__ . '/../../vendor/autoload.php') && + !includeIfExists(__DIR__ . '/../../../../../../vendor/autoload.php') +) { + fwrite(STDERR, 'Install dependencies using Composer.'.PHP_EOL); + exit(1); +} + +if (!class_exists(Application::class)) { + fwrite(STDERR, 'You need the "symfony/console" component in order to run the VarDumper server.'.PHP_EOL); + exit(1); +} + +$input = new ArgvInput(); +$output = new ConsoleOutput(); +$defaultHost = '127.0.0.1:9912'; +$host = $input->getParameterOption(['--host'], $_SERVER['VAR_DUMPER_SERVER'] ?? $defaultHost, true); +$logger = interface_exists(LoggerInterface::class) ? new ConsoleLogger($output->getErrorOutput()) : null; + +$app = new Application(); + +$app->getDefinition()->addOption( + new InputOption('--host', null, InputOption::VALUE_REQUIRED, 'The address the server should listen to', $defaultHost) +); + +$app->add($command = new ServerDumpCommand(new DumpServer($host, $logger))) + ->getApplication() + ->setDefaultCommand($command->getName(), true) + ->run($input, $output) +; diff --git a/vendor/symfony/var-dumper/Resources/css/htmlDescriptor.css b/vendor/symfony/var-dumper/Resources/css/htmlDescriptor.css new file mode 100644 index 000000000..8f706d640 --- /dev/null +++ b/vendor/symfony/var-dumper/Resources/css/htmlDescriptor.css @@ -0,0 +1,130 @@ +body { + display: flex; + flex-direction: column-reverse; + justify-content: flex-end; + max-width: 1140px; + margin: auto; + padding: 15px; + word-wrap: break-word; + background-color: #F9F9F9; + color: #222; + font-family: Helvetica, Arial, sans-serif; + font-size: 14px; + line-height: 1.4; +} +p { + margin: 0; +} +a { + color: #218BC3; + text-decoration: none; +} +a:hover { + text-decoration: underline; +} +.text-small { + font-size: 12px !important; +} +article { + margin: 5px; + margin-bottom: 10px; +} +article > header > .row { + display: flex; + flex-direction: row; + align-items: baseline; + margin-bottom: 10px; +} +article > header > .row > .col { + flex: 1; + display: flex; + align-items: baseline; +} +article > header > .row > h2 { + font-size: 14px; + color: #222; + font-weight: normal; + font-family: "Lucida Console", monospace, sans-serif; + word-break: break-all; + margin: 20px 5px 0 0; + user-select: all; +} +article > header > .row > h2 > code { + white-space: nowrap; + user-select: none; + color: #cc2255; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; + border-radius: 3px; + margin-right: 5px; + padding: 0 3px; +} +article > header > .row > time.col { + flex: 0; + text-align: right; + white-space: nowrap; + color: #999; + font-style: italic; +} +article > header ul.tags { + list-style: none; + padding: 0; + margin: 0; + font-size: 12px; +} +article > header ul.tags > li { + user-select: all; + margin-bottom: 2px; +} +article > header ul.tags > li > span.badge { + display: inline-block; + padding: .25em .4em; + margin-right: 5px; + border-radius: 4px; + background-color: #6c757d3b; + color: #524d4d; + font-size: 12px; + text-align: center; + font-weight: 700; + line-height: 1; + white-space: nowrap; + vertical-align: baseline; + user-select: none; +} +article > section.body { + border: 1px solid #d8d8d8; + background: #FFF; + padding: 10px; + border-radius: 3px; +} +pre.sf-dump { + border-radius: 3px; + margin-bottom: 0; +} +.hidden { + display: none !important; +} +.dumped-tag > .sf-dump { + display: inline-block; + margin: 0; + padding: 1px 5px; + line-height: 1.4; + vertical-align: top; + background-color: transparent; + user-select: auto; +} +.dumped-tag > pre.sf-dump, +.dumped-tag > .sf-dump-default { + color: #CC7832; + background: none; +} +.dumped-tag > .sf-dump .sf-dump-str { color: #629755; } +.dumped-tag > .sf-dump .sf-dump-private, +.dumped-tag > .sf-dump .sf-dump-protected, +.dumped-tag > .sf-dump .sf-dump-public { color: #262626; } +.dumped-tag > .sf-dump .sf-dump-note { color: #6897BB; } +.dumped-tag > .sf-dump .sf-dump-key { color: #789339; } +.dumped-tag > .sf-dump .sf-dump-ref { color: #6E6E6E; } +.dumped-tag > .sf-dump .sf-dump-ellipsis { color: #CC7832; max-width: 100em; } +.dumped-tag > .sf-dump .sf-dump-ellipsis-path { max-width: 5em; } +.dumped-tag > .sf-dump .sf-dump-ns { user-select: none; } diff --git a/vendor/symfony/var-dumper/Resources/functions/dump.php b/vendor/symfony/var-dumper/Resources/functions/dump.php new file mode 100644 index 000000000..a485d573a --- /dev/null +++ b/vendor/symfony/var-dumper/Resources/functions/dump.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Component\VarDumper\VarDumper; + +if (!function_exists('dump')) { + /** + * @author Nicolas Grekas + */ + function dump($var, ...$moreVars) + { + VarDumper::dump($var); + + foreach ($moreVars as $v) { + VarDumper::dump($v); + } + + if (1 < func_num_args()) { + return func_get_args(); + } + + return $var; + } +} + +if (!function_exists('dd')) { + function dd(...$vars) + { + foreach ($vars as $v) { + VarDumper::dump($v); + } + + exit(1); + } +} diff --git a/vendor/symfony/var-dumper/Resources/js/htmlDescriptor.js b/vendor/symfony/var-dumper/Resources/js/htmlDescriptor.js new file mode 100644 index 000000000..63101e57c --- /dev/null +++ b/vendor/symfony/var-dumper/Resources/js/htmlDescriptor.js @@ -0,0 +1,10 @@ +document.addEventListener('DOMContentLoaded', function() { + let prev = null; + Array.from(document.getElementsByTagName('article')).reverse().forEach(function (article) { + const dedupId = article.dataset.dedupId; + if (dedupId === prev) { + article.getElementsByTagName('header')[0].classList.add('hidden'); + } + prev = dedupId; + }); +}); diff --git a/vendor/symfony/var-dumper/Server/Connection.php b/vendor/symfony/var-dumper/Server/Connection.php new file mode 100644 index 000000000..d8be23587 --- /dev/null +++ b/vendor/symfony/var-dumper/Server/Connection.php @@ -0,0 +1,95 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Server; + +use Symfony\Component\VarDumper\Cloner\Data; +use Symfony\Component\VarDumper\Dumper\ContextProvider\ContextProviderInterface; + +/** + * Forwards serialized Data clones to a server. + * + * @author Maxime Steinhausser + */ +class Connection +{ + private $host; + private $contextProviders; + private $socket; + + /** + * @param string $host The server host + * @param ContextProviderInterface[] $contextProviders Context providers indexed by context name + */ + public function __construct(string $host, array $contextProviders = []) + { + if (false === strpos($host, '://')) { + $host = 'tcp://'.$host; + } + + $this->host = $host; + $this->contextProviders = $contextProviders; + } + + public function getContextProviders(): array + { + return $this->contextProviders; + } + + public function write(Data $data): bool + { + $socketIsFresh = !$this->socket; + if (!$this->socket = $this->socket ?: $this->createSocket()) { + return false; + } + + $context = ['timestamp' => microtime(true)]; + foreach ($this->contextProviders as $name => $provider) { + $context[$name] = $provider->getContext(); + } + $context = array_filter($context); + $encodedPayload = base64_encode(serialize([$data, $context]))."\n"; + + set_error_handler([self::class, 'nullErrorHandler']); + try { + if (-1 !== stream_socket_sendto($this->socket, $encodedPayload)) { + return true; + } + if (!$socketIsFresh) { + stream_socket_shutdown($this->socket, \STREAM_SHUT_RDWR); + fclose($this->socket); + $this->socket = $this->createSocket(); + } + if (-1 !== stream_socket_sendto($this->socket, $encodedPayload)) { + return true; + } + } finally { + restore_error_handler(); + } + + return false; + } + + private static function nullErrorHandler($t, $m) + { + // no-op + } + + private function createSocket() + { + set_error_handler([self::class, 'nullErrorHandler']); + try { + return stream_socket_client($this->host, $errno, $errstr, 3, \STREAM_CLIENT_CONNECT | \STREAM_CLIENT_ASYNC_CONNECT); + } finally { + restore_error_handler(); + } + } +} diff --git a/vendor/symfony/var-dumper/Server/DumpServer.php b/vendor/symfony/var-dumper/Server/DumpServer.php new file mode 100644 index 000000000..55510c0e2 --- /dev/null +++ b/vendor/symfony/var-dumper/Server/DumpServer.php @@ -0,0 +1,107 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Server; + +use Psr\Log\LoggerInterface; +use Symfony\Component\VarDumper\Cloner\Data; +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * A server collecting Data clones sent by a ServerDumper. + * + * @author Maxime Steinhausser + * + * @final + */ +class DumpServer +{ + private $host; + private $socket; + private $logger; + + public function __construct(string $host, LoggerInterface $logger = null) + { + if (false === strpos($host, '://')) { + $host = 'tcp://'.$host; + } + + $this->host = $host; + $this->logger = $logger; + } + + public function start(): void + { + if (!$this->socket = stream_socket_server($this->host, $errno, $errstr)) { + throw new \RuntimeException(sprintf('Server start failed on "%s": ', $this->host).$errstr.' '.$errno); + } + } + + public function listen(callable $callback): void + { + if (null === $this->socket) { + $this->start(); + } + + foreach ($this->getMessages() as $clientId => $message) { + $payload = @unserialize(base64_decode($message), ['allowed_classes' => [Data::class, Stub::class]]); + + // Impossible to decode the message, give up. + if (false === $payload) { + if ($this->logger) { + $this->logger->warning('Unable to decode a message from {clientId} client.', ['clientId' => $clientId]); + } + + continue; + } + + if (!\is_array($payload) || \count($payload) < 2 || !$payload[0] instanceof Data || !\is_array($payload[1])) { + if ($this->logger) { + $this->logger->warning('Invalid payload from {clientId} client. Expected an array of two elements (Data $data, array $context)', ['clientId' => $clientId]); + } + + continue; + } + + [$data, $context] = $payload; + + $callback($data, $context, $clientId); + } + } + + public function getHost(): string + { + return $this->host; + } + + private function getMessages(): iterable + { + $sockets = [(int) $this->socket => $this->socket]; + $write = []; + + while (true) { + $read = $sockets; + stream_select($read, $write, $write, null); + + foreach ($read as $stream) { + if ($this->socket === $stream) { + $stream = stream_socket_accept($this->socket); + $sockets[(int) $stream] = $stream; + } elseif (feof($stream)) { + unset($sockets[(int) $stream]); + fclose($stream); + } else { + yield (int) $stream => fgets($stream); + } + } + } + } +} diff --git a/vendor/symfony/var-dumper/Test/VarDumperTestTrait.php b/vendor/symfony/var-dumper/Test/VarDumperTestTrait.php new file mode 100644 index 000000000..3d3d18eeb --- /dev/null +++ b/vendor/symfony/var-dumper/Test/VarDumperTestTrait.php @@ -0,0 +1,87 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Test; + +use Symfony\Component\VarDumper\Cloner\VarCloner; +use Symfony\Component\VarDumper\Dumper\CliDumper; + +/** + * @author Nicolas Grekas + */ +trait VarDumperTestTrait +{ + /** + * @internal + */ + private $varDumperConfig = [ + 'casters' => [], + 'flags' => null, + ]; + + protected function setUpVarDumper(array $casters, int $flags = null): void + { + $this->varDumperConfig['casters'] = $casters; + $this->varDumperConfig['flags'] = $flags; + } + + /** + * @after + */ + protected function tearDownVarDumper(): void + { + $this->varDumperConfig['casters'] = []; + $this->varDumperConfig['flags'] = null; + } + + public function assertDumpEquals($expected, $data, $filter = 0, $message = '') + { + $this->assertSame($this->prepareExpectation($expected, $filter), $this->getDump($data, null, $filter), $message); + } + + public function assertDumpMatchesFormat($expected, $data, $filter = 0, $message = '') + { + $this->assertStringMatchesFormat($this->prepareExpectation($expected, $filter), $this->getDump($data, null, $filter), $message); + } + + /** + * @return string|null + */ + protected function getDump($data, $key = null, $filter = 0) + { + if (null === $flags = $this->varDumperConfig['flags']) { + $flags = getenv('DUMP_LIGHT_ARRAY') ? CliDumper::DUMP_LIGHT_ARRAY : 0; + $flags |= getenv('DUMP_STRING_LENGTH') ? CliDumper::DUMP_STRING_LENGTH : 0; + $flags |= getenv('DUMP_COMMA_SEPARATOR') ? CliDumper::DUMP_COMMA_SEPARATOR : 0; + } + + $cloner = new VarCloner(); + $cloner->addCasters($this->varDumperConfig['casters']); + $cloner->setMaxItems(-1); + $dumper = new CliDumper(null, null, $flags); + $dumper->setColors(false); + $data = $cloner->cloneVar($data, $filter)->withRefHandles(false); + if (null !== $key && null === $data = $data->seek($key)) { + return null; + } + + return rtrim($dumper->dump($data, true)); + } + + private function prepareExpectation($expected, int $filter): string + { + if (!\is_string($expected)) { + $expected = $this->getDump($expected, null, $filter); + } + + return rtrim($expected); + } +} diff --git a/vendor/symfony/var-dumper/VarDumper.php b/vendor/symfony/var-dumper/VarDumper.php new file mode 100644 index 000000000..febc1e0d1 --- /dev/null +++ b/vendor/symfony/var-dumper/VarDumper.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper; + +use Symfony\Component\VarDumper\Caster\ReflectionCaster; +use Symfony\Component\VarDumper\Cloner\VarCloner; +use Symfony\Component\VarDumper\Dumper\CliDumper; +use Symfony\Component\VarDumper\Dumper\ContextProvider\SourceContextProvider; +use Symfony\Component\VarDumper\Dumper\ContextualizedDumper; +use Symfony\Component\VarDumper\Dumper\HtmlDumper; + +// Load the global dump() function +require_once __DIR__.'/Resources/functions/dump.php'; + +/** + * @author Nicolas Grekas + */ +class VarDumper +{ + private static $handler; + + public static function dump($var) + { + if (null === self::$handler) { + $cloner = new VarCloner(); + $cloner->addCasters(ReflectionCaster::UNSET_CLOSURE_FILE_INFO); + + if (isset($_SERVER['VAR_DUMPER_FORMAT'])) { + $dumper = 'html' === $_SERVER['VAR_DUMPER_FORMAT'] ? new HtmlDumper() : new CliDumper(); + } else { + $dumper = \in_array(\PHP_SAPI, ['cli', 'phpdbg']) ? new CliDumper() : new HtmlDumper(); + } + + $dumper = new ContextualizedDumper($dumper, [new SourceContextProvider()]); + + self::$handler = function ($var) use ($cloner, $dumper) { + $dumper->dump($cloner->cloneVar($var)); + }; + } + + return (self::$handler)($var); + } + + public static function setHandler(callable $callable = null) + { + $prevHandler = self::$handler; + + // Prevent replacing the handler with expected format as soon as the env var was set: + if (isset($_SERVER['VAR_DUMPER_FORMAT'])) { + return $prevHandler; + } + + self::$handler = $callable; + + return $prevHandler; + } +} diff --git a/vendor/symfony/var-dumper/composer.json b/vendor/symfony/var-dumper/composer.json new file mode 100644 index 000000000..642ee62b0 --- /dev/null +++ b/vendor/symfony/var-dumper/composer.json @@ -0,0 +1,50 @@ +{ + "name": "symfony/var-dumper", + "type": "library", + "description": "Provides mechanisms for walking through any arbitrary PHP variable", + "keywords": ["dump", "debug"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php72": "~1.5", + "symfony/polyfill-php80": "^1.15" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/process": "^4.4|^5.0", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "conflict": { + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/console": "<3.4" + }, + "suggest": { + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump", + "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" + }, + "autoload": { + "files": [ "Resources/functions/dump.php" ], + "psr-4": { "Symfony\\Component\\VarDumper\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "minimum-stability": "dev" +} diff --git a/thinkphp/.gitignore b/vendor/topthink/framework/.gitignore old mode 100755 new mode 100644 similarity index 75% rename from thinkphp/.gitignore rename to vendor/topthink/framework/.gitignore index f7775ba41..b267fbae4 --- a/thinkphp/.gitignore +++ b/vendor/topthink/framework/.gitignore @@ -3,6 +3,5 @@ composer.phar composer.lock .DS_Store Thumbs.db -/phpunit.xml /.idea /.vscode \ No newline at end of file diff --git a/vendor/topthink/framework/.travis.yml b/vendor/topthink/framework/.travis.yml new file mode 100644 index 000000000..28987af82 --- /dev/null +++ b/vendor/topthink/framework/.travis.yml @@ -0,0 +1,35 @@ +dist: xenial +language: php + +matrix: + fast_finish: true + include: + - php: 7.1 + - php: 7.2 + - php: 7.3 + +cache: + directories: + - $HOME/.composer/cache + +services: + - memcached + - redis-server + - mysql + +before_install: + - echo "extension = memcached.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini + - echo 'xdebug.mode = coverage' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini + - printf "\n" | pecl install -f redis + - travis_retry composer self-update + - mysql -e 'CREATE DATABASE test;' + +install: + - travis_retry composer update --prefer-dist --no-interaction --prefer-stable --no-suggest + +script: + - vendor/bin/phpunit --coverage-clover build/logs/coverage.xml + +after_script: + - travis_retry wget https://scrutinizer-ci.com/ocular.phar + - php ocular.phar code-coverage:upload --format=php-clover build/logs/coverage.xml diff --git a/thinkphp/CONTRIBUTING.md b/vendor/topthink/framework/CONTRIBUTING.md old mode 100755 new mode 100644 similarity index 95% rename from thinkphp/CONTRIBUTING.md rename to vendor/topthink/framework/CONTRIBUTING.md index 6cefcb38c..efa3ad972 --- a/thinkphp/CONTRIBUTING.md +++ b/vendor/topthink/framework/CONTRIBUTING.md @@ -22,7 +22,7 @@ ThinkPHP 目前使用 Git 来控制程序版本,如果你想为 ThinkPHP 贡 * 本项目代码格式化标准选用 [**PSR-2**](http://www.kancloud.cn/thinkphp/php-fig-psr/3141); * 类名和类文件名遵循 [**PSR-4**](http://www.kancloud.cn/thinkphp/php-fig-psr/3144); * 对于 Issues 的处理,请使用诸如 `fix #xxx(Issue ID)` 的 commit title 直接关闭 issue。 -* 系统会自动在 PHP 5.4 5.5 5.6 7.0 和 HHVM 上测试修改,其中 HHVM 下的测试容许报错,请确保你的修改符合 PHP 5.4 ~ 5.6 和 PHP 7.0 的语法规范; +* 系统会自动在 PHP 7.1 ~ 7.3 上测试修改,请确保你的修改符合 PHP 7.1 ~ 7.3 的语法规范; * 管理员不会合并造成 CI faild 的修改,若出现 CI faild 请检查自己的源代码或修改相应的[单元测试文件](tests); ## GitHub Issue @@ -84,7 +84,7 @@ GitHub 提供了 Issue 功能,该功能可以用于: 或自行安装 - Apache / Nginx -- PHP 5.4 ~ 5.6 +- PHP 7.1 ~ 7.3 - MySQL / MariaDB *Windows 用户推荐添加 PHP bin 目录到 PATH,方便使用 composer* diff --git a/thinkphp/LICENSE.txt b/vendor/topthink/framework/LICENSE.txt old mode 100755 new mode 100644 similarity index 96% rename from thinkphp/LICENSE.txt rename to vendor/topthink/framework/LICENSE.txt index 774fa76fd..4e910bb20 --- a/thinkphp/LICENSE.txt +++ b/vendor/topthink/framework/LICENSE.txt @@ -1,6 +1,6 @@ ThinkPHP遵循Apache2开源协议发布,并提供免费使用。 -版权所有Copyright © 2006-2018 by ThinkPHP (http://thinkphp.cn) +版权所有Copyright © 2006-2019 by ThinkPHP (http://thinkphp.cn) All rights reserved。 ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。 diff --git a/vendor/topthink/framework/README.md b/vendor/topthink/framework/README.md new file mode 100644 index 000000000..0ea03c987 --- /dev/null +++ b/vendor/topthink/framework/README.md @@ -0,0 +1,86 @@ +![](https://box.kancloud.cn/5a0aaa69a5ff42657b5c4715f3d49221) + +ThinkPHP 6.0 +=============== + +[![Build Status](https://travis-ci.org/top-think/framework.svg?branch=6.0)](https://travis-ci.org/top-think/framework) +[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/top-think/framework/badges/quality-score.png?b=6.0)](https://scrutinizer-ci.com/g/top-think/framework/?branch=6.0) +[![Code Coverage](https://scrutinizer-ci.com/g/top-think/framework/badges/coverage.png?b=6.0)](https://scrutinizer-ci.com/g/top-think/framework/?branch=6.0) +[![Total Downloads](https://poser.pugx.org/topthink/framework/downloads)](https://packagist.org/packages/topthink/framework) +[![Latest Stable Version](https://poser.pugx.org/topthink/framework/v/stable)](https://packagist.org/packages/topthink/framework) +[![PHP Version](https://img.shields.io/badge/php-%3E%3D7.1-8892BF.svg)](http://www.php.net/) +[![License](https://poser.pugx.org/topthink/framework/license)](https://packagist.org/packages/topthink/framework) + +ThinkPHP6.0底层架构采用PHP7.1改写和进一步优化。 + +[官方应用服务市场](https://market.topthink.com) | [`ThinkAPI`——官方统一API服务](https://docs.topthink.com/think-api/) + +## 主要新特性 + +* 采用`PHP7`强类型(严格模式) +* 支持更多的`PSR`规范 +* 原生多应用支持 +* 系统服务注入支持 +* ORM作为独立组件使用 +* 增加Filesystem +* 全新的事件系统 +* 模板引擎分离出核心 +* 内部功能中间件化 +* SESSION机制改进 +* 日志多通道支持 +* 规范扩展接口 +* 更强大的控制台 +* 对Swoole以及协程支持改进 +* 对IDE更加友好 +* 统一和精简大量用法 + + +> ThinkPHP6.0的运行环境要求PHP7.1+,兼容PHP8.0。 + +## 安装 + +~~~ +composer create-project topthink/think tp +~~~ + +启动服务 + +~~~ +cd tp +php think run +~~~ + +然后就可以在浏览器中访问 + +~~~ +http://localhost:8000 +~~~ + +如果需要更新框架使用 +~~~ +composer update topthink/framework +~~~ + +## 文档 + +[完全开发手册](https://www.kancloud.cn/manual/thinkphp6_0/content) + +## 命名规范 + +`ThinkPHP6`遵循PSR-2命名规范和PSR-4自动加载规范。 + +## 参与开发 + +直接提交PR或者Issue即可 + +## 版权信息 + +ThinkPHP遵循Apache2开源协议发布,并提供免费使用。 + +本项目包含的第三方源码和二进制文件之版权信息另行标注。 + +版权所有Copyright © 2006-2021 by ThinkPHP (http://thinkphp.cn) All rights reserved。 + +ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。 + +更多细节参阅 [LICENSE.txt](LICENSE.txt) diff --git a/vendor/topthink/framework/composer.json b/vendor/topthink/framework/composer.json new file mode 100644 index 000000000..9afc513a6 --- /dev/null +++ b/vendor/topthink/framework/composer.json @@ -0,0 +1,54 @@ +{ + "name": "topthink/framework", + "description": "The ThinkPHP Framework.", + "keywords": [ + "framework", + "thinkphp", + "ORM" + ], + "homepage": "http://thinkphp.cn/", + "license": "Apache-2.0", + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + }, + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "require": { + "php": ">=7.1.0", + "ext-json": "*", + "ext-mbstring": "*", + "league/flysystem": "^1.0", + "league/flysystem-cached-adapter": "^1.0", + "psr/log": "~1.0", + "psr/container": "~1.0", + "psr/simple-cache": "^1.0", + "topthink/think-orm": "^2.0", + "topthink/think-helper": "^3.1.1" + }, + "require-dev": { + "mikey179/vfsstream": "^1.6", + "mockery/mockery": "^1.2", + "phpunit/phpunit": "^7.0" + }, + "autoload": { + "files": [], + "psr-4": { + "think\\": "src/think/" + } + }, + "autoload-dev": { + "psr-4": { + "think\\tests\\": "tests/" + } + }, + "minimum-stability": "dev", + "prefer-stable": true, + "config": { + "sort-packages": true + } +} diff --git a/thinkphp/logo.png b/vendor/topthink/framework/logo.png old mode 100755 new mode 100644 similarity index 100% rename from thinkphp/logo.png rename to vendor/topthink/framework/logo.png diff --git a/vendor/topthink/framework/phpunit.xml.dist b/vendor/topthink/framework/phpunit.xml.dist new file mode 100644 index 000000000..e20a13381 --- /dev/null +++ b/vendor/topthink/framework/phpunit.xml.dist @@ -0,0 +1,25 @@ + + + + + ./tests + + + + + ./src/think + + + diff --git a/vendor/topthink/framework/src/helper.php b/vendor/topthink/framework/src/helper.php new file mode 100644 index 000000000..650edcb9f --- /dev/null +++ b/vendor/topthink/framework/src/helper.php @@ -0,0 +1,663 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +//------------------------ +// ThinkPHP 助手函数 +//------------------------- + +use think\App; +use think\Container; +use think\exception\HttpException; +use think\exception\HttpResponseException; +use think\facade\Cache; +use think\facade\Config; +use think\facade\Cookie; +use think\facade\Env; +use think\facade\Event; +use think\facade\Lang; +use think\facade\Log; +use think\facade\Request; +use think\facade\Route; +use think\facade\Session; +use think\Response; +use think\response\File; +use think\response\Json; +use think\response\Jsonp; +use think\response\Redirect; +use think\response\View; +use think\response\Xml; +use think\route\Url as UrlBuild; +use think\Validate; + +if (!function_exists('abort')) { + /** + * 抛出HTTP异常 + * @param integer|Response $code 状态码 或者 Response对象实例 + * @param string $message 错误信息 + * @param array $header 参数 + */ + function abort($code, string $message = '', array $header = []) + { + if ($code instanceof Response) { + throw new HttpResponseException($code); + } else { + throw new HttpException($code, $message, null, $header); + } + } +} + +if (!function_exists('app')) { + /** + * 快速获取容器中的实例 支持依赖注入 + * @param string $name 类名或标识 默认获取当前应用实例 + * @param array $args 参数 + * @param bool $newInstance 是否每次创建新的实例 + * @return object|App + */ + function app(string $name = '', array $args = [], bool $newInstance = false) + { + return Container::getInstance()->make($name ?: App::class, $args, $newInstance); + } +} + +if (!function_exists('bind')) { + /** + * 绑定一个类到容器 + * @param string|array $abstract 类标识、接口(支持批量绑定) + * @param mixed $concrete 要绑定的类、闭包或者实例 + * @return Container + */ + function bind($abstract, $concrete = null) + { + return Container::getInstance()->bind($abstract, $concrete); + } +} + +if (!function_exists('cache')) { + /** + * 缓存管理 + * @param string $name 缓存名称 + * @param mixed $value 缓存值 + * @param mixed $options 缓存参数 + * @param string $tag 缓存标签 + * @return mixed + */ + function cache(string $name = null, $value = '', $options = null, $tag = null) + { + if (is_null($name)) { + return app('cache'); + } + + if ('' === $value) { + // 获取缓存 + return 0 === strpos($name, '?') ? Cache::has(substr($name, 1)) : Cache::get($name); + } elseif (is_null($value)) { + // 删除缓存 + return Cache::delete($name); + } + + // 缓存数据 + if (is_array($options)) { + $expire = $options['expire'] ?? null; //修复查询缓存无法设置过期时间 + } else { + $expire = $options; + } + + if (is_null($tag)) { + return Cache::set($name, $value, $expire); + } else { + return Cache::tag($tag)->set($name, $value, $expire); + } + } +} + +if (!function_exists('config')) { + /** + * 获取和设置配置参数 + * @param string|array $name 参数名 + * @param mixed $value 参数值 + * @return mixed + */ + function config($name = '', $value = null) + { + if (is_array($name)) { + return Config::set($name, $value); + } + + return 0 === strpos($name, '?') ? Config::has(substr($name, 1)) : Config::get($name, $value); + } +} + +if (!function_exists('cookie')) { + /** + * Cookie管理 + * @param string $name cookie名称 + * @param mixed $value cookie值 + * @param mixed $option 参数 + * @return mixed + */ + function cookie(string $name, $value = '', $option = null) + { + if (is_null($value)) { + // 删除 + Cookie::delete($name); + } elseif ('' === $value) { + // 获取 + return 0 === strpos($name, '?') ? Cookie::has(substr($name, 1)) : Cookie::get($name); + } else { + // 设置 + return Cookie::set($name, $value, $option); + } + } +} + +if (!function_exists('download')) { + /** + * 获取\think\response\Download对象实例 + * @param string $filename 要下载的文件 + * @param string $name 显示文件名 + * @param bool $content 是否为内容 + * @param int $expire 有效期(秒) + * @return \think\response\File + */ + function download(string $filename, string $name = '', bool $content = false, int $expire = 180): File + { + return Response::create($filename, 'file')->name($name)->isContent($content)->expire($expire); + } +} + +if (!function_exists('dump')) { + /** + * 浏览器友好的变量输出 + * @param mixed $vars 要输出的变量 + * @return void + */ + function dump(...$vars) + { + ob_start(); + var_dump(...$vars); + + $output = ob_get_clean(); + $output = preg_replace('/\]\=\>\n(\s+)/m', '] => ', $output); + + if (PHP_SAPI == 'cli') { + $output = PHP_EOL . $output . PHP_EOL; + } else { + if (!extension_loaded('xdebug')) { + $output = htmlspecialchars($output, ENT_SUBSTITUTE); + } + $output = '
    ' . $output . '
    '; + } + + echo $output; + } +} + +if (!function_exists('env')) { + /** + * 获取环境变量值 + * @access public + * @param string $name 环境变量名(支持二级 .号分割) + * @param string $default 默认值 + * @return mixed + */ + function env(string $name = null, $default = null) + { + return Env::get($name, $default); + } +} + +if (!function_exists('event')) { + /** + * 触发事件 + * @param mixed $event 事件名(或者类名) + * @param mixed $args 参数 + * @return mixed + */ + function event($event, $args = null) + { + return Event::trigger($event, $args); + } +} + +if (!function_exists('halt')) { + /** + * 调试变量并且中断输出 + * @param mixed $vars 调试变量或者信息 + */ + function halt(...$vars) + { + dump(...$vars); + + throw new HttpResponseException(Response::create()); + } +} + +if (!function_exists('input')) { + /** + * 获取输入数据 支持默认值和过滤 + * @param string $key 获取的变量名 + * @param mixed $default 默认值 + * @param string $filter 过滤方法 + * @return mixed + */ + function input(string $key = '', $default = null, $filter = '') + { + if (0 === strpos($key, '?')) { + $key = substr($key, 1); + $has = true; + } + + if ($pos = strpos($key, '.')) { + // 指定参数来源 + $method = substr($key, 0, $pos); + if (in_array($method, ['get', 'post', 'put', 'patch', 'delete', 'route', 'param', 'request', 'session', 'cookie', 'server', 'env', 'path', 'file'])) { + $key = substr($key, $pos + 1); + if ('server' == $method && is_null($default)) { + $default = ''; + } + } else { + $method = 'param'; + } + } else { + // 默认为自动判断 + $method = 'param'; + } + + return isset($has) ? + request()->has($key, $method) : + request()->$method($key, $default, $filter); + } +} + +if (!function_exists('invoke')) { + /** + * 调用反射实例化对象或者执行方法 支持依赖注入 + * @param mixed $call 类名或者callable + * @param array $args 参数 + * @return mixed + */ + function invoke($call, array $args = []) + { + if (is_callable($call)) { + return Container::getInstance()->invoke($call, $args); + } + + return Container::getInstance()->invokeClass($call, $args); + } +} + +if (!function_exists('json')) { + /** + * 获取\think\response\Json对象实例 + * @param mixed $data 返回的数据 + * @param int $code 状态码 + * @param array $header 头部 + * @param array $options 参数 + * @return \think\response\Json + */ + function json($data = [], $code = 200, $header = [], $options = []): Json + { + return Response::create($data, 'json', $code)->header($header)->options($options); + } +} + +if (!function_exists('jsonp')) { + /** + * 获取\think\response\Jsonp对象实例 + * @param mixed $data 返回的数据 + * @param int $code 状态码 + * @param array $header 头部 + * @param array $options 参数 + * @return \think\response\Jsonp + */ + function jsonp($data = [], $code = 200, $header = [], $options = []): Jsonp + { + return Response::create($data, 'jsonp', $code)->header($header)->options($options); + } +} + +if (!function_exists('lang')) { + /** + * 获取语言变量值 + * @param string $name 语言变量名 + * @param array $vars 动态变量值 + * @param string $lang 语言 + * @return mixed + */ + function lang(string $name, array $vars = [], string $lang = '') + { + return Lang::get($name, $vars, $lang); + } +} + +if (!function_exists('parse_name')) { + /** + * 字符串命名风格转换 + * type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格 + * @param string $name 字符串 + * @param int $type 转换类型 + * @param bool $ucfirst 首字母是否大写(驼峰规则) + * @return string + */ + function parse_name(string $name, int $type = 0, bool $ucfirst = true): string + { + if ($type) { + $name = preg_replace_callback('/_([a-zA-Z])/', function ($match) { + return strtoupper($match[1]); + }, $name); + + return $ucfirst ? ucfirst($name) : lcfirst($name); + } + + return strtolower(trim(preg_replace('/[A-Z]/', '_\\0', $name), '_')); + } +} + +if (!function_exists('redirect')) { + /** + * 获取\think\response\Redirect对象实例 + * @param string $url 重定向地址 + * @param int $code 状态码 + * @return \think\response\Redirect + */ + function redirect(string $url = '', int $code = 302): Redirect + { + return Response::create($url, 'redirect', $code); + } +} + +if (!function_exists('request')) { + /** + * 获取当前Request对象实例 + * @return Request + */ + function request(): \think\Request + { + return app('request'); + } +} + +if (!function_exists('response')) { + /** + * 创建普通 Response 对象实例 + * @param mixed $data 输出数据 + * @param int|string $code 状态码 + * @param array $header 头信息 + * @param string $type + * @return Response + */ + function response($data = '', $code = 200, $header = [], $type = 'html'): Response + { + return Response::create($data, $type, $code)->header($header); + } +} + +if (!function_exists('session')) { + /** + * Session管理 + * @param string $name session名称 + * @param mixed $value session值 + * @return mixed + */ + function session($name = '', $value = '') + { + if (is_null($name)) { + // 清除 + Session::clear(); + } elseif ('' === $name) { + return Session::all(); + } elseif (is_null($value)) { + // 删除 + Session::delete($name); + } elseif ('' === $value) { + // 判断或获取 + return 0 === strpos($name, '?') ? Session::has(substr($name, 1)) : Session::get($name); + } else { + // 设置 + Session::set($name, $value); + } + } +} + +if (!function_exists('token')) { + /** + * 获取Token令牌 + * @param string $name 令牌名称 + * @param mixed $type 令牌生成方法 + * @return string + */ + function token(string $name = '__token__', string $type = 'md5'): string + { + return Request::buildToken($name, $type); + } +} + +if (!function_exists('token_field')) { + /** + * 生成令牌隐藏表单 + * @param string $name 令牌名称 + * @param mixed $type 令牌生成方法 + * @return string + */ + function token_field(string $name = '__token__', string $type = 'md5'): string + { + $token = Request::buildToken($name, $type); + + return ''; + } +} + +if (!function_exists('token_meta')) { + /** + * 生成令牌meta + * @param string $name 令牌名称 + * @param mixed $type 令牌生成方法 + * @return string + */ + function token_meta(string $name = '__token__', string $type = 'md5'): string + { + $token = Request::buildToken($name, $type); + + return ''; + } +} + +if (!function_exists('trace')) { + /** + * 记录日志信息 + * @param mixed $log log信息 支持字符串和数组 + * @param string $level 日志级别 + * @return array|void + */ + function trace($log = '[think]', string $level = 'log') + { + if ('[think]' === $log) { + return Log::getLog(); + } + + Log::record($log, $level); + } +} + +if (!function_exists('url')) { + /** + * Url生成 + * @param string $url 路由地址 + * @param array $vars 变量 + * @param bool|string $suffix 生成的URL后缀 + * @param bool|string $domain 域名 + * @return UrlBuild + */ + function url(string $url = '', array $vars = [], $suffix = true, $domain = false): UrlBuild + { + return Route::buildUrl($url, $vars)->suffix($suffix)->domain($domain); + } +} + +if (!function_exists('validate')) { + /** + * 生成验证对象 + * @param string|array $validate 验证器类名或者验证规则数组 + * @param array $message 错误提示信息 + * @param bool $batch 是否批量验证 + * @param bool $failException 是否抛出异常 + * @return Validate + */ + function validate($validate = '', array $message = [], bool $batch = false, bool $failException = true): Validate + { + if (is_array($validate) || '' === $validate) { + $v = new Validate(); + if (is_array($validate)) { + $v->rule($validate); + } + } else { + if (strpos($validate, '.')) { + // 支持场景 + [$validate, $scene] = explode('.', $validate); + } + + $class = false !== strpos($validate, '\\') ? $validate : app()->parseClass('validate', $validate); + + $v = new $class(); + + if (!empty($scene)) { + $v->scene($scene); + } + } + + return $v->message($message)->batch($batch)->failException($failException); + } +} + +if (!function_exists('view')) { + /** + * 渲染模板输出 + * @param string $template 模板文件 + * @param array $vars 模板变量 + * @param int $code 状态码 + * @param callable $filter 内容过滤 + * @return \think\response\View + */ + function view(string $template = '', $vars = [], $code = 200, $filter = null): View + { + return Response::create($template, 'view', $code)->assign($vars)->filter($filter); + } +} + +if (!function_exists('display')) { + /** + * 渲染模板输出 + * @param string $content 渲染内容 + * @param array $vars 模板变量 + * @param int $code 状态码 + * @param callable $filter 内容过滤 + * @return \think\response\View + */ + function display(string $content, $vars = [], $code = 200, $filter = null): View + { + return Response::create($content, 'view', $code)->isContent(true)->assign($vars)->filter($filter); + } +} + +if (!function_exists('xml')) { + /** + * 获取\think\response\Xml对象实例 + * @param mixed $data 返回的数据 + * @param int $code 状态码 + * @param array $header 头部 + * @param array $options 参数 + * @return \think\response\Xml + */ + function xml($data = [], $code = 200, $header = [], $options = []): Xml + { + return Response::create($data, 'xml', $code)->header($header)->options($options); + } +} + +if (!function_exists('app_path')) { + /** + * 获取当前应用目录 + * + * @param string $path + * @return string + */ + function app_path($path = '') + { + return app()->getAppPath() . ($path ? $path . DIRECTORY_SEPARATOR : $path); + } +} + +if (!function_exists('base_path')) { + /** + * 获取应用基础目录 + * + * @param string $path + * @return string + */ + function base_path($path = '') + { + return app()->getBasePath() . ($path ? $path . DIRECTORY_SEPARATOR : $path); + } +} + +if (!function_exists('config_path')) { + /** + * 获取应用配置目录 + * + * @param string $path + * @return string + */ + function config_path($path = '') + { + return app()->getConfigPath() . ($path ? $path . DIRECTORY_SEPARATOR : $path); + } +} + +if (!function_exists('public_path')) { + /** + * 获取web根目录 + * + * @param string $path + * @return string + */ + function public_path($path = '') + { + return app()->getRootPath() . 'public' . DIRECTORY_SEPARATOR . ($path ? ltrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR : $path); + } +} + +if (!function_exists('runtime_path')) { + /** + * 获取应用运行时目录 + * + * @param string $path + * @return string + */ + function runtime_path($path = '') + { + return app()->getRuntimePath() . ($path ? $path . DIRECTORY_SEPARATOR : $path); + } +} + +if (!function_exists('root_path')) { + /** + * 获取项目根目录 + * + * @param string $path + * @return string + */ + function root_path($path = '') + { + return app()->getRootPath() . ($path ? $path . DIRECTORY_SEPARATOR : $path); + } +} diff --git a/thinkphp/lang/zh-cn.php b/vendor/topthink/framework/src/lang/zh-cn.php old mode 100755 new mode 100644 similarity index 94% rename from thinkphp/lang/zh-cn.php rename to vendor/topthink/framework/src/lang/zh-cn.php index 1e0508204..a546330a0 --- a/thinkphp/lang/zh-cn.php +++ b/vendor/topthink/framework/src/lang/zh-cn.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -25,8 +25,7 @@ return [ 'method param miss' => '方法参数错误', 'method not exists' => '方法不存在', 'function not exists' => '函数不存在', - 'file not exists' => '文件不存在', - 'module not exists' => '模块不存在', + 'app not exists' => '应用不存在', 'controller not exists' => '控制器不存在', 'class not exists' => '类不存在', 'property not exists' => '类的属性不存在', @@ -34,15 +33,20 @@ return [ 'illegal controller name' => '非法的控制器名称', 'illegal action name' => '非法的操作名称', 'url suffix deny' => '禁止的URL后缀访问', + 'Undefined cache config' => '缓存配置未定义', 'Route Not Found' => '当前访问路由未定义或不匹配', + 'Undefined db config' => '数据库配置未定义', + 'Undefined log config' => '日志配置未定义', 'Undefined db type' => '未定义数据库类型', 'variable type error' => '变量类型错误', 'PSR-4 error' => 'PSR-4 规范错误', + 'not support type' => '不支持的分页索引字段类型', 'not support total' => '简洁模式下不能获取数据总数', 'not support last' => '简洁模式下不能获取最后一页', 'error session handler' => '错误的SESSION处理器类', 'not allow php tag' => '模板不允许使用PHP语法', 'not support' => '不支持', + 'database config error' => '数据库配置信息错误', 'redisd master' => 'Redisd 主服务器错误', 'redisd slave' => 'Redisd 从服务器错误', 'must run at sae' => '必须在SAE运行', @@ -50,10 +54,8 @@ return [ 'KVDB init error' => '没有初始化KVDB,请在SAE管理平台初始化KVDB服务', 'fields not exists' => '数据表字段不存在', 'where express error' => '查询表达式错误', - 'order express error' => '排序表达式错误', 'no data to update' => '没有任何数据需要更新', 'miss data to insert' => '缺少需要写入的数据', - 'not support data' => '不支持的数据表达式', 'miss complex primary data' => '缺少复合主键数据', 'miss update condition' => '缺少更新条件', 'model data Not Found' => '模型数据不存在', @@ -141,4 +143,6 @@ return [ 'invalid Request method' => '无效的请求类型', 'invalid token' => '令牌数据无效', 'not conform to the rules' => '规则错误', + + 'record has update' => '记录已经被更新了', ]; diff --git a/vendor/topthink/framework/src/think/App.php b/vendor/topthink/framework/src/think/App.php new file mode 100644 index 000000000..cdcfeb8d2 --- /dev/null +++ b/vendor/topthink/framework/src/think/App.php @@ -0,0 +1,639 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think; + +use think\event\AppInit; +use think\helper\Str; +use think\initializer\BootService; +use think\initializer\Error; +use think\initializer\RegisterService; + +/** + * App 基础类 + * @property Route $route + * @property Config $config + * @property Cache $cache + * @property Request $request + * @property Http $http + * @property Console $console + * @property Env $env + * @property Event $event + * @property Middleware $middleware + * @property Log $log + * @property Lang $lang + * @property Db $db + * @property Cookie $cookie + * @property Session $session + * @property Validate $validate + * @property Filesystem $filesystem + */ +class App extends Container +{ + const VERSION = '6.0.8'; + + /** + * 应用调试模式 + * @var bool + */ + protected $appDebug = false; + + /** + * 环境变量标识 + * @var string + */ + protected $envName = ''; + + /** + * 应用开始时间 + * @var float + */ + protected $beginTime; + + /** + * 应用内存初始占用 + * @var integer + */ + protected $beginMem; + + /** + * 当前应用类库命名空间 + * @var string + */ + protected $namespace = 'app'; + + /** + * 应用根目录 + * @var string + */ + protected $rootPath = ''; + + /** + * 框架目录 + * @var string + */ + protected $thinkPath = ''; + + /** + * 应用目录 + * @var string + */ + protected $appPath = ''; + + /** + * Runtime目录 + * @var string + */ + protected $runtimePath = ''; + + /** + * 路由定义目录 + * @var string + */ + protected $routePath = ''; + + /** + * 配置后缀 + * @var string + */ + protected $configExt = '.php'; + + /** + * 应用初始化器 + * @var array + */ + protected $initializers = [ + Error::class, + RegisterService::class, + BootService::class, + ]; + + /** + * 注册的系统服务 + * @var array + */ + protected $services = []; + + /** + * 初始化 + * @var bool + */ + protected $initialized = false; + + /** + * 容器绑定标识 + * @var array + */ + protected $bind = [ + 'app' => App::class, + 'cache' => Cache::class, + 'config' => Config::class, + 'console' => Console::class, + 'cookie' => Cookie::class, + 'db' => Db::class, + 'env' => Env::class, + 'event' => Event::class, + 'http' => Http::class, + 'lang' => Lang::class, + 'log' => Log::class, + 'middleware' => Middleware::class, + 'request' => Request::class, + 'response' => Response::class, + 'route' => Route::class, + 'session' => Session::class, + 'validate' => Validate::class, + 'view' => View::class, + 'filesystem' => Filesystem::class, + 'think\DbManager' => Db::class, + 'think\LogManager' => Log::class, + 'think\CacheManager' => Cache::class, + + // 接口依赖注入 + 'Psr\Log\LoggerInterface' => Log::class, + ]; + + /** + * 架构方法 + * @access public + * @param string $rootPath 应用根目录 + */ + public function __construct(string $rootPath = '') + { + $this->thinkPath = dirname(__DIR__) . DIRECTORY_SEPARATOR; + $this->rootPath = $rootPath ? rtrim($rootPath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR : $this->getDefaultRootPath(); + $this->appPath = $this->rootPath . 'app' . DIRECTORY_SEPARATOR; + $this->runtimePath = $this->rootPath . 'runtime' . DIRECTORY_SEPARATOR; + + if (is_file($this->appPath . 'provider.php')) { + $this->bind(include $this->appPath . 'provider.php'); + } + + static::setInstance($this); + + $this->instance('app', $this); + $this->instance('think\Container', $this); + } + + /** + * 注册服务 + * @access public + * @param Service|string $service 服务 + * @param bool $force 强制重新注册 + * @return Service|null + */ + public function register($service, bool $force = false) + { + $registered = $this->getService($service); + + if ($registered && !$force) { + return $registered; + } + + if (is_string($service)) { + $service = new $service($this); + } + + if (method_exists($service, 'register')) { + $service->register(); + } + + if (property_exists($service, 'bind')) { + $this->bind($service->bind); + } + + $this->services[] = $service; + } + + /** + * 执行服务 + * @access public + * @param Service $service 服务 + * @return mixed + */ + public function bootService($service) + { + if (method_exists($service, 'boot')) { + return $this->invoke([$service, 'boot']); + } + } + + /** + * 获取服务 + * @param string|Service $service + * @return Service|null + */ + public function getService($service) + { + $name = is_string($service) ? $service : get_class($service); + return array_values(array_filter($this->services, function ($value) use ($name) { + return $value instanceof $name; + }, ARRAY_FILTER_USE_BOTH))[0] ?? null; + } + + /** + * 开启应用调试模式 + * @access public + * @param bool $debug 开启应用调试模式 + * @return $this + */ + public function debug(bool $debug = true) + { + $this->appDebug = $debug; + return $this; + } + + /** + * 是否为调试模式 + * @access public + * @return bool + */ + public function isDebug(): bool + { + return $this->appDebug; + } + + /** + * 设置应用命名空间 + * @access public + * @param string $namespace 应用命名空间 + * @return $this + */ + public function setNamespace(string $namespace) + { + $this->namespace = $namespace; + return $this; + } + + /** + * 获取应用类库命名空间 + * @access public + * @return string + */ + public function getNamespace(): string + { + return $this->namespace; + } + + /** + * 设置环境变量标识 + * @access public + * @param string $name 环境标识 + * @return $this + */ + public function setEnvName(string $name) + { + $this->envName = $name; + return $this; + } + + /** + * 获取框架版本 + * @access public + * @return string + */ + public function version(): string + { + return static::VERSION; + } + + /** + * 获取应用根目录 + * @access public + * @return string + */ + public function getRootPath(): string + { + return $this->rootPath; + } + + /** + * 获取应用基础目录 + * @access public + * @return string + */ + public function getBasePath(): string + { + return $this->rootPath . 'app' . DIRECTORY_SEPARATOR; + } + + /** + * 获取当前应用目录 + * @access public + * @return string + */ + public function getAppPath(): string + { + return $this->appPath; + } + + /** + * 设置应用目录 + * @param string $path 应用目录 + */ + public function setAppPath(string $path) + { + $this->appPath = $path; + } + + /** + * 获取应用运行时目录 + * @access public + * @return string + */ + public function getRuntimePath(): string + { + return $this->runtimePath; + } + + /** + * 设置runtime目录 + * @param string $path 定义目录 + */ + public function setRuntimePath(string $path): void + { + $this->runtimePath = $path; + } + + /** + * 获取核心框架目录 + * @access public + * @return string + */ + public function getThinkPath(): string + { + return $this->thinkPath; + } + + /** + * 获取应用配置目录 + * @access public + * @return string + */ + public function getConfigPath(): string + { + return $this->rootPath . 'config' . DIRECTORY_SEPARATOR; + } + + /** + * 获取配置后缀 + * @access public + * @return string + */ + public function getConfigExt(): string + { + return $this->configExt; + } + + /** + * 获取应用开启时间 + * @access public + * @return float + */ + public function getBeginTime(): float + { + return $this->beginTime; + } + + /** + * 获取应用初始内存占用 + * @access public + * @return integer + */ + public function getBeginMem(): int + { + return $this->beginMem; + } + + /** + * 加载环境变量定义 + * @access public + * @param string $envName 环境标识 + * @return void + */ + public function loadEnv(string $envName = ''): void + { + // 加载环境变量 + $envFile = $envName ? $this->rootPath . '.env.' . $envName : $this->rootPath . '.env'; + + if (is_file($envFile)) { + $this->env->load($envFile); + } + } + + /** + * 初始化应用 + * @access public + * @return $this + */ + public function initialize() + { + $this->initialized = true; + + $this->beginTime = microtime(true); + $this->beginMem = memory_get_usage(); + + $this->loadEnv($this->envName); + + $this->configExt = $this->env->get('config_ext', '.php'); + + $this->debugModeInit(); + + // 加载全局初始化文件 + $this->load(); + + // 加载框架默认语言包 + $langSet = $this->lang->defaultLangSet(); + + $this->lang->load($this->thinkPath . 'lang' . DIRECTORY_SEPARATOR . $langSet . '.php'); + + // 加载应用默认语言包 + $this->loadLangPack($langSet); + + // 监听AppInit + $this->event->trigger(AppInit::class); + + date_default_timezone_set($this->config->get('app.default_timezone', 'Asia/Shanghai')); + + // 初始化 + foreach ($this->initializers as $initializer) { + $this->make($initializer)->init($this); + } + + return $this; + } + + /** + * 是否初始化过 + * @return bool + */ + public function initialized() + { + return $this->initialized; + } + + /** + * 加载语言包 + * @param string $langset 语言 + * @return void + */ + public function loadLangPack($langset) + { + if (empty($langset)) { + return; + } + + // 加载系统语言包 + $files = glob($this->appPath . 'lang' . DIRECTORY_SEPARATOR . $langset . '.*'); + $this->lang->load($files); + + // 加载扩展(自定义)语言包 + $list = $this->config->get('lang.extend_list', []); + + if (isset($list[$langset])) { + $this->lang->load($list[$langset]); + } + } + + /** + * 引导应用 + * @access public + * @return void + */ + public function boot(): void + { + array_walk($this->services, function ($service) { + $this->bootService($service); + }); + } + + /** + * 加载应用文件和配置 + * @access protected + * @return void + */ + protected function load(): void + { + $appPath = $this->getAppPath(); + + if (is_file($appPath . 'common.php')) { + include_once $appPath . 'common.php'; + } + + include_once $this->thinkPath . 'helper.php'; + + $configPath = $this->getConfigPath(); + + $files = []; + + if (is_dir($configPath)) { + $files = glob($configPath . '*' . $this->configExt); + } + + foreach ($files as $file) { + $this->config->load($file, pathinfo($file, PATHINFO_FILENAME)); + } + + if (is_file($appPath . 'event.php')) { + $this->loadEvent(include $appPath . 'event.php'); + } + + if (is_file($appPath . 'service.php')) { + $services = include $appPath . 'service.php'; + foreach ($services as $service) { + $this->register($service); + } + } + } + + /** + * 调试模式设置 + * @access protected + * @return void + */ + protected function debugModeInit(): void + { + // 应用调试模式 + if (!$this->appDebug) { + $this->appDebug = $this->env->get('app_debug') ? true : false; + ini_set('display_errors', 'Off'); + } + + if (!$this->runningInConsole()) { + //重新申请一块比较大的buffer + if (ob_get_level() > 0) { + $output = ob_get_clean(); + } + ob_start(); + if (!empty($output)) { + echo $output; + } + } + } + + /** + * 注册应用事件 + * @access protected + * @param array $event 事件数据 + * @return void + */ + public function loadEvent(array $event): void + { + if (isset($event['bind'])) { + $this->event->bind($event['bind']); + } + + if (isset($event['listen'])) { + $this->event->listenEvents($event['listen']); + } + + if (isset($event['subscribe'])) { + $this->event->subscribe($event['subscribe']); + } + } + + /** + * 解析应用类的类名 + * @access public + * @param string $layer 层名 controller model ... + * @param string $name 类名 + * @return string + */ + public function parseClass(string $layer, string $name): string + { + $name = str_replace(['/', '.'], '\\', $name); + $array = explode('\\', $name); + $class = Str::studly(array_pop($array)); + $path = $array ? implode('\\', $array) . '\\' : ''; + + return $this->namespace . '\\' . $layer . '\\' . $path . $class; + } + + /** + * 是否运行在命令行下 + * @return bool + */ + public function runningInConsole(): bool + { + return php_sapi_name() === 'cli' || php_sapi_name() === 'phpdbg'; + } + + /** + * 获取应用根目录 + * @access protected + * @return string + */ + protected function getDefaultRootPath(): string + { + return dirname($this->thinkPath, 4) . DIRECTORY_SEPARATOR; + } + +} diff --git a/vendor/topthink/framework/src/think/Cache.php b/vendor/topthink/framework/src/think/Cache.php new file mode 100644 index 000000000..f802b556f --- /dev/null +++ b/vendor/topthink/framework/src/think/Cache.php @@ -0,0 +1,197 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think; + +use Psr\SimpleCache\CacheInterface; +use think\cache\Driver; +use think\cache\TagSet; +use think\exception\InvalidArgumentException; +use think\helper\Arr; + +/** + * 缓存管理类 + * @mixin Driver + * @mixin \think\cache\driver\File + */ +class Cache extends Manager implements CacheInterface +{ + + protected $namespace = '\\think\\cache\\driver\\'; + + /** + * 默认驱动 + * @return string|null + */ + public function getDefaultDriver() + { + return $this->getConfig('default'); + } + + /** + * 获取缓存配置 + * @access public + * @param null|string $name 名称 + * @param mixed $default 默认值 + * @return mixed + */ + public function getConfig(string $name = null, $default = null) + { + if (!is_null($name)) { + return $this->app->config->get('cache.' . $name, $default); + } + + return $this->app->config->get('cache'); + } + + /** + * 获取驱动配置 + * @param string $store + * @param string $name + * @param null $default + * @return array + */ + public function getStoreConfig(string $store, string $name = null, $default = null) + { + if ($config = $this->getConfig("stores.{$store}")) { + return Arr::get($config, $name, $default); + } + + throw new \InvalidArgumentException("Store [$store] not found."); + } + + protected function resolveType(string $name) + { + return $this->getStoreConfig($name, 'type', 'file'); + } + + protected function resolveConfig(string $name) + { + return $this->getStoreConfig($name); + } + + /** + * 连接或者切换缓存 + * @access public + * @param string $name 连接配置名 + * @return Driver + */ + public function store(string $name = null) + { + return $this->driver($name); + } + + /** + * 清空缓冲池 + * @access public + * @return bool + */ + public function clear(): bool + { + return $this->store()->clear(); + } + + /** + * 读取缓存 + * @access public + * @param string $key 缓存变量名 + * @param mixed $default 默认值 + * @return mixed + */ + public function get($key, $default = null) + { + return $this->store()->get($key, $default); + } + + /** + * 写入缓存 + * @access public + * @param string $key 缓存变量名 + * @param mixed $value 存储数据 + * @param int|\DateTime $ttl 有效时间 0为永久 + * @return bool + */ + public function set($key, $value, $ttl = null): bool + { + return $this->store()->set($key, $value, $ttl); + } + + /** + * 删除缓存 + * @access public + * @param string $key 缓存变量名 + * @return bool + */ + public function delete($key): bool + { + return $this->store()->delete($key); + } + + /** + * 读取缓存 + * @access public + * @param iterable $keys 缓存变量名 + * @param mixed $default 默认值 + * @return iterable + * @throws InvalidArgumentException + */ + public function getMultiple($keys, $default = null): iterable + { + return $this->store()->getMultiple($keys, $default); + } + + /** + * 写入缓存 + * @access public + * @param iterable $values 缓存数据 + * @param null|int|\DateInterval $ttl 有效时间 0为永久 + * @return bool + */ + public function setMultiple($values, $ttl = null): bool + { + return $this->store()->setMultiple($values, $ttl); + } + + /** + * 删除缓存 + * @access public + * @param iterable $keys 缓存变量名 + * @return bool + * @throws InvalidArgumentException + */ + public function deleteMultiple($keys): bool + { + return $this->store()->deleteMultiple($keys); + } + + /** + * 判断缓存是否存在 + * @access public + * @param string $key 缓存变量名 + * @return bool + */ + public function has($key): bool + { + return $this->store()->has($key); + } + + /** + * 缓存标签 + * @access public + * @param string|array $name 标签名 + * @return TagSet + */ + public function tag($name): TagSet + { + return $this->store()->tag($name); + } +} diff --git a/vendor/topthink/framework/src/think/Config.php b/vendor/topthink/framework/src/think/Config.php new file mode 100644 index 000000000..9162e82fd --- /dev/null +++ b/vendor/topthink/framework/src/think/Config.php @@ -0,0 +1,197 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think; + +/** + * 配置管理类 + * @package think + */ +class Config +{ + /** + * 配置参数 + * @var array + */ + protected $config = []; + + /** + * 配置文件目录 + * @var string + */ + protected $path; + + /** + * 配置文件后缀 + * @var string + */ + protected $ext; + + /** + * 构造方法 + * @access public + */ + public function __construct(string $path = null, string $ext = '.php') + { + $this->path = $path ?: ''; + $this->ext = $ext; + } + + public static function __make(App $app) + { + $path = $app->getConfigPath(); + $ext = $app->getConfigExt(); + + return new static($path, $ext); + } + + /** + * 加载配置文件(多种格式) + * @access public + * @param string $file 配置文件名 + * @param string $name 一级配置名 + * @return array + */ + public function load(string $file, string $name = ''): array + { + if (is_file($file)) { + $filename = $file; + } elseif (is_file($this->path . $file . $this->ext)) { + $filename = $this->path . $file . $this->ext; + } + + if (isset($filename)) { + return $this->parse($filename, $name); + } + + return $this->config; + } + + /** + * 解析配置文件 + * @access public + * @param string $file 配置文件名 + * @param string $name 一级配置名 + * @return array + */ + protected function parse(string $file, string $name): array + { + $type = pathinfo($file, PATHINFO_EXTENSION); + $config = []; + switch ($type) { + case 'php': + $config = include $file; + break; + case 'yml': + case 'yaml': + if (function_exists('yaml_parse_file')) { + $config = yaml_parse_file($file); + } + break; + case 'ini': + $config = parse_ini_file($file, true, INI_SCANNER_TYPED) ?: []; + break; + case 'json': + $config = json_decode(file_get_contents($file), true); + break; + } + + return is_array($config) ? $this->set($config, strtolower($name)) : []; + } + + /** + * 检测配置是否存在 + * @access public + * @param string $name 配置参数名(支持多级配置 .号分割) + * @return bool + */ + public function has(string $name): bool + { + if (false === strpos($name, '.') && !isset($this->config[strtolower($name)])) { + return false; + } + + return !is_null($this->get($name)); + } + + /** + * 获取一级配置 + * @access protected + * @param string $name 一级配置名 + * @return array + */ + protected function pull(string $name): array + { + $name = strtolower($name); + + return $this->config[$name] ?? []; + } + + /** + * 获取配置参数 为空则获取所有配置 + * @access public + * @param string $name 配置参数名(支持多级配置 .号分割) + * @param mixed $default 默认值 + * @return mixed + */ + public function get(string $name = null, $default = null) + { + // 无参数时获取所有 + if (empty($name)) { + return $this->config; + } + + if (false === strpos($name, '.')) { + return $this->pull($name); + } + + $name = explode('.', $name); + $name[0] = strtolower($name[0]); + $config = $this->config; + + // 按.拆分成多维数组进行判断 + foreach ($name as $val) { + if (isset($config[$val])) { + $config = $config[$val]; + } else { + return $default; + } + } + + return $config; + } + + /** + * 设置配置参数 name为数组则为批量设置 + * @access public + * @param array $config 配置参数 + * @param string $name 配置名 + * @return array + */ + public function set(array $config, string $name = null): array + { + if (!empty($name)) { + if (isset($this->config[$name])) { + $result = array_merge($this->config[$name], $config); + } else { + $result = $config; + } + + $this->config[$name] = $result; + } else { + $result = $this->config = array_merge($this->config, array_change_key_case($config)); + } + + return $result; + } + +} diff --git a/thinkphp/library/think/Console.php b/vendor/topthink/framework/src/think/Console.php old mode 100755 new mode 100644 similarity index 55% rename from thinkphp/library/think/Console.php rename to vendor/topthink/framework/src/think/Console.php index d12129072..389d104d5 --- a/thinkphp/library/think/Console.php +++ b/vendor/topthink/framework/src/think/Console.php @@ -6,11 +6,34 @@ // +---------------------------------------------------------------------- // | Author: zhangyajun <448901948@qq.com> // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think; +use Closure; +use InvalidArgumentException; +use LogicException; use think\console\Command; +use think\console\command\Clear; +use think\console\command\Help; use think\console\command\Help as HelpCommand; +use think\console\command\Lists; +use think\console\command\make\Command as MakeCommand; +use think\console\command\make\Controller; +use think\console\command\make\Event; +use think\console\command\make\Listener; +use think\console\command\make\Middleware; +use think\console\command\make\Model; +use think\console\command\make\Service; +use think\console\command\make\Subscribe; +use think\console\command\make\Validate; +use think\console\command\optimize\Route; +use think\console\command\optimize\Schema; +use think\console\command\RouteList; +use think\console\command\RunServer; +use think\console\command\ServiceDiscover; +use think\console\command\VendorPublish; +use think\console\command\Version; use think\console\Input; use think\console\input\Argument as InputArgument; use think\console\input\Definition as InputDefinition; @@ -18,164 +41,194 @@ use think\console\input\Option as InputOption; use think\console\Output; use think\console\output\driver\Buffer; +/** + * 控制台应用管理类 + */ class Console { - private $name; - private $version; + protected $app; /** @var Command[] */ - private $commands = []; + protected $commands = []; - private $wantHelps = false; + protected $wantHelps = false; - private $catchExceptions = true; - private $autoExit = true; - private $definition; - private $defaultCommand; + protected $catchExceptions = true; + protected $autoExit = true; + protected $definition; + protected $defaultCommand = 'list'; - private static $defaultCommands = [ - 'help' => "think\\console\\command\\Help", - 'list' => "think\\console\\command\\Lists", - 'build' => "think\\console\\command\\Build", - 'clear' => "think\\console\\command\\Clear", - 'make:command' => "think\\console\\command\\make\\Command", - 'make:controller' => "think\\console\\command\\make\\Controller", - 'make:model' => "think\\console\\command\\make\\Model", - 'make:middleware' => "think\\console\\command\\make\\Middleware", - 'make:validate' => "think\\console\\command\\make\\Validate", - 'optimize:autoload' => "think\\console\\command\\optimize\\Autoload", - 'optimize:config' => "think\\console\\command\\optimize\\Config", - 'optimize:schema' => "think\\console\\command\\optimize\\Schema", - 'optimize:route' => "think\\console\\command\\optimize\\Route", - 'run' => "think\\console\\command\\RunServer", - 'version' => "think\\console\\command\\Version", - 'route:list' => "think\\console\\command\\RouteList", + protected $defaultCommands = [ + 'help' => Help::class, + 'list' => Lists::class, + 'clear' => Clear::class, + 'make:command' => MakeCommand::class, + 'make:controller' => Controller::class, + 'make:model' => Model::class, + 'make:middleware' => Middleware::class, + 'make:validate' => Validate::class, + 'make:event' => Event::class, + 'make:listener' => Listener::class, + 'make:service' => Service::class, + 'make:subscribe' => Subscribe::class, + 'optimize:route' => Route::class, + 'optimize:schema' => Schema::class, + 'run' => RunServer::class, + 'version' => Version::class, + 'route:list' => RouteList::class, + 'service:discover' => ServiceDiscover::class, + 'vendor:publish' => VendorPublish::class, ]; /** - * Console constructor. - * @access public - * @param string $name 名称 - * @param string $version 版本 - * @param null|string $user 执行用户 + * 启动器 + * @var array */ - public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN', $user = null) - { - $this->name = $name; - $this->version = $version; + protected static $startCallbacks = []; - if ($user) { - $this->setUser($user); + public function __construct(App $app) + { + $this->app = $app; + + $this->initialize(); + + $this->definition = $this->getDefaultInputDefinition(); + + //加载指令 + $this->loadCommands(); + + $this->start(); + } + + /** + * 初始化 + */ + protected function initialize() + { + if (!$this->app->initialized()) { + $this->app->initialize(); + } + $this->makeRequest(); + } + + /** + * 构造request + */ + protected function makeRequest() + { + $uri = $this->app->config->get('app.url', 'http://localhost'); + + $components = parse_url($uri); + + $server = $_SERVER; + + if (isset($components['path'])) { + $server = array_merge($server, [ + 'SCRIPT_FILENAME' => $components['path'], + 'SCRIPT_NAME' => $components['path'], + ]); } - $this->defaultCommand = 'list'; - $this->definition = $this->getDefaultInputDefinition(); + if (isset($components['host'])) { + $server['SERVER_NAME'] = $components['host']; + $server['HTTP_HOST'] = $components['host']; + } + + if (isset($components['scheme'])) { + if ('https' === $components['scheme']) { + $server['HTTPS'] = 'on'; + $server['SERVER_PORT'] = 443; + } else { + unset($server['HTTPS']); + $server['SERVER_PORT'] = 80; + } + } + + if (isset($components['port'])) { + $server['SERVER_PORT'] = $components['port']; + $server['HTTP_HOST'] .= ':' . $components['port']; + } + + $server['REQUEST_URI'] = $uri; + + /** @var Request $request */ + $request = $this->app->make('request'); + + $request->withServer($server); + } + + /** + * 添加初始化器 + * @param Closure $callback + */ + public static function starting(Closure $callback): void + { + static::$startCallbacks[] = $callback; + } + + /** + * 清空启动器 + */ + public static function flushStartCallbacks(): void + { + static::$startCallbacks = []; } /** * 设置执行用户 * @param $user */ - public function setUser($user) + public static function setUser(string $user): void { - if (DIRECTORY_SEPARATOR == '\\') { - return; - } + if (extension_loaded('posix')) { + $user = posix_getpwnam($user); - $user = posix_getpwnam($user); - if ($user) { - posix_setuid($user['uid']); - posix_setgid($user['gid']); - } - } - - /** - * 初始化 Console - * @access public - * @param bool $run 是否运行 Console - * @return int|Console - */ - public static function init($run = true) - { - static $console; - - if (!$console) { - $config = Container::get('config')->pull('console'); - $console = new self($config['name'], $config['version'], $config['user']); - - $commands = $console->getDefinedCommands($config); - - // 添加指令集 - $console->addCommands($commands); - } - - if ($run) { - // 运行 - return $console->run(); - } else { - return $console; - } - } - - /** - * @access public - * @param array $config - * @return array - */ - public function getDefinedCommands(array $config = []) - { - $commands = self::$defaultCommands; - - if (!empty($config['auto_path']) && is_dir($config['auto_path'])) { - // 自动加载指令类 - $files = scandir($config['auto_path']); - - if (count($files) > 2) { - $beforeClass = get_declared_classes(); - - foreach ($files as $file) { - if (pathinfo($file, PATHINFO_EXTENSION) == 'php') { - include $config['auto_path'] . $file; - } - } - - $afterClass = get_declared_classes(); - $commands = array_merge($commands, array_diff($afterClass, $beforeClass)); + if (!empty($user)) { + posix_setgid($user['gid']); + posix_setuid($user['uid']); } } + } - $file = Container::get('env')->get('app_path') . 'command.php'; - - if (is_file($file)) { - $appCommands = include $file; - - if (is_array($appCommands)) { - $commands = array_merge($commands, $appCommands); - } + /** + * 启动 + */ + protected function start(): void + { + foreach (static::$startCallbacks as $callback) { + $callback($this); } + } - return $commands; + /** + * 加载指令 + * @access protected + */ + protected function loadCommands(): void + { + $commands = $this->app->config->get('console.commands', []); + $commands = array_merge($this->defaultCommands, $commands); + + $this->addCommands($commands); } /** * @access public - * @param string $command - * @param array $parameters - * @param string $driver + * @param string $command + * @param array $parameters + * @param string $driver * @return Output|Buffer */ - public static function call($command, array $parameters = [], $driver = 'buffer') + public function call(string $command, array $parameters = [], string $driver = 'buffer') { - $console = self::init(false); - array_unshift($parameters, $command); $input = new Input($parameters); $output = new Output($driver); - $console->setCatchExceptions(false); - $console->find($command)->run($input, $output); + $this->setCatchExceptions(false); + $this->find($command)->run($input, $output); return $output; } @@ -228,8 +281,8 @@ class Console /** * 执行指令 * @access public - * @param Input $input - * @param Output $output + * @param Input $input + * @param Output $output * @return int */ public function doRun(Input $input, Output $output) @@ -258,17 +311,15 @@ class Console $command = $this->find($name); - $exitCode = $this->doRunCommand($command, $input, $output); - - return $exitCode; + return $this->doRunCommand($command, $input, $output); } /** * 设置输入参数定义 * @access public - * @param InputDefinition $definition + * @param InputDefinition $definition */ - public function setDefinition(InputDefinition $definition) + public function setDefinition(InputDefinition $definition): void { $this->definition = $definition; } @@ -278,7 +329,7 @@ class Console * @access public * @return InputDefinition The InputDefinition instance */ - public function getDefinition() + public function getDefinition(): InputDefinition { return $this->definition; } @@ -288,7 +339,7 @@ class Console * @access public * @return string A help message. */ - public function getHelp() + public function getHelp(): string { return $this->getLongVersion(); } @@ -296,64 +347,23 @@ class Console /** * 是否捕获异常 * @access public - * @param bool $boolean + * @param bool $boolean * @api */ - public function setCatchExceptions($boolean) + public function setCatchExceptions(bool $boolean): void { - $this->catchExceptions = (bool) $boolean; + $this->catchExceptions = $boolean; } /** * 是否自动退出 * @access public - * @param bool $boolean + * @param bool $boolean * @api */ - public function setAutoExit($boolean) + public function setAutoExit(bool $boolean): void { - $this->autoExit = (bool) $boolean; - } - - /** - * 获取名称 - * @access public - * @return string - */ - public function getName() - { - return $this->name; - } - - /** - * 设置名称 - * @access public - * @param string $name - */ - public function setName($name) - { - $this->name = $name; - } - - /** - * 获取版本 - * @access public - * @return string - * @api - */ - public function getVersion() - { - return $this->version; - } - - /** - * 设置版本 - * @access public - * @param string $version - */ - public function setVersion($version) - { - $this->version = $version; + $this->autoExit = $boolean; } /** @@ -361,49 +371,38 @@ class Console * @access public * @return string */ - public function getLongVersion() + public function getLongVersion(): string { - if ('UNKNOWN' !== $this->getName() && 'UNKNOWN' !== $this->getVersion()) { - return sprintf('%s version %s', $this->getName(), $this->getVersion()); + if ($this->app->version()) { + return sprintf('version %s', $this->app->version()); } return 'Console Tool'; } - /** - * 注册一个指令 (便于动态创建指令) - * @access public - * @param string $name 指令名 - * @return Command - */ - public function register($name) - { - return $this->add(new Command($name)); - } - /** * 添加指令集 * @access public - * @param array $commands + * @param array $commands */ - public function addCommands(array $commands) + public function addCommands(array $commands): void { foreach ($commands as $key => $command) { - if (is_subclass_of($command, "\\think\\console\\Command")) { + if (is_subclass_of($command, Command::class)) { // 注册指令 - $this->add($command, is_numeric($key) ? '' : $key); + $this->addCommand($command, is_numeric($key) ? '' : $key); } } } /** - * 注册一个指令(对象) + * 添加一个指令 * @access public - * @param mixed $command 指令对象或者指令类名 - * @param string $name 指令名 留空则自动获取 - * @return mixed + * @param string|Command $command 指令对象或者指令类名 + * @param string $name 指令名 留空则自动获取 + * @return Command|void */ - public function add($command, $name) + public function addCommand($command, string $name = '') { if ($name) { $this->commands[$name] = $command; @@ -411,7 +410,7 @@ class Console } if (is_string($command)) { - $command = new $command(); + $command = $this->app->invokeClass($command); } $command->setConsole($this); @@ -421,8 +420,10 @@ class Console return; } + $command->setApp($this->app); + if (null === $command->getDefinition()) { - throw new \LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', get_class($command))); + throw new LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', get_class($command))); } $this->commands[$command->getName()] = $command; @@ -437,29 +438,30 @@ class Console /** * 获取指令 * @access public - * @param string $name 指令名称 + * @param string $name 指令名称 * @return Command - * @throws \InvalidArgumentException + * @throws InvalidArgumentException */ - public function get($name) + public function getCommand(string $name): Command { if (!isset($this->commands[$name])) { - throw new \InvalidArgumentException(sprintf('The command "%s" does not exist.', $name)); + throw new InvalidArgumentException(sprintf('The command "%s" does not exist.', $name)); } $command = $this->commands[$name]; if (is_string($command)) { - $command = new $command(); + $command = $this->app->invokeClass($command); + /** @var Command $command */ + $command->setConsole($this); + $command->setApp($this->app); } - $command->setConsole($this); - if ($this->wantHelps) { $this->wantHelps = false; /** @var HelpCommand $helpCommand */ - $helpCommand = $this->get('help'); + $helpCommand = $this->getCommand('help'); $helpCommand->setCommand($command); return $helpCommand; @@ -471,10 +473,10 @@ class Console /** * 某个指令是否存在 * @access public - * @param string $name 指令名称 + * @param string $name 指令名称 * @return bool */ - public function has($name) + public function hasCommand(string $name): bool { return isset($this->commands[$name]); } @@ -484,14 +486,18 @@ class Console * @access public * @return array */ - public function getNamespaces() + public function getNamespaces(): array { $namespaces = []; - foreach ($this->commands as $command) { - $namespaces = array_merge($namespaces, $this->extractAllNamespaces($command->getName())); + foreach ($this->commands as $key => $command) { + if (is_string($command)) { + $namespaces = array_merge($namespaces, $this->extractAllNamespaces($key)); + } else { + $namespaces = array_merge($namespaces, $this->extractAllNamespaces($command->getName())); - foreach ($command->getAliases() as $alias) { - $namespaces = array_merge($namespaces, $this->extractAllNamespaces($alias)); + foreach ($command->getAliases() as $alias) { + $namespaces = array_merge($namespaces, $this->extractAllNamespaces($alias)); + } } } @@ -501,17 +507,17 @@ class Console /** * 查找注册命名空间中的名称或缩写。 * @access public - * @param string $namespace + * @param string $namespace * @return string - * @throws \InvalidArgumentException + * @throws InvalidArgumentException */ - public function findNamespace($namespace) + public function findNamespace(string $namespace): string { $allNamespaces = $this->getNamespaces(); $expr = preg_replace_callback('{([^:]+|)}', function ($matches) { return preg_quote($matches[1]) . '[^:]*'; }, $namespace); - $namespaces = preg_grep('{^' . $expr . '}', $allNamespaces); + $namespaces = preg_grep('{^' . $expr . '}', $allNamespaces); if (empty($namespaces)) { $message = sprintf('There are no commands defined in the "%s" namespace.', $namespace); @@ -526,12 +532,12 @@ class Console $message .= implode("\n ", $alternatives); } - throw new \InvalidArgumentException($message); + throw new InvalidArgumentException($message); } $exact = in_array($namespace, $namespaces, true); if (count($namespaces) > 1 && !$exact) { - throw new \InvalidArgumentException(sprintf('The namespace "%s" is ambiguous (%s).', $namespace, $this->getAbbreviationSuggestions(array_values($namespaces)))); + throw new InvalidArgumentException(sprintf('The namespace "%s" is ambiguous (%s).', $namespace, $this->getAbbreviationSuggestions(array_values($namespaces)))); } return $exact ? $namespace : reset($namespaces); @@ -540,11 +546,11 @@ class Console /** * 查找指令 * @access public - * @param string $name 名称或者别名 + * @param string $name 名称或者别名 * @return Command - * @throws \InvalidArgumentException + * @throws InvalidArgumentException */ - public function find($name) + public function find(string $name): Command { $allCommands = array_keys($this->commands); @@ -570,27 +576,27 @@ class Console $message .= implode("\n ", $alternatives); } - throw new \InvalidArgumentException($message); + throw new InvalidArgumentException($message); } $exact = in_array($name, $commands, true); if (count($commands) > 1 && !$exact) { $suggestions = $this->getAbbreviationSuggestions(array_values($commands)); - throw new \InvalidArgumentException(sprintf('Command "%s" is ambiguous (%s).', $name, $suggestions)); + throw new InvalidArgumentException(sprintf('Command "%s" is ambiguous (%s).', $name, $suggestions)); } - return $this->get($exact ? $name : reset($commands)); + return $this->getCommand($exact ? $name : reset($commands)); } /** * 获取所有的指令 * @access public - * @param string $namespace 命名空间 + * @param string $namespace 命名空间 * @return Command[] * @api */ - public function all($namespace = null) + public function all(string $namespace = null): array { if (null === $namespace) { return $this->commands; @@ -606,32 +612,13 @@ class Console return $commands; } - /** - * 获取可能的指令名 - * @access public - * @param array $names - * @return array - */ - public static function getAbbreviations($names) - { - $abbrevs = []; - foreach ($names as $name) { - for ($len = strlen($name); $len > 0; --$len) { - $abbrev = substr($name, 0, $len); - $abbrevs[$abbrev][] = $name; - } - } - - return $abbrevs; - } - /** * 配置基于用户的参数和选项的输入和输出实例。 * @access protected - * @param Input $input 输入实例 - * @param Output $output 输出实例 + * @param Input $input 输入实例 + * @param Output $output 输出实例 */ - protected function configureIO(Input $input, Output $output) + protected function configureIO(Input $input, Output $output): void { if (true === $input->hasParameterOption(['--ansi'])) { $output->setDecorated(true); @@ -645,23 +632,21 @@ class Console if (true === $input->hasParameterOption(['--quiet', '-q'])) { $output->setVerbosity(Output::VERBOSITY_QUIET); - } else { - if ($input->hasParameterOption('-vvv') || $input->hasParameterOption('--verbose=3') || $input->getParameterOption('--verbose') === 3) { - $output->setVerbosity(Output::VERBOSITY_DEBUG); - } elseif ($input->hasParameterOption('-vv') || $input->hasParameterOption('--verbose=2') || $input->getParameterOption('--verbose') === 2) { - $output->setVerbosity(Output::VERBOSITY_VERY_VERBOSE); - } elseif ($input->hasParameterOption('-v') || $input->hasParameterOption('--verbose=1') || $input->hasParameterOption('--verbose') || $input->getParameterOption('--verbose')) { - $output->setVerbosity(Output::VERBOSITY_VERBOSE); - } + } elseif ($input->hasParameterOption('-vvv') || $input->hasParameterOption('--verbose=3') || $input->getParameterOption('--verbose') === 3) { + $output->setVerbosity(Output::VERBOSITY_DEBUG); + } elseif ($input->hasParameterOption('-vv') || $input->hasParameterOption('--verbose=2') || $input->getParameterOption('--verbose') === 2) { + $output->setVerbosity(Output::VERBOSITY_VERY_VERBOSE); + } elseif ($input->hasParameterOption('-v') || $input->hasParameterOption('--verbose=1') || $input->hasParameterOption('--verbose') || $input->getParameterOption('--verbose')) { + $output->setVerbosity(Output::VERBOSITY_VERBOSE); } } /** * 执行指令 * @access protected - * @param Command $command 指令实例 - * @param Input $input 输入实例 - * @param Output $output 输出实例 + * @param Command $command 指令实例 + * @param Input $input 输入实例 + * @param Output $output 输出实例 * @return int * @throws \Exception */ @@ -673,12 +658,12 @@ class Console /** * 获取指令的基础名称 * @access protected - * @param Input $input + * @param Input $input * @return string */ - protected function getCommandName(Input $input) + protected function getCommandName(Input $input): string { - return $input->getFirstArgument(); + return $input->getFirstArgument() ?: ''; } /** @@ -686,7 +671,7 @@ class Console * @access protected * @return InputDefinition */ - protected function getDefaultInputDefinition() + protected function getDefaultInputDefinition(): InputDefinition { return new InputDefinition([ new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'), @@ -700,18 +685,13 @@ class Console ]); } - public static function addDefaultCommands(array $classnames) - { - self::$defaultCommands = array_merge(self::$defaultCommands, $classnames); - } - /** * 获取可能的建议 * @access private - * @param array $abbrevs + * @param array $abbrevs * @return string */ - private function getAbbreviationSuggestions($abbrevs) + private function getAbbreviationSuggestions(array $abbrevs): string { return sprintf('%s, %s%s', $abbrevs[0], $abbrevs[1], count($abbrevs) > 2 ? sprintf(' and %d more', count($abbrevs) - 2) : ''); } @@ -719,26 +699,26 @@ class Console /** * 返回命名空间部分 * @access public - * @param string $name 指令 - * @param string $limit 部分的命名空间的最大数量 + * @param string $name 指令 + * @param int $limit 部分的命名空间的最大数量 * @return string */ - public function extractNamespace($name, $limit = null) + public function extractNamespace(string $name, int $limit = 0): string { $parts = explode(':', $name); array_pop($parts); - return implode(':', null === $limit ? $parts : array_slice($parts, 0, $limit)); + return implode(':', 0 === $limit ? $parts : array_slice($parts, 0, $limit)); } /** * 查找可替代的建议 * @access private - * @param string $name - * @param array|\Traversable $collection + * @param string $name + * @param array|\Traversable $collection * @return array */ - private function findAlternatives($name, $collection) + private function findAlternatives(string $name, $collection): array { $threshold = 1e3; $alternatives = []; @@ -782,23 +762,13 @@ class Console return array_keys($alternatives); } - /** - * 设置默认的指令 - * @access public - * @param string $commandName The Command name - */ - public function setDefaultCommand($commandName) - { - $this->defaultCommand = $commandName; - } - /** * 返回所有的命名空间 * @access private - * @param string $name + * @param string $name * @return array */ - private function extractAllNamespaces($name) + private function extractAllNamespaces(string $name): array { $parts = explode(':', $name, -1); $namespaces = []; @@ -814,11 +784,4 @@ class Console return $namespaces; } - public function __debugInfo() - { - $data = get_object_vars($this); - unset($data['commands'], $data['definition']); - - return $data; - } } diff --git a/vendor/topthink/framework/src/think/Container.php b/vendor/topthink/framework/src/think/Container.php new file mode 100644 index 000000000..74026bb09 --- /dev/null +++ b/vendor/topthink/framework/src/think/Container.php @@ -0,0 +1,554 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think; + +use ArrayAccess; +use ArrayIterator; +use Closure; +use Countable; +use InvalidArgumentException; +use IteratorAggregate; +use Psr\Container\ContainerInterface; +use ReflectionClass; +use ReflectionException; +use ReflectionFunction; +use ReflectionFunctionAbstract; +use ReflectionMethod; +use think\exception\ClassNotFoundException; +use think\exception\FuncNotFoundException; +use think\helper\Str; + +/** + * 容器管理类 支持PSR-11 + */ +class Container implements ContainerInterface, ArrayAccess, IteratorAggregate, Countable +{ + /** + * 容器对象实例 + * @var Container|Closure + */ + protected static $instance; + + /** + * 容器中的对象实例 + * @var array + */ + protected $instances = []; + + /** + * 容器绑定标识 + * @var array + */ + protected $bind = []; + + /** + * 容器回调 + * @var array + */ + protected $invokeCallback = []; + + /** + * 获取当前容器的实例(单例) + * @access public + * @return static + */ + public static function getInstance() + { + if (is_null(static::$instance)) { + static::$instance = new static; + } + + if (static::$instance instanceof Closure) { + return (static::$instance)(); + } + + return static::$instance; + } + + /** + * 设置当前容器的实例 + * @access public + * @param object|Closure $instance + * @return void + */ + public static function setInstance($instance): void + { + static::$instance = $instance; + } + + /** + * 注册一个容器对象回调 + * + * @param string|Closure $abstract + * @param Closure|null $callback + * @return void + */ + public function resolving($abstract, Closure $callback = null): void + { + if ($abstract instanceof Closure) { + $this->invokeCallback['*'][] = $abstract; + return; + } + + $abstract = $this->getAlias($abstract); + + $this->invokeCallback[$abstract][] = $callback; + } + + /** + * 获取容器中的对象实例 不存在则创建 + * @access public + * @param string $abstract 类名或者标识 + * @param array|true $vars 变量 + * @param bool $newInstance 是否每次创建新的实例 + * @return object + */ + public static function pull(string $abstract, array $vars = [], bool $newInstance = false) + { + return static::getInstance()->make($abstract, $vars, $newInstance); + } + + /** + * 获取容器中的对象实例 + * @access public + * @param string $abstract 类名或者标识 + * @return object + */ + public function get($abstract) + { + if ($this->has($abstract)) { + return $this->make($abstract); + } + + throw new ClassNotFoundException('class not exists: ' . $abstract, $abstract); + } + + /** + * 绑定一个类、闭包、实例、接口实现到容器 + * @access public + * @param string|array $abstract 类标识、接口 + * @param mixed $concrete 要绑定的类、闭包或者实例 + * @return $this + */ + public function bind($abstract, $concrete = null) + { + if (is_array($abstract)) { + foreach ($abstract as $key => $val) { + $this->bind($key, $val); + } + } elseif ($concrete instanceof Closure) { + $this->bind[$abstract] = $concrete; + } elseif (is_object($concrete)) { + $this->instance($abstract, $concrete); + } else { + $abstract = $this->getAlias($abstract); + if ($abstract != $concrete) { + $this->bind[$abstract] = $concrete; + } + } + + return $this; + } + + /** + * 根据别名获取真实类名 + * @param string $abstract + * @return string + */ + public function getAlias(string $abstract): string + { + if (isset($this->bind[$abstract])) { + $bind = $this->bind[$abstract]; + + if (is_string($bind)) { + return $this->getAlias($bind); + } + } + + return $abstract; + } + + /** + * 绑定一个类实例到容器 + * @access public + * @param string $abstract 类名或者标识 + * @param object $instance 类的实例 + * @return $this + */ + public function instance(string $abstract, $instance) + { + $abstract = $this->getAlias($abstract); + + $this->instances[$abstract] = $instance; + + return $this; + } + + /** + * 判断容器中是否存在类及标识 + * @access public + * @param string $abstract 类名或者标识 + * @return bool + */ + public function bound(string $abstract): bool + { + return isset($this->bind[$abstract]) || isset($this->instances[$abstract]); + } + + /** + * 判断容器中是否存在类及标识 + * @access public + * @param string $name 类名或者标识 + * @return bool + */ + public function has($name): bool + { + return $this->bound($name); + } + + /** + * 判断容器中是否存在对象实例 + * @access public + * @param string $abstract 类名或者标识 + * @return bool + */ + public function exists(string $abstract): bool + { + $abstract = $this->getAlias($abstract); + + return isset($this->instances[$abstract]); + } + + /** + * 创建类的实例 已经存在则直接获取 + * @access public + * @param string $abstract 类名或者标识 + * @param array $vars 变量 + * @param bool $newInstance 是否每次创建新的实例 + * @return mixed + */ + public function make(string $abstract, array $vars = [], bool $newInstance = false) + { + $abstract = $this->getAlias($abstract); + + if (isset($this->instances[$abstract]) && !$newInstance) { + return $this->instances[$abstract]; + } + + if (isset($this->bind[$abstract]) && $this->bind[$abstract] instanceof Closure) { + $object = $this->invokeFunction($this->bind[$abstract], $vars); + } else { + $object = $this->invokeClass($abstract, $vars); + } + + if (!$newInstance) { + $this->instances[$abstract] = $object; + } + + return $object; + } + + /** + * 删除容器中的对象实例 + * @access public + * @param string $name 类名或者标识 + * @return void + */ + public function delete($name) + { + $name = $this->getAlias($name); + + if (isset($this->instances[$name])) { + unset($this->instances[$name]); + } + } + + /** + * 执行函数或者闭包方法 支持参数调用 + * @access public + * @param string|Closure $function 函数或者闭包 + * @param array $vars 参数 + * @return mixed + */ + public function invokeFunction($function, array $vars = []) + { + try { + $reflect = new ReflectionFunction($function); + } catch (ReflectionException $e) { + throw new FuncNotFoundException("function not exists: {$function}()", $function, $e); + } + + $args = $this->bindParams($reflect, $vars); + + return $function(...$args); + } + + /** + * 调用反射执行类的方法 支持参数绑定 + * @access public + * @param mixed $method 方法 + * @param array $vars 参数 + * @param bool $accessible 设置是否可访问 + * @return mixed + */ + public function invokeMethod($method, array $vars = [], bool $accessible = false) + { + if (is_array($method)) { + [$class, $method] = $method; + + $class = is_object($class) ? $class : $this->invokeClass($class); + } else { + // 静态方法 + [$class, $method] = explode('::', $method); + } + + try { + $reflect = new ReflectionMethod($class, $method); + } catch (ReflectionException $e) { + $class = is_object($class) ? get_class($class) : $class; + throw new FuncNotFoundException('method not exists: ' . $class . '::' . $method . '()', "{$class}::{$method}", $e); + } + + $args = $this->bindParams($reflect, $vars); + + if ($accessible) { + $reflect->setAccessible($accessible); + } + + return $reflect->invokeArgs(is_object($class) ? $class : null, $args); + } + + /** + * 调用反射执行类的方法 支持参数绑定 + * @access public + * @param object $instance 对象实例 + * @param mixed $reflect 反射类 + * @param array $vars 参数 + * @return mixed + */ + public function invokeReflectMethod($instance, $reflect, array $vars = []) + { + $args = $this->bindParams($reflect, $vars); + + return $reflect->invokeArgs($instance, $args); + } + + /** + * 调用反射执行callable 支持参数绑定 + * @access public + * @param mixed $callable + * @param array $vars 参数 + * @param bool $accessible 设置是否可访问 + * @return mixed + */ + public function invoke($callable, array $vars = [], bool $accessible = false) + { + if ($callable instanceof Closure) { + return $this->invokeFunction($callable, $vars); + } elseif (is_string($callable) && false === strpos($callable, '::')) { + return $this->invokeFunction($callable, $vars); + } else { + return $this->invokeMethod($callable, $vars, $accessible); + } + } + + /** + * 调用反射执行类的实例化 支持依赖注入 + * @access public + * @param string $class 类名 + * @param array $vars 参数 + * @return mixed + */ + public function invokeClass(string $class, array $vars = []) + { + try { + $reflect = new ReflectionClass($class); + } catch (ReflectionException $e) { + throw new ClassNotFoundException('class not exists: ' . $class, $class, $e); + } + + if ($reflect->hasMethod('__make')) { + $method = $reflect->getMethod('__make'); + if ($method->isPublic() && $method->isStatic()) { + $args = $this->bindParams($method, $vars); + $object = $method->invokeArgs(null, $args); + $this->invokeAfter($class, $object); + return $object; + } + } + + $constructor = $reflect->getConstructor(); + + $args = $constructor ? $this->bindParams($constructor, $vars) : []; + + $object = $reflect->newInstanceArgs($args); + + $this->invokeAfter($class, $object); + + return $object; + } + + /** + * 执行invokeClass回调 + * @access protected + * @param string $class 对象类名 + * @param object $object 容器对象实例 + * @return void + */ + protected function invokeAfter(string $class, $object): void + { + if (isset($this->invokeCallback['*'])) { + foreach ($this->invokeCallback['*'] as $callback) { + $callback($object, $this); + } + } + + if (isset($this->invokeCallback[$class])) { + foreach ($this->invokeCallback[$class] as $callback) { + $callback($object, $this); + } + } + } + + /** + * 绑定参数 + * @access protected + * @param ReflectionFunctionAbstract $reflect 反射类 + * @param array $vars 参数 + * @return array + */ + protected function bindParams(ReflectionFunctionAbstract $reflect, array $vars = []): array + { + if ($reflect->getNumberOfParameters() == 0) { + return []; + } + + // 判断数组类型 数字数组时按顺序绑定参数 + reset($vars); + $type = key($vars) === 0 ? 1 : 0; + $params = $reflect->getParameters(); + $args = []; + + foreach ($params as $param) { + $name = $param->getName(); + $lowerName = Str::snake($name); + $reflectionType = $param->getType(); + + if ($reflectionType && $reflectionType->isBuiltin() === false) { + $args[] = $this->getObjectParam($reflectionType->getName(), $vars); + } elseif (1 == $type && !empty($vars)) { + $args[] = array_shift($vars); + } elseif (0 == $type && array_key_exists($name, $vars)) { + $args[] = $vars[$name]; + } elseif (0 == $type && array_key_exists($lowerName, $vars)) { + $args[] = $vars[$lowerName]; + } elseif ($param->isDefaultValueAvailable()) { + $args[] = $param->getDefaultValue(); + } else { + throw new InvalidArgumentException('method param miss:' . $name); + } + } + + return $args; + } + + /** + * 创建工厂对象实例 + * @param string $name 工厂类名 + * @param string $namespace 默认命名空间 + * @param array $args + * @return mixed + * @deprecated + * @access public + */ + public static function factory(string $name, string $namespace = '', ...$args) + { + $class = false !== strpos($name, '\\') ? $name : $namespace . ucwords($name); + + return Container::getInstance()->invokeClass($class, $args); + } + + /** + * 获取对象类型的参数值 + * @access protected + * @param string $className 类名 + * @param array $vars 参数 + * @return mixed + */ + protected function getObjectParam(string $className, array &$vars) + { + $array = $vars; + $value = array_shift($array); + + if ($value instanceof $className) { + $result = $value; + array_shift($vars); + } else { + $result = $this->make($className); + } + + return $result; + } + + public function __set($name, $value) + { + $this->bind($name, $value); + } + + public function __get($name) + { + return $this->get($name); + } + + public function __isset($name): bool + { + return $this->exists($name); + } + + public function __unset($name) + { + $this->delete($name); + } + + public function offsetExists($key) + { + return $this->exists($key); + } + + public function offsetGet($key) + { + return $this->make($key); + } + + public function offsetSet($key, $value) + { + $this->bind($key, $value); + } + + public function offsetUnset($key) + { + $this->delete($key); + } + + //Countable + public function count() + { + return count($this->instances); + } + + //IteratorAggregate + public function getIterator() + { + return new ArrayIterator($this->instances); + } +} diff --git a/vendor/topthink/framework/src/think/Cookie.php b/vendor/topthink/framework/src/think/Cookie.php new file mode 100644 index 000000000..ebbfd64e0 --- /dev/null +++ b/vendor/topthink/framework/src/think/Cookie.php @@ -0,0 +1,230 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think; + +use DateTimeInterface; + +/** + * Cookie管理类 + * @package think + */ +class Cookie +{ + /** + * 配置参数 + * @var array + */ + protected $config = [ + // cookie 保存时间 + 'expire' => 0, + // cookie 保存路径 + 'path' => '/', + // cookie 有效域名 + 'domain' => '', + // cookie 启用安全传输 + 'secure' => false, + // httponly设置 + 'httponly' => false, + // samesite 设置,支持 'strict' 'lax' + 'samesite' => '', + ]; + + /** + * Cookie写入数据 + * @var array + */ + protected $cookie = []; + + /** + * 当前Request对象 + * @var Request + */ + protected $request; + + /** + * 构造方法 + * @access public + */ + public function __construct(Request $request, array $config = []) + { + $this->request = $request; + $this->config = array_merge($this->config, array_change_key_case($config)); + } + + public static function __make(Request $request, Config $config) + { + return new static($request, $config->get('cookie')); + } + + /** + * 获取cookie + * @access public + * @param mixed $name 数据名称 + * @param string $default 默认值 + * @return mixed + */ + public function get(string $name = '', $default = null) + { + return $this->request->cookie($name, $default); + } + + /** + * 是否存在Cookie参数 + * @access public + * @param string $name 变量名 + * @return bool + */ + public function has(string $name): bool + { + return $this->request->has($name, 'cookie'); + } + + /** + * Cookie 设置 + * + * @access public + * @param string $name cookie名称 + * @param string $value cookie值 + * @param mixed $option 可选参数 + * @return void + */ + public function set(string $name, string $value, $option = null): void + { + // 参数设置(会覆盖黙认设置) + if (!is_null($option)) { + if (is_numeric($option) || $option instanceof DateTimeInterface) { + $option = ['expire' => $option]; + } + + $config = array_merge($this->config, array_change_key_case($option)); + } else { + $config = $this->config; + } + + if ($config['expire'] instanceof DateTimeInterface) { + $expire = $config['expire']->getTimestamp(); + } else { + $expire = !empty($config['expire']) ? time() + intval($config['expire']) : 0; + } + + $this->setCookie($name, $value, $expire, $config); + } + + /** + * Cookie 保存 + * + * @access public + * @param string $name cookie名称 + * @param string $value cookie值 + * @param int $expire 有效期 + * @param array $option 可选参数 + * @return void + */ + protected function setCookie(string $name, string $value, int $expire, array $option = []): void + { + $this->cookie[$name] = [$value, $expire, $option]; + } + + /** + * 永久保存Cookie数据 + * @access public + * @param string $name cookie名称 + * @param string $value cookie值 + * @param mixed $option 可选参数 可能会是 null|integer|string + * @return void + */ + public function forever(string $name, string $value = '', $option = null): void + { + if (is_null($option) || is_numeric($option)) { + $option = []; + } + + $option['expire'] = 315360000; + + $this->set($name, $value, $option); + } + + /** + * Cookie删除 + * @access public + * @param string $name cookie名称 + * @return void + */ + public function delete(string $name): void + { + $this->setCookie($name, '', time() - 3600, $this->config); + } + + /** + * 获取cookie保存数据 + * @access public + * @return array + */ + public function getCookie(): array + { + return $this->cookie; + } + + /** + * 保存Cookie + * @access public + * @return void + */ + public function save(): void + { + foreach ($this->cookie as $name => $val) { + [$value, $expire, $option] = $val; + + $this->saveCookie( + $name, + $value, + $expire, + $option['path'], + $option['domain'], + $option['secure'] ? true : false, + $option['httponly'] ? true : false, + $option['samesite'] + ); + } + } + + /** + * 保存Cookie + * @access public + * @param string $name cookie名称 + * @param string $value cookie值 + * @param int $expire cookie过期时间 + * @param string $path 有效的服务器路径 + * @param string $domain 有效域名/子域名 + * @param bool $secure 是否仅仅通过HTTPS + * @param bool $httponly 仅可通过HTTP访问 + * @param string $samesite 防止CSRF攻击和用户追踪 + * @return void + */ + protected function saveCookie(string $name, string $value, int $expire, string $path, string $domain, bool $secure, bool $httponly, string $samesite): void + { + if (version_compare(PHP_VERSION, '7.3.0', '>=')) { + setcookie($name, $value, [ + 'expires' => $expire, + 'path' => $path, + 'domain' => $domain, + 'secure' => $secure, + 'httponly' => $httponly, + 'samesite' => $samesite, + ]); + } else { + setcookie($name, $value, $expire, $path, $domain, $secure, $httponly); + } + } + +} diff --git a/vendor/topthink/framework/src/think/Db.php b/vendor/topthink/framework/src/think/Db.php new file mode 100644 index 000000000..0048874fb --- /dev/null +++ b/vendor/topthink/framework/src/think/Db.php @@ -0,0 +1,117 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think; + +/** + * 数据库管理类 + * @package think + * @property Config $config + */ +class Db extends DbManager +{ + /** + * @param Event $event + * @param Config $config + * @param Log $log + * @param Cache $cache + * @return Db + * @codeCoverageIgnore + */ + public static function __make(Event $event, Config $config, Log $log, Cache $cache) + { + $db = new static(); + $db->setConfig($config); + $db->setEvent($event); + $db->setLog($log); + + $store = $db->getConfig('cache_store'); + $db->setCache($cache->store($store)); + $db->triggerSql(); + + return $db; + } + + /** + * 注入模型对象 + * @access public + * @return void + */ + protected function modelMaker() + { + } + + /** + * 设置配置对象 + * @access public + * @param Config $config 配置对象 + * @return void + */ + public function setConfig($config): void + { + $this->config = $config; + } + + /** + * 获取配置参数 + * @access public + * @param string $name 配置参数 + * @param mixed $default 默认值 + * @return mixed + */ + public function getConfig(string $name = '', $default = null) + { + if ('' !== $name) { + return $this->config->get('database.' . $name, $default); + } + + return $this->config->get('database', []); + } + + /** + * 设置Event对象 + * @param Event $event + */ + public function setEvent(Event $event): void + { + $this->event = $event; + } + + /** + * 注册回调方法 + * @access public + * @param string $event 事件名 + * @param callable $callback 回调方法 + * @return void + */ + public function event(string $event, callable $callback): void + { + if ($this->event) { + $this->event->listen('db.' . $event, $callback); + } + } + + /** + * 触发事件 + * @access public + * @param string $event 事件名 + * @param mixed $params 传入参数 + * @param bool $once + * @return mixed + */ + public function trigger(string $event, $params = null, bool $once = false) + { + if ($this->event) { + return $this->event->trigger('db.' . $event, $params, $once); + } + } +} diff --git a/thinkphp/library/think/Env.php b/vendor/topthink/framework/src/think/Env.php old mode 100755 new mode 100644 similarity index 51% rename from thinkphp/library/think/Env.php rename to vendor/topthink/framework/src/think/Env.php index eaeee943e..4c26b33a9 --- a/thinkphp/library/think/Env.php +++ b/vendor/topthink/framework/src/think/Env.php @@ -2,16 +2,23 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think; -class Env +use ArrayAccess; + +/** + * Env管理类 + * @package think + */ +class Env implements ArrayAccess { /** * 环境变量数据 @@ -27,23 +34,23 @@ class Env /** * 读取环境变量定义文件 * @access public - * @param string $file 环境变量定义文件 + * @param string $file 环境变量定义文件 * @return void */ - public function load($file) + public function load(string $file): void { - $env = parse_ini_file($file, true); + $env = parse_ini_file($file, true) ?: []; $this->set($env); } /** * 获取环境变量值 * @access public - * @param string $name 环境变量名 - * @param mixed $default 默认值 + * @param string $name 环境变量名 + * @param mixed $default 默认值 * @return mixed */ - public function get($name = null, $default = null, $php_prefix = true) + public function get(string $name = null, $default = null) { if (is_null($name)) { return $this->data; @@ -55,16 +62,12 @@ class Env return $this->data[$name]; } - return $this->getEnv($name, $default, $php_prefix); + return $this->getEnv($name, $default); } - protected function getEnv($name, $default = null, $php_prefix = true) + protected function getEnv(string $name, $default = null) { - if ($php_prefix) { - $name = 'PHP_' . $name; - } - - $result = getenv($name); + $result = getenv('PHP_' . $name); if (false === $result) { return $default; @@ -86,11 +89,11 @@ class Env /** * 设置环境变量值 * @access public - * @param string|array $env 环境变量 - * @param mixed $value 值 + * @param string|array $env 环境变量 + * @param mixed $value 值 * @return void */ - public function set($env, $value = null) + public function set($env, $value = null): void { if (is_array($env)) { $env = array_change_key_case($env, CASE_UPPER); @@ -110,4 +113,69 @@ class Env $this->data[$name] = $value; } } + + /** + * 检测是否存在环境变量 + * @access public + * @param string $name 参数名 + * @return bool + */ + public function has(string $name): bool + { + return !is_null($this->get($name)); + } + + /** + * 设置环境变量 + * @access public + * @param string $name 参数名 + * @param mixed $value 值 + */ + public function __set(string $name, $value): void + { + $this->set($name, $value); + } + + /** + * 获取环境变量 + * @access public + * @param string $name 参数名 + * @return mixed + */ + public function __get(string $name) + { + return $this->get($name); + } + + /** + * 检测是否存在环境变量 + * @access public + * @param string $name 参数名 + * @return bool + */ + public function __isset(string $name): bool + { + return $this->has($name); + } + + // ArrayAccess + public function offsetSet($name, $value): void + { + $this->set($name, $value); + } + + public function offsetExists($name): bool + { + return $this->__isset($name); + } + + public function offsetUnset($name) + { + throw new Exception('not support: unset'); + } + + public function offsetGet($name) + { + return $this->get($name); + } } diff --git a/vendor/topthink/framework/src/think/Event.php b/vendor/topthink/framework/src/think/Event.php new file mode 100644 index 000000000..6a0eb1f0e --- /dev/null +++ b/vendor/topthink/framework/src/think/Event.php @@ -0,0 +1,263 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think; + +use ReflectionClass; +use ReflectionMethod; + +/** + * 事件管理类 + * @package think + */ +class Event +{ + /** + * 监听者 + * @var array + */ + protected $listener = []; + + /** + * 事件别名 + * @var array + */ + protected $bind = [ + 'AppInit' => event\AppInit::class, + 'HttpRun' => event\HttpRun::class, + 'HttpEnd' => event\HttpEnd::class, + 'RouteLoaded' => event\RouteLoaded::class, + 'LogWrite' => event\LogWrite::class, + ]; + + /** + * 应用对象 + * @var App + */ + protected $app; + + public function __construct(App $app) + { + $this->app = $app; + } + + /** + * 批量注册事件监听 + * @access public + * @param array $events 事件定义 + * @return $this + */ + public function listenEvents(array $events) + { + foreach ($events as $event => $listeners) { + if (isset($this->bind[$event])) { + $event = $this->bind[$event]; + } + + $this->listener[$event] = array_merge($this->listener[$event] ?? [], $listeners); + } + + return $this; + } + + /** + * 注册事件监听 + * @access public + * @param string $event 事件名称 + * @param mixed $listener 监听操作(或者类名) + * @param bool $first 是否优先执行 + * @return $this + */ + public function listen(string $event, $listener, bool $first = false) + { + if (isset($this->bind[$event])) { + $event = $this->bind[$event]; + } + + if ($first && isset($this->listener[$event])) { + array_unshift($this->listener[$event], $listener); + } else { + $this->listener[$event][] = $listener; + } + + return $this; + } + + /** + * 是否存在事件监听 + * @access public + * @param string $event 事件名称 + * @return bool + */ + public function hasListener(string $event): bool + { + if (isset($this->bind[$event])) { + $event = $this->bind[$event]; + } + + return isset($this->listener[$event]); + } + + /** + * 移除事件监听 + * @access public + * @param string $event 事件名称 + * @return void + */ + public function remove(string $event): void + { + if (isset($this->bind[$event])) { + $event = $this->bind[$event]; + } + + unset($this->listener[$event]); + } + + /** + * 指定事件别名标识 便于调用 + * @access public + * @param array $events 事件别名 + * @return $this + */ + public function bind(array $events) + { + $this->bind = array_merge($this->bind, $events); + + return $this; + } + + /** + * 注册事件订阅者 + * @access public + * @param mixed $subscriber 订阅者 + * @return $this + */ + public function subscribe($subscriber) + { + $subscribers = (array) $subscriber; + + foreach ($subscribers as $subscriber) { + if (is_string($subscriber)) { + $subscriber = $this->app->make($subscriber); + } + + if (method_exists($subscriber, 'subscribe')) { + // 手动订阅 + $subscriber->subscribe($this); + } else { + // 智能订阅 + $this->observe($subscriber); + } + } + + return $this; + } + + /** + * 自动注册事件观察者 + * @access public + * @param string|object $observer 观察者 + * @param null|string $prefix 事件名前缀 + * @return $this + */ + public function observe($observer, string $prefix = '') + { + if (is_string($observer)) { + $observer = $this->app->make($observer); + } + + $reflect = new ReflectionClass($observer); + $methods = $reflect->getMethods(ReflectionMethod::IS_PUBLIC); + + if (empty($prefix) && $reflect->hasProperty('eventPrefix')) { + $reflectProperty = $reflect->getProperty('eventPrefix'); + $reflectProperty->setAccessible(true); + $prefix = $reflectProperty->getValue($observer); + } + + foreach ($methods as $method) { + $name = $method->getName(); + if (0 === strpos($name, 'on')) { + $this->listen($prefix . substr($name, 2), [$observer, $name]); + } + } + + return $this; + } + + /** + * 触发事件 + * @access public + * @param string|object $event 事件名称 + * @param mixed $params 传入参数 + * @param bool $once 只获取一个有效返回值 + * @return mixed + */ + public function trigger($event, $params = null, bool $once = false) + { + if (is_object($event)) { + $params = $event; + $event = get_class($event); + } + + if (isset($this->bind[$event])) { + $event = $this->bind[$event]; + } + + $result = []; + $listeners = $this->listener[$event] ?? []; + $listeners = array_unique($listeners, SORT_REGULAR); + + foreach ($listeners as $key => $listener) { + $result[$key] = $this->dispatch($listener, $params); + + if (false === $result[$key] || (!is_null($result[$key]) && $once)) { + break; + } + } + + return $once ? end($result) : $result; + } + + /** + * 触发事件(只获取一个有效返回值) + * @param $event + * @param null $params + * @return mixed + */ + public function until($event, $params = null) + { + return $this->trigger($event, $params, true); + } + + /** + * 执行事件调度 + * @access protected + * @param mixed $event 事件方法 + * @param mixed $params 参数 + * @return mixed + */ + protected function dispatch($event, $params = null) + { + if (!is_string($event)) { + $call = $event; + } elseif (strpos($event, '::')) { + $call = $event; + } else { + $obj = $this->app->make($event); + $call = [$obj, 'handle']; + } + + return $this->app->invoke($call, [$params]); + } + +} diff --git a/thinkphp/library/think/Exception.php b/vendor/topthink/framework/src/think/Exception.php old mode 100755 new mode 100644 similarity index 88% rename from thinkphp/library/think/Exception.php rename to vendor/topthink/framework/src/think/Exception.php index 414a090ad..5cf79548a --- a/thinkphp/library/think/Exception.php +++ b/vendor/topthink/framework/src/think/Exception.php @@ -2,18 +2,22 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: 麦当苗儿 // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think; +/** + * 异常基础类 + * @package think + */ class Exception extends \Exception { - /** * 保存异常页面显示的额外Debug数据 * @var array @@ -37,7 +41,7 @@ class Exception extends \Exception * @param string $label 数据分类,用于异常页面显示 * @param array $data 需要显示的数据,必须为关联数组 */ - final protected function setData($label, array $data) + final protected function setData(string $label, array $data) { $this->data[$label] = $data; } diff --git a/thinkphp/library/think/Facade.php b/vendor/topthink/framework/src/think/Facade.php old mode 100755 new mode 100644 similarity index 59% rename from thinkphp/library/think/Facade.php rename to vendor/topthink/framework/src/think/Facade.php index ac5ae28bc..9a0e33394 --- a/thinkphp/library/think/Facade.php +++ b/vendor/topthink/framework/src/think/Facade.php @@ -2,60 +2,35 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- - namespace think; +/** + * Facade管理类 + */ class Facade { - /** - * 绑定对象 - * @var array - */ - protected static $bind = []; - /** * 始终创建新的对象实例 * @var bool */ protected static $alwaysNewInstance; - /** - * 绑定类的静态代理 - * @static - * @access public - * @param string|array $name 类标识 - * @param string $class 类名 - * @return object - */ - public static function bind($name, $class = null) - { - if (__CLASS__ != static::class) { - return self::__callStatic('bind', func_get_args()); - } - - if (is_array($name)) { - self::$bind = array_merge(self::$bind, $name); - } else { - self::$bind[$name] = $class; - } - } - /** * 创建Facade实例 * @static * @access protected - * @param string $class 类名或标识 - * @param array $args 变量 - * @param bool $newInstance 是否每次创建新的实例 + * @param string $class 类名或标识 + * @param array $args 变量 + * @param bool $newInstance 是否每次创建新的实例 * @return object */ - protected static function createFacade($class = '', $args = [], $newInstance = false) + protected static function createFacade(string $class = '', array $args = [], bool $newInstance = false) { $class = $class ?: static::class; @@ -63,8 +38,6 @@ class Facade if ($facadeClass) { $class = $facadeClass; - } elseif (isset(self::$bind[$class])) { - $class = self::$bind[$class]; } if (static::$alwaysNewInstance) { @@ -75,7 +48,7 @@ class Facade } /** - * 获取当前Facade对应类名(或者已经绑定的容器对象标识) + * 获取当前Facade对应类名 * @access protected * @return string */ @@ -85,7 +58,7 @@ class Facade /** * 带参数实例化当前Facade类 * @access public - * @return mixed + * @return object */ public static function instance(...$args) { @@ -97,12 +70,12 @@ class Facade /** * 调用类的实例 * @access public - * @param string $class 类名或者标识 - * @param array|true $args 变量 - * @param bool $newInstance 是否每次创建新的实例 - * @return mixed + * @param string $class 类名或者标识 + * @param array|true $args 变量 + * @param bool $newInstance 是否每次创建新的实例 + * @return object */ - public static function make($class, $args = [], $newInstance = false) + public static function make(string $class, $args = [], $newInstance = false) { if (__CLASS__ != static::class) { return self::__callStatic('make', func_get_args()); diff --git a/vendor/topthink/framework/src/think/File.php b/vendor/topthink/framework/src/think/File.php new file mode 100644 index 000000000..f7c37bdbe --- /dev/null +++ b/vendor/topthink/framework/src/think/File.php @@ -0,0 +1,187 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think; + +use SplFileInfo; +use think\exception\FileException; + +/** + * 文件上传类 + * @package think + */ +class File extends SplFileInfo +{ + + /** + * 文件hash规则 + * @var array + */ + protected $hash = []; + + protected $hashName; + + public function __construct(string $path, bool $checkPath = true) + { + if ($checkPath && !is_file($path)) { + throw new FileException(sprintf('The file "%s" does not exist', $path)); + } + + parent::__construct($path); + } + + /** + * 获取文件的哈希散列值 + * @access public + * @param string $type + * @return string + */ + public function hash(string $type = 'sha1'): string + { + if (!isset($this->hash[$type])) { + $this->hash[$type] = hash_file($type, $this->getPathname()); + } + + return $this->hash[$type]; + } + + /** + * 获取文件的MD5值 + * @access public + * @return string + */ + public function md5(): string + { + return $this->hash('md5'); + } + + /** + * 获取文件的SHA1值 + * @access public + * @return string + */ + public function sha1(): string + { + return $this->hash('sha1'); + } + + /** + * 获取文件类型信息 + * @access public + * @return string + */ + public function getMime(): string + { + $finfo = finfo_open(FILEINFO_MIME_TYPE); + + return finfo_file($finfo, $this->getPathname()); + } + + /** + * 移动文件 + * @access public + * @param string $directory 保存路径 + * @param string|null $name 保存的文件名 + * @return File + */ + public function move(string $directory, string $name = null): File + { + $target = $this->getTargetFile($directory, $name); + + set_error_handler(function ($type, $msg) use (&$error) { + $error = $msg; + }); + $renamed = rename($this->getPathname(), (string) $target); + restore_error_handler(); + if (!$renamed) { + throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s)', $this->getPathname(), $target, strip_tags($error))); + } + + @chmod((string) $target, 0666 & ~umask()); + + return $target; + } + + /** + * 实例化一个新文件 + * @param string $directory + * @param null|string $name + * @return File + */ + protected function getTargetFile(string $directory, string $name = null): File + { + if (!is_dir($directory)) { + if (false === @mkdir($directory, 0777, true) && !is_dir($directory)) { + throw new FileException(sprintf('Unable to create the "%s" directory', $directory)); + } + } elseif (!is_writable($directory)) { + throw new FileException(sprintf('Unable to write in the "%s" directory', $directory)); + } + + $target = rtrim($directory, '/\\') . \DIRECTORY_SEPARATOR . (null === $name ? $this->getBasename() : $this->getName($name)); + + return new self($target, false); + } + + /** + * 获取文件名 + * @param string $name + * @return string + */ + protected function getName(string $name): string + { + $originalName = str_replace('\\', '/', $name); + $pos = strrpos($originalName, '/'); + $originalName = false === $pos ? $originalName : substr($originalName, $pos + 1); + + return $originalName; + } + + /** + * 文件扩展名 + * @return string + */ + public function extension(): string + { + return $this->getExtension(); + } + + /** + * 自动生成文件名 + * @access public + * @param string|\Closure $rule + * @return string + */ + public function hashName($rule = ''): string + { + if (!$this->hashName) { + if ($rule instanceof \Closure) { + $this->hashName = call_user_func_array($rule, [$this]); + } else { + switch (true) { + case in_array($rule, hash_algos()): + $hash = $this->hash($rule); + $this->hashName = substr($hash, 0, 2) . DIRECTORY_SEPARATOR . substr($hash, 2); + break; + case is_callable($rule): + $this->hashName = call_user_func($rule); + break; + default: + $this->hashName = date('Ymd') . DIRECTORY_SEPARATOR . md5((string) microtime(true)); + break; + } + } + } + + return $this->hashName . '.' . $this->extension(); + } +} diff --git a/vendor/topthink/framework/src/think/Filesystem.php b/vendor/topthink/framework/src/think/Filesystem.php new file mode 100644 index 000000000..0aee929f5 --- /dev/null +++ b/vendor/topthink/framework/src/think/Filesystem.php @@ -0,0 +1,89 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think; + +use InvalidArgumentException; +use think\filesystem\Driver; +use think\filesystem\driver\Local; +use think\helper\Arr; + +/** + * Class Filesystem + * @package think + * @mixin Driver + * @mixin Local + */ +class Filesystem extends Manager +{ + protected $namespace = '\\think\\filesystem\\driver\\'; + + /** + * @param null|string $name + * @return Driver + */ + public function disk(string $name = null): Driver + { + return $this->driver($name); + } + + protected function resolveType(string $name) + { + return $this->getDiskConfig($name, 'type', 'local'); + } + + protected function resolveConfig(string $name) + { + return $this->getDiskConfig($name); + } + + /** + * 获取缓存配置 + * @access public + * @param null|string $name 名称 + * @param mixed $default 默认值 + * @return mixed + */ + public function getConfig(string $name = null, $default = null) + { + if (!is_null($name)) { + return $this->app->config->get('filesystem.' . $name, $default); + } + + return $this->app->config->get('filesystem'); + } + + /** + * 获取磁盘配置 + * @param string $disk + * @param null $name + * @param null $default + * @return array + */ + public function getDiskConfig($disk, $name = null, $default = null) + { + if ($config = $this->getConfig("disks.{$disk}")) { + return Arr::get($config, $name, $default); + } + + throw new InvalidArgumentException("Disk [$disk] not found."); + } + + /** + * 默认驱动 + * @return string|null + */ + public function getDefaultDriver() + { + return $this->getConfig('default'); + } +} diff --git a/vendor/topthink/framework/src/think/Http.php b/vendor/topthink/framework/src/think/Http.php new file mode 100644 index 000000000..4e49c88cb --- /dev/null +++ b/vendor/topthink/framework/src/think/Http.php @@ -0,0 +1,288 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think; + +use think\event\HttpEnd; +use think\event\HttpRun; +use think\event\RouteLoaded; +use think\exception\Handle; +use Throwable; + +/** + * Web应用管理类 + * @package think + */ +class Http +{ + + /** + * @var App + */ + protected $app; + + /** + * 应用名称 + * @var string + */ + protected $name; + + /** + * 应用路径 + * @var string + */ + protected $path; + + /** + * 路由路径 + * @var string + */ + protected $routePath; + + /** + * 是否绑定应用 + * @var bool + */ + protected $isBind = false; + + public function __construct(App $app) + { + $this->app = $app; + + $this->routePath = $this->app->getRootPath() . 'route' . DIRECTORY_SEPARATOR; + } + + /** + * 设置应用名称 + * @access public + * @param string $name 应用名称 + * @return $this + */ + public function name(string $name) + { + $this->name = $name; + return $this; + } + + /** + * 获取应用名称 + * @access public + * @return string + */ + public function getName(): string + { + return $this->name ?: ''; + } + + /** + * 设置应用目录 + * @access public + * @param string $path 应用目录 + * @return $this + */ + public function path(string $path) + { + if (substr($path, -1) != DIRECTORY_SEPARATOR) { + $path .= DIRECTORY_SEPARATOR; + } + + $this->path = $path; + return $this; + } + + /** + * 获取应用路径 + * @access public + * @return string + */ + public function getPath(): string + { + return $this->path ?: ''; + } + + /** + * 获取路由目录 + * @access public + * @return string + */ + public function getRoutePath(): string + { + return $this->routePath; + } + + /** + * 设置路由目录 + * @access public + * @param string $path 路由定义目录 + */ + public function setRoutePath(string $path): void + { + $this->routePath = $path; + } + + /** + * 设置应用绑定 + * @access public + * @param bool $bind 是否绑定 + * @return $this + */ + public function setBind(bool $bind = true) + { + $this->isBind = $bind; + return $this; + } + + /** + * 是否绑定应用 + * @access public + * @return bool + */ + public function isBind(): bool + { + return $this->isBind; + } + + /** + * 执行应用程序 + * @access public + * @param Request|null $request + * @return Response + */ + public function run(Request $request = null): Response + { + //初始化 + $this->initialize(); + + //自动创建request对象 + $request = $request ?? $this->app->make('request', [], true); + $this->app->instance('request', $request); + + try { + $response = $this->runWithRequest($request); + } catch (Throwable $e) { + $this->reportException($e); + + $response = $this->renderException($request, $e); + } + + return $response; + } + + /** + * 初始化 + */ + protected function initialize() + { + if (!$this->app->initialized()) { + $this->app->initialize(); + } + } + + /** + * 执行应用程序 + * @param Request $request + * @return mixed + */ + protected function runWithRequest(Request $request) + { + // 加载全局中间件 + $this->loadMiddleware(); + + // 监听HttpRun + $this->app->event->trigger(HttpRun::class); + + return $this->app->middleware->pipeline() + ->send($request) + ->then(function ($request) { + return $this->dispatchToRoute($request); + }); + } + + protected function dispatchToRoute($request) + { + $withRoute = $this->app->config->get('app.with_route', true) ? function () { + $this->loadRoutes(); + } : null; + + return $this->app->route->dispatch($request, $withRoute); + } + + /** + * 加载全局中间件 + */ + protected function loadMiddleware(): void + { + if (is_file($this->app->getBasePath() . 'middleware.php')) { + $this->app->middleware->import(include $this->app->getBasePath() . 'middleware.php'); + } + } + + /** + * 加载路由 + * @access protected + * @return void + */ + protected function loadRoutes(): void + { + // 加载路由定义 + $routePath = $this->getRoutePath(); + + if (is_dir($routePath)) { + $files = glob($routePath . '*.php'); + foreach ($files as $file) { + include $file; + } + } + + $this->app->event->trigger(RouteLoaded::class); + } + + /** + * Report the exception to the exception handler. + * + * @param Throwable $e + * @return void + */ + protected function reportException(Throwable $e) + { + $this->app->make(Handle::class)->report($e); + } + + /** + * Render the exception to a response. + * + * @param Request $request + * @param Throwable $e + * @return Response + */ + protected function renderException($request, Throwable $e) + { + return $this->app->make(Handle::class)->render($request, $e); + } + + /** + * HttpEnd + * @param Response $response + * @return void + */ + public function end(Response $response): void + { + $this->app->event->trigger(HttpEnd::class, $response); + + //执行中间件 + $this->app->middleware->end($response); + + // 写入日志 + $this->app->log->save(); + } + +} diff --git a/vendor/topthink/framework/src/think/Lang.php b/vendor/topthink/framework/src/think/Lang.php new file mode 100644 index 000000000..0b79b7604 --- /dev/null +++ b/vendor/topthink/framework/src/think/Lang.php @@ -0,0 +1,294 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think; + +/** + * 多语言管理类 + * @package think + */ +class Lang +{ + /** + * 配置参数 + * @var array + */ + protected $config = [ + // 默认语言 + 'default_lang' => 'zh-cn', + // 允许的语言列表 + 'allow_lang_list' => [], + // 是否使用Cookie记录 + 'use_cookie' => true, + // 扩展语言包 + 'extend_list' => [], + // 多语言cookie变量 + 'cookie_var' => 'think_lang', + // 多语言header变量 + 'header_var' => 'think-lang', + // 多语言自动侦测变量名 + 'detect_var' => 'lang', + // Accept-Language转义为对应语言包名称 + 'accept_language' => [ + 'zh-hans-cn' => 'zh-cn', + ], + // 是否支持语言分组 + 'allow_group' => false, + ]; + + /** + * 多语言信息 + * @var array + */ + private $lang = []; + + /** + * 当前语言 + * @var string + */ + private $range = 'zh-cn'; + + /** + * 构造方法 + * @access public + * @param array $config + */ + public function __construct(array $config = []) + { + $this->config = array_merge($this->config, array_change_key_case($config)); + $this->range = $this->config['default_lang']; + } + + public static function __make(Config $config) + { + return new static($config->get('lang')); + } + + /** + * 设置当前语言 + * @access public + * @param string $lang 语言 + * @return void + */ + public function setLangSet(string $lang): void + { + $this->range = $lang; + } + + /** + * 获取当前语言 + * @access public + * @return string + */ + public function getLangSet(): string + { + return $this->range; + } + + /** + * 获取默认语言 + * @access public + * @return string + */ + public function defaultLangSet() + { + return $this->config['default_lang']; + } + + /** + * 加载语言定义(不区分大小写) + * @access public + * @param string|array $file 语言文件 + * @param string $range 语言作用域 + * @return array + */ + public function load($file, $range = ''): array + { + $range = $range ?: $this->range; + if (!isset($this->lang[$range])) { + $this->lang[$range] = []; + } + + $lang = []; + + foreach ((array) $file as $name) { + if (is_file($name)) { + $result = $this->parse($name); + $lang = array_change_key_case($result) + $lang; + } + } + + if (!empty($lang)) { + $this->lang[$range] = $lang + $this->lang[$range]; + } + + return $this->lang[$range]; + } + + /** + * 解析语言文件 + * @access protected + * @param string $file 语言文件名 + * @return array + */ + protected function parse(string $file): array + { + $type = pathinfo($file, PATHINFO_EXTENSION); + + switch ($type) { + case 'php': + $result = include $file; + break; + case 'yml': + case 'yaml': + if (function_exists('yaml_parse_file')) { + $result = yaml_parse_file($file); + } + break; + case 'json': + $data = file_get_contents($file); + + if (false !== $data) { + $data = json_decode($data, true); + + if (json_last_error() === JSON_ERROR_NONE) { + $result = $data; + } + } + + break; + } + + return isset($result) && is_array($result) ? $result : []; + } + + /** + * 判断是否存在语言定义(不区分大小写) + * @access public + * @param string|null $name 语言变量 + * @param string $range 语言作用域 + * @return bool + */ + public function has(string $name, string $range = ''): bool + { + $range = $range ?: $this->range; + + if ($this->config['allow_group'] && strpos($name, '.')) { + [$name1, $name2] = explode('.', $name, 2); + return isset($this->lang[$range][strtolower($name1)][$name2]); + } + + return isset($this->lang[$range][strtolower($name)]); + } + + /** + * 获取语言定义(不区分大小写) + * @access public + * @param string|null $name 语言变量 + * @param array $vars 变量替换 + * @param string $range 语言作用域 + * @return mixed + */ + public function get(string $name = null, array $vars = [], string $range = '') + { + $range = $range ?: $this->range; + + // 空参数返回所有定义 + if (is_null($name)) { + return $this->lang[$range] ?? []; + } + + if ($this->config['allow_group'] && strpos($name, '.')) { + [$name1, $name2] = explode('.', $name, 2); + + $value = $this->lang[$range][strtolower($name1)][$name2] ?? $name; + } else { + $value = $this->lang[$range][strtolower($name)] ?? $name; + } + + // 变量解析 + if (!empty($vars) && is_array($vars)) { + /** + * Notes: + * 为了检测的方便,数字索引的判断仅仅是参数数组的第一个元素的key为数字0 + * 数字索引采用的是系统的 sprintf 函数替换,用法请参考 sprintf 函数 + */ + if (key($vars) === 0) { + // 数字索引解析 + array_unshift($vars, $value); + $value = call_user_func_array('sprintf', $vars); + } else { + // 关联索引解析 + $replace = array_keys($vars); + foreach ($replace as &$v) { + $v = "{:{$v}}"; + } + $value = str_replace($replace, $vars, $value); + } + } + + return $value; + } + + /** + * 自动侦测设置获取语言选择 + * @access public + * @param Request $request + * @return string + */ + public function detect(Request $request): string + { + // 自动侦测设置获取语言选择 + $langSet = ''; + + if ($request->get($this->config['detect_var'])) { + // url中设置了语言变量 + $langSet = strtolower($request->get($this->config['detect_var'])); + } elseif ($request->header($this->config['header_var'])) { + // Header中设置了语言变量 + $langSet = strtolower($request->header($this->config['header_var'])); + } elseif ($request->cookie($this->config['cookie_var'])) { + // Cookie中设置了语言变量 + $langSet = strtolower($request->cookie($this->config['cookie_var'])); + } elseif ($request->server('HTTP_ACCEPT_LANGUAGE')) { + // 自动侦测浏览器语言 + $match = preg_match('/^([a-z\d\-]+)/i', $request->server('HTTP_ACCEPT_LANGUAGE'), $matches); + if ($match) { + $langSet = strtolower($matches[1]); + if (isset($this->config['accept_language'][$langSet])) { + $langSet = $this->config['accept_language'][$langSet]; + } + } + } + + if (empty($this->config['allow_lang_list']) || in_array($langSet, $this->config['allow_lang_list'])) { + // 合法的语言 + $this->range = $langSet; + } + + return $this->range; + } + + /** + * 保存当前语言到Cookie + * @access public + * @param Cookie $cookie Cookie对象 + * @return void + */ + public function saveToCookie(Cookie $cookie) + { + if ($this->config['use_cookie']) { + $cookie->set($this->config['cookie_var'], $this->range); + } + } + +} diff --git a/vendor/topthink/framework/src/think/Log.php b/vendor/topthink/framework/src/think/Log.php new file mode 100644 index 000000000..c31210ce4 --- /dev/null +++ b/vendor/topthink/framework/src/think/Log.php @@ -0,0 +1,342 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think; + +use InvalidArgumentException; +use Psr\Log\LoggerInterface; +use think\event\LogWrite; +use think\helper\Arr; +use think\log\Channel; +use think\log\ChannelSet; + +/** + * 日志管理类 + * @package think + * @mixin Channel + */ +class Log extends Manager implements LoggerInterface +{ + const EMERGENCY = 'emergency'; + const ALERT = 'alert'; + const CRITICAL = 'critical'; + const ERROR = 'error'; + const WARNING = 'warning'; + const NOTICE = 'notice'; + const INFO = 'info'; + const DEBUG = 'debug'; + const SQL = 'sql'; + + protected $namespace = '\\think\\log\\driver\\'; + + /** + * 默认驱动 + * @return string|null + */ + public function getDefaultDriver() + { + return $this->getConfig('default'); + } + + /** + * 获取日志配置 + * @access public + * @param null|string $name 名称 + * @param mixed $default 默认值 + * @return mixed + */ + public function getConfig(string $name = null, $default = null) + { + if (!is_null($name)) { + return $this->app->config->get('log.' . $name, $default); + } + + return $this->app->config->get('log'); + } + + /** + * 获取渠道配置 + * @param string $channel + * @param null $name + * @param null $default + * @return array + */ + public function getChannelConfig($channel, $name = null, $default = null) + { + if ($config = $this->getConfig("channels.{$channel}")) { + return Arr::get($config, $name, $default); + } + + throw new InvalidArgumentException("Channel [$channel] not found."); + } + + /** + * driver()的别名 + * @param string|array $name 渠道名 + * @return Channel|ChannelSet + */ + public function channel($name = null) + { + if (is_array($name)) { + return new ChannelSet($this, $name); + } + + return $this->driver($name); + } + + protected function resolveType(string $name) + { + return $this->getChannelConfig($name, 'type', 'file'); + } + + public function createDriver(string $name) + { + $driver = parent::createDriver($name); + + $lazy = !$this->getChannelConfig($name, "realtime_write", false) && !$this->app->runningInConsole(); + $allow = array_merge($this->getConfig("level", []), $this->getChannelConfig($name, "level", [])); + + return new Channel($name, $driver, $allow, $lazy, $this->app->event); + } + + protected function resolveConfig(string $name) + { + return $this->getChannelConfig($name); + } + + /** + * 清空日志信息 + * @access public + * @param string|array $channel 日志通道名 + * @return $this + */ + public function clear($channel = '*') + { + if ('*' == $channel) { + $channel = array_keys($this->drivers); + } + + $this->channel($channel)->clear(); + + return $this; + } + + /** + * 关闭本次请求日志写入 + * @access public + * @param string|array $channel 日志通道名 + * @return $this + */ + public function close($channel = '*') + { + if ('*' == $channel) { + $channel = array_keys($this->drivers); + } + + $this->channel($channel)->close(); + + return $this; + } + + /** + * 获取日志信息 + * @access public + * @param string $channel 日志通道名 + * @return array + */ + public function getLog(string $channel = null): array + { + return $this->channel($channel)->getLog(); + } + + /** + * 保存日志信息 + * @access public + * @return bool + */ + public function save(): bool + { + /** @var Channel $channel */ + foreach ($this->drivers as $channel) { + $channel->save(); + } + + return true; + } + + /** + * 记录日志信息 + * @access public + * @param mixed $msg 日志信息 + * @param string $type 日志级别 + * @param array $context 替换内容 + * @param bool $lazy + * @return $this + */ + public function record($msg, string $type = 'info', array $context = [], bool $lazy = true) + { + $channel = $this->getConfig('type_channel.' . $type); + + $this->channel($channel)->record($msg, $type, $context, $lazy); + + return $this; + } + + /** + * 实时写入日志信息 + * @access public + * @param mixed $msg 调试信息 + * @param string $type 日志级别 + * @param array $context 替换内容 + * @return $this + */ + public function write($msg, string $type = 'info', array $context = []) + { + return $this->record($msg, $type, $context, false); + } + + /** + * 注册日志写入事件监听 + * @param $listener + * @return Event + */ + public function listen($listener) + { + return $this->app->event->listen(LogWrite::class, $listener); + } + + /** + * 记录日志信息 + * @access public + * @param string $level 日志级别 + * @param mixed $message 日志信息 + * @param array $context 替换内容 + * @return void + */ + public function log($level, $message, array $context = []): void + { + $this->record($message, $level, $context); + } + + /** + * 记录emergency信息 + * @access public + * @param mixed $message 日志信息 + * @param array $context 替换内容 + * @return void + */ + public function emergency($message, array $context = []): void + { + $this->log(__FUNCTION__, $message, $context); + } + + /** + * 记录警报信息 + * @access public + * @param mixed $message 日志信息 + * @param array $context 替换内容 + * @return void + */ + public function alert($message, array $context = []): void + { + $this->log(__FUNCTION__, $message, $context); + } + + /** + * 记录紧急情况 + * @access public + * @param mixed $message 日志信息 + * @param array $context 替换内容 + * @return void + */ + public function critical($message, array $context = []): void + { + $this->log(__FUNCTION__, $message, $context); + } + + /** + * 记录错误信息 + * @access public + * @param mixed $message 日志信息 + * @param array $context 替换内容 + * @return void + */ + public function error($message, array $context = []): void + { + $this->log(__FUNCTION__, $message, $context); + } + + /** + * 记录warning信息 + * @access public + * @param mixed $message 日志信息 + * @param array $context 替换内容 + * @return void + */ + public function warning($message, array $context = []): void + { + $this->log(__FUNCTION__, $message, $context); + } + + /** + * 记录notice信息 + * @access public + * @param mixed $message 日志信息 + * @param array $context 替换内容 + * @return void + */ + public function notice($message, array $context = []): void + { + $this->log(__FUNCTION__, $message, $context); + } + + /** + * 记录一般信息 + * @access public + * @param mixed $message 日志信息 + * @param array $context 替换内容 + * @return void + */ + public function info($message, array $context = []): void + { + $this->log(__FUNCTION__, $message, $context); + } + + /** + * 记录调试信息 + * @access public + * @param mixed $message 日志信息 + * @param array $context 替换内容 + * @return void + */ + public function debug($message, array $context = []): void + { + $this->log(__FUNCTION__, $message, $context); + } + + /** + * 记录sql信息 + * @access public + * @param mixed $message 日志信息 + * @param array $context 替换内容 + * @return void + */ + public function sql($message, array $context = []): void + { + $this->log(__FUNCTION__, $message, $context); + } + + public function __call($method, $parameters) + { + $this->log($method, ...$parameters); + } +} diff --git a/vendor/topthink/framework/src/think/Manager.php b/vendor/topthink/framework/src/think/Manager.php new file mode 100644 index 000000000..ca3f6a5a9 --- /dev/null +++ b/vendor/topthink/framework/src/think/Manager.php @@ -0,0 +1,177 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think; + +use InvalidArgumentException; +use think\helper\Str; + +abstract class Manager +{ + /** @var App */ + protected $app; + + /** + * 驱动 + * @var array + */ + protected $drivers = []; + + /** + * 驱动的命名空间 + * @var string + */ + protected $namespace = null; + + public function __construct(App $app) + { + $this->app = $app; + } + + /** + * 获取驱动实例 + * @param null|string $name + * @return mixed + */ + protected function driver(string $name = null) + { + $name = $name ?: $this->getDefaultDriver(); + + if (is_null($name)) { + throw new InvalidArgumentException(sprintf( + 'Unable to resolve NULL driver for [%s].', + static::class + )); + } + + return $this->drivers[$name] = $this->getDriver($name); + } + + /** + * 获取驱动实例 + * @param string $name + * @return mixed + */ + protected function getDriver(string $name) + { + return $this->drivers[$name] ?? $this->createDriver($name); + } + + /** + * 获取驱动类型 + * @param string $name + * @return mixed + */ + protected function resolveType(string $name) + { + return $name; + } + + /** + * 获取驱动配置 + * @param string $name + * @return mixed + */ + protected function resolveConfig(string $name) + { + return $name; + } + + /** + * 获取驱动类 + * @param string $type + * @return string + */ + protected function resolveClass(string $type): string + { + if ($this->namespace || false !== strpos($type, '\\')) { + $class = false !== strpos($type, '\\') ? $type : $this->namespace . Str::studly($type); + + if (class_exists($class)) { + return $class; + } + } + + throw new InvalidArgumentException("Driver [$type] not supported."); + } + + /** + * 获取驱动参数 + * @param $name + * @return array + */ + protected function resolveParams($name): array + { + $config = $this->resolveConfig($name); + return [$config]; + } + + /** + * 创建驱动 + * + * @param string $name + * @return mixed + * + */ + protected function createDriver(string $name) + { + $type = $this->resolveType($name); + + $method = 'create' . Str::studly($type) . 'Driver'; + + $params = $this->resolveParams($name); + + if (method_exists($this, $method)) { + return $this->$method(...$params); + } + + $class = $this->resolveClass($type); + + return $this->app->invokeClass($class, $params); + } + + /** + * 移除一个驱动实例 + * + * @param array|string|null $name + * @return $this + */ + public function forgetDriver($name = null) + { + $name = $name ?? $this->getDefaultDriver(); + + foreach ((array) $name as $cacheName) { + if (isset($this->drivers[$cacheName])) { + unset($this->drivers[$cacheName]); + } + } + + return $this; + } + + /** + * 默认驱动 + * @return string|null + */ + abstract public function getDefaultDriver(); + + /** + * 动态调用 + * @param string $method + * @param array $parameters + * @return mixed + */ + public function __call($method, $parameters) + { + return $this->driver()->$method(...$parameters); + } +} diff --git a/vendor/topthink/framework/src/think/Middleware.php b/vendor/topthink/framework/src/think/Middleware.php new file mode 100644 index 000000000..a3db0f2f3 --- /dev/null +++ b/vendor/topthink/framework/src/think/Middleware.php @@ -0,0 +1,257 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think; + +use Closure; +use InvalidArgumentException; +use LogicException; +use think\exception\Handle; +use Throwable; + +/** + * 中间件管理类 + * @package think + */ +class Middleware +{ + /** + * 中间件执行队列 + * @var array + */ + protected $queue = []; + + /** + * 应用对象 + * @var App + */ + protected $app; + + public function __construct(App $app) + { + $this->app = $app; + } + + /** + * 导入中间件 + * @access public + * @param array $middlewares + * @param string $type 中间件类型 + * @return void + */ + public function import(array $middlewares = [], string $type = 'global'): void + { + foreach ($middlewares as $middleware) { + $this->add($middleware, $type); + } + } + + /** + * 注册中间件 + * @access public + * @param mixed $middleware + * @param string $type 中间件类型 + * @return void + */ + public function add($middleware, string $type = 'global'): void + { + $middleware = $this->buildMiddleware($middleware, $type); + + if (!empty($middleware)) { + $this->queue[$type][] = $middleware; + $this->queue[$type] = array_unique($this->queue[$type], SORT_REGULAR); + } + } + + /** + * 注册路由中间件 + * @access public + * @param mixed $middleware + * @return void + */ + public function route($middleware): void + { + $this->add($middleware, 'route'); + } + + /** + * 注册控制器中间件 + * @access public + * @param mixed $middleware + * @return void + */ + public function controller($middleware): void + { + $this->add($middleware, 'controller'); + } + + /** + * 注册中间件到开始位置 + * @access public + * @param mixed $middleware + * @param string $type 中间件类型 + */ + public function unshift($middleware, string $type = 'global') + { + $middleware = $this->buildMiddleware($middleware, $type); + + if (!empty($middleware)) { + if (!isset($this->queue[$type])) { + $this->queue[$type] = []; + } + + array_unshift($this->queue[$type], $middleware); + } + } + + /** + * 获取注册的中间件 + * @access public + * @param string $type 中间件类型 + * @return array + */ + public function all(string $type = 'global'): array + { + return $this->queue[$type] ?? []; + } + + /** + * 调度管道 + * @access public + * @param string $type 中间件类型 + * @return Pipeline + */ + public function pipeline(string $type = 'global') + { + return (new Pipeline()) + ->through(array_map(function ($middleware) { + return function ($request, $next) use ($middleware) { + [$call, $params] = $middleware; + if (is_array($call) && is_string($call[0])) { + $call = [$this->app->make($call[0]), $call[1]]; + } + $response = call_user_func($call, $request, $next, ...$params); + + if (!$response instanceof Response) { + throw new LogicException('The middleware must return Response instance'); + } + return $response; + }; + }, $this->sortMiddleware($this->queue[$type] ?? []))) + ->whenException([$this, 'handleException']); + } + + /** + * 结束调度 + * @param Response $response + */ + public function end(Response $response) + { + foreach ($this->queue as $queue) { + foreach ($queue as $middleware) { + [$call] = $middleware; + if (is_array($call) && is_string($call[0])) { + $instance = $this->app->make($call[0]); + if (method_exists($instance, 'end')) { + $instance->end($response); + } + } + } + } + } + + /** + * 异常处理 + * @param Request $passable + * @param Throwable $e + * @return Response + */ + public function handleException($passable, Throwable $e) + { + /** @var Handle $handler */ + $handler = $this->app->make(Handle::class); + + $handler->report($e); + + return $handler->render($passable, $e); + } + + /** + * 解析中间件 + * @access protected + * @param mixed $middleware + * @param string $type 中间件类型 + * @return array + */ + protected function buildMiddleware($middleware, string $type): array + { + if (is_array($middleware)) { + [$middleware, $params] = $middleware; + } + + if ($middleware instanceof Closure) { + return [$middleware, $params ?? []]; + } + + if (!is_string($middleware)) { + throw new InvalidArgumentException('The middleware is invalid'); + } + + //中间件别名检查 + $alias = $this->app->config->get('middleware.alias', []); + + if (isset($alias[$middleware])) { + $middleware = $alias[$middleware]; + } + + if (is_array($middleware)) { + $this->import($middleware, $type); + return []; + } + + return [[$middleware, 'handle'], $params ?? []]; + } + + /** + * 中间件排序 + * @param array $middlewares + * @return array + */ + protected function sortMiddleware(array $middlewares) + { + $priority = $this->app->config->get('middleware.priority', []); + uasort($middlewares, function ($a, $b) use ($priority) { + $aPriority = $this->getMiddlewarePriority($priority, $a); + $bPriority = $this->getMiddlewarePriority($priority, $b); + return $bPriority - $aPriority; + }); + + return $middlewares; + } + + /** + * 获取中间件优先级 + * @param $priority + * @param $middleware + * @return int + */ + protected function getMiddlewarePriority($priority, $middleware) + { + [$call] = $middleware; + if (is_array($call) && is_string($call[0])) { + $index = array_search($call[0], array_reverse($priority)); + return false === $index ? -1 : $index; + } + return -1; + } + +} diff --git a/vendor/topthink/framework/src/think/Pipeline.php b/vendor/topthink/framework/src/think/Pipeline.php new file mode 100644 index 000000000..77151f3ac --- /dev/null +++ b/vendor/topthink/framework/src/think/Pipeline.php @@ -0,0 +1,107 @@ + +// +---------------------------------------------------------------------- +namespace think; + +use Closure; +use Exception; +use Throwable; + +class Pipeline +{ + protected $passable; + + protected $pipes = []; + + protected $exceptionHandler; + + /** + * 初始数据 + * @param $passable + * @return $this + */ + public function send($passable) + { + $this->passable = $passable; + return $this; + } + + /** + * 调用栈 + * @param $pipes + * @return $this + */ + public function through($pipes) + { + $this->pipes = is_array($pipes) ? $pipes : func_get_args(); + return $this; + } + + /** + * 执行 + * @param Closure $destination + * @return mixed + */ + public function then(Closure $destination) + { + $pipeline = array_reduce( + array_reverse($this->pipes), + $this->carry(), + function ($passable) use ($destination) { + try { + return $destination($passable); + } catch (Throwable | Exception $e) { + return $this->handleException($passable, $e); + } + } + ); + + return $pipeline($this->passable); + } + + /** + * 设置异常处理器 + * @param callable $handler + * @return $this + */ + public function whenException($handler) + { + $this->exceptionHandler = $handler; + return $this; + } + + protected function carry() + { + return function ($stack, $pipe) { + return function ($passable) use ($stack, $pipe) { + try { + return $pipe($passable, $stack); + } catch (Throwable | Exception $e) { + return $this->handleException($passable, $e); + } + }; + }; + } + + /** + * 异常处理 + * @param $passable + * @param $e + * @return mixed + */ + protected function handleException($passable, Throwable $e) + { + if ($this->exceptionHandler) { + return call_user_func($this->exceptionHandler, $passable, $e); + } + throw $e; + } + +} diff --git a/thinkphp/library/think/Request.php b/vendor/topthink/framework/src/think/Request.php old mode 100755 new mode 100644 similarity index 55% rename from thinkphp/library/think/Request.php rename to vendor/topthink/framework/src/think/Request.php index 92a401d73..a21976df1 --- a/thinkphp/library/think/Request.php +++ b/vendor/topthink/framework/src/think/Request.php @@ -2,46 +2,79 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think; -use think\facade\Cookie; -use think\facade\Session; +use ArrayAccess; +use think\file\UploadedFile; +use think\route\Rule; -class Request +/** + * 请求管理类 + * @package think + */ +class Request implements ArrayAccess { /** - * 配置参数 + * 兼容PATH_INFO获取 * @var array */ - protected $config = [ - // 表单请求类型伪装变量 - 'var_method' => '_method', - // 表单ajax伪装变量 - 'var_ajax' => '_ajax', - // 表单pjax伪装变量 - 'var_pjax' => '_pjax', - // PATHINFO变量名 用于兼容模式 - 'var_pathinfo' => 's', - // 兼容PATH_INFO获取 - 'pathinfo_fetch' => ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO', 'REDIRECT_URL'], - // 默认全局过滤方法 用逗号分隔多个 - 'default_filter' => '', - // 域名根,如thinkphp.cn - 'url_domain_root' => '', - // HTTPS代理标识 - 'https_agent_name' => '', - // IP代理获取标识 - 'http_agent_ip' => 'HTTP_X_REAL_IP', - // URL伪静态后缀 - 'url_html_suffix' => 'html', - ]; + protected $pathinfoFetch = ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO', 'REDIRECT_URL']; + + /** + * PATHINFO变量名 用于兼容模式 + * @var string + */ + protected $varPathinfo = 's'; + + /** + * 请求类型 + * @var string + */ + protected $varMethod = '_method'; + + /** + * 表单ajax伪装变量 + * @var string + */ + protected $varAjax = '_ajax'; + + /** + * 表单pjax伪装变量 + * @var string + */ + protected $varPjax = '_pjax'; + + /** + * 域名根 + * @var string + */ + protected $rootDomain = ''; + + /** + * HTTPS代理标识 + * @var string + */ + protected $httpsAgentName = ''; + + /** + * 前端代理服务器IP + * @var array + */ + protected $proxyServerIp = []; + + /** + * 前端代理服务器真实IP头 + * @var array + */ + protected $proxyServerIpHeader = ['HTTP_X_REAL_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_CLIENT_IP', 'HTTP_X_CLIENT_IP', 'HTTP_X_CLUSTER_CLIENT_IP']; /** * 请求类型 @@ -49,18 +82,18 @@ class Request */ protected $method; - /** - * 主机名(含端口) - * @var string - */ - protected $host; - /** * 域名(含协议及端口) * @var string */ protected $domain; + /** + * HOST(含端口) + * @var string + */ + protected $host; + /** * 子域名 * @var string @@ -110,22 +143,10 @@ class Request protected $path; /** - * 当前路由信息 - * @var array - */ - protected $routeInfo = []; - - /** - * 当前调度信息 - * @var \think\route\Dispatch - */ - protected $dispatch; - - /** - * 当前模块名 + * 当前请求的IP地址 * @var string */ - protected $module; + protected $realIP; /** * 当前控制器名 @@ -139,12 +160,6 @@ class Request */ protected $action; - /** - * 当前语言集 - * @var string - */ - protected $langset; - /** * 当前请求参数 * @var array @@ -169,12 +184,24 @@ class Request */ protected $request = []; + /** + * 当前路由对象 + * @var Rule + */ + protected $rule; + /** * 当前ROUTE参数 * @var array */ protected $route = []; + /** + * 中间件传递的参数 + * @var array + */ + protected $middleware = []; + /** * 当前PUT参数 * @var array @@ -182,23 +209,23 @@ class Request protected $put; /** - * 当前SESSION参数 - * @var array + * SESSION对象 + * @var Session */ - protected $session = []; + protected $session; /** - * 当前FILE参数 - * @var array - */ - protected $file = []; - - /** - * 当前COOKIE参数 + * COOKIE数据 * @var array */ protected $cookie = []; + /** + * ENV对象 + * @var Env + */ + protected $env; + /** * 当前SERVER参数 * @var array @@ -206,10 +233,10 @@ class Request protected $server = []; /** - * 当前ENV参数 + * 当前FILE参数 * @var array */ - protected $env = []; + protected $file = []; /** * 当前HEADER参数 @@ -248,30 +275,13 @@ class Request */ protected $filter; - /** - * 扩展方法 - * @var array - */ - protected $hook = []; - /** * php://input内容 * @var string */ + // php://input protected $input; - /** - * 请求缓存 - * @var array - */ - protected $cache; - - /** - * 缓存是否检查 - * @var bool - */ - protected $isCheckCache; - /** * 请求安全Key * @var string @@ -287,172 +297,71 @@ class Request /** * 架构函数 * @access public - * @param array $options 参数 */ - public function __construct(array $options = []) + public function __construct() { - $this->init($options); - // 保存 php://input $this->input = file_get_contents('php://input'); } - public function init(array $options = []) + public static function __make(App $app) { - $this->config = array_merge($this->config, $options); - - if (is_null($this->filter) && !empty($this->config['default_filter'])) { - $this->filter = $this->config['default_filter']; - } - } - - public function config($name = null) - { - if (is_null($name)) { - return $this->config; - } - return isset($this->config[$name]) ? $this->config[$name] : null; - } - - public static function __make(App $app, Config $config) - { - $request = new static($config->pull('app')); - - $request->server = $_SERVER; - $request->env = $app['env']->get(); - - return $request; - } - - public function __call($method, $args) - { - if (array_key_exists($method, $this->hook)) { - array_unshift($args, $this); - return call_user_func_array($this->hook[$method], $args); - } - - throw new Exception('method not exists:' . static::class . '->' . $method); - } - - /** - * Hook 方法注入 - * @access public - * @param string|array $method 方法名 - * @param mixed $callback callable - * @return void - */ - public function hook($method, $callback = null) - { - if (is_array($method)) { - $this->hook = array_merge($this->hook, $method); - } else { - $this->hook[$method] = $callback; - } - } - - /** - * 创建一个URL请求 - * @access public - * @param string $uri URL地址 - * @param string $method 请求类型 - * @param array $params 请求参数 - * @param array $cookie - * @param array $files - * @param array $server - * @param string $content - * @return \think\Request - */ - public function create($uri, $method = 'GET', $params = [], $cookie = [], $files = [], $server = [], $content = null) - { - $server['PATH_INFO'] = ''; - $server['REQUEST_METHOD'] = strtoupper($method); - $info = parse_url($uri); - - if (isset($info['host'])) { - $server['SERVER_NAME'] = $info['host']; - $server['HTTP_HOST'] = $info['host']; - } - - if (isset($info['scheme'])) { - if ('https' === $info['scheme']) { - $server['HTTPS'] = 'on'; - $server['SERVER_PORT'] = 443; - } else { - unset($server['HTTPS']); - $server['SERVER_PORT'] = 80; - } - } - - if (isset($info['port'])) { - $server['SERVER_PORT'] = $info['port']; - $server['HTTP_HOST'] = $server['HTTP_HOST'] . ':' . $info['port']; - } - - if (isset($info['user'])) { - $server['PHP_AUTH_USER'] = $info['user']; - } - - if (isset($info['pass'])) { - $server['PHP_AUTH_PW'] = $info['pass']; - } - - if (!isset($info['path'])) { - $info['path'] = '/'; - } - - $options = []; - $queryString = ''; - - $options[strtolower($method)] = $params; - - if (isset($info['query'])) { - parse_str(html_entity_decode($info['query']), $query); - if (!empty($params)) { - $params = array_replace($query, $params); - $queryString = http_build_query($params, '', '&'); - } else { - $params = $query; - $queryString = $info['query']; - } - } elseif (!empty($params)) { - $queryString = http_build_query($params, '', '&'); - } - - if ($queryString) { - parse_str($queryString, $get); - $options['get'] = isset($options['get']) ? array_merge($get, $options['get']) : $get; - } - - $server['REQUEST_URI'] = $info['path'] . ('' !== $queryString ? '?' . $queryString : ''); - $server['QUERY_STRING'] = $queryString; - $options['cookie'] = $cookie; - $options['param'] = $params; - $options['file'] = $files; - $options['server'] = $server; - $options['url'] = $server['REQUEST_URI']; - $options['baseUrl'] = $info['path']; - $options['pathinfo'] = '/' == $info['path'] ? '/' : ltrim($info['path'], '/'); - $options['method'] = $server['REQUEST_METHOD']; - $options['domain'] = isset($info['scheme']) ? $info['scheme'] . '://' . $server['HTTP_HOST'] : ''; - $options['content'] = $content; - $request = new static(); - foreach ($options as $name => $item) { - if (property_exists($request, $name)) { - $request->$name = $item; + + if (function_exists('apache_request_headers') && $result = apache_request_headers()) { + $header = $result; + } else { + $header = []; + $server = $_SERVER; + foreach ($server as $key => $val) { + if (0 === strpos($key, 'HTTP_')) { + $key = str_replace('_', '-', strtolower(substr($key, 5))); + $header[$key] = $val; + } + } + if (isset($server['CONTENT_TYPE'])) { + $header['content-type'] = $server['CONTENT_TYPE']; + } + if (isset($server['CONTENT_LENGTH'])) { + $header['content-length'] = $server['CONTENT_LENGTH']; } } + $request->header = array_change_key_case($header); + $request->server = $_SERVER; + $request->env = $app->env; + + $inputData = $request->getInputData($request->input); + + $request->get = $_GET; + $request->post = $_POST ?: $inputData; + $request->put = $inputData; + $request->request = $_REQUEST; + $request->cookie = $_COOKIE; + $request->file = $_FILES ?? []; + return $request; } /** - * 获取当前包含协议、端口的域名 + * 设置当前包含协议的域名 + * @access public + * @param string $domain 域名 + * @return $this + */ + public function setDomain(string $domain) + { + $this->domain = $domain; + return $this; + } + + /** + * 获取当前包含协议的域名 * @access public * @param bool $port 是否需要去除端口号 * @return string */ - public function domain($port = false) + public function domain(bool $port = false): string { return $this->scheme() . '://' . $this->host($port); } @@ -462,12 +371,12 @@ class Request * @access public * @return string */ - public function rootDomain() + public function rootDomain(): string { - $root = $this->config['url_domain_root']; + $root = $this->rootDomain; if (!$root) { - $item = explode('.', $this->host(true)); + $item = explode('.', $this->host()); $count = count($item); $root = $count > 1 ? $item[$count - 2] . '.' . $item[$count - 1] : $item[0]; } @@ -475,25 +384,34 @@ class Request return $root; } + /** + * 设置当前泛域名的值 + * @access public + * @param string $domain 域名 + * @return $this + */ + public function setSubDomain(string $domain) + { + $this->subDomain = $domain; + return $this; + } + /** * 获取当前子域名 * @access public * @return string */ - public function subDomain() + public function subDomain(): string { if (is_null($this->subDomain)) { // 获取当前主域名 - $rootDomain = $this->config['url_domain_root']; + $rootDomain = $this->rootDomain(); if ($rootDomain) { - // 配置域名根 例如 thinkphp.cn 163.com.cn 如果是国家级域名 com.cn net.cn 之类的域名需要配置 - $domain = explode('.', rtrim(stristr($this->host(true), $rootDomain, true), '.')); + $this->subDomain = rtrim(stristr($this->host(), $rootDomain, true), '.'); } else { - $domain = explode('.', $this->host(true), -2); + $this->subDomain = ''; } - - $this->subDomain = implode('.', $domain); } return $this->subDomain; @@ -505,7 +423,7 @@ class Request * @param string $domain 域名 * @return $this */ - public function setPanDomain($domain) + public function setPanDomain(string $domain) { $this->panDomain = $domain; return $this; @@ -516,18 +434,18 @@ class Request * @access public * @return string */ - public function panDomain() + public function panDomain(): string { - return $this->panDomain; + return $this->panDomain ?: ''; } /** * 设置当前完整URL 包括QUERY_STRING * @access public - * @param string $url URL + * @param string $url URL地址 * @return $this */ - public function setUrl($url) + public function setUrl(string $url) { $this->url = $url; return $this; @@ -536,35 +454,35 @@ class Request /** * 获取当前完整URL 包括QUERY_STRING * @access public - * @param bool $complete 是否包含域名 + * @param bool $complete 是否包含完整域名 * @return string */ - public function url($complete = false) + public function url(bool $complete = false): string { - if (!$this->url) { - if ($this->isCli()) { - $this->url = isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : ''; - } elseif ($this->server('HTTP_X_REWRITE_URL')) { - $this->url = $this->server('HTTP_X_REWRITE_URL'); - } elseif ($this->server('REQUEST_URI')) { - $this->url = $this->server('REQUEST_URI'); - } elseif ($this->server('ORIG_PATH_INFO')) { - $this->url = $this->server('ORIG_PATH_INFO') . (!empty($this->server('QUERY_STRING')) ? '?' . $this->server('QUERY_STRING') : ''); - } else { - $this->url = ''; - } + if ($this->url) { + $url = $this->url; + } elseif ($this->server('HTTP_X_REWRITE_URL')) { + $url = $this->server('HTTP_X_REWRITE_URL'); + } elseif ($this->server('REQUEST_URI')) { + $url = $this->server('REQUEST_URI'); + } elseif ($this->server('ORIG_PATH_INFO')) { + $url = $this->server('ORIG_PATH_INFO') . (!empty($this->server('QUERY_STRING')) ? '?' . $this->server('QUERY_STRING') : ''); + } elseif (isset($_SERVER['argv'][1])) { + $url = $_SERVER['argv'][1]; + } else { + $url = ''; } - return $complete ? $this->domain() . $this->url : $this->url; + return $complete ? $this->domain() . $url : $url; } /** - * 设置当前完整URL 不包括QUERY_STRING + * 设置当前URL 不含QUERY_STRING * @access public - * @param string $url URL + * @param string $url URL地址 * @return $this */ - public function setBaseUrl($url) + public function setBaseUrl(string $url) { $this->baseUrl = $url; return $this; @@ -573,26 +491,26 @@ class Request /** * 获取当前URL 不含QUERY_STRING * @access public - * @param bool $domain 是否包含域名 - * @return string|$this + * @param bool $complete 是否包含完整域名 + * @return string */ - public function baseUrl($domain = false) + public function baseUrl(bool $complete = false): string { if (!$this->baseUrl) { $str = $this->url(); $this->baseUrl = strpos($str, '?') ? strstr($str, '?', true) : $str; } - return $domain ? $this->domain() . $this->baseUrl : $this->baseUrl; + return $complete ? $this->domain() . $this->baseUrl : $this->baseUrl; } /** - * 设置或获取当前执行的文件 SCRIPT_NAME + * 获取当前执行的文件 SCRIPT_NAME * @access public - * @param bool $domain 是否包含域名 - * @return string|$this + * @param bool $complete 是否包含完整域名 + * @return string */ - public function baseFile($domain = false) + public function baseFile(bool $complete = false): string { if (!$this->baseFile) { $url = ''; @@ -613,16 +531,16 @@ class Request $this->baseFile = $url; } - return $domain ? $this->domain() . $this->baseFile : $this->baseFile; + return $complete ? $this->domain() . $this->baseFile : $this->baseFile; } /** * 设置URL访问根地址 * @access public * @param string $url URL地址 - * @return string|$this + * @return $this */ - public function setRoot($url = null) + public function setRoot(string $url) { $this->root = $url; return $this; @@ -631,10 +549,10 @@ class Request /** * 获取URL访问根地址 * @access public - * @param bool $domain 是否包含域名 - * @return string|$this + * @param bool $complete 是否包含完整域名 + * @return string */ - public function root($domain = false) + public function root(bool $complete = false): string { if (!$this->root) { $file = $this->baseFile(); @@ -644,7 +562,7 @@ class Request $this->root = rtrim($file, '/'); } - return $domain ? $this->domain() . $this->root : $this->root; + return $complete ? $this->domain() . $this->root : $this->root; } /** @@ -652,7 +570,7 @@ class Request * @access public * @return string */ - public function rootUrl() + public function rootUrl(): string { $base = $this->root(); $root = strpos($base, '.') ? ltrim(dirname($base), DIRECTORY_SEPARATOR) : $base; @@ -664,7 +582,13 @@ class Request return $root; } - public function setPathinfo($pathinfo) + /** + * 设置当前请求的pathinfo + * @access public + * @param string $pathinfo + * @return $this + */ + public function setPathinfo(string $pathinfo) { $this->pathinfo = $pathinfo; return $this; @@ -675,26 +599,23 @@ class Request * @access public * @return string */ - public function pathinfo() + public function pathinfo(): string { if (is_null($this->pathinfo)) { - if (isset($_GET[$this->config['var_pathinfo']])) { + if (isset($_GET[$this->varPathinfo])) { // 判断URL里面是否有兼容模式参数 - $pathinfo = $_GET[$this->config['var_pathinfo']]; - unset($_GET[$this->config['var_pathinfo']]); - unset($this->get[$this->config['var_pathinfo']]); - } elseif ($this->isCli()) { - // CLI模式下 index.php module/controller/action/params/... - $pathinfo = isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : ''; - } elseif ('cli-server' == PHP_SAPI) { - $pathinfo = strpos($this->server('REQUEST_URI'), '?') ? strstr($this->server('REQUEST_URI'), '?', true) : $this->server('REQUEST_URI'); + $pathinfo = $_GET[$this->varPathinfo]; + unset($_GET[$this->varPathinfo]); + unset($this->get[$this->varPathinfo]); } elseif ($this->server('PATH_INFO')) { $pathinfo = $this->server('PATH_INFO'); + } elseif (false !== strpos(PHP_SAPI, 'cli')) { + $pathinfo = strpos($this->server('REQUEST_URI'), '?') ? strstr($this->server('REQUEST_URI'), '?', true) : $this->server('REQUEST_URI'); } // 分析PATHINFO信息 if (!isset($pathinfo)) { - foreach ($this->config['pathinfo_fetch'] as $type) { + foreach ($this->pathinfoFetch as $type) { if ($this->server($type)) { $pathinfo = (0 === strpos($this->server($type), $this->server('SCRIPT_NAME'))) ? substr($this->server($type), strlen($this->server('SCRIPT_NAME'))) : $this->server($type); @@ -713,38 +634,12 @@ class Request return $this->pathinfo; } - /** - * 获取当前请求URL的pathinfo信息(不含URL后缀) - * @access public - * @return string - */ - public function path() - { - if (is_null($this->path)) { - $suffix = $this->config['url_html_suffix']; - $pathinfo = $this->pathinfo(); - - if (false === $suffix) { - // 禁止伪静态访问 - $this->path = $pathinfo; - } elseif ($suffix) { - // 去除正常的URL后缀 - $this->path = preg_replace('/\.(' . ltrim($suffix, '.') . ')$/i', '', $pathinfo); - } else { - // 允许任何后缀访问 - $this->path = preg_replace('/\.' . $this->ext() . '$/i', '', $pathinfo); - } - } - - return $this->path; - } - /** * 当前URL的访问后缀 * @access public * @return string */ - public function ext() + public function ext(): string { return pathinfo($this->pathinfo(), PATHINFO_EXTENSION); } @@ -755,7 +650,7 @@ class Request * @param bool $float 是否使用浮点类型 * @return integer|float */ - public function time($float = false) + public function time(bool $float = false) { return $float ? $this->server('REQUEST_TIME_FLOAT') : $this->server('REQUEST_TIME'); } @@ -763,14 +658,14 @@ class Request /** * 当前请求的资源类型 * @access public - * @return false|string + * @return string */ - public function type() + public function type(): string { $accept = $this->server('HTTP_ACCEPT'); if (empty($accept)) { - return false; + return ''; } foreach ($this->mimeType as $key => $val) { @@ -782,17 +677,17 @@ class Request } } - return false; + return ''; } /** * 设置资源类型 * @access public - * @param string|array $type 资源类型名 - * @param string $val 资源类型 + * @param string|array $type 资源类型名 + * @param string $val 资源类型 * @return void */ - public function mimeType($type, $val = '') + public function mimeType($type, $val = ''): void { if (is_array($type)) { $this->mimeType = array_merge($this->mimeType, $type); @@ -801,27 +696,39 @@ class Request } } + /** + * 设置请求类型 + * @access public + * @param string $method 请求类型 + * @return $this + */ + public function setMethod(string $method) + { + $this->method = strtoupper($method); + return $this; + } + /** * 当前的请求类型 * @access public - * @param bool $origin 是否获取原始请求类型 + * @param bool $origin 是否获取原始请求类型 * @return string */ - public function method($origin = false) + public function method(bool $origin = false): string { if ($origin) { // 获取原始请求类型 return $this->server('REQUEST_METHOD') ?: 'GET'; } elseif (!$this->method) { - if (isset($_POST[$this->config['var_method']])) { - $method = strtolower($_POST[$this->config['var_method']]); + if (isset($this->post[$this->varMethod])) { + $method = strtolower($this->post[$this->varMethod]); if (in_array($method, ['get', 'post', 'put', 'patch', 'delete'])) { $this->method = strtoupper($method); - $this->{$method} = $_POST; + $this->{$method} = $this->post; } else { $this->method = 'POST'; } - unset($_POST[$this->config['var_method']]); + unset($this->post[$this->varMethod]); } elseif ($this->server('HTTP_X_HTTP_METHOD_OVERRIDE')) { $this->method = strtoupper($this->server('HTTP_X_HTTP_METHOD_OVERRIDE')); } else { @@ -837,7 +744,7 @@ class Request * @access public * @return bool */ - public function isGet() + public function isGet(): bool { return $this->method() == 'GET'; } @@ -847,7 +754,7 @@ class Request * @access public * @return bool */ - public function isPost() + public function isPost(): bool { return $this->method() == 'POST'; } @@ -857,7 +764,7 @@ class Request * @access public * @return bool */ - public function isPut() + public function isPut(): bool { return $this->method() == 'PUT'; } @@ -867,7 +774,7 @@ class Request * @access public * @return bool */ - public function isDelete() + public function isDelete(): bool { return $this->method() == 'DELETE'; } @@ -877,7 +784,7 @@ class Request * @access public * @return bool */ - public function isHead() + public function isHead(): bool { return $this->method() == 'HEAD'; } @@ -887,7 +794,7 @@ class Request * @access public * @return bool */ - public function isPatch() + public function isPatch(): bool { return $this->method() == 'PATCH'; } @@ -897,7 +804,7 @@ class Request * @access public * @return bool */ - public function isOptions() + public function isOptions(): bool { return $this->method() == 'OPTIONS'; } @@ -907,7 +814,7 @@ class Request * @access public * @return bool */ - public function isCli() + public function isCli(): bool { return PHP_SAPI == 'cli'; } @@ -917,7 +824,7 @@ class Request * @access public * @return bool */ - public function isCgi() + public function isCgi(): bool { return strpos(PHP_SAPI, 'cgi') === 0; } @@ -925,14 +832,14 @@ class Request /** * 获取当前请求的参数 * @access public - * @param mixed $name 变量名 - * @param mixed $default 默认值 - * @param string|array $filter 过滤方法 + * @param string|array $name 变量名 + * @param mixed $default 默认值 + * @param string|array $filter 过滤方法 * @return mixed */ public function param($name = '', $default = null, $filter = '') { - if (!$this->mergeParam) { + if (empty($this->mergeParam)) { $method = $this->method(true); // 自动获取请求变量 @@ -955,71 +862,124 @@ class Request $this->mergeParam = true; } - if (true === $name) { - // 获取包含文件上传信息的数组 - $file = $this->file(); - $data = is_array($file) ? array_merge($this->param, $file) : $this->param; - - return $this->input($data, '', $default, $filter); + if (is_array($name)) { + return $this->only($name, $this->param, $filter); } return $this->input($this->param, $name, $default, $filter); } + /** + * 获取包含文件在内的请求参数 + * @access public + * @param string|array $name 变量名 + * @param string|array $filter 过滤方法 + * @return mixed + */ + public function all($name = '', $filter = '') + { + $data = array_merge($this->param(), $this->file()); + + if (is_array($name)) { + $data = $this->only($name, $data, $filter); + } + + return $data; + } + /** * 设置路由变量 * @access public - * @param array $route 路由变量 + * @param Rule $rule 路由对象 * @return $this */ - public function setRouteVars(array $route) + public function setRule(Rule $rule) { - $this->route = array_merge($this->route, $route); + $this->rule = $rule; + return $this; + } + + /** + * 获取当前路由对象 + * @access public + * @return Rule|null + */ + public function rule() + { + return $this->rule; + } + + /** + * 设置路由变量 + * @access public + * @param array $route 路由变量 + * @return $this + */ + public function setRoute(array $route) + { + $this->route = array_merge($this->route, $route); + $this->mergeParam = false; return $this; } /** * 获取路由参数 * @access public - * @param string|false $name 变量名 - * @param mixed $default 默认值 - * @param string|array $filter 过滤方法 + * @param string|array $name 变量名 + * @param mixed $default 默认值 + * @param string|array $filter 过滤方法 * @return mixed */ public function route($name = '', $default = null, $filter = '') { + if (is_array($name)) { + return $this->only($name, $this->route, $filter); + } + return $this->input($this->route, $name, $default, $filter); } /** * 获取GET参数 * @access public - * @param string|false $name 变量名 - * @param mixed $default 默认值 - * @param string|array $filter 过滤方法 + * @param string|array $name 变量名 + * @param mixed $default 默认值 + * @param string|array $filter 过滤方法 * @return mixed */ public function get($name = '', $default = null, $filter = '') { - if (empty($this->get)) { - $this->get = $_GET; + if (is_array($name)) { + return $this->only($name, $this->get, $filter); } return $this->input($this->get, $name, $default, $filter); } + /** + * 获取中间件传递的参数 + * @access public + * @param mixed $name 变量名 + * @param mixed $default 默认值 + * @return mixed + */ + public function middleware($name, $default = null) + { + return $this->middleware[$name] ?? $default; + } + /** * 获取POST参数 * @access public - * @param string|false $name 变量名 - * @param mixed $default 默认值 - * @param string|array $filter 过滤方法 + * @param string|array $name 变量名 + * @param mixed $default 默认值 + * @param string|array $filter 过滤方法 * @return mixed */ public function post($name = '', $default = null, $filter = '') { - if (empty($this->post)) { - $this->post = !empty($_POST) ? $_POST : $this->getInputData($this->input); + if (is_array($name)) { + return $this->only($name, $this->post, $filter); } return $this->input($this->post, $name, $default, $filter); @@ -1028,38 +988,39 @@ class Request /** * 获取PUT参数 * @access public - * @param string|false $name 变量名 - * @param mixed $default 默认值 - * @param string|array $filter 过滤方法 + * @param string|array $name 变量名 + * @param mixed $default 默认值 + * @param string|array $filter 过滤方法 * @return mixed */ public function put($name = '', $default = null, $filter = '') { - if (is_null($this->put)) { - $this->put = $this->getInputData($this->input); + if (is_array($name)) { + return $this->only($name, $this->put, $filter); } return $this->input($this->put, $name, $default, $filter); } - protected function getInputData($content) + protected function getInputData($content): array { - if (false !== strpos($this->contentType(), 'json')) { - return (array) json_decode($content, true); - } elseif (strpos($content, '=')) { + $contentType = $this->contentType(); + if ('application/x-www-form-urlencoded' == $contentType) { parse_str($content, $data); return $data; + } elseif (false !== strpos($contentType, 'json')) { + return (array) json_decode($content, true); } return []; } /** - * 获取DELETE参数 + * 设置获取DELETE参数 * @access public - * @param string|false $name 变量名 - * @param mixed $default 默认值 - * @param string|array $filter 过滤方法 + * @param mixed $name 变量名 + * @param mixed $default 默认值 + * @param string|array $filter 过滤方法 * @return mixed */ public function delete($name = '', $default = null, $filter = '') @@ -1068,11 +1029,11 @@ class Request } /** - * 获取PATCH参数 + * 设置获取PATCH参数 * @access public - * @param string|false $name 变量名 - * @param mixed $default 默认值 - * @param string|array $filter 过滤方法 + * @param mixed $name 变量名 + * @param mixed $default 默认值 + * @param string|array $filter 过滤方法 * @return mixed */ public function patch($name = '', $default = null, $filter = '') @@ -1083,58 +1044,65 @@ class Request /** * 获取request变量 * @access public - * @param string|false $name 变量名 - * @param mixed $default 默认值 - * @param string|array $filter 过滤方法 + * @param string|array $name 数据名称 + * @param mixed $default 默认值 + * @param string|array $filter 过滤方法 * @return mixed */ public function request($name = '', $default = null, $filter = '') { - if (empty($this->request)) { - $this->request = $_REQUEST; + if (is_array($name)) { + return $this->only($name, $this->request, $filter); } return $this->input($this->request, $name, $default, $filter); } /** - * 获取session数据 + * 获取环境变量 * @access public - * @param string $name 数据名称 - * @param string $default 默认值 + * @param string $name 数据名称 + * @param string $default 默认值 * @return mixed */ - public function session($name = '', $default = null) + public function env(string $name = '', string $default = null) { - if (empty($this->session)) { - $this->session = Session::get(); + if (empty($name)) { + return $this->env->get(); + } else { + $name = strtoupper($name); } + return $this->env->get($name, $default); + } + + /** + * 获取session数据 + * @access public + * @param string $name 数据名称 + * @param string $default 默认值 + * @return mixed + */ + public function session(string $name = '', $default = null) + { if ('' === $name) { - return $this->session; + return $this->session->all(); } - - $data = $this->getData($this->session, $name); - - return is_null($data) ? $default : $data; + return $this->session->get($name, $default); } /** * 获取cookie参数 * @access public - * @param string $name 变量名 - * @param string $default 默认值 - * @param string|array $filter 过滤方法 + * @param mixed $name 数据名称 + * @param string $default 默认值 + * @param string|array $filter 过滤方法 * @return mixed */ - public function cookie($name = '', $default = null, $filter = '') + public function cookie(string $name = '', $default = null, $filter = '') { - if (empty($this->cookie)) { - $this->cookie = Cookie::get(); - } - if (!empty($name)) { - $data = Cookie::has($name) ? Cookie::get($name) : $default; + $data = $this->getData($this->cookie, $name, $default); } else { $data = $this->cookie; } @@ -1144,7 +1112,6 @@ class Request if (is_array($data)) { array_walk_recursive($data, [$this, 'filterValue'], $filter); - reset($data); } else { $this->filterValue($data, $name, $filter); } @@ -1155,11 +1122,11 @@ class Request /** * 获取server参数 * @access public - * @param string $name 数据名称 - * @param string $default 默认值 + * @param string $name 数据名称 + * @param string $default 默认值 * @return mixed */ - public function server($name = '', $default = null) + public function server(string $name = '', string $default = '') { if (empty($name)) { return $this->server; @@ -1167,25 +1134,22 @@ class Request $name = strtoupper($name); } - return isset($this->server[$name]) ? $this->server[$name] : $default; + return $this->server[$name] ?? $default; } /** * 获取上传的文件信息 * @access public - * @param string $name 名称 - * @return null|array|\think\File + * @param string $name 名称 + * @return null|array|UploadedFile */ - public function file($name = '') + public function file(string $name = '') { - if (empty($this->file)) { - $this->file = isset($_FILES) ? $_FILES : []; - } - $files = $this->file; if (!empty($files)) { + if (strpos($name, '.')) { - list($name, $sub) = explode('.', $name); + [$name, $sub] = explode('.', $name); } // 处理上传文件 @@ -1200,17 +1164,13 @@ class Request return $array[$name]; } } - - return; } - protected function dealUploadFile($files, $name) + protected function dealUploadFile(array $files, string $name): array { $array = []; foreach ($files as $key => $file) { - if ($file instanceof File) { - $array[$key] = $file; - } elseif (is_array($file['name'])) { + if (is_array($file['name'])) { $item = []; $keys = array_keys($file); $count = count($file['name']); @@ -1230,20 +1190,24 @@ class Request $temp[$_key] = $file[$_key][$i]; } - $item[] = (new File($temp['tmp_name']))->setUploadInfo($temp); + $item[] = new UploadedFile($temp['tmp_name'], $temp['name'], $temp['type'], $temp['error']); } $array[$key] = $item; } else { - if ($file['error'] > 0) { - if ($key == $name) { - $this->throwUploadFileError($file['error']); - } else { - continue; + if ($file instanceof File) { + $array[$key] = $file; + } else { + if ($file['error'] > 0) { + if ($key == $name) { + $this->throwUploadFileError($file['error']); + } else { + continue; + } } - } - $array[$key] = (new File($file['tmp_name']))->setUploadInfo($file); + $array[$key] = new UploadedFile($file['tmp_name'], $file['name'], $file['type'], $file['error']); + } } } @@ -1262,94 +1226,37 @@ class Request ]; $msg = $fileUploadErrors[$error]; - - throw new Exception($msg); + throw new Exception($msg, $error); } /** - * 获取环境变量 + * 设置或者获取当前的Header * @access public - * @param string $name 数据名称 - * @param string $default 默认值 - * @return mixed - */ - public function env($name = '', $default = null) - { - if (empty($name)) { - return $this->env; - } else { - $name = strtoupper($name); - } - - return isset($this->env[$name]) ? $this->env[$name] : $default; - } - - /** - * 获取当前的Header - * @access public - * @param string $name header名称 - * @param string $default 默认值 + * @param string $name header名称 + * @param string $default 默认值 * @return string|array */ - public function header($name = '', $default = null) + public function header(string $name = '', string $default = null) { - if (empty($this->header)) { - $header = []; - if (function_exists('apache_request_headers') && $result = apache_request_headers()) { - $header = $result; - } else { - $server = $this->server; - foreach ($server as $key => $val) { - if (0 === strpos($key, 'HTTP_')) { - $key = str_replace('_', '-', strtolower(substr($key, 5))); - $header[$key] = $val; - } - } - if (isset($server['CONTENT_TYPE'])) { - $header['content-type'] = $server['CONTENT_TYPE']; - } - if (isset($server['CONTENT_LENGTH'])) { - $header['content-length'] = $server['CONTENT_LENGTH']; - } - } - $this->header = array_change_key_case($header); - } - if ('' === $name) { return $this->header; } $name = str_replace('_', '-', strtolower($name)); - return isset($this->header[$name]) ? $this->header[$name] : $default; - } - - /** - * 递归重置数组指针 - * @access public - * @param array $data 数据源 - * @return void - */ - public function arrayReset(array &$data) - { - foreach ($data as &$value) { - if (is_array($value)) { - $this->arrayReset($value); - } - } - reset($data); + return $this->header[$name] ?? $default; } /** * 获取变量 支持过滤和默认值 * @access public - * @param array $data 数据源 - * @param string|false $name 字段名 - * @param mixed $default 默认值 - * @param string|array $filter 过滤函数 + * @param array $data 数据源 + * @param string|false $name 字段名 + * @param mixed $default 默认值 + * @param string|array $filter 过滤函数 * @return mixed */ - public function input($data = [], $name = '', $default = null, $filter = '') + public function input(array $data = [], $name = '', $default = null, $filter = '') { if (false === $name) { // 获取原始数据 @@ -1360,7 +1267,7 @@ class Request if ('' != $name) { // 解析name if (strpos($name, '/')) { - list($name, $type) = explode('/', $name); + [$name, $type] = explode('/', $name); } $data = $this->getData($data, $name); @@ -1374,18 +1281,7 @@ class Request } } - // 解析过滤器 - $filter = $this->getFilter($filter, $default); - - if (is_array($data)) { - array_walk_recursive($data, [$this, 'filterValue'], $filter); - if (version_compare(PHP_VERSION, '7.1.0', '<')) { - // 恢复PHP版本低于 7.1 时 array_walk_recursive 中消耗的内部指针 - $this->arrayReset($data); - } - } else { - $this->filterValue($data, $name, $filter); - } + $data = $this->filterData($data, $filter, $name, $default); if (isset($type) && $data !== $default) { // 强制类型转换 @@ -1395,106 +1291,28 @@ class Request return $data; } - /** - * 获取数据 - * @access public - * @param array $data 数据源 - * @param string|false $name 字段名 - * @return mixed - */ - protected function getData(array $data, $name) + protected function filterData($data, $filter, $name, $default) { - foreach (explode('.', $name) as $val) { - if (isset($data[$val])) { - $data = $data[$val]; - } else { - return; - } + // 解析过滤器 + $filter = $this->getFilter($filter, $default); + + if (is_array($data)) { + array_walk_recursive($data, [$this, 'filterValue'], $filter); + } else { + $this->filterValue($data, $name, $filter); } return $data; } - /** - * 设置或获取当前的过滤规则 - * @access public - * @param mixed $filter 过滤规则 - * @return mixed - */ - public function filter($filter = null) - { - if (is_null($filter)) { - return $this->filter; - } - - $this->filter = $filter; - } - - protected function getFilter($filter, $default) - { - if (is_null($filter)) { - $filter = []; - } else { - $filter = $filter ?: $this->filter; - if (is_string($filter) && false === strpos($filter, '/')) { - $filter = explode(',', $filter); - } else { - $filter = (array) $filter; - } - } - - $filter[] = $default; - - return $filter; - } - - /** - * 递归过滤给定的值 - * @access public - * @param mixed $value 键值 - * @param mixed $key 键名 - * @param array $filters 过滤方法+默认值 - * @return mixed - */ - private function filterValue(&$value, $key, $filters) - { - $default = array_pop($filters); - - foreach ($filters as $filter) { - if (is_callable($filter)) { - // 调用函数或者方法过滤 - $value = call_user_func($filter, $value); - } elseif (is_scalar($value)) { - if (false !== strpos($filter, '/')) { - // 正则过滤 - if (!preg_match($filter, $value)) { - // 匹配不成功返回默认值 - $value = $default; - break; - } - } elseif (!empty($filter)) { - // filter函数不存在时, 则使用filter_var进行过滤 - // filter为非整形值时, 调用filter_id取得过滤id - $value = filter_var($value, is_int($filter) ? $filter : filter_id($filter)); - if (false === $value) { - $value = $default; - break; - } - } - } - } - - return $value; - } - /** * 强制类型转换 * @access public - * @param string $data + * @param mixed $data * @param string $type * @return mixed */ - private function typeCast(&$data, $type) + private function typeCast(&$data, string $type) { switch (strtolower($type)) { // 数组 @@ -1525,23 +1343,118 @@ class Request } /** - * 是否存在某个请求参数 + * 获取数据 * @access public - * @param string $name 变量名 - * @param string $type 变量类型 - * @param bool $checkEmpty 是否检测空值 + * @param array $data 数据源 + * @param string $name 字段名 + * @param mixed $default 默认值 * @return mixed */ - public function has($name, $type = 'param', $checkEmpty = false) + protected function getData(array $data, string $name, $default = null) { - if (!in_array($type, ['param', 'get', 'post', 'request', 'put', 'patch', 'file', 'session', 'cookie', 'env', 'header', 'route'])) { + foreach (explode('.', $name) as $val) { + if (isset($data[$val])) { + $data = $data[$val]; + } else { + return $default; + } + } + + return $data; + } + + /** + * 设置或获取当前的过滤规则 + * @access public + * @param mixed $filter 过滤规则 + * @return mixed + */ + public function filter($filter = null) + { + if (is_null($filter)) { + return $this->filter; + } + + $this->filter = $filter; + + return $this; + } + + protected function getFilter($filter, $default): array + { + if (is_null($filter)) { + $filter = []; + } else { + $filter = $filter ?: $this->filter; + if (is_string($filter) && false === strpos($filter, '/')) { + $filter = explode(',', $filter); + } else { + $filter = (array) $filter; + } + } + + $filter[] = $default; + + return $filter; + } + + /** + * 递归过滤给定的值 + * @access public + * @param mixed $value 键值 + * @param mixed $key 键名 + * @param array $filters 过滤方法+默认值 + * @return mixed + */ + public function filterValue(&$value, $key, $filters) + { + $default = array_pop($filters); + + foreach ($filters as $filter) { + if (is_callable($filter)) { + // 调用函数或者方法过滤 + $value = call_user_func($filter, $value); + } elseif (is_scalar($value)) { + if (is_string($filter) && false !== strpos($filter, '/')) { + // 正则过滤 + if (!preg_match($filter, $value)) { + // 匹配不成功返回默认值 + $value = $default; + break; + } + } elseif (!empty($filter)) { + // filter函数不存在时, 则使用filter_var进行过滤 + // filter为非整形值时, 调用filter_id取得过滤id + $value = filter_var($value, is_int($filter) ? $filter : filter_id($filter)); + if (false === $value) { + $value = $default; + break; + } + } + } + } + + return $value; + } + + /** + * 是否存在某个请求参数 + * @access public + * @param string $name 变量名 + * @param string $type 变量类型 + * @param bool $checkEmpty 是否检测空值 + * @return bool + */ + public function has(string $name, string $type = 'param', bool $checkEmpty = false): bool + { + if (!in_array($type, ['param', 'get', 'post', 'put', 'patch', 'route', 'delete', 'cookie', 'session', 'env', 'request', 'server', 'header', 'file'])) { return false; } - if (empty($this->$type)) { - $param = $this->$type(); - } else { - $param = $this->$type; + $param = empty($this->$type) ? $this->$type() : $this->$type; + + if (is_object($param)) { + return $param->has($name); } // 按.拆分成多维数组进行判断 @@ -1559,17 +1472,14 @@ class Request /** * 获取指定的参数 * @access public - * @param string|array $name 变量名 - * @param string $type 变量类型 - * @return mixed + * @param array $name 变量名 + * @param mixed $data 数据或者变量类型 + * @param string|array $filter 过滤方法 + * @return array */ - public function only($name, $type = 'param') + public function only(array $name, $data = 'param', $filter = ''): array { - $param = $this->$type(); - - if (is_string($name)) { - $name = explode(',', $name); - } + $data = is_array($data) ? $data : $this->$data(); $item = []; foreach ($name as $key => $val) { @@ -1577,15 +1487,14 @@ class Request if (is_int($key)) { $default = null; $key = $val; + if (!isset($data[$key])) { + continue; + } } else { $default = $val; } - if (isset($param[$key])) { - $item[$key] = $param[$key]; - } elseif (isset($default)) { - $item[$key] = $default; - } + $item[$key] = $this->filterData($data[$key] ?? $default, $filter, $key, $default); } return $item; @@ -1594,16 +1503,13 @@ class Request /** * 排除指定参数获取 * @access public - * @param string|array $name 变量名 - * @param string $type 变量类型 + * @param array $name 变量名 + * @param string $type 变量类型 * @return mixed */ - public function except($name, $type = 'param') + public function except(array $name, string $type = 'param'): array { $param = $this->$type(); - if (is_string($name)) { - $name = explode(',', $name); - } foreach ($name as $key) { if (isset($param[$key])) { @@ -1619,7 +1525,7 @@ class Request * @access public * @return bool */ - public function isSsl() + public function isSsl(): bool { if ($this->server('HTTPS') && ('1' == $this->server('HTTPS') || 'on' == strtolower($this->server('HTTPS')))) { return true; @@ -1629,7 +1535,7 @@ class Request return true; } elseif ('https' == $this->server('HTTP_X_FORWARDED_PROTO')) { return true; - } elseif ($this->config['https_agent_name'] && $this->server($this->config['https_agent_name'])) { + } elseif ($this->httpsAgentName && $this->server($this->httpsAgentName)) { return true; } @@ -1641,101 +1547,167 @@ class Request * @access public * @return bool */ - public function isJson() + public function isJson(): bool { - return false !== strpos($this->type(), 'json'); + $acceptType = $this->type(); + + return false !== strpos($acceptType, 'json'); } /** * 当前是否Ajax请求 * @access public - * @param bool $ajax true 获取原始ajax请求 + * @param bool $ajax true 获取原始ajax请求 * @return bool */ - public function isAjax($ajax = false) + public function isAjax(bool $ajax = false): bool { $value = $this->server('HTTP_X_REQUESTED_WITH'); - $result = 'xmlhttprequest' == strtolower($value) ? true : false; + $result = $value && 'xmlhttprequest' == strtolower($value) ? true : false; if (true === $ajax) { return $result; } - $result = $this->param($this->config['var_ajax']) ? true : $result; - $this->mergeParam = false; - return $result; + return $this->param($this->varAjax) ? true : $result; } /** * 当前是否Pjax请求 * @access public - * @param bool $pjax true 获取原始pjax请求 + * @param bool $pjax true 获取原始pjax请求 * @return bool */ - public function isPjax($pjax = false) + public function isPjax(bool $pjax = false): bool { - $result = !is_null($this->server('HTTP_X_PJAX')) ? true : false; + $result = !empty($this->server('HTTP_X_PJAX')) ? true : false; if (true === $pjax) { return $result; } - $result = $this->param($this->config['var_pjax']) ? true : $result; - $this->mergeParam = false; - return $result; + return $this->param($this->varPjax) ? true : $result; } /** * 获取客户端IP地址 * @access public - * @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字 - * @param boolean $adv 是否进行高级模式获取(有可能被伪装) - * @return mixed + * @return string */ - public function ip($type = 0, $adv = true) + public function ip(): string { - $type = $type ? 1 : 0; - static $ip = null; - - if (null !== $ip) { - return $ip[$type]; + if (!empty($this->realIP)) { + return $this->realIP; } - $httpAgentIp = $this->config['http_agent_ip']; + $this->realIP = $this->server('REMOTE_ADDR', ''); - if ($httpAgentIp && $this->server($httpAgentIp)) { - $ip = $this->server($httpAgentIp); - } elseif ($adv) { - if ($this->server('HTTP_X_FORWARDED_FOR')) { - $arr = explode(',', $this->server('HTTP_X_FORWARDED_FOR')); - $pos = array_search('unknown', $arr); - if (false !== $pos) { - unset($arr[$pos]); + // 如果指定了前端代理服务器IP以及其会发送的IP头 + // 则尝试获取前端代理服务器发送过来的真实IP + $proxyIp = $this->proxyServerIp; + $proxyIpHeader = $this->proxyServerIpHeader; + + if (count($proxyIp) > 0 && count($proxyIpHeader) > 0) { + // 从指定的HTTP头中依次尝试获取IP地址 + // 直到获取到一个合法的IP地址 + foreach ($proxyIpHeader as $header) { + $tempIP = $this->server($header); + + if (empty($tempIP)) { + continue; + } + + $tempIP = trim(explode(',', $tempIP)[0]); + + if (!$this->isValidIP($tempIP)) { + $tempIP = null; + } else { + break; + } + } + + // tempIP不为空,说明获取到了一个IP地址 + // 这时我们检查 REMOTE_ADDR 是不是指定的前端代理服务器之一 + // 如果是的话说明该 IP头 是由前端代理服务器设置的 + // 否则则是伪装的 + if (!empty($tempIP)) { + $realIPBin = $this->ip2bin($this->realIP); + + foreach ($proxyIp as $ip) { + $serverIPElements = explode('/', $ip); + $serverIP = $serverIPElements[0]; + $serverIPPrefix = $serverIPElements[1] ?? 128; + $serverIPBin = $this->ip2bin($serverIP); + + // IP类型不符 + if (strlen($realIPBin) !== strlen($serverIPBin)) { + continue; + } + + if (strncmp($realIPBin, $serverIPBin, (int) $serverIPPrefix) === 0) { + $this->realIP = $tempIP; + break; + } } - $ip = trim(current($arr)); - } elseif ($this->server('HTTP_CLIENT_IP')) { - $ip = $this->server('HTTP_CLIENT_IP'); - } elseif ($this->server('REMOTE_ADDR')) { - $ip = $this->server('REMOTE_ADDR'); } - } elseif ($this->server('REMOTE_ADDR')) { - $ip = $this->server('REMOTE_ADDR'); } - // IP地址类型 - $ip_mode = (strpos($ip, ':') === false) ? 'ipv4' : 'ipv6'; - - // IP地址合法验证 - if (filter_var($ip, FILTER_VALIDATE_IP) !== $ip) { - $ip = ('ipv4' === $ip_mode) ? '0.0.0.0' : '::'; + if (!$this->isValidIP($this->realIP)) { + $this->realIP = '0.0.0.0'; } - // 如果是ipv4地址,则直接使用ip2long返回int类型ip;如果是ipv6地址,暂时不支持,直接返回0 - $long_ip = ('ipv4' === $ip_mode) ? sprintf("%u", ip2long($ip)) : 0; + return $this->realIP; + } - $ip = [$ip, $long_ip]; + /** + * 检测是否是合法的IP地址 + * + * @param string $ip IP地址 + * @param string $type IP地址类型 (ipv4, ipv6) + * + * @return boolean + */ + public function isValidIP(string $ip, string $type = ''): bool + { + switch (strtolower($type)) { + case 'ipv4': + $flag = FILTER_FLAG_IPV4; + break; + case 'ipv6': + $flag = FILTER_FLAG_IPV6; + break; + default: + $flag = 0; + break; + } - return $ip[$type]; + return boolval(filter_var($ip, FILTER_VALIDATE_IP, $flag)); + } + + /** + * 将IP地址转换为二进制字符串 + * + * @param string $ip + * + * @return string + */ + public function ip2bin(string $ip): string + { + if ($this->isValidIP($ip, 'ipv6')) { + $IPHex = str_split(bin2hex(inet_pton($ip)), 4); + foreach ($IPHex as $key => $value) { + $IPHex[$key] = intval($value, 16); + } + $IPBin = vsprintf('%016b%016b%016b%016b%016b%016b%016b%016b', $IPHex); + } else { + $IPHex = str_split(bin2hex(inet_pton($ip)), 2); + foreach ($IPHex as $key => $value) { + $IPHex[$key] = intval($value, 16); + } + $IPBin = vsprintf('%08b%08b%08b%08b', $IPHex); + } + + return $IPBin; } /** @@ -1743,7 +1715,7 @@ class Request * @access public * @return bool */ - public function isMobile() + public function isMobile(): bool { if ($this->server('HTTP_VIA') && stristr($this->server('HTTP_VIA'), "wap")) { return true; @@ -1763,7 +1735,7 @@ class Request * @access public * @return string */ - public function scheme() + public function scheme(): string { return $this->isSsl() ? 'https' : 'http'; } @@ -1773,9 +1745,9 @@ class Request * @access public * @return string */ - public function query() + public function query(): string { - return $this->server('QUERY_STRING'); + return $this->server('QUERY_STRING', ''); } /** @@ -1784,7 +1756,7 @@ class Request * @param string $host 主机名(含端口) * @return $this */ - public function setHost($host) + public function setHost(string $host) { $this->host = $host; @@ -1797,23 +1769,25 @@ class Request * @param bool $strict true 仅仅获取HOST * @return string */ - public function host($strict = false) + public function host(bool $strict = false): string { - if (!$this->host) { - $this->host = $this->server('HTTP_X_REAL_HOST') ?: $this->server('HTTP_HOST'); + if ($this->host) { + $host = $this->host; + } else { + $host = strval($this->server('HTTP_X_FORWARDED_HOST') ?: $this->server('HTTP_HOST')); } - return true === $strict && strpos($this->host, ':') ? strstr($this->host, ':', true) : $this->host; + return true === $strict && strpos($host, ':') ? strstr($host, ':', true) : $host; } /** * 当前请求URL地址中的port参数 * @access public - * @return integer + * @return int */ - public function port() + public function port(): int { - return $this->server('SERVER_PORT'); + return (int) ($this->server('HTTP_X_FORWARDED_PORT') ?: $this->server('SERVER_PORT', '')); } /** @@ -1821,19 +1795,19 @@ class Request * @access public * @return string */ - public function protocol() + public function protocol(): string { - return $this->server('SERVER_PROTOCOL'); + return $this->server('SERVER_PROTOCOL', ''); } /** * 当前请求 REMOTE_PORT * @access public - * @return integer + * @return int */ - public function remotePort() + public function remotePort(): int { - return $this->server('REMOTE_PORT'); + return (int) $this->server('REMOTE_PORT', ''); } /** @@ -1841,13 +1815,13 @@ class Request * @access public * @return string */ - public function contentType() + public function contentType(): string { - $contentType = $this->server('CONTENT_TYPE'); + $contentType = $this->header('Content-Type'); if ($contentType) { if (strpos($contentType, ';')) { - list($type) = explode(';', $contentType); + [$type] = explode(';', $contentType); } else { $type = $contentType; } @@ -1857,42 +1831,12 @@ class Request return ''; } - /** - * 获取当前请求的路由信息 - * @access public - * @param array $route 路由名称 - * @return array - */ - public function routeInfo(array $route = []) - { - if (!empty($route)) { - $this->routeInfo = $route; - } - - return $this->routeInfo; - } - - /** - * 设置或者获取当前请求的调度信息 - * @access public - * @param \think\route\Dispatch $dispatch 调度信息 - * @return \think\route\Dispatch - */ - public function dispatch($dispatch = null) - { - if (!is_null($dispatch)) { - $this->dispatch = $dispatch; - } - - return $this->dispatch; - } - /** * 获取当前请求的安全Key * @access public * @return string */ - public function secureKey() + public function secureKey(): string { if (is_null($this->secureKey)) { $this->secureKey = uniqid('', true); @@ -1901,25 +1845,13 @@ class Request return $this->secureKey; } - /** - * 设置当前的模块名 - * @access public - * @param string $module 模块名 - * @return $this - */ - public function setModule($module) - { - $this->module = $module; - return $this; - } - /** * 设置当前的控制器名 * @access public * @param string $controller 控制器名 * @return $this */ - public function setController($controller) + public function setController(string $controller) { $this->controller = $controller; return $this; @@ -1931,29 +1863,19 @@ class Request * @param string $action 操作名 * @return $this */ - public function setAction($action) + public function setAction(string $action) { $this->action = $action; return $this; } - /** - * 获取当前的模块名 - * @access public - * @return string - */ - public function module() - { - return $this->module ?: ''; - } - /** * 获取当前的控制器名 * @access public * @param bool $convert 转换为小写 * @return string */ - public function controller($convert = false) + public function controller(bool $convert = false): string { $name = $this->controller ?: ''; return $convert ? strtolower($name) : $name; @@ -1962,35 +1884,13 @@ class Request /** * 获取当前的操作名 * @access public - * @param bool $convert 转换为驼峰 + * @param bool $convert 转换为小写 * @return string */ - public function action($convert = false) + public function action(bool $convert = false): string { $name = $this->action ?: ''; - return $convert ? $name : strtolower($name); - } - - /** - * 设置当前的语言 - * @access public - * @param string $lang 语言名 - * @return $this - */ - public function setLangset($lang) - { - $this->langset = $lang; - return $this; - } - - /** - * 获取当前的语言 - * @access public - * @return string - */ - public function langset() - { - return $this->langset ?: ''; + return $convert ? strtolower($name) : $name; } /** @@ -1998,7 +1898,7 @@ class Request * @access public * @return string */ - public function getContent() + public function getContent(): string { if (is_null($this->content)) { $this->content = $this->input; @@ -2012,7 +1912,7 @@ class Request * @access public * @return string */ - public function getInput() + public function getInput(): string { return $this->input; } @@ -2024,96 +1924,67 @@ class Request * @param mixed $type 令牌生成方法 * @return string */ - public function token($name = '__token__', $type = null) + public function buildToken(string $name = '__token__', $type = 'md5'): string { $type = is_callable($type) ? $type : 'md5'; $token = call_user_func($type, $this->server('REQUEST_TIME_FLOAT')); - if ($this->isAjax()) { - header($name . ': ' . $token); - } - - facade\Session::set($name, $token); + $this->session->set($name, $token); return $token; } /** - * 设置当前地址的请求缓存 + * 检查请求令牌 * @access public - * @param string $key 缓存标识,支持变量规则 ,例如 item/:name/:id - * @param mixed $expire 缓存有效期 - * @param array $except 缓存排除 - * @param string $tag 缓存标签 - * @return mixed + * @param string $token 令牌名称 + * @param array $data 表单数据 + * @return bool */ - public function cache($key, $expire = null, $except = [], $tag = null) + public function checkToken(string $token = '__token__', array $data = []): bool { - if (!is_array($except)) { - $tag = $except; - $except = []; + if (in_array($this->method(), ['GET', 'HEAD', 'OPTIONS'], true)) { + return true; } - if (false === $key || !$this->isGet() || $this->isCheckCache || false === $expire) { - // 关闭当前缓存 - return; + if (!$this->session->has($token)) { + // 令牌数据无效 + return false; } - // 标记请求缓存检查 - $this->isCheckCache = true; - - foreach ($except as $rule) { - if (0 === stripos($this->url(), $rule)) { - return; - } + // Header验证 + if ($this->header('X-CSRF-TOKEN') && $this->session->get($token) === $this->header('X-CSRF-TOKEN')) { + // 防止重复提交 + $this->session->delete($token); // 验证完成销毁session + return true; } - if ($key instanceof \Closure) { - $key = call_user_func_array($key, [$this]); - } elseif (true === $key) { - // 自动缓存功能 - $key = '__URL__'; - } elseif (strpos($key, '|')) { - list($key, $fun) = explode('|', $key); + if (empty($data)) { + $data = $this->post(); } - // 特殊规则替换 - if (false !== strpos($key, '__')) { - $key = str_replace(['__MODULE__', '__CONTROLLER__', '__ACTION__', '__URL__'], [$this->module, $this->controller, $this->action, md5($this->url(true))], $key); + // 令牌验证 + if (isset($data[$token]) && $this->session->get($token) === $data[$token]) { + // 防止重复提交 + $this->session->delete($token); // 验证完成销毁session + return true; } - if (false !== strpos($key, ':')) { - $param = $this->param(); - foreach ($param as $item => $val) { - if (is_string($val) && false !== strpos($key, ':' . $item)) { - $key = str_replace(':' . $item, $val, $key); - } - } - } elseif (strpos($key, ']')) { - if ('[' . $this->ext() . ']' == $key) { - // 缓存某个后缀的请求 - $key = md5($this->url()); - } else { - return; - } - } - - if (isset($fun)) { - $key = $fun($key); - } - - $this->cache = [$key, $expire, $tag]; - return $this->cache; + // 开启TOKEN重置 + $this->session->delete($token); + return false; } /** - * 读取请求缓存设置 + * 设置在中间件传递的数据 * @access public - * @return array + * @param array $middleware 数据 + * @return $this */ - public function getCache() + public function withMiddleware(array $middleware) { - return $this->cache; + $this->middleware = array_merge($this->middleware, $middleware); + return $this; } /** @@ -2140,34 +2011,10 @@ class Request return $this; } - /** - * 设置php://input数据 - * @access public - * @param string $input RAW数据 - * @return $this - */ - public function withInput($input) - { - $this->input = $input; - return $this; - } - - /** - * 设置文件上传数据 - * @access public - * @param array $files 上传信息 - * @return $this - */ - public function withFiles(array $files) - { - $this->file = $files; - return $this; - } - /** * 设置COOKIE数据 * @access public - * @param array $cookie 数据 + * @param array $cookie 数据 * @return $this */ public function withCookie(array $cookie) @@ -2176,6 +2023,18 @@ class Request return $this; } + /** + * 设置SESSION数据 + * @access public + * @param Session $session 数据 + * @return $this + */ + public function withSession(Session $session) + { + $this->session = $session; + return $this; + } + /** * 设置SERVER数据 * @access public @@ -2203,15 +2062,46 @@ class Request /** * 设置ENV数据 * @access public - * @param array $env 数据 + * @param Env $env 数据 * @return $this */ - public function withEnv(array $env) + public function withEnv(Env $env) { $this->env = $env; return $this; } + /** + * 设置php://input数据 + * @access public + * @param string $input RAW数据 + * @return $this + */ + public function withInput(string $input) + { + $this->input = $input; + if (!empty($input)) { + $inputData = $this->getInputData($input); + if (!empty($inputData)) { + $this->post = $inputData; + $this->put = $inputData; + } + } + return $this; + } + + /** + * 设置文件上传数据 + * @access public + * @param array $files 上传信息 + * @return $this + */ + public function withFiles(array $files) + { + $this->file = $files; + return $this; + } + /** * 设置ROUTE变量 * @access public @@ -2225,43 +2115,53 @@ class Request } /** - * 设置请求数据 + * 设置中间传递数据 * @access public * @param string $name 参数名 * @param mixed $value 值 */ - public function __set($name, $value) + public function __set(string $name, $value) { - return $this->param[$name] = $value; + $this->middleware[$name] = $value; } /** - * 获取请求数据的值 + * 获取中间传递数据的值 * @access public - * @param string $name 参数名 + * @param string $name 名称 * @return mixed */ - public function __get($name) + public function __get(string $name) { - return $this->param($name); + return $this->middleware($name); } /** - * 检测请求数据的值 + * 检测中间传递数据的值 * @access public * @param string $name 名称 * @return boolean */ - public function __isset($name) + public function __isset(string $name): bool { - return isset($this->param[$name]); + return isset($this->middleware[$name]); } - public function __debugInfo() + // ArrayAccess + public function offsetExists($name): bool { - $data = get_object_vars($this); - unset($data['dispatch'], $data['config']); - - return $data; + return $this->has($name); } + + public function offsetGet($name) + { + return $this->param($name); + } + + public function offsetSet($name, $value) + {} + + public function offsetUnset($name) + {} + } diff --git a/thinkphp/library/think/Response.php b/vendor/topthink/framework/src/think/Response.php old mode 100755 new mode 100644 similarity index 64% rename from thinkphp/library/think/Response.php rename to vendor/topthink/framework/src/think/Response.php index 5fa5402ab..a8a61ffb2 --- a/thinkphp/library/think/Response.php +++ b/vendor/topthink/framework/src/think/Response.php @@ -2,18 +2,21 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think; -use think\response\Redirect as RedirectResponse; - -class Response +/** + * 响应输出基础类 + * @package think + */ +abstract class Response { /** * 原始数据 @@ -21,12 +24,6 @@ class Response */ protected $data; - /** - * 应用对象实例 - * @var App - */ - protected $app; - /** * 当前contentType * @var string @@ -70,47 +67,56 @@ class Response protected $content = null; /** - * 架构函数 - * @access public - * @param mixed $data 输出数据 - * @param int $code - * @param array $header - * @param array $options 输出参数 + * Cookie对象 + * @var Cookie */ - public function __construct($data = '', $code = 200, array $header = [], $options = []) + protected $cookie; + + /** + * Session对象 + * @var Session + */ + protected $session; + + /** + * 初始化 + * @access protected + * @param mixed $data 输出数据 + * @param int $code 状态码 + */ + protected function init($data = '', int $code = 200) { $this->data($data); - - if (!empty($options)) { - $this->options = array_merge($this->options, $options); - } + $this->code = $code; $this->contentType($this->contentType, $this->charset); - - $this->code = $code; - $this->app = Container::get('app'); - $this->header = array_merge($this->header, $header); } /** * 创建Response对象 * @access public - * @param mixed $data 输出数据 - * @param string $type 输出类型 - * @param int $code - * @param array $header - * @param array $options 输出参数 + * @param mixed $data 输出数据 + * @param string $type 输出类型 + * @param int $code 状态码 * @return Response */ - public static function create($data = '', $type = '', $code = 200, array $header = [], $options = []) + public static function create($data = '', string $type = 'html', int $code = 200): Response { $class = false !== strpos($type, '\\') ? $type : '\\think\\response\\' . ucfirst(strtolower($type)); - if (class_exists($class)) { - return new $class($data, $code, $header, $options); - } + return Container::getInstance()->invokeClass($class, [$data, $code]); + } - return new static($data, $code, $header, $options); + /** + * 设置Session对象 + * @access public + * @param Session $session Session对象 + * @return $this + */ + public function setSession(Session $session) + { + $this->session = $session; + return $this; } /** @@ -119,30 +125,11 @@ class Response * @return void * @throws \InvalidArgumentException */ - public function send() + public function send(): void { - // 监听response_send - $this->app['hook']->listen('response_send', $this); - // 处理输出数据 $data = $this->getContent(); - // Trace调试注入 - if ('cli' != PHP_SAPI && $this->app['env']->get('app_trace', $this->app->config('app.app_trace'))) { - $this->app['debug']->inject($this, $data); - } - - if (200 == $this->code && $this->allowCache) { - $cache = $this->app['request']->getCache(); - if ($cache) { - $this->header['Cache-Control'] = 'max-age=' . $cache[1] . ',must-revalidate'; - $this->header['Last-Modified'] = gmdate('D, d M Y H:i:s') . ' GMT'; - $this->header['Expires'] = gmdate('D, d M Y H:i:s', $_SERVER['REQUEST_TIME'] + $cache[1]) . ' GMT'; - - $this->app['cache']->tag($cache[2])->set($cache[0], [$data, $this->header], $cache[1]); - } - } - if (!headers_sent() && !empty($this->header)) { // 发送状态码 http_response_code($this->code); @@ -151,6 +138,9 @@ class Response header($name . (!is_null($val) ? ':' . $val : '')); } } + if ($this->cookie) { + $this->cookie->save(); + } $this->sendData($data); @@ -158,14 +148,6 @@ class Response // 提高页面响应 fastcgi_finish_request(); } - - // 监听response_end - $this->app['hook']->listen('response_end', $this); - - // 清空当次请求有效的数据 - if (!($this instanceof RedirectResponse)) { - $this->app['session']->flush(); - } } /** @@ -185,7 +167,7 @@ class Response * @param string $data 要处理的数据 * @return void */ - protected function sendData($data) + protected function sendData(string $data): void { echo $data; } @@ -196,7 +178,7 @@ class Response * @param mixed $options 输出参数 * @return $this */ - public function options($options = []) + public function options(array $options = []) { $this->options = array_merge($this->options, $options); @@ -222,7 +204,7 @@ class Response * @param bool $cache 允许请求缓存 * @return $this */ - public function allowCache($cache) + public function allowCache(bool $cache) { $this->allowCache = $cache; @@ -230,19 +212,39 @@ class Response } /** - * 设置响应头 + * 是否允许请求缓存 * @access public - * @param string|array $name 参数名 - * @param string $value 参数值 + * @return bool + */ + public function isAllowCache() + { + return $this->allowCache; + } + + /** + * 设置Cookie + * @access public + * @param string $name cookie名称 + * @param string $value cookie值 + * @param mixed $option 可选参数 * @return $this */ - public function header($name, $value = null) + public function cookie(string $name, string $value, $option = null) { - if (is_array($name)) { - $this->header = array_merge($this->header, $name); - } else { - $this->header[$name] = $value; - } + $this->cookie->set($name, $value, $option); + + return $this; + } + + /** + * 设置响应头 + * @access public + * @param array $header 参数 + * @return $this + */ + public function header(array $header = []) + { + $this->header = array_merge($this->header, $header); return $this; } @@ -274,7 +276,7 @@ class Response * @param integer $code 状态码 * @return $this */ - public function code($code) + public function code(int $code) { $this->code = $code; @@ -287,7 +289,7 @@ class Response * @param string $time * @return $this */ - public function lastModified($time) + public function lastModified(string $time) { $this->header['Last-Modified'] = $time; @@ -300,7 +302,7 @@ class Response * @param string $time * @return $this */ - public function expires($time) + public function expires(string $time) { $this->header['Expires'] = $time; @@ -313,7 +315,7 @@ class Response * @param string $eTag * @return $this */ - public function eTag($eTag) + public function eTag(string $eTag) { $this->header['ETag'] = $eTag; @@ -323,29 +325,16 @@ class Response /** * 页面缓存控制 * @access public - * @param string $cache 缓存设置 + * @param string $cache 状态码 * @return $this */ - public function cacheControl($cache) + public function cacheControl(string $cache) { $this->header['Cache-control'] = $cache; return $this; } - /** - * 设置页面不做任何缓存 - * @access public - * @return $this - */ - public function noCache() - { - $this->header['Cache-Control'] = 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0'; - $this->header['Pragma'] = 'no-cache'; - - return $this; - } - /** * 页面输出类型 * @access public @@ -353,7 +342,7 @@ class Response * @param string $charset 输出编码 * @return $this */ - public function contentType($contentType, $charset = 'utf-8') + public function contentType(string $contentType, string $charset = 'utf-8') { $this->header['Content-Type'] = $contentType . '; charset=' . $charset; @@ -366,10 +355,10 @@ class Response * @param string $name 头部名称 * @return mixed */ - public function getHeader($name = '') + public function getHeader(string $name = '') { if (!empty($name)) { - return isset($this->header[$name]) ? $this->header[$name] : null; + return $this->header[$name] ?? null; } return $this->header; @@ -388,9 +377,9 @@ class Response /** * 获取输出数据 * @access public - * @return mixed + * @return string */ - public function getContent() + public function getContent(): string { if (null == $this->content) { $content = $this->output($this->data); @@ -414,16 +403,8 @@ class Response * @access public * @return integer */ - public function getCode() + public function getCode(): int { return $this->code; } - - public function __debugInfo() - { - $data = get_object_vars($this); - unset($data['app']); - - return $data; - } } diff --git a/vendor/topthink/framework/src/think/Route.php b/vendor/topthink/framework/src/think/Route.php new file mode 100644 index 000000000..a3acf85b5 --- /dev/null +++ b/vendor/topthink/framework/src/think/Route.php @@ -0,0 +1,926 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think; + +use Closure; +use think\exception\RouteNotFoundException; +use think\route\Dispatch; +use think\route\dispatch\Callback; +use think\route\dispatch\Url as UrlDispatch; +use think\route\Domain; +use think\route\Resource; +use think\route\Rule; +use think\route\RuleGroup; +use think\route\RuleItem; +use think\route\RuleName; +use think\route\Url as UrlBuild; + +/** + * 路由管理类 + * @package think + */ +class Route +{ + /** + * REST定义 + * @var array + */ + protected $rest = [ + 'index' => ['get', '', 'index'], + 'create' => ['get', '/create', 'create'], + 'edit' => ['get', '//edit', 'edit'], + 'read' => ['get', '/', 'read'], + 'save' => ['post', '', 'save'], + 'update' => ['put', '/', 'update'], + 'delete' => ['delete', '/', 'delete'], + ]; + + /** + * 配置参数 + * @var array + */ + protected $config = [ + // pathinfo分隔符 + 'pathinfo_depr' => '/', + // 是否开启路由延迟解析 + 'url_lazy_route' => false, + // 是否强制使用路由 + 'url_route_must' => false, + // 合并路由规则 + 'route_rule_merge' => false, + // 路由是否完全匹配 + 'route_complete_match' => false, + // 去除斜杠 + 'remove_slash' => false, + // 使用注解路由 + 'route_annotation' => false, + // 默认的路由变量规则 + 'default_route_pattern' => '[\w\.]+', + // URL伪静态后缀 + 'url_html_suffix' => 'html', + // 访问控制器层名称 + 'controller_layer' => 'controller', + // 空控制器名 + 'empty_controller' => 'Error', + // 是否使用控制器后缀 + 'controller_suffix' => false, + // 默认控制器名 + 'default_controller' => 'Index', + // 默认操作名 + 'default_action' => 'index', + // 操作方法后缀 + 'action_suffix' => '', + // 非路由变量是否使用普通参数方式(用于URL生成) + 'url_common_param' => true, + ]; + + /** + * 当前应用 + * @var App + */ + protected $app; + + /** + * 请求对象 + * @var Request + */ + protected $request; + + /** + * @var RuleName + */ + protected $ruleName; + + /** + * 当前HOST + * @var string + */ + protected $host; + + /** + * 当前分组对象 + * @var RuleGroup + */ + protected $group; + + /** + * 路由绑定 + * @var array + */ + protected $bind = []; + + /** + * 域名对象 + * @var Domain[] + */ + protected $domains = []; + + /** + * 跨域路由规则 + * @var RuleGroup + */ + protected $cross; + + /** + * 路由是否延迟解析 + * @var bool + */ + protected $lazy = false; + + /** + * 路由是否测试模式 + * @var bool + */ + protected $isTest = false; + + /** + * (分组)路由规则是否合并解析 + * @var bool + */ + protected $mergeRuleRegex = false; + + /** + * 是否去除URL最后的斜线 + * @var bool + */ + protected $removeSlash = false; + + public function __construct(App $app) + { + $this->app = $app; + $this->ruleName = new RuleName(); + $this->setDefaultDomain(); + + if (is_file($this->app->getRuntimePath() . 'route.php')) { + // 读取路由映射文件 + $this->import(include $this->app->getRuntimePath() . 'route.php'); + } + + $this->config = array_merge($this->config, $this->app->config->get('route')); + } + + protected function init() + { + if (!empty($this->config['middleware'])) { + $this->app->middleware->import($this->config['middleware'], 'route'); + } + + $this->lazy($this->config['url_lazy_route']); + $this->mergeRuleRegex = $this->config['route_rule_merge']; + $this->removeSlash = $this->config['remove_slash']; + + $this->group->removeSlash($this->removeSlash); + } + + public function config(string $name = null) + { + if (is_null($name)) { + return $this->config; + } + + return $this->config[$name] ?? null; + } + + /** + * 设置路由域名及分组(包括资源路由)是否延迟解析 + * @access public + * @param bool $lazy 路由是否延迟解析 + * @return $this + */ + public function lazy(bool $lazy = true) + { + $this->lazy = $lazy; + return $this; + } + + /** + * 设置路由为测试模式 + * @access public + * @param bool $test 路由是否测试模式 + * @return void + */ + public function setTestMode(bool $test): void + { + $this->isTest = $test; + } + + /** + * 检查路由是否为测试模式 + * @access public + * @return bool + */ + public function isTest(): bool + { + return $this->isTest; + } + + /** + * 设置路由域名及分组(包括资源路由)是否合并解析 + * @access public + * @param bool $merge 路由是否合并解析 + * @return $this + */ + public function mergeRuleRegex(bool $merge = true) + { + $this->mergeRuleRegex = $merge; + $this->group->mergeRuleRegex($merge); + + return $this; + } + + /** + * 初始化默认域名 + * @access protected + * @return void + */ + protected function setDefaultDomain(): void + { + // 注册默认域名 + $domain = new Domain($this); + + $this->domains['-'] = $domain; + + // 默认分组 + $this->group = $domain; + } + + /** + * 设置当前分组 + * @access public + * @param RuleGroup $group 域名 + * @return void + */ + public function setGroup(RuleGroup $group): void + { + $this->group = $group; + } + + /** + * 获取指定标识的路由分组 不指定则获取当前分组 + * @access public + * @param string $name 分组标识 + * @return RuleGroup + */ + public function getGroup(string $name = null) + { + return $name ? $this->ruleName->getGroup($name) : $this->group; + } + + /** + * 注册变量规则 + * @access public + * @param array $pattern 变量规则 + * @return $this + */ + public function pattern(array $pattern) + { + $this->group->pattern($pattern); + + return $this; + } + + /** + * 注册路由参数 + * @access public + * @param array $option 参数 + * @return $this + */ + public function option(array $option) + { + $this->group->option($option); + + return $this; + } + + /** + * 注册域名路由 + * @access public + * @param string|array $name 子域名 + * @param mixed $rule 路由规则 + * @return Domain + */ + public function domain($name, $rule = null): Domain + { + // 支持多个域名使用相同路由规则 + $domainName = is_array($name) ? array_shift($name) : $name; + + if (!isset($this->domains[$domainName])) { + $domain = (new Domain($this, $domainName, $rule)) + ->lazy($this->lazy) + ->removeSlash($this->removeSlash) + ->mergeRuleRegex($this->mergeRuleRegex); + + $this->domains[$domainName] = $domain; + } else { + $domain = $this->domains[$domainName]; + $domain->parseGroupRule($rule); + } + + if (is_array($name) && !empty($name)) { + foreach ($name as $item) { + $this->domains[$item] = $domainName; + } + } + + // 返回域名对象 + return $domain; + } + + /** + * 获取域名 + * @access public + * @return array + */ + public function getDomains(): array + { + return $this->domains; + } + + /** + * 获取RuleName对象 + * @access public + * @return RuleName + */ + public function getRuleName(): RuleName + { + return $this->ruleName; + } + + /** + * 设置路由绑定 + * @access public + * @param string $bind 绑定信息 + * @param string $domain 域名 + * @return $this + */ + public function bind(string $bind, string $domain = null) + { + $domain = is_null($domain) ? '-' : $domain; + + $this->bind[$domain] = $bind; + + return $this; + } + + /** + * 读取路由绑定信息 + * @access public + * @return array + */ + public function getBind(): array + { + return $this->bind; + } + + /** + * 读取路由绑定 + * @access public + * @param string $domain 域名 + * @return string|null + */ + public function getDomainBind(string $domain = null) + { + if (is_null($domain)) { + $domain = $this->host; + } elseif (false === strpos($domain, '.') && $this->request) { + $domain .= '.' . $this->request->rootDomain(); + } + + if ($this->request) { + $subDomain = $this->request->subDomain(); + + if (strpos($subDomain, '.')) { + $name = '*' . strstr($subDomain, '.'); + } + } + + if (isset($this->bind[$domain])) { + $result = $this->bind[$domain]; + } elseif (isset($name) && isset($this->bind[$name])) { + $result = $this->bind[$name]; + } elseif (!empty($subDomain) && isset($this->bind['*'])) { + $result = $this->bind['*']; + } else { + $result = null; + } + + return $result; + } + + /** + * 读取路由标识 + * @access public + * @param string $name 路由标识 + * @param string $domain 域名 + * @param string $method 请求类型 + * @return array + */ + public function getName(string $name = null, string $domain = null, string $method = '*'): array + { + return $this->ruleName->getName($name, $domain, $method); + } + + /** + * 批量导入路由标识 + * @access public + * @param array $name 路由标识 + * @return void + */ + public function import(array $name): void + { + $this->ruleName->import($name); + } + + /** + * 注册路由标识 + * @access public + * @param string $name 路由标识 + * @param RuleItem $ruleItem 路由规则 + * @param bool $first 是否优先 + * @return void + */ + public function setName(string $name, RuleItem $ruleItem, bool $first = false): void + { + $this->ruleName->setName($name, $ruleItem, $first); + } + + /** + * 保存路由规则 + * @access public + * @param string $rule 路由规则 + * @param RuleItem $ruleItem RuleItem对象 + * @return void + */ + public function setRule(string $rule, RuleItem $ruleItem = null): void + { + $this->ruleName->setRule($rule, $ruleItem); + } + + /** + * 读取路由 + * @access public + * @param string $rule 路由规则 + * @return RuleItem[] + */ + public function getRule(string $rule): array + { + return $this->ruleName->getRule($rule); + } + + /** + * 读取路由列表 + * @access public + * @return array + */ + public function getRuleList(): array + { + return $this->ruleName->getRuleList(); + } + + /** + * 清空路由规则 + * @access public + * @return void + */ + public function clear(): void + { + $this->ruleName->clear(); + + if ($this->group) { + $this->group->clear(); + } + } + + /** + * 注册路由规则 + * @access public + * @param string $rule 路由规则 + * @param mixed $route 路由地址 + * @param string $method 请求类型 + * @return RuleItem + */ + public function rule(string $rule, $route = null, string $method = '*'): RuleItem + { + if ($route instanceof Response) { + // 兼容之前的路由到响应对象,感觉不需要,使用场景很少,闭包就能实现 + $route = function () use ($route) { + return $route; + }; + } + return $this->group->addRule($rule, $route, $method); + } + + /** + * 设置跨域有效路由规则 + * @access public + * @param Rule $rule 路由规则 + * @param string $method 请求类型 + * @return $this + */ + public function setCrossDomainRule(Rule $rule, string $method = '*') + { + if (!isset($this->cross)) { + $this->cross = (new RuleGroup($this))->mergeRuleRegex($this->mergeRuleRegex); + } + + $this->cross->addRuleItem($rule, $method); + + return $this; + } + + /** + * 注册路由分组 + * @access public + * @param string|\Closure $name 分组名称或者参数 + * @param mixed $route 分组路由 + * @return RuleGroup + */ + public function group($name, $route = null): RuleGroup + { + if ($name instanceof Closure) { + $route = $name; + $name = ''; + } + + return (new RuleGroup($this, $this->group, $name, $route)) + ->lazy($this->lazy) + ->removeSlash($this->removeSlash) + ->mergeRuleRegex($this->mergeRuleRegex); + } + + /** + * 注册路由 + * @access public + * @param string $rule 路由规则 + * @param mixed $route 路由地址 + * @return RuleItem + */ + public function any(string $rule, $route): RuleItem + { + return $this->rule($rule, $route, '*'); + } + + /** + * 注册GET路由 + * @access public + * @param string $rule 路由规则 + * @param mixed $route 路由地址 + * @return RuleItem + */ + public function get(string $rule, $route): RuleItem + { + return $this->rule($rule, $route, 'GET'); + } + + /** + * 注册POST路由 + * @access public + * @param string $rule 路由规则 + * @param mixed $route 路由地址 + * @return RuleItem + */ + public function post(string $rule, $route): RuleItem + { + return $this->rule($rule, $route, 'POST'); + } + + /** + * 注册PUT路由 + * @access public + * @param string $rule 路由规则 + * @param mixed $route 路由地址 + * @return RuleItem + */ + public function put(string $rule, $route): RuleItem + { + return $this->rule($rule, $route, 'PUT'); + } + + /** + * 注册DELETE路由 + * @access public + * @param string $rule 路由规则 + * @param mixed $route 路由地址 + * @return RuleItem + */ + public function delete(string $rule, $route): RuleItem + { + return $this->rule($rule, $route, 'DELETE'); + } + + /** + * 注册PATCH路由 + * @access public + * @param string $rule 路由规则 + * @param mixed $route 路由地址 + * @return RuleItem + */ + public function patch(string $rule, $route): RuleItem + { + return $this->rule($rule, $route, 'PATCH'); + } + + /** + * 注册OPTIONS路由 + * @access public + * @param string $rule 路由规则 + * @param mixed $route 路由地址 + * @return RuleItem + */ + public function options(string $rule, $route): RuleItem + { + return $this->rule($rule, $route, 'OPTIONS'); + } + + /** + * 注册资源路由 + * @access public + * @param string $rule 路由规则 + * @param string $route 路由地址 + * @return Resource + */ + public function resource(string $rule, string $route): Resource + { + return (new Resource($this, $this->group, $rule, $route, $this->rest)) + ->lazy($this->lazy); + } + + /** + * 注册视图路由 + * @access public + * @param string $rule 路由规则 + * @param string $template 路由模板地址 + * @param array $vars 模板变量 + * @return RuleItem + */ + public function view(string $rule, string $template = '', array $vars = []): RuleItem + { + return $this->rule($rule, function () use ($vars, $template) { + return Response::create($template, 'view')->assign($vars); + }, 'GET'); + } + + /** + * 注册重定向路由 + * @access public + * @param string $rule 路由规则 + * @param string $route 路由地址 + * @param int $status 状态码 + * @return RuleItem + */ + public function redirect(string $rule, string $route = '', int $status = 301): RuleItem + { + return $this->rule($rule, function (Request $request) use ($status, $route) { + $search = $replace = []; + $matches = $request->rule()->getVars(); + + foreach ($matches as $key => $value) { + $search[] = '<' . $key . '>'; + $replace[] = $value; + + $search[] = ':' . $key; + $replace[] = $value; + } + + $route = str_replace($search, $replace, $route); + return Response::create($route, 'redirect')->code($status); + }, '*'); + } + + /** + * rest方法定义和修改 + * @access public + * @param string|array $name 方法名称 + * @param array|bool $resource 资源 + * @return $this + */ + public function rest($name, $resource = []) + { + if (is_array($name)) { + $this->rest = $resource ? $name : array_merge($this->rest, $name); + } else { + $this->rest[$name] = $resource; + } + + return $this; + } + + /** + * 获取rest方法定义的参数 + * @access public + * @param string $name 方法名称 + * @return array|null + */ + public function getRest(string $name = null) + { + if (is_null($name)) { + return $this->rest; + } + + return $this->rest[$name] ?? null; + } + + /** + * 注册未匹配路由规则后的处理 + * @access public + * @param string|Closure $route 路由地址 + * @param string $method 请求类型 + * @return RuleItem + */ + public function miss($route, string $method = '*'): RuleItem + { + return $this->group->miss($route, $method); + } + + /** + * 路由调度 + * @param Request $request + * @param Closure|bool $withRoute + * @return Response + */ + public function dispatch(Request $request, $withRoute = true) + { + $this->request = $request; + $this->host = $this->request->host(true); + $this->init(); + + if ($withRoute) { + //加载路由 + if ($withRoute instanceof Closure) { + $withRoute(); + } + $dispatch = $this->check(); + } else { + $dispatch = $this->url($this->path()); + } + + $dispatch->init($this->app); + + return $this->app->middleware->pipeline('route') + ->send($request) + ->then(function () use ($dispatch) { + return $dispatch->run(); + }); + } + + /** + * 检测URL路由 + * @access public + * @return Dispatch|false + * @throws RouteNotFoundException + */ + public function check() + { + // 自动检测域名路由 + $url = str_replace($this->config['pathinfo_depr'], '|', $this->path()); + + $completeMatch = $this->config['route_complete_match']; + + $result = $this->checkDomain()->check($this->request, $url, $completeMatch); + + if (false === $result && !empty($this->cross)) { + // 检测跨域路由 + $result = $this->cross->check($this->request, $url, $completeMatch); + } + + if (false !== $result) { + return $result; + } elseif ($this->config['url_route_must']) { + throw new RouteNotFoundException(); + } + + return $this->url($url); + } + + /** + * 获取当前请求URL的pathinfo信息(不含URL后缀) + * @access protected + * @return string + */ + protected function path(): string + { + $suffix = $this->config['url_html_suffix']; + $pathinfo = $this->request->pathinfo(); + + if (false === $suffix) { + // 禁止伪静态访问 + $path = $pathinfo; + } elseif ($suffix) { + // 去除正常的URL后缀 + $path = preg_replace('/\.(' . ltrim($suffix, '.') . ')$/i', '', $pathinfo); + } else { + // 允许任何后缀访问 + $path = preg_replace('/\.' . $this->request->ext() . '$/i', '', $pathinfo); + } + + return $path; + } + + /** + * 默认URL解析 + * @access public + * @param string $url URL地址 + * @return Dispatch + */ + public function url(string $url): Dispatch + { + if ($this->request->method() == 'OPTIONS') { + // 自动响应options请求 + return new Callback($this->request, $this->group, function () { + return Response::create('', 'html', 204)->header(['Allow' => 'GET, POST, PUT, DELETE']); + }); + } + + return new UrlDispatch($this->request, $this->group, $url); + } + + /** + * 检测域名的路由规则 + * @access protected + * @return Domain + */ + protected function checkDomain(): Domain + { + $item = false; + + if (count($this->domains) > 1) { + // 获取当前子域名 + $subDomain = $this->request->subDomain(); + + $domain = $subDomain ? explode('.', $subDomain) : []; + $domain2 = $domain ? array_pop($domain) : ''; + + if ($domain) { + // 存在三级域名 + $domain3 = array_pop($domain); + } + + if (isset($this->domains[$this->host])) { + // 子域名配置 + $item = $this->domains[$this->host]; + } elseif (isset($this->domains[$subDomain])) { + $item = $this->domains[$subDomain]; + } elseif (isset($this->domains['*.' . $domain2]) && !empty($domain3)) { + // 泛三级域名 + $item = $this->domains['*.' . $domain2]; + $panDomain = $domain3; + } elseif (isset($this->domains['*']) && !empty($domain2)) { + // 泛二级域名 + if ('www' != $domain2) { + $item = $this->domains['*']; + $panDomain = $domain2; + } + } + + if (isset($panDomain)) { + // 保存当前泛域名 + $this->request->setPanDomain($panDomain); + } + } + + if (false === $item) { + // 检测全局域名规则 + $item = $this->domains['-']; + } + + if (is_string($item)) { + $item = $this->domains[$item]; + } + + return $item; + } + + /** + * URL生成 支持路由反射 + * @access public + * @param string $url 路由地址 + * @param array $vars 参数 ['a'=>'val1', 'b'=>'val2'] + * @return UrlBuild + */ + public function buildUrl(string $url = '', array $vars = []): UrlBuild + { + return $this->app->make(UrlBuild::class, [$this, $this->app, $url, $vars], true); + } + + /** + * 设置全局的路由分组参数 + * @access public + * @param string $method 方法名 + * @param array $args 调用参数 + * @return RuleGroup + */ + public function __call($method, $args) + { + return call_user_func_array([$this->group, $method], $args); + } +} diff --git a/vendor/topthink/framework/src/think/Service.php b/vendor/topthink/framework/src/think/Service.php new file mode 100644 index 000000000..d9e89601a --- /dev/null +++ b/vendor/topthink/framework/src/think/Service.php @@ -0,0 +1,66 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think; + +use Closure; +use think\event\RouteLoaded; + +/** + * 系统服务基础类 + * @method void register() + * @method void boot() + */ +abstract class Service +{ + protected $app; + + public function __construct(App $app) + { + $this->app = $app; + } + + /** + * 加载路由 + * @access protected + * @param string $path 路由路径 + */ + protected function loadRoutesFrom($path) + { + $this->registerRoutes(function () use ($path) { + include $path; + }); + } + + /** + * 注册路由 + * @param Closure $closure + */ + protected function registerRoutes(Closure $closure) + { + $this->app->event->listen(RouteLoaded::class, $closure); + } + + /** + * 添加指令 + * @access protected + * @param array|string $commands 指令 + */ + protected function commands($commands) + { + $commands = is_array($commands) ? $commands : func_get_args(); + + Console::starting(function (Console $console) use ($commands) { + $console->addCommands($commands); + }); + } +} diff --git a/vendor/topthink/framework/src/think/Session.php b/vendor/topthink/framework/src/think/Session.php new file mode 100644 index 000000000..6c84faf8f --- /dev/null +++ b/vendor/topthink/framework/src/think/Session.php @@ -0,0 +1,65 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think; + +use think\helper\Arr; +use think\session\Store; + +/** + * Session管理类 + * @package think + * @mixin Store + */ +class Session extends Manager +{ + protected $namespace = '\\think\\session\\driver\\'; + + protected function createDriver(string $name) + { + $handler = parent::createDriver($name); + + return new Store($this->getConfig('name') ?: 'PHPSESSID', $handler, $this->getConfig('serialize')); + } + + /** + * 获取Session配置 + * @access public + * @param null|string $name 名称 + * @param mixed $default 默认值 + * @return mixed + */ + public function getConfig(string $name = null, $default = null) + { + if (!is_null($name)) { + return $this->app->config->get('session.' . $name, $default); + } + + return $this->app->config->get('session'); + } + + protected function resolveConfig(string $name) + { + $config = $this->app->config->get('session', []); + Arr::forget($config, 'type'); + return $config; + } + + /** + * 默认驱动 + * @return string|null + */ + public function getDefaultDriver() + { + return $this->app->config->get('session.type', 'file'); + } +} diff --git a/thinkphp/library/think/Validate.php b/vendor/topthink/framework/src/think/Validate.php old mode 100755 new mode 100644 similarity index 60% rename from thinkphp/library/think/Validate.php rename to vendor/topthink/framework/src/think/Validate.php index 54c3a7370..078840641 --- a/thinkphp/library/think/Validate.php +++ b/vendor/topthink/framework/src/think/Validate.php @@ -2,26 +2,32 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think; -use think\exception\ClassNotFoundException; +use Closure; +use think\exception\ValidateException; +use think\helper\Str; use think\validate\ValidateRule; +/** + * 数据验证类 + * @package think + */ class Validate { - /** * 自定义验证类型 * @var array */ - protected static $type = []; + protected $type = []; /** * 验证类型别名 @@ -53,7 +59,7 @@ class Validate * 默认规则提示 * @var array */ - protected static $typeMsg = [ + protected $typeMsg = [ 'require' => ':attribute require', 'must' => ':attribute must', 'number' => ':attribute must be numeric', @@ -87,8 +93,6 @@ class Validate 'min' => 'min size of :attribute must be :rule', 'after' => ':attribute cannot be less than :rule', 'before' => ':attribute cannot exceed :rule', - 'afterWith' => ':attribute cannot be less than :rule', - 'beforeWith' => ':attribute cannot exceed :rule', 'expire' => ':attribute not within :rule', 'allowIp' => 'access IP is not allowed', 'denyIp' => 'access IP denied', @@ -110,9 +114,26 @@ class Validate /** * 当前验证场景 + * @var string + */ + protected $currentScene; + + /** + * 内置正则验证规则 * @var array */ - protected $currentScene = null; + protected $defaultRegex = [ + 'alpha' => '/^[A-Za-z]+$/', + 'alphaNum' => '/^[A-Za-z0-9]+$/', + 'alphaDash' => '/^[A-Za-z0-9\-\_]+$/', + 'chs' => '/^[\x{4e00}-\x{9fa5}\x{9fa6}-\x{9fef}\x{3400}-\x{4db5}\x{20000}-\x{2ebe0}]+$/u', + 'chsAlpha' => '/^[\x{4e00}-\x{9fa5}\x{9fa6}-\x{9fef}\x{3400}-\x{4db5}\x{20000}-\x{2ebe0}a-zA-Z]+$/u', + 'chsAlphaNum' => '/^[\x{4e00}-\x{9fa5}\x{9fa6}-\x{9fef}\x{3400}-\x{4db5}\x{20000}-\x{2ebe0}a-zA-Z0-9]+$/u', + 'chsDash' => '/^[\x{4e00}-\x{9fa5}\x{9fa6}-\x{9fef}\x{3400}-\x{4db5}\x{20000}-\x{2ebe0}a-zA-Z0-9\_\-]+$/u', + 'mobile' => '/^1[3-9]\d{9}$/', + 'idCard' => '/(^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|(^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}$)/', + 'zip' => '/\d{6}/', + ]; /** * Filter_var 规则 @@ -127,21 +148,6 @@ class Validate 'float' => FILTER_VALIDATE_FLOAT, ]; - /** - * 内置正则验证规则 - * @var array - */ - protected $regex = [ - 'alphaDash' => '/^[A-Za-z0-9\-\_]+$/', - 'chs' => '/^[\x{4e00}-\x{9fa5}]+$/u', - 'chsAlpha' => '/^[\x{4e00}-\x{9fa5}a-zA-Z]+$/u', - 'chsAlphaNum' => '/^[\x{4e00}-\x{9fa5}a-zA-Z0-9]+$/u', - 'chsDash' => '/^[\x{4e00}-\x{9fa5}a-zA-Z0-9\_\-]+$/u', - 'mobile' => '/^1[3-9][0-9]\d{8}$/', - 'idCard' => '/(^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|(^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{2}$)/', - 'zip' => '/\d{6}/', - ]; - /** * 验证场景定义 * @var array @@ -150,7 +156,7 @@ class Validate /** * 验证失败错误信息 - * @var array + * @var string|array */ protected $error = []; @@ -160,6 +166,12 @@ class Validate */ protected $batch = false; + /** + * 验证失败是否抛出异常 + * @var bool + */ + protected $failException = false; + /** * 场景需要验证的规则 * @var array @@ -179,37 +191,96 @@ class Validate protected $append = []; /** - * 架构函数 - * @access public - * @param array $rules 验证规则 - * @param array $message 验证提示信息 - * @param array $field 验证字段描述信息 + * 验证正则定义 + * @var array */ - public function __construct(array $rules = [], array $message = [], array $field = []) + protected $regex = []; + + /** + * Db对象 + * @var Db + */ + protected $db; + + /** + * 语言对象 + * @var Lang + */ + protected $lang; + + /** + * 请求对象 + * @var Request + */ + protected $request; + + /** + * @var Closure[] + */ + protected static $maker = []; + + /** + * 构造方法 + * @access public + */ + public function __construct() { - $this->rule = $rules + $this->rule; - $this->message = array_merge($this->message, $message); - $this->field = array_merge($this->field, $field); + if (!empty(static::$maker)) { + foreach (static::$maker as $maker) { + call_user_func($maker, $this); + } + } } /** - * 创建一个验证器类 + * 设置服务注入 * @access public - * @param array $rules 验证规则 - * @param array $message 验证提示信息 - * @param array $field 验证字段描述信息 - * @return Validate + * @param Closure $maker + * @return void */ - public static function make(array $rules = [], array $message = [], array $field = []) + public static function maker(Closure $maker) { - return new self($rules, $message, $field); + static::$maker[] = $maker; + } + + /** + * 设置Lang对象 + * @access public + * @param Lang $lang Lang对象 + * @return void + */ + public function setLang(Lang $lang) + { + $this->lang = $lang; + } + + /** + * 设置Db对象 + * @access public + * @param Db $db Db对象 + * @return void + */ + public function setDb(Db $db) + { + $this->db = $db; + } + + /** + * 设置Request对象 + * @access public + * @param Request $request Request对象 + * @return void + */ + public function setRequest(Request $request) + { + $this->request = $request; } /** * 添加字段验证规则 * @access protected - * @param string|array $name 字段名称或者规则数组 - * @param mixed $rule 验证规则或者字段描述信息 + * @param string|array $name 字段名称或者规则数组 + * @param mixed $rule 验证规则或者字段描述信息 * @return $this */ public function rule($name, $rule = '') @@ -227,51 +298,49 @@ class Validate } /** - * 注册扩展验证(类型)规则 + * 注册验证(类型)规则 * @access public - * @param string $type 验证规则类型 - * @param mixed $callback callback方法(或闭包) - * @return void + * @param string $type 验证规则类型 + * @param callable $callback callback方法(或闭包) + * @param string $message 验证失败提示信息 + * @return $this */ - public static function extend($type, $callback = null) + public function extend(string $type, callable $callback = null, string $message = null) { - if (is_array($type)) { - self::$type = array_merge(self::$type, $type); - } else { - self::$type[$type] = $callback; + $this->type[$type] = $callback; + + if ($message) { + $this->typeMsg[$type] = $message; } + + return $this; } /** * 设置验证规则的默认提示信息 * @access public - * @param string|array $type 验证规则类型名称或者数组 - * @param string $msg 验证提示信息 + * @param string|array $type 验证规则类型名称或者数组 + * @param string $msg 验证提示信息 * @return void */ - public static function setTypeMsg($type, $msg = null) + public function setTypeMsg($type, string $msg = null): void { if (is_array($type)) { - self::$typeMsg = array_merge(self::$typeMsg, $type); + $this->typeMsg = array_merge($this->typeMsg, $type); } else { - self::$typeMsg[$type] = $msg; + $this->typeMsg[$type] = $msg; } } /** * 设置提示信息 * @access public - * @param string|array $name 字段名称 - * @param string $message 提示信息 + * @param array $message 错误信息 * @return Validate */ - public function message($name, $message = '') + public function message(array $message) { - if (is_array($name)) { - $this->message = array_merge($this->message, $name); - } else { - $this->message[$name] = $message; - } + $this->message = array_merge($this->message, $message); return $this; } @@ -279,10 +348,10 @@ class Validate /** * 设置验证场景 * @access public - * @param string $name 场景名 + * @param string $name 场景名 * @return $this */ - public function scene($name) + public function scene(string $name) { // 设置当前场景 $this->currentScene = $name; @@ -293,10 +362,10 @@ class Validate /** * 判断是否存在某个验证场景 * @access public - * @param string $name 场景名 + * @param string $name 场景名 * @return bool */ - public function hasScene($name) + public function hasScene(string $name): bool { return isset($this->scene[$name]) || method_exists($this, 'scene' . $name); } @@ -304,10 +373,10 @@ class Validate /** * 设置批量验证 * @access public - * @param bool $batch 是否批量验证 + * @param bool $batch 是否批量验证 * @return $this */ - public function batch($batch = true) + public function batch(bool $batch = true) { $this->batch = $batch; @@ -315,12 +384,25 @@ class Validate } /** - * 指定需要验证的字段列表 - * @access public - * @param array $fields 字段名 + * 设置验证失败后是否抛出异常 + * @access protected + * @param bool $fail 是否抛出异常 * @return $this */ - public function only($fields) + public function failException(bool $fail = true) + { + $this->failException = $fail; + + return $this; + } + + /** + * 指定需要验证的字段列表 + * @access public + * @param array $fields 字段名 + * @return $this + */ + public function only(array $fields) { $this->only = $fields; @@ -330,8 +412,8 @@ class Validate /** * 移除某个字段的验证规则 * @access public - * @param string|array $field 字段名 - * @param mixed $rule 验证规则 null 移除所有规则 + * @param string|array $field 字段名 + * @param mixed $rule 验证规则 true 移除所有规则 * @return $this */ public function remove($field, $rule = null) @@ -358,8 +440,8 @@ class Validate /** * 追加某个字段的验证规则 * @access public - * @param string|array $field 字段名 - * @param mixed $rule 验证规则 + * @param string|array $field 字段名 + * @param mixed $rule 验证规则 * @return $this */ public function append($field, $rule = null) @@ -382,26 +464,27 @@ class Validate /** * 数据自动验证 * @access public - * @param array $data 数据 - * @param mixed $rules 验证规则 - * @param string $scene 验证场景 + * @param array $data 数据 + * @param array $rules 验证规则 * @return bool */ - public function check($data, $rules = [], $scene = '') + public function check(array $data, array $rules = []): bool { $this->error = []; + if ($this->currentScene) { + $this->getScene($this->currentScene); + } + if (empty($rules)) { // 读取验证规则 $rules = $this->rule; } - // 获取场景定义 - $this->getScene($scene); - foreach ($this->append as $key => $rule) { if (!isset($rules[$key])) { $rules[$key] = $rule; + unset($this->append[$key]); } } @@ -409,9 +492,9 @@ class Validate // field => 'rule1|rule2...' field => ['rule1','rule2',...] if (strpos($key, '|')) { // 字段|描述 用于指定属性名称 - list($key, $title) = explode('|', $key); + [$key, $title] = explode('|', $key); } else { - $title = isset($this->field[$key]) ? $this->field[$key] : $key; + $title = $this->field[$key] ?? $key; } // 场景检测 @@ -419,12 +502,12 @@ class Validate continue; } - // 获取数据 支持多维数组 + // 获取数据 支持二维数组 $value = $this->getDataValue($data, $key); // 字段验证 - if ($rule instanceof \Closure) { - $result = call_user_func_array($rule, [$value, $data, $title, $this]); + if ($rule instanceof Closure) { + $result = call_user_func_array($rule, [$value, $data]); } elseif ($rule instanceof ValidateRule) { // 验证因子 $result = $this->checkItem($key, $value, $rule->getRule(), $data, $rule->getTitle() ?: $title, $rule->getMsg()); @@ -436,11 +519,9 @@ class Validate // 没有返回true 则表示验证失败 if (!empty($this->batch)) { // 批量验证 - if (is_array($result)) { - $this->error = array_merge($this->error, $result); - } else { - $this->error[$key] = $result; - } + $this->error[$key] = $result; + } elseif ($this->failException) { + throw new ValidateException($result); } else { $this->error = $result; return false; @@ -448,19 +529,26 @@ class Validate } } - return !empty($this->error) ? false : true; + if (!empty($this->error)) { + if ($this->failException) { + throw new ValidateException($this->error); + } + return false; + } + + return true; } /** * 根据验证规则验证数据 * @access public - * @param mixed $value 字段值 - * @param mixed $rules 验证规则 + * @param mixed $value 字段值 + * @param mixed $rules 验证规则 * @return bool */ - public function checkRule($value, $rules) + public function checkRule($value, $rules): bool { - if ($rules instanceof \Closure) { + if ($rules instanceof Closure) { return call_user_func_array($rules, [$value]); } elseif ($rules instanceof ValidateRule) { $rules = $rules->getRule(); @@ -469,18 +557,22 @@ class Validate } foreach ($rules as $key => $rule) { - if ($rule instanceof \Closure) { + if ($rule instanceof Closure) { $result = call_user_func_array($rule, [$value]); } else { // 判断验证类型 - list($type, $rule) = $this->getValidateType($key, $rule); + [$type, $rule] = $this->getValidateType($key, $rule); - $callback = isset(self::$type[$type]) ? self::$type[$type] : [$this, $type]; + $callback = $this->type[$type] ?? [$this, $type]; $result = call_user_func_array($callback, [$value, $rule]); } if (true !== $result) { + if ($this->failException) { + throw new ValidateException($result); + } + return $result; } } @@ -491,15 +583,15 @@ class Validate /** * 验证单个字段规则 * @access protected - * @param string $field 字段名 - * @param mixed $value 字段值 - * @param mixed $rules 验证规则 - * @param array $data 数据 - * @param string $title 字段描述 - * @param array $msg 提示信息 + * @param string $field 字段名 + * @param mixed $value 字段值 + * @param mixed $rules 验证规则 + * @param array $data 数据 + * @param string $title 字段描述 + * @param array $msg 提示信息 * @return mixed */ - protected function checkItem($field, $value, $rules, $data, $title = '', $msg = []) + protected function checkItem(string $field, $value, $rules, $data, string $title = '', array $msg = []) { if (isset($this->remove[$field]) && true === $this->remove[$field] && empty($this->append[$field])) { // 字段已经移除 无需验证 @@ -513,33 +605,33 @@ class Validate if (isset($this->append[$field])) { // 追加额外的验证规则 - $rules = array_merge($rules, $this->append[$field]); + $rules = array_unique(array_merge($rules, $this->append[$field]), SORT_REGULAR); + unset($this->append[$field]); } - $i = 0; - $result = true; + if (empty($rules)) { + return true; + } + $i = 0; foreach ($rules as $key => $rule) { - if ($rule instanceof \Closure) { + if ($rule instanceof Closure) { $result = call_user_func_array($rule, [$value, $data]); $info = is_numeric($key) ? '' : $key; } else { // 判断验证类型 - list($type, $rule, $info) = $this->getValidateType($key, $rule); + [$type, $rule, $info] = $this->getValidateType($key, $rule); if (isset($this->append[$field]) && in_array($info, $this->append[$field])) { - - } elseif (array_key_exists($field, $this->remove) && (null === $this->remove[$field] || in_array($info, $this->remove[$field]))) { + } elseif (isset($this->remove[$field]) && in_array($info, $this->remove[$field])) { // 规则已经移除 $i++; continue; } - // 验证类型 - if (isset(self::$type[$type])) { - $result = call_user_func_array(self::$type[$type], [$value, $rule, $data, $field, $title]); + if (isset($this->type[$type])) { + $result = call_user_func_array($this->type[$type], [$value, $rule, $data, $field, $title]); } elseif ('must' == $info || 0 === strpos($info, 'require') || (!is_null($value) && '' !== $value)) { - // 验证数据 $result = call_user_func_array([$this, $type], [$value, $rule, $data, $field, $title]); } else { $result = true; @@ -551,7 +643,7 @@ class Validate if (!empty($msg[$i])) { $message = $msg[$i]; if (is_string($message) && strpos($message, '{%') === 0) { - $message = facade\Lang::get(substr($message, 2, -1)); + $message = $this->lang->get(substr($message, 2, -1)); } } else { $message = $this->getRuleMsg($field, $title, $info, $rule); @@ -561,10 +653,11 @@ class Validate } elseif (true !== $result) { // 返回自定义错误信息 if (is_string($result) && false !== strpos($result, ':')) { - $result = str_replace( - [':attribute', ':rule'], - [$title, (string) $rule], - $result); + $result = str_replace(':attribute', $title, $result); + + if (strpos($result, ':rule') && is_scalar($rule)) { + $result = str_replace(':rule', (string) $rule, $result); + } } return $result; @@ -572,25 +665,29 @@ class Validate $i++; } - return $result; + return $result ?? true; } /** * 获取当前验证类型及规则 * @access public - * @param mixed $key - * @param mixed $rule + * @param mixed $key + * @param mixed $rule * @return array */ - protected function getValidateType($key, $rule) + protected function getValidateType($key, $rule): array { // 判断验证类型 if (!is_numeric($key)) { + if (isset($this->alias[$key])) { + // 判断别名 + $key = $this->alias[$key]; + } return [$key, $rule, $key]; } if (strpos($rule, ':')) { - list($type, $rule) = explode(':', $rule, 2); + [$type, $rule] = explode(':', $rule, 2); if (isset($this->alias[$type])) { // 判断别名 $type = $this->alias[$type]; @@ -611,13 +708,13 @@ class Validate /** * 验证是否和某个字段的值一致 * @access public - * @param mixed $value 字段值 - * @param mixed $rule 验证规则 - * @param array $data 数据 - * @param string $field 字段名 + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 + * @param array $data 数据 + * @param string $field 字段名 * @return bool */ - public function confirm($value, $rule, $data = [], $field = '') + public function confirm($value, $rule, array $data = [], string $field = ''): bool { if ('' == $rule) { if (strpos($field, '_confirm')) { @@ -633,12 +730,12 @@ class Validate /** * 验证是否和某个字段的值是否不同 * @access public - * @param mixed $value 字段值 - * @param mixed $rule 验证规则 - * @param array $data 数据 + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 + * @param array $data 数据 * @return bool */ - public function different($value, $rule, $data = []) + public function different($value, $rule, array $data = []): bool { return $this->getDataValue($data, $rule) != $value; } @@ -646,12 +743,12 @@ class Validate /** * 验证是否大于等于某个值 * @access public - * @param mixed $value 字段值 - * @param mixed $rule 验证规则 - * @param array $data 数据 + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 + * @param array $data 数据 * @return bool */ - public function egt($value, $rule, $data = []) + public function egt($value, $rule, array $data = []): bool { return $value >= $this->getDataValue($data, $rule); } @@ -659,12 +756,12 @@ class Validate /** * 验证是否大于某个值 * @access public - * @param mixed $value 字段值 - * @param mixed $rule 验证规则 - * @param array $data 数据 + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 + * @param array $data 数据 * @return bool */ - public function gt($value, $rule, $data) + public function gt($value, $rule, array $data = []): bool { return $value > $this->getDataValue($data, $rule); } @@ -672,12 +769,12 @@ class Validate /** * 验证是否小于等于某个值 * @access public - * @param mixed $value 字段值 - * @param mixed $rule 验证规则 - * @param array $data 数据 + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 + * @param array $data 数据 * @return bool */ - public function elt($value, $rule, $data = []) + public function elt($value, $rule, array $data = []): bool { return $value <= $this->getDataValue($data, $rule); } @@ -685,12 +782,12 @@ class Validate /** * 验证是否小于某个值 * @access public - * @param mixed $value 字段值 - * @param mixed $rule 验证规则 - * @param array $data 数据 + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 + * @param array $data 数据 * @return bool */ - public function lt($value, $rule, $data = []) + public function lt($value, $rule, array $data = []): bool { return $value < $this->getDataValue($data, $rule); } @@ -698,11 +795,11 @@ class Validate /** * 验证是否等于某个值 * @access public - * @param mixed $value 字段值 - * @param mixed $rule 验证规则 + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 * @return bool */ - public function eq($value, $rule) + public function eq($value, $rule): bool { return $value == $rule; } @@ -710,11 +807,11 @@ class Validate /** * 必须验证 * @access public - * @param mixed $value 字段值 - * @param mixed $rule 验证规则 + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 * @return bool */ - public function must($value, $rule = null) + public function must($value, $rule = null): bool { return !empty($value) || '0' == $value; } @@ -722,14 +819,14 @@ class Validate /** * 验证字段值是否为有效格式 * @access public - * @param mixed $value 字段值 - * @param string $rule 验证规则 - * @param array $data 验证数据 + * @param mixed $value 字段值 + * @param string $rule 验证规则 + * @param array $data 数据 * @return bool */ - public function is($value, $rule, $data = []) + public function is($value, string $rule, array $data = []): bool { - switch (Loader::parseName($rule, 1, false)) { + switch (Str::camel($rule)) { case 'require': // 必须 $result = !empty($value) || '0' == $value; @@ -771,9 +868,9 @@ class Validate $result = $this->token($value, '__token__', $data); break; default: - if (isset(self::$type[$rule])) { + if (isset($this->type[$rule])) { // 注册的验证规则 - $result = call_user_func_array(self::$type[$rule], [$value]); + $result = call_user_func_array($this->type[$rule], [$value]); } elseif (function_exists('ctype_' . $rule)) { // ctype验证规则 $ctypeFun = 'ctype_' . $rule; @@ -806,13 +903,27 @@ class Validate } /** - * 验证是否为合格的域名或者IP 支持A,MX,NS,SOA,PTR,CNAME,AAAA,A6, SRV,NAPTR,TXT 或者 ANY类型 + * 验证表单令牌 * @access public - * @param mixed $value 字段值 - * @param mixed $rule 验证规则 + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 + * @param array $data 数据 * @return bool */ - public function activeUrl($value, $rule = 'MX') + public function token($value, string $rule, array $data): bool + { + $rule = !empty($rule) ? $rule : '__token__'; + return $this->request->checkToken($rule, $data); + } + + /** + * 验证是否为合格的域名或者IP 支持A,MX,NS,SOA,PTR,CNAME,AAAA,A6, SRV,NAPTR,TXT 或者 ANY类型 + * @access public + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 + * @return bool + */ + public function activeUrl(string $value, string $rule = 'MX'): bool { if (!in_array($rule, ['A', 'MX', 'NS', 'SOA', 'PTR', 'CNAME', 'AAAA', 'A6', 'SRV', 'NAPTR', 'TXT', 'ANY'])) { $rule = 'MX'; @@ -824,11 +935,11 @@ class Validate /** * 验证是否有效IP * @access public - * @param mixed $value 字段值 - * @param mixed $rule 验证规则 ipv4 ipv6 + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 ipv4 ipv6 * @return bool */ - public function ip($value, $rule = 'ipv4') + public function ip($value, string $rule = 'ipv4'): bool { if (!in_array($rule, ['ipv4', 'ipv6'])) { $rule = 'ipv4'; @@ -838,23 +949,67 @@ class Validate } /** - * 验证上传文件后缀 + * 检测上传文件后缀 * @access public - * @param mixed $file 上传文件 - * @param mixed $rule 验证规则 + * @param File $file + * @param array|string $ext 允许后缀 * @return bool */ - public function fileExt($file, $rule) + protected function checkExt(File $file, $ext): bool + { + if (is_string($ext)) { + $ext = explode(',', $ext); + } + + return in_array(strtolower($file->extension()), $ext); + } + + /** + * 检测上传文件大小 + * @access public + * @param File $file + * @param integer $size 最大大小 + * @return bool + */ + protected function checkSize(File $file, $size): bool + { + return $file->getSize() <= (int) $size; + } + + /** + * 检测上传文件类型 + * @access public + * @param File $file + * @param array|string $mime 允许类型 + * @return bool + */ + protected function checkMime(File $file, $mime): bool + { + if (is_string($mime)) { + $mime = explode(',', $mime); + } + + return in_array(strtolower($file->getMime()), $mime); + } + + /** + * 验证上传文件后缀 + * @access public + * @param mixed $file 上传文件 + * @param mixed $rule 验证规则 + * @return bool + */ + public function fileExt($file, $rule): bool { if (is_array($file)) { foreach ($file as $item) { - if (!($item instanceof File) || !$item->checkExt($rule)) { + if (!($item instanceof File) || !$this->checkExt($item, $rule)) { return false; } } return true; } elseif ($file instanceof File) { - return $file->checkExt($rule); + return $this->checkExt($file, $rule); } return false; @@ -863,21 +1018,21 @@ class Validate /** * 验证上传文件类型 * @access public - * @param mixed $file 上传文件 - * @param mixed $rule 验证规则 + * @param mixed $file 上传文件 + * @param mixed $rule 验证规则 * @return bool */ - public function fileMime($file, $rule) + public function fileMime($file, $rule): bool { if (is_array($file)) { foreach ($file as $item) { - if (!($item instanceof File) || !$item->checkMime($rule)) { + if (!($item instanceof File) || !$this->checkMime($item, $rule)) { return false; } } return true; } elseif ($file instanceof File) { - return $file->checkMime($rule); + return $this->checkMime($file, $rule); } return false; @@ -886,21 +1041,21 @@ class Validate /** * 验证上传文件大小 * @access public - * @param mixed $file 上传文件 - * @param mixed $rule 验证规则 + * @param mixed $file 上传文件 + * @param mixed $rule 验证规则 * @return bool */ - public function fileSize($file, $rule) + public function fileSize($file, $rule): bool { if (is_array($file)) { foreach ($file as $item) { - if (!($item instanceof File) || !$item->checkSize($rule)) { + if (!($item instanceof File) || !$this->checkSize($item, $rule)) { return false; } } return true; } elseif ($file instanceof File) { - return $file->checkSize($rule); + return $this->checkSize($file, $rule); } return false; @@ -909,11 +1064,11 @@ class Validate /** * 验证图片的宽高及类型 * @access public - * @param mixed $file 上传文件 - * @param mixed $rule 验证规则 + * @param mixed $file 上传文件 + * @param mixed $rule 验证规则 * @return bool */ - public function image($file, $rule) + public function image($file, $rule): bool { if (!($file instanceof File)) { return false; @@ -922,13 +1077,13 @@ class Validate if ($rule) { $rule = explode(',', $rule); - list($width, $height, $type) = getimagesize($file->getRealPath()); + [$width, $height, $type] = getimagesize($file->getRealPath()); if (isset($rule[2])) { $imageType = strtolower($rule[2]); - if ('jpeg' == $imageType) { - $imageType = 'jpg'; + if ('jpg' == $imageType) { + $imageType = 'jpeg'; } if (image_type_to_extension($type, false) != $imageType) { @@ -936,7 +1091,7 @@ class Validate } } - list($w, $h) = $rule; + [$w, $h] = $rule; return $w == $width && $h == $height; } @@ -944,27 +1099,14 @@ class Validate return in_array($this->getImageType($file->getRealPath()), [1, 2, 3, 6]); } - /** - * 验证请求类型 - * @access public - * @param mixed $value 字段值 - * @param mixed $rule 验证规则 - * @return bool - */ - public function method($value, $rule) - { - $method = Container::get('request')->method(); - return strtoupper($rule) == $method; - } - /** * 验证时间和日期是否符合指定格式 * @access public - * @param mixed $value 字段值 - * @param mixed $rule 验证规则 + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 * @return bool */ - public function dateFormat($value, $rule) + public function dateFormat($value, $rule): bool { $info = date_parse_from_format($rule, $value); return 0 == $info['warning_count'] && 0 == $info['error_count']; @@ -973,13 +1115,13 @@ class Validate /** * 验证是否唯一 * @access public - * @param mixed $value 字段值 - * @param mixed $rule 验证规则 格式:数据表,字段名,排除ID,主键名 - * @param array $data 数据 - * @param string $field 验证字段名 + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 格式:数据表,字段名,排除ID,主键名 + * @param array $data 数据 + * @param string $field 验证字段名 * @return bool */ - public function unique($value, $rule, $data, $field) + public function unique($value, $rule, array $data = [], string $field = ''): bool { if (is_string($rule)) { $rule = explode(',', $rule); @@ -989,14 +1131,11 @@ class Validate // 指定模型类 $db = new $rule[0]; } else { - try { - $db = Container::get('app')->model($rule[0]); - } catch (ClassNotFoundException $e) { - $db = Db::name($rule[0]); - } + $db = $this->db->name($rule[0]); } - $key = isset($rule[1]) ? $rule[1] : $field; + $key = $rule[1] ?? $field; + $map = []; if (strpos($key, '^')) { // 支持多个字段验证 @@ -1029,35 +1168,22 @@ class Validate return true; } - /** - * 使用行为类验证 - * @access public - * @param mixed $value 字段值 - * @param mixed $rule 验证规则 - * @param array $data 数据 - * @return mixed - */ - public function behavior($value, $rule, $data) - { - return Container::get('hook')->exec($rule, $data); - } - /** * 使用filter_var方式验证 * @access public - * @param mixed $value 字段值 - * @param mixed $rule 验证规则 + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 * @return bool */ - public function filter($value, $rule) + public function filter($value, $rule): bool { if (is_string($rule) && strpos($rule, ',')) { - list($rule, $param) = explode(',', $rule); + [$rule, $param] = explode(',', $rule); } elseif (is_array($rule)) { - $param = isset($rule[1]) ? $rule[1] : null; + $param = $rule[1] ?? 0; $rule = $rule[0]; } else { - $param = null; + $param = 0; } return false !== filter_var($value, is_int($rule) ? $rule : filter_id($rule), $param); @@ -1066,14 +1192,14 @@ class Validate /** * 验证某个字段等于某个值的时候必须 * @access public - * @param mixed $value 字段值 - * @param mixed $rule 验证规则 - * @param array $data 数据 + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 + * @param array $data 数据 * @return bool */ - public function requireIf($value, $rule, $data) + public function requireIf($value, $rule, array $data = []): bool { - list($field, $val) = explode(',', $rule); + [$field, $val] = explode(',', $rule); if ($this->getDataValue($data, $field) == $val) { return !empty($value) || '0' == $value; @@ -1085,12 +1211,12 @@ class Validate /** * 通过回调方法验证某个字段是否必须 * @access public - * @param mixed $value 字段值 - * @param mixed $rule 验证规则 - * @param array $data 数据 + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 + * @param array $data 数据 * @return bool */ - public function requireCallback($value, $rule, $data) + public function requireCallback($value, $rule, array $data = []): bool { $result = call_user_func_array([$this, $rule], [$value, $data]); @@ -1104,12 +1230,12 @@ class Validate /** * 验证某个字段有值的情况下必须 * @access public - * @param mixed $value 字段值 - * @param mixed $rule 验证规则 - * @param array $data 数据 + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 + * @param array $data 数据 * @return bool */ - public function requireWith($value, $rule, $data) + public function requireWith($value, $rule, array $data = []): bool { $val = $this->getDataValue($data, $rule); @@ -1121,13 +1247,32 @@ class Validate } /** - * 验证是否在范围内 + * 验证某个字段没有值的情况下必须 * @access public - * @param mixed $value 字段值 - * @param mixed $rule 验证规则 + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 + * @param array $data 数据 * @return bool */ - public function in($value, $rule) + public function requireWithout($value, $rule, array $data = []): bool + { + $val = $this->getDataValue($data, $rule); + + if (empty($val)) { + return !empty($value) || '0' == $value; + } + + return true; + } + + /** + * 验证是否在范围内 + * @access public + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 + * @return bool + */ + public function in($value, $rule): bool { return in_array($value, is_array($rule) ? $rule : explode(',', $rule)); } @@ -1135,11 +1280,11 @@ class Validate /** * 验证是否不在某个范围 * @access public - * @param mixed $value 字段值 - * @param mixed $rule 验证规则 + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 * @return bool */ - public function notIn($value, $rule) + public function notIn($value, $rule): bool { return !in_array($value, is_array($rule) ? $rule : explode(',', $rule)); } @@ -1147,16 +1292,16 @@ class Validate /** * between验证数据 * @access public - * @param mixed $value 字段值 - * @param mixed $rule 验证规则 + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 * @return bool */ - public function between($value, $rule) + public function between($value, $rule): bool { if (is_string($rule)) { $rule = explode(',', $rule); } - list($min, $max) = $rule; + [$min, $max] = $rule; return $value >= $min && $value <= $max; } @@ -1164,16 +1309,16 @@ class Validate /** * 使用notbetween验证数据 * @access public - * @param mixed $value 字段值 - * @param mixed $rule 验证规则 + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 * @return bool */ - public function notBetween($value, $rule) + public function notBetween($value, $rule): bool { if (is_string($rule)) { $rule = explode(',', $rule); } - list($min, $max) = $rule; + [$min, $max] = $rule; return $value < $min || $value > $max; } @@ -1181,11 +1326,11 @@ class Validate /** * 验证数据长度 * @access public - * @param mixed $value 字段值 - * @param mixed $rule 验证规则 + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 * @return bool */ - public function length($value, $rule) + public function length($value, $rule): bool { if (is_array($value)) { $length = count($value); @@ -1195,9 +1340,9 @@ class Validate $length = mb_strlen((string) $value); } - if (strpos($rule, ',')) { + if (is_string($rule) && strpos($rule, ',')) { // 长度区间 - list($min, $max) = explode(',', $rule); + [$min, $max] = explode(',', $rule); return $length >= $min && $length <= $max; } @@ -1208,11 +1353,11 @@ class Validate /** * 验证数据最大长度 * @access public - * @param mixed $value 字段值 - * @param mixed $rule 验证规则 + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 * @return bool */ - public function max($value, $rule) + public function max($value, $rule): bool { if (is_array($value)) { $length = count($value); @@ -1228,11 +1373,11 @@ class Validate /** * 验证数据最小长度 * @access public - * @param mixed $value 字段值 - * @param mixed $rule 验证规则 + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 * @return bool */ - public function min($value, $rule) + public function min($value, $rule): bool { if (is_array($value)) { $length = count($value); @@ -1248,12 +1393,12 @@ class Validate /** * 验证日期 * @access public - * @param mixed $value 字段值 - * @param mixed $rule 验证规则 - * @param array $data 数据 + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 + * @param array $data 数据 * @return bool */ - public function after($value, $rule, $data) + public function after($value, $rule, array $data = []): bool { return strtotime($value) >= strtotime($rule); } @@ -1261,39 +1406,39 @@ class Validate /** * 验证日期 * @access public - * @param mixed $value 字段值 - * @param mixed $rule 验证规则 - * @param array $data 数据 + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 + * @param array $data 数据 * @return bool */ - public function before($value, $rule, $data) + public function before($value, $rule, array $data = []): bool { return strtotime($value) <= strtotime($rule); } /** - * 验证日期字段 - * @access protected - * @param mixed $value 字段值 - * @param mixed $rule 验证规则 - * @param array $data 数据 + * 验证日期 + * @access public + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 + * @param array $data 数据 * @return bool */ - protected function afterWith($value, $rule, $data) + public function afterWith($value, $rule, array $data = []): bool { $rule = $this->getDataValue($data, $rule); return !is_null($rule) && strtotime($value) >= strtotime($rule); } /** - * 验证日期字段 - * @access protected - * @param mixed $value 字段值 - * @param mixed $rule 验证规则 - * @param array $data 数据 + * 验证日期 + * @access public + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 + * @param array $data 数据 * @return bool */ - protected function beforeWith($value, $rule, $data) + public function beforeWith($value, $rule, array $data = []): bool { $rule = $this->getDataValue($data, $rule); return !is_null($rule) && strtotime($value) <= strtotime($rule); @@ -1302,17 +1447,17 @@ class Validate /** * 验证有效期 * @access public - * @param mixed $value 字段值 - * @param mixed $rule 验证规则 + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 * @return bool */ - public function expire($value, $rule) + public function expire($value, $rule): bool { if (is_string($rule)) { $rule = explode(',', $rule); } - list($start, $end) = $rule; + [$start, $end] = $rule; if (!is_numeric($start)) { $start = strtotime($start); @@ -1322,17 +1467,17 @@ class Validate $end = strtotime($end); } - return $_SERVER['REQUEST_TIME'] >= $start && $_SERVER['REQUEST_TIME'] <= $end; + return time() >= $start && time() <= $end; } /** * 验证IP许可 * @access public - * @param string $value 字段值 - * @param mixed $rule 验证规则 - * @return mixed + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 + * @return bool */ - public function allowIp($value, $rule) + public function allowIp($value, $rule): bool { return in_array($value, is_array($rule) ? $rule : explode(',', $rule)); } @@ -1340,11 +1485,11 @@ class Validate /** * 验证IP禁用 * @access public - * @param string $value 字段值 - * @param mixed $rule 验证规则 - * @return mixed + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 + * @return bool */ - public function denyIp($value, $rule) + public function denyIp($value, $rule): bool { return !in_array($value, is_array($rule) ? $rule : explode(',', $rule)); } @@ -1352,17 +1497,19 @@ class Validate /** * 使用正则验证数据 * @access public - * @param mixed $value 字段值 - * @param mixed $rule 验证规则 正则规则或者预定义正则名 + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 正则规则或者预定义正则名 * @return bool */ - public function regex($value, $rule) + public function regex($value, $rule): bool { if (isset($this->regex[$rule])) { $rule = $this->regex[$rule]; + } elseif (isset($this->defaultRegex[$rule])) { + $rule = $this->defaultRegex[$rule]; } - if (0 !== strpos($rule, '/') && !preg_match('/\/[imsU]{0,4}$/', $rule)) { + if (is_string($rule) && 0 !== strpos($rule, '/') && !preg_match('/\/[imsU]{0,4}$/', $rule)) { // 不是正则表达式则两端补上/ $rule = '/^' . $rule . '$/'; } @@ -1371,37 +1518,9 @@ class Validate } /** - * 验证表单令牌 - * @access public - * @param mixed $value 字段值 - * @param mixed $rule 验证规则 - * @param array $data 数据 - * @return bool + * 获取错误信息 + * @return array|string */ - public function token($value, $rule, $data) - { - $rule = !empty($rule) ? $rule : '__token__'; - $session = Container::get('session'); - - if (!isset($data[$rule]) || !$session->has($rule)) { - // 令牌数据无效 - return false; - } - - // 令牌验证 - if (isset($data[$rule]) && $session->get($rule) === $data[$rule]) { - // 防止重复提交 - $session->delete($rule); // 验证完成销毁session - return true; - } - - // 开启TOKEN重置 - $session->delete($rule); - - return false; - } - - // 获取错误信息 public function getError() { return $this->error; @@ -1410,15 +1529,15 @@ class Validate /** * 获取数据值 * @access protected - * @param array $data 数据 - * @param string $key 数据标识 支持多维 + * @param array $data 数据 + * @param string $key 数据标识 支持二维 * @return mixed */ - protected function getDataValue($data, $key) + protected function getDataValue(array $data, $key) { if (is_numeric($key)) { $value = $key; - } elseif (strpos($key, '.')) { + } elseif (is_string($key) && strpos($key, '.')) { // 支持多维数组验证 foreach (explode('.', $key) as $key) { if (!isset($data[$key])) { @@ -1428,7 +1547,7 @@ class Validate $value = $data = $data[$key]; } } else { - $value = isset($data[$key]) ? $data[$key] : null; + $value = $data[$key] ?? null; } return $value; @@ -1437,90 +1556,123 @@ class Validate /** * 获取验证规则的错误提示信息 * @access protected - * @param string $attribute 字段英文名 - * @param string $title 字段描述名 - * @param string $type 验证规则名称 - * @param mixed $rule 验证规则数据 - * @return string + * @param string $attribute 字段英文名 + * @param string $title 字段描述名 + * @param string $type 验证规则名称 + * @param mixed $rule 验证规则数据 + * @return string|array */ - protected function getRuleMsg($attribute, $title, $type, $rule) + protected function getRuleMsg(string $attribute, string $title, string $type, $rule) { - $lang = Container::get('lang'); - if (isset($this->message[$attribute . '.' . $type])) { $msg = $this->message[$attribute . '.' . $type]; } elseif (isset($this->message[$attribute][$type])) { $msg = $this->message[$attribute][$type]; } elseif (isset($this->message[$attribute])) { $msg = $this->message[$attribute]; - } elseif (isset(self::$typeMsg[$type])) { - $msg = self::$typeMsg[$type]; + } elseif (isset($this->typeMsg[$type])) { + $msg = $this->typeMsg[$type]; } elseif (0 === strpos($type, 'require')) { - $msg = self::$typeMsg['require']; + $msg = $this->typeMsg['require']; } else { - $msg = $title . $lang->get('not conform to the rules'); + $msg = $title . $this->lang->get('not conform to the rules'); } - if (is_string($msg) && 0 === strpos($msg, '{%')) { - $msg = $lang->get(substr($msg, 2, -1)); - } elseif ($lang->has($msg)) { - $msg = $lang->get($msg); + if (is_array($msg)) { + return $this->errorMsgIsArray($msg, $rule, $title); } - if (is_string($msg) && is_scalar($rule) && false !== strpos($msg, ':')) { + return $this->parseErrorMsg($msg, $rule, $title); + } + + /** + * 获取验证规则的错误提示信息 + * @access protected + * @param string $msg 错误信息 + * @param mixed $rule 验证规则数据 + * @param string $title 字段描述名 + * @return string|array + */ + protected function parseErrorMsg(string $msg, $rule, string $title) + { + if (0 === strpos($msg, '{%')) { + $msg = $this->lang->get(substr($msg, 2, -1)); + } elseif ($this->lang->has($msg)) { + $msg = $this->lang->get($msg); + } + + if (is_array($msg)) { + return $this->errorMsgIsArray($msg, $rule, $title); + } + + // rule若是数组则转为字符串 + if (is_array($rule)) { + $rule = implode(',', $rule); + } + + if (is_scalar($rule) && false !== strpos($msg, ':')) { // 变量替换 if (is_string($rule) && strpos($rule, ',')) { $array = array_pad(explode(',', $rule), 3, ''); } else { $array = array_pad([], 3, ''); } + $msg = str_replace( - [':attribute', ':rule', ':1', ':2', ':3'], - [$title, (string) $rule, $array[0], $array[1], $array[2]], - $msg); + [':attribute', ':1', ':2', ':3'], + [$title, $array[0], $array[1], $array[2]], + $msg + ); + + if (strpos($msg, ':rule')) { + $msg = str_replace(':rule', (string) $rule, $msg); + } } return $msg; } + /** + * 错误信息数组处理 + * @access protected + * @param array $msg 错误信息 + * @param mixed $rule 验证规则数据 + * @param string $title 字段描述名 + * @return array + */ + protected function errorMsgIsArray(array $msg, $rule, string $title) + { + foreach ($msg as $key => $val) { + if (is_string($val)) { + $msg[$key] = $this->parseErrorMsg($val, $rule, $title); + } + } + return $msg; + } + /** * 获取数据验证的场景 * @access protected - * @param string $scene 验证场景 + * @param string $scene 验证场景 * @return void */ - protected function getScene($scene = '') + protected function getScene(string $scene): void { - if (empty($scene)) { - // 读取指定场景 - $scene = $this->currentScene; - } - - if (empty($scene)) { - return; - } - $this->only = $this->append = $this->remove = []; if (method_exists($this, 'scene' . $scene)) { call_user_func([$this, 'scene' . $scene]); } elseif (isset($this->scene[$scene])) { // 如果设置了验证适用场景 - $scene = $this->scene[$scene]; - - if (is_string($scene)) { - $scene = explode(',', $scene); - } - - $this->only = $scene; + $this->only = $this->scene[$scene]; } } /** * 动态方法 直接调用is方法进行验证 * @access public - * @param string $method 方法名 - * @param array $args 调用参数 + * @param string $method 方法名 + * @param array $args 调用参数 * @return bool */ public function __call($method, $args) diff --git a/vendor/topthink/framework/src/think/View.php b/vendor/topthink/framework/src/think/View.php new file mode 100644 index 000000000..2e7108840 --- /dev/null +++ b/vendor/topthink/framework/src/think/View.php @@ -0,0 +1,191 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think; + +use think\helper\Arr; + +/** + * 视图类 + * @package think + */ +class View extends Manager +{ + + protected $namespace = '\\think\\view\\driver\\'; + + /** + * 模板变量 + * @var array + */ + protected $data = []; + + /** + * 内容过滤 + * @var mixed + */ + protected $filter; + + /** + * 获取模板引擎 + * @access public + * @param string $type 模板引擎类型 + * @return $this + */ + public function engine(string $type = null) + { + return $this->driver($type); + } + + /** + * 模板变量赋值 + * @access public + * @param string|array $name 模板变量 + * @param mixed $value 变量值 + * @return $this + */ + public function assign($name, $value = null) + { + if (is_array($name)) { + $this->data = array_merge($this->data, $name); + } else { + $this->data[$name] = $value; + } + + return $this; + } + + /** + * 视图过滤 + * @access public + * @param Callable $filter 过滤方法或闭包 + * @return $this + */ + public function filter(callable $filter = null) + { + $this->filter = $filter; + return $this; + } + + /** + * 解析和获取模板内容 用于输出 + * @access public + * @param string $template 模板文件名或者内容 + * @param array $vars 模板变量 + * @return string + * @throws \Exception + */ + public function fetch(string $template = '', array $vars = []): string + { + return $this->getContent(function () use ($vars, $template) { + $this->engine()->fetch($template, array_merge($this->data, $vars)); + }); + } + + /** + * 渲染内容输出 + * @access public + * @param string $content 内容 + * @param array $vars 模板变量 + * @return string + */ + public function display(string $content, array $vars = []): string + { + return $this->getContent(function () use ($vars, $content) { + $this->engine()->display($content, array_merge($this->data, $vars)); + }); + } + + /** + * 获取模板引擎渲染内容 + * @param $callback + * @return string + * @throws \Exception + */ + protected function getContent($callback): string + { + // 页面缓存 + ob_start(); + if (PHP_VERSION > 8.0) { + ob_implicit_flush(false); + } else { + ob_implicit_flush(0); + } + + // 渲染输出 + try { + $callback(); + } catch (\Exception $e) { + ob_end_clean(); + throw $e; + } + + // 获取并清空缓存 + $content = ob_get_clean(); + + if ($this->filter) { + $content = call_user_func_array($this->filter, [$content]); + } + + return $content; + } + + /** + * 模板变量赋值 + * @access public + * @param string $name 变量名 + * @param mixed $value 变量值 + */ + public function __set($name, $value) + { + $this->data[$name] = $value; + } + + /** + * 取得模板显示变量的值 + * @access protected + * @param string $name 模板变量 + * @return mixed + */ + public function __get($name) + { + return $this->data[$name]; + } + + /** + * 检测模板变量是否设置 + * @access public + * @param string $name 模板变量名 + * @return bool + */ + public function __isset($name) + { + return isset($this->data[$name]); + } + + protected function resolveConfig(string $name) + { + $config = $this->app->config->get('view', []); + Arr::forget($config, 'type'); + return $config; + } + + /** + * 默认驱动 + * @return string|null + */ + public function getDefaultDriver() + { + return $this->app->config->get('view.type', 'php'); + } + +} diff --git a/vendor/topthink/framework/src/think/cache/Driver.php b/vendor/topthink/framework/src/think/cache/Driver.php new file mode 100644 index 000000000..5813c7b34 --- /dev/null +++ b/vendor/topthink/framework/src/think/cache/Driver.php @@ -0,0 +1,357 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\cache; + +use Closure; +use DateInterval; +use DateTime; +use DateTimeInterface; +use Exception; +use Psr\SimpleCache\CacheInterface; +use think\Container; +use think\contract\CacheHandlerInterface; +use think\exception\InvalidArgumentException; +use throwable; + +/** + * 缓存基础类 + */ +abstract class Driver implements CacheInterface, CacheHandlerInterface +{ + /** + * 驱动句柄 + * @var object + */ + protected $handler = null; + + /** + * 缓存读取次数 + * @var integer + */ + protected $readTimes = 0; + + /** + * 缓存写入次数 + * @var integer + */ + protected $writeTimes = 0; + + /** + * 缓存参数 + * @var array + */ + protected $options = []; + + /** + * 缓存标签 + * @var array + */ + protected $tag = []; + + /** + * 获取有效期 + * @access protected + * @param integer|DateTimeInterface|DateInterval $expire 有效期 + * @return int + */ + protected function getExpireTime($expire): int + { + if ($expire instanceof DateTimeInterface) { + $expire = $expire->getTimestamp() - time(); + } elseif ($expire instanceof DateInterval) { + $expire = DateTime::createFromFormat('U', (string) time()) + ->add($expire) + ->format('U') - time(); + } + + return (int) $expire; + } + + /** + * 获取实际的缓存标识 + * @access public + * @param string $name 缓存名 + * @return string + */ + public function getCacheKey(string $name): string + { + return $this->options['prefix'] . $name; + } + + /** + * 读取缓存并删除 + * @access public + * @param string $name 缓存变量名 + * @return mixed + */ + public function pull(string $name) + { + $result = $this->get($name, false); + + if ($result) { + $this->delete($name); + return $result; + } + } + + /** + * 追加(数组)缓存 + * @access public + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @return void + */ + public function push(string $name, $value): void + { + $item = $this->get($name, []); + + if (!is_array($item)) { + throw new InvalidArgumentException('only array cache can be push'); + } + + $item[] = $value; + + if (count($item) > 1000) { + array_shift($item); + } + + $item = array_unique($item); + + $this->set($name, $item); + } + + /** + * 追加TagSet数据 + * @access public + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @return void + */ + public function append(string $name, $value): void + { + $this->push($name, $value); + } + + /** + * 如果不存在则写入缓存 + * @access public + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param int $expire 有效时间 0为永久 + * @return mixed + */ + public function remember(string $name, $value, $expire = null) + { + if ($this->has($name)) { + return $this->get($name); + } + + $time = time(); + + while ($time + 5 > time() && $this->has($name . '_lock')) { + // 存在锁定则等待 + usleep(200000); + } + + try { + // 锁定 + $this->set($name . '_lock', true); + + if ($value instanceof Closure) { + // 获取缓存数据 + $value = Container::getInstance()->invokeFunction($value); + } + + // 缓存数据 + $this->set($name, $value, $expire); + + // 解锁 + $this->delete($name . '_lock'); + } catch (Exception | throwable $e) { + $this->delete($name . '_lock'); + throw $e; + } + + return $value; + } + + /** + * 缓存标签 + * @access public + * @param string|array $name 标签名 + * @return TagSet + */ + public function tag($name): TagSet + { + $name = (array) $name; + $key = implode('-', $name); + + if (!isset($this->tag[$key])) { + $this->tag[$key] = new TagSet($name, $this); + } + + return $this->tag[$key]; + } + + /** + * 获取标签包含的缓存标识 + * @access public + * @param string $tag 标签标识 + * @return array + */ + public function getTagItems(string $tag): array + { + $name = $this->getTagKey($tag); + return $this->get($name, []); + } + + /** + * 获取实际标签名 + * @access public + * @param string $tag 标签名 + * @return string + */ + public function getTagKey(string $tag): string + { + return $this->options['tag_prefix'] . md5($tag); + } + + /** + * 序列化数据 + * @access protected + * @param mixed $data 缓存数据 + * @return string + */ + protected function serialize($data): string + { + if (is_numeric($data)) { + return (string) $data; + } + + $serialize = $this->options['serialize'][0] ?? "serialize"; + + return $serialize($data); + } + + /** + * 反序列化数据 + * @access protected + * @param string $data 缓存数据 + * @return mixed + */ + protected function unserialize(string $data) + { + if (is_numeric($data)) { + return $data; + } + + $unserialize = $this->options['serialize'][1] ?? "unserialize"; + + return $unserialize($data); + } + + /** + * 返回句柄对象,可执行其它高级方法 + * + * @access public + * @return object + */ + public function handler() + { + return $this->handler; + } + + /** + * 返回缓存读取次数 + * @access public + * @return int + */ + public function getReadTimes(): int + { + return $this->readTimes; + } + + /** + * 返回缓存写入次数 + * @access public + * @return int + */ + public function getWriteTimes(): int + { + return $this->writeTimes; + } + + /** + * 读取缓存 + * @access public + * @param iterable $keys 缓存变量名 + * @param mixed $default 默认值 + * @return iterable + * @throws InvalidArgumentException + */ + public function getMultiple($keys, $default = null): iterable + { + $result = []; + + foreach ($keys as $key) { + $result[$key] = $this->get($key, $default); + } + + return $result; + } + + /** + * 写入缓存 + * @access public + * @param iterable $values 缓存数据 + * @param null|int|\DateInterval $ttl 有效时间 0为永久 + * @return bool + */ + public function setMultiple($values, $ttl = null): bool + { + foreach ($values as $key => $val) { + $result = $this->set($key, $val, $ttl); + + if (false === $result) { + return false; + } + } + + return true; + } + + /** + * 删除缓存 + * @access public + * @param iterable $keys 缓存变量名 + * @return bool + * @throws InvalidArgumentException + */ + public function deleteMultiple($keys): bool + { + foreach ($keys as $key) { + $result = $this->delete($key); + + if (false === $result) { + return false; + } + } + + return true; + } + + public function __call($method, $args) + { + return call_user_func_array([$this->handler, $method], $args); + } +} diff --git a/vendor/topthink/framework/src/think/cache/TagSet.php b/vendor/topthink/framework/src/think/cache/TagSet.php new file mode 100644 index 000000000..5ba20769a --- /dev/null +++ b/vendor/topthink/framework/src/think/cache/TagSet.php @@ -0,0 +1,132 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\cache; + +/** + * 标签集合 + */ +class TagSet +{ + /** + * 标签的缓存Key + * @var array + */ + protected $tag; + + /** + * 缓存句柄 + * @var Driver + */ + protected $handler; + + /** + * 架构函数 + * @access public + * @param array $tag 缓存标签 + * @param Driver $cache 缓存对象 + */ + public function __construct(array $tag, Driver $cache) + { + $this->tag = $tag; + $this->handler = $cache; + } + + /** + * 写入缓存 + * @access public + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param integer|\DateTime $expire 有效时间(秒) + * @return bool + */ + public function set(string $name, $value, $expire = null): bool + { + $this->handler->set($name, $value, $expire); + + $this->append($name); + + return true; + } + + /** + * 追加缓存标识到标签 + * @access public + * @param string $name 缓存变量名 + * @return void + */ + public function append(string $name): void + { + $name = $this->handler->getCacheKey($name); + + foreach ($this->tag as $tag) { + $key = $this->handler->getTagKey($tag); + $this->handler->append($key, $name); + } + } + + /** + * 写入缓存 + * @access public + * @param iterable $values 缓存数据 + * @param null|int|\DateInterval $ttl 有效时间 0为永久 + * @return bool + */ + public function setMultiple($values, $ttl = null): bool + { + foreach ($values as $key => $val) { + $result = $this->set($key, $val, $ttl); + + if (false === $result) { + return false; + } + } + + return true; + } + + /** + * 如果不存在则写入缓存 + * @access public + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param int $expire 有效时间 0为永久 + * @return mixed + */ + public function remember(string $name, $value, $expire = null) + { + $result = $this->handler->remember($name, $value, $expire); + + $this->append($name); + + return $result; + } + + /** + * 清除缓存 + * @access public + * @return bool + */ + public function clear(): bool + { + // 指定标签清除 + foreach ($this->tag as $tag) { + $names = $this->handler->getTagItems($tag); + $this->handler->clearTag($names); + + $key = $this->handler->getTagKey($tag); + $this->handler->delete($key); + } + + return true; + } +} diff --git a/vendor/topthink/framework/src/think/cache/driver/File.php b/vendor/topthink/framework/src/think/cache/driver/File.php new file mode 100644 index 000000000..b36b06965 --- /dev/null +++ b/vendor/topthink/framework/src/think/cache/driver/File.php @@ -0,0 +1,304 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\cache\driver; + +use FilesystemIterator; +use think\App; +use think\cache\Driver; + +/** + * 文件缓存类 + */ +class File extends Driver +{ + /** + * 配置参数 + * @var array + */ + protected $options = [ + 'expire' => 0, + 'cache_subdir' => true, + 'prefix' => '', + 'path' => '', + 'hash_type' => 'md5', + 'data_compress' => false, + 'tag_prefix' => 'tag:', + 'serialize' => [], + ]; + + /** + * 架构函数 + * @param App $app + * @param array $options 参数 + */ + public function __construct(App $app, array $options = []) + { + if (!empty($options)) { + $this->options = array_merge($this->options, $options); + } + + if (empty($this->options['path'])) { + $this->options['path'] = $app->getRuntimePath() . 'cache'; + } + + if (substr($this->options['path'], -1) != DIRECTORY_SEPARATOR) { + $this->options['path'] .= DIRECTORY_SEPARATOR; + } + } + + /** + * 取得变量的存储文件名 + * @access public + * @param string $name 缓存变量名 + * @return string + */ + public function getCacheKey(string $name): string + { + $name = hash($this->options['hash_type'], $name); + + if ($this->options['cache_subdir']) { + // 使用子目录 + $name = substr($name, 0, 2) . DIRECTORY_SEPARATOR . substr($name, 2); + } + + if ($this->options['prefix']) { + $name = $this->options['prefix'] . DIRECTORY_SEPARATOR . $name; + } + + return $this->options['path'] . $name . '.php'; + } + + /** + * 获取缓存数据 + * @param string $name 缓存标识名 + * @return array|null + */ + protected function getRaw(string $name) + { + $filename = $this->getCacheKey($name); + + if (!is_file($filename)) { + return; + } + + $content = @file_get_contents($filename); + + if (false !== $content) { + $expire = (int) substr($content, 8, 12); + if (0 != $expire && time() - $expire > filemtime($filename)) { + //缓存过期删除缓存文件 + $this->unlink($filename); + return; + } + + $content = substr($content, 32); + + if ($this->options['data_compress'] && function_exists('gzcompress')) { + //启用数据压缩 + $content = gzuncompress($content); + } + + return is_string($content) ? ['content' => $content, 'expire' => $expire] : null; + } + } + + /** + * 判断缓存是否存在 + * @access public + * @param string $name 缓存变量名 + * @return bool + */ + public function has($name): bool + { + return $this->getRaw($name) !== null; + } + + /** + * 读取缓存 + * @access public + * @param string $name 缓存变量名 + * @param mixed $default 默认值 + * @return mixed + */ + public function get($name, $default = null) + { + $this->readTimes++; + + $raw = $this->getRaw($name); + + return is_null($raw) ? $default : $this->unserialize($raw['content']); + } + + /** + * 写入缓存 + * @access public + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param int|\DateTime $expire 有效时间 0为永久 + * @return bool + */ + public function set($name, $value, $expire = null): bool + { + $this->writeTimes++; + + if (is_null($expire)) { + $expire = $this->options['expire']; + } + + $expire = $this->getExpireTime($expire); + $filename = $this->getCacheKey($name); + + $dir = dirname($filename); + + if (!is_dir($dir)) { + try { + mkdir($dir, 0755, true); + } catch (\Exception $e) { + // 创建失败 + } + } + + $data = $this->serialize($value); + + if ($this->options['data_compress'] && function_exists('gzcompress')) { + //数据压缩 + $data = gzcompress($data, 3); + } + + $data = "\n" . $data; + $result = file_put_contents($filename, $data); + + if ($result) { + clearstatcache(); + return true; + } + + return false; + } + + /** + * 自增缓存(针对数值缓存) + * @access public + * @param string $name 缓存变量名 + * @param int $step 步长 + * @return false|int + */ + public function inc(string $name, int $step = 1) + { + if ($raw = $this->getRaw($name)) { + $value = $this->unserialize($raw['content']) + $step; + $expire = $raw['expire']; + } else { + $value = $step; + $expire = 0; + } + + return $this->set($name, $value, $expire) ? $value : false; + } + + /** + * 自减缓存(针对数值缓存) + * @access public + * @param string $name 缓存变量名 + * @param int $step 步长 + * @return false|int + */ + public function dec(string $name, int $step = 1) + { + return $this->inc($name, -$step); + } + + /** + * 删除缓存 + * @access public + * @param string $name 缓存变量名 + * @return bool + */ + public function delete($name): bool + { + $this->writeTimes++; + + return $this->unlink($this->getCacheKey($name)); + } + + /** + * 清除缓存 + * @access public + * @return bool + */ + public function clear(): bool + { + $this->writeTimes++; + + $dirname = $this->options['path'] . $this->options['prefix']; + + $this->rmdir($dirname); + + return true; + } + + /** + * 删除缓存标签 + * @access public + * @param array $keys 缓存标识列表 + * @return void + */ + public function clearTag(array $keys): void + { + foreach ($keys as $key) { + $this->unlink($key); + } + } + + /** + * 判断文件是否存在后,删除 + * @access private + * @param string $path + * @return bool + */ + private function unlink(string $path): bool + { + try { + return is_file($path) && unlink($path); + } catch (\Exception $e) { + return false; + } + } + + /** + * 删除文件夹 + * @param $dirname + * @return bool + */ + private function rmdir($dirname) + { + if (!is_dir($dirname)) { + return false; + } + + $items = new FilesystemIterator($dirname); + + foreach ($items as $item) { + if ($item->isDir() && !$item->isLink()) { + $this->rmdir($item->getPathname()); + } else { + $this->unlink($item->getPathname()); + } + } + + @rmdir($dirname); + + return true; + } + +} diff --git a/thinkphp/library/think/cache/driver/Memcache.php b/vendor/topthink/framework/src/think/cache/driver/Memcache.php old mode 100755 new mode 100644 similarity index 64% rename from thinkphp/library/think/cache/driver/Memcache.php rename to vendor/topthink/framework/src/think/cache/driver/Memcache.php index 1c535597e..2fbbb9c72 --- a/thinkphp/library/think/cache/driver/Memcache.php +++ b/vendor/topthink/framework/src/think/cache/driver/Memcache.php @@ -2,19 +2,27 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\cache\driver; use think\cache\Driver; +/** + * Memcache缓存类 + */ class Memcache extends Driver { + /** + * 配置参数 + * @var array + */ protected $options = [ 'host' => '127.0.0.1', 'port' => 11211, @@ -22,16 +30,17 @@ class Memcache extends Driver 'timeout' => 0, // 超时时间(单位:毫秒) 'persistent' => true, 'prefix' => '', - 'serialize' => true, + 'tag_prefix' => 'tag:', + 'serialize' => [], ]; /** * 架构函数 * @access public - * @param array $options 缓存参数 + * @param array $options 缓存参数 * @throws \BadFunctionCallException */ - public function __construct($options = []) + public function __construct(array $options = []) { if (!extension_loaded('memcache')) { throw new \BadFunctionCallException('not support: memcache'); @@ -44,29 +53,29 @@ class Memcache extends Driver $this->handler = new \Memcache; // 支持集群 - $hosts = explode(',', $this->options['host']); - $ports = explode(',', $this->options['port']); + $hosts = (array) $this->options['host']; + $ports = (array) $this->options['port']; if (empty($ports[0])) { $ports[0] = 11211; } // 建立连接 - foreach ((array) $hosts as $i => $host) { - $port = isset($ports[$i]) ? $ports[$i] : $ports[0]; + foreach ($hosts as $i => $host) { + $port = $ports[$i] ?? $ports[0]; $this->options['timeout'] > 0 ? - $this->handler->addServer($host, $port, $this->options['persistent'], 1, $this->options['timeout']) : - $this->handler->addServer($host, $port, $this->options['persistent'], 1); + $this->handler->addServer($host, (int) $port, $this->options['persistent'], 1, (int) $this->options['timeout']) : + $this->handler->addServer($host, (int) $port, $this->options['persistent'], 1); } } /** * 判断缓存 * @access public - * @param string $name 缓存变量名 + * @param string $name 缓存变量名 * @return bool */ - public function has($name) + public function has($name): bool { $key = $this->getCacheKey($name); @@ -76,11 +85,11 @@ class Memcache extends Driver /** * 读取缓存 * @access public - * @param string $name 缓存变量名 - * @param mixed $default 默认值 + * @param string $name 缓存变量名 + * @param mixed $default 默认值 * @return mixed */ - public function get($name, $default = false) + public function get($name, $default = null) { $this->readTimes++; @@ -92,12 +101,12 @@ class Memcache extends Driver /** * 写入缓存 * @access public - * @param string $name 缓存变量名 - * @param mixed $value 存储数据 - * @param int|DateTime $expire 有效时间(秒) + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param int|\DateTime $expire 有效时间(秒) * @return bool */ - public function set($name, $value, $expire = null) + public function set($name, $value, $expire = null): bool { $this->writeTimes++; @@ -105,16 +114,11 @@ class Memcache extends Driver $expire = $this->options['expire']; } - if ($this->tag && !$this->has($name)) { - $first = true; - } - $key = $this->getCacheKey($name); $expire = $this->getExpireTime($expire); $value = $this->serialize($value); if ($this->handler->set($key, $value, 0, $expire)) { - isset($first) && $this->setTagItem($key); return true; } @@ -124,11 +128,11 @@ class Memcache extends Driver /** * 自增缓存(针对数值缓存) * @access public - * @param string $name 缓存变量名 - * @param int $step 步长 + * @param string $name 缓存变量名 + * @param int $step 步长 * @return false|int */ - public function inc($name, $step = 1) + public function inc(string $name, int $step = 1) { $this->writeTimes++; @@ -144,11 +148,11 @@ class Memcache extends Driver /** * 自减缓存(针对数值缓存) * @access public - * @param string $name 缓存变量名 - * @param int $step 步长 + * @param string $name 缓存变量名 + * @param int $step 步长 * @return false|int */ - public function dec($name, $step = 1) + public function dec(string $name, int $step = 1) { $this->writeTimes++; @@ -162,11 +166,11 @@ class Memcache extends Driver /** * 删除缓存 * @access public - * @param string $name 缓存变量名 - * @param bool|false $ttl + * @param string $name 缓存变量名 + * @param bool|false $ttl * @return bool */ - public function rm($name, $ttl = false) + public function delete($name, $ttl = false): bool { $this->writeTimes++; @@ -180,27 +184,26 @@ class Memcache extends Driver /** * 清除缓存 * @access public - * @param string $tag 标签名 * @return bool */ - public function clear($tag = null) + public function clear(): bool { - if ($tag) { - // 指定标签清除 - $keys = $this->getTagItem($tag); - - foreach ($keys as $key) { - $this->handler->delete($key); - } - - $tagName = $this->getTagKey($tag); - $this->rm($tagName); - return true; - } - $this->writeTimes++; return $this->handler->flush(); } + /** + * 删除缓存标签 + * @access public + * @param array $keys 缓存标识列表 + * @return void + */ + public function clearTag(array $keys): void + { + foreach ($keys as $key) { + $this->handler->delete($key); + } + } + } diff --git a/thinkphp/library/think/cache/driver/Memcached.php b/vendor/topthink/framework/src/think/cache/driver/Memcached.php old mode 100755 new mode 100644 similarity index 53% rename from thinkphp/library/think/cache/driver/Memcached.php rename to vendor/topthink/framework/src/think/cache/driver/Memcached.php index 6af60d19b..71edb058f --- a/thinkphp/library/think/cache/driver/Memcached.php +++ b/vendor/topthink/framework/src/think/cache/driver/Memcached.php @@ -2,37 +2,46 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\cache\driver; use think\cache\Driver; +/** + * Memcached缓存类 + */ class Memcached extends Driver { + /** + * 配置参数 + * @var array + */ protected $options = [ - 'host' => '127.0.0.1', - 'port' => 11211, - 'expire' => 0, - 'timeout' => 0, // 超时时间(单位:毫秒) - 'prefix' => '', - 'username' => '', //账号 - 'password' => '', //密码 - 'option' => [], - 'serialize' => true, + 'host' => '127.0.0.1', + 'port' => 11211, + 'expire' => 0, + 'timeout' => 0, // 超时时间(单位:毫秒) + 'prefix' => '', + 'username' => '', //账号 + 'password' => '', //密码 + 'option' => [], + 'tag_prefix' => 'tag:', + 'serialize' => [], ]; /** * 架构函数 * @access public - * @param array $options 缓存参数 + * @param array $options 缓存参数 */ - public function __construct($options = []) + public function __construct(array $options = []) { if (!extension_loaded('memcached')) { throw new \BadFunctionCallException('not support: memcached'); @@ -54,16 +63,16 @@ class Memcached extends Driver } // 支持集群 - $hosts = explode(',', $this->options['host']); - $ports = explode(',', $this->options['port']); + $hosts = (array) $this->options['host']; + $ports = (array) $this->options['port']; if (empty($ports[0])) { $ports[0] = 11211; } // 建立连接 $servers = []; - foreach ((array) $hosts as $i => $host) { - $servers[] = [$host, (isset($ports[$i]) ? $ports[$i] : $ports[0]), 1]; + foreach ($hosts as $i => $host) { + $servers[] = [$host, $ports[$i] ?? $ports[0], 1]; } $this->handler->addServers($servers); @@ -77,10 +86,10 @@ class Memcached extends Driver /** * 判断缓存 * @access public - * @param string $name 缓存变量名 + * @param string $name 缓存变量名 * @return bool */ - public function has($name) + public function has($name): bool { $key = $this->getCacheKey($name); @@ -90,11 +99,11 @@ class Memcached extends Driver /** * 读取缓存 * @access public - * @param string $name 缓存变量名 - * @param mixed $default 默认值 + * @param string $name 缓存变量名 + * @param mixed $default 默认值 * @return mixed */ - public function get($name, $default = false) + public function get($name, $default = null) { $this->readTimes++; @@ -106,12 +115,12 @@ class Memcached extends Driver /** * 写入缓存 * @access public - * @param string $name 缓存变量名 - * @param mixed $value 存储数据 - * @param integer|\DateTime $expire 有效时间(秒) + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param integer|\DateTime $expire 有效时间(秒) * @return bool */ - public function set($name, $value, $expire = null) + public function set($name, $value, $expire = null): bool { $this->writeTimes++; @@ -119,16 +128,11 @@ class Memcached extends Driver $expire = $this->options['expire']; } - if ($this->tag && !$this->has($name)) { - $first = true; - } - $key = $this->getCacheKey($name); $expire = $this->getExpireTime($expire); $value = $this->serialize($value); if ($this->handler->set($key, $value, $expire)) { - isset($first) && $this->setTagItem($key); return true; } @@ -138,11 +142,11 @@ class Memcached extends Driver /** * 自增缓存(针对数值缓存) * @access public - * @param string $name 缓存变量名 - * @param int $step 步长 + * @param string $name 缓存变量名 + * @param int $step 步长 * @return false|int */ - public function inc($name, $step = 1) + public function inc(string $name, int $step = 1) { $this->writeTimes++; @@ -158,11 +162,11 @@ class Memcached extends Driver /** * 自减缓存(针对数值缓存) * @access public - * @param string $name 缓存变量名 - * @param int $step 步长 + * @param string $name 缓存变量名 + * @param int $step 步长 * @return false|int */ - public function dec($name, $step = 1) + public function dec(string $name, int $step = 1) { $this->writeTimes++; @@ -176,11 +180,11 @@ class Memcached extends Driver /** * 删除缓存 * @access public - * @param string $name 缓存变量名 - * @param bool|false $ttl + * @param string $name 缓存变量名 + * @param bool|false $ttl * @return bool */ - public function rm($name, $ttl = false) + public function delete($name, $ttl = false): bool { $this->writeTimes++; @@ -194,86 +198,24 @@ class Memcached extends Driver /** * 清除缓存 * @access public - * @param string $tag 标签名 * @return bool */ - public function clear($tag = null) + public function clear(): bool { - if ($tag) { - // 指定标签清除 - $keys = $this->getTagItem($tag); - - $this->handler->deleteMulti($keys); - $this->rm($this->getTagKey($tag)); - - return true; - } - $this->writeTimes++; return $this->handler->flush(); } /** - * 缓存标签 + * 删除缓存标签 * @access public - * @param string $name 标签名 - * @param string|array $keys 缓存标识 - * @param bool $overlay 是否覆盖 - * @return $this - */ - public function tag($name, $keys = null, $overlay = false) - { - if (is_null($keys)) { - $this->tag = $name; - } else { - $tagName = $this->getTagKey($name); - if ($overlay) { - $this->handler->delete($tagName); - } - - if (!$this->handler->has($tagName)) { - $this->handler->set($tagName, ''); - } - - foreach ($keys as $key) { - $this->handler->append($tagName, ',' . $key); - } - } - - return $this; - } - - /** - * 更新标签 - * @access protected - * @param string $name 缓存标识 + * @param array $keys 缓存标识列表 * @return void */ - protected function setTagItem($name) + public function clearTag(array $keys): void { - if ($this->tag) { - $tagName = $this->getTagKey($this->tag); - - if ($this->handler->has($tagName)) { - $this->handler->append($tagName, ',' . $name); - } else { - $this->handler->set($tagName, $name); - } - - $this->tag = null; - } + $this->handler->deleteMulti($keys); } - /** - * 获取标签包含的缓存标识 - * @access public - * @param string $tag 缓存标签 - * @return array - */ - public function getTagItem($tag) - { - $tagName = $this->getTagKey($tag); - return explode(',', trim($this->handler->get($tagName), ',')); - } } diff --git a/thinkphp/library/think/cache/driver/Redis.php b/vendor/topthink/framework/src/think/cache/driver/Redis.php old mode 100755 new mode 100644 similarity index 55% rename from thinkphp/library/think/cache/driver/Redis.php rename to vendor/topthink/framework/src/think/cache/driver/Redis.php index 813746e77..791b27b88 --- a/thinkphp/library/think/cache/driver/Redis.php +++ b/vendor/topthink/framework/src/think/cache/driver/Redis.php @@ -2,12 +2,13 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\cache\driver; @@ -22,6 +23,13 @@ use think\cache\Driver; */ class Redis extends Driver { + /** @var \Predis\Client|\Redis */ + protected $handler; + + /** + * 配置参数 + * @var array + */ protected $options = [ 'host' => '127.0.0.1', 'port' => 6379, @@ -31,15 +39,16 @@ class Redis extends Driver 'expire' => 0, 'persistent' => false, 'prefix' => '', - 'serialize' => true, + 'tag_prefix' => 'tag:', + 'serialize' => [], ]; /** * 架构函数 * @access public - * @param array $options 缓存参数 + * @param array $options 缓存参数 */ - public function __construct($options = []) + public function __construct(array $options = []) { if (!empty($options)) { $this->options = array_merge($this->options, $options); @@ -49,18 +58,14 @@ class Redis extends Driver $this->handler = new \Redis; if ($this->options['persistent']) { - $this->handler->pconnect($this->options['host'], $this->options['port'], $this->options['timeout'], 'persistent_id_' . $this->options['select']); + $this->handler->pconnect($this->options['host'], (int) $this->options['port'], (int) $this->options['timeout'], 'persistent_id_' . $this->options['select']); } else { - $this->handler->connect($this->options['host'], $this->options['port'], $this->options['timeout']); + $this->handler->connect($this->options['host'], (int) $this->options['port'], (int) $this->options['timeout']); } if ('' != $this->options['password']) { $this->handler->auth($this->options['password']); } - - if (0 != $this->options['select']) { - $this->handler->select($this->options['select']); - } } elseif (class_exists('\Predis\Client')) { $params = []; foreach ($this->options as $key => $val) { @@ -80,33 +85,37 @@ class Redis extends Driver } else { throw new \BadFunctionCallException('not support: redis'); } + + if (0 != $this->options['select']) { + $this->handler->select((int) $this->options['select']); + } } /** * 判断缓存 * @access public - * @param string $name 缓存变量名 + * @param string $name 缓存变量名 * @return bool */ - public function has($name) + public function has($name): bool { - return $this->handler->exists($this->getCacheKey($name)); + return $this->handler->exists($this->getCacheKey($name)) ? true : false; } /** * 读取缓存 * @access public - * @param string $name 缓存变量名 - * @param mixed $default 默认值 + * @param string $name 缓存变量名 + * @param mixed $default 默认值 * @return mixed */ - public function get($name, $default = false) + public function get($name, $default = null) { $this->readTimes++; + $key = $this->getCacheKey($name); + $value = $this->handler->get($key); - $value = $this->handler->get($this->getCacheKey($name)); - - if (is_null($value) || false === $value) { + if (false === $value || is_null($value)) { return $default; } @@ -116,12 +125,12 @@ class Redis extends Driver /** * 写入缓存 * @access public - * @param string $name 缓存变量名 - * @param mixed $value 存储数据 - * @param integer|\DateTime $expire 有效时间(秒) - * @return boolean + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param integer|\DateTime $expire 有效时间(秒) + * @return bool */ - public function set($name, $value, $expire = null) + public function set($name, $value, $expire = null): bool { $this->writeTimes++; @@ -129,37 +138,29 @@ class Redis extends Driver $expire = $this->options['expire']; } - if ($this->tag && !$this->has($name)) { - $first = true; - } - $key = $this->getCacheKey($name); $expire = $this->getExpireTime($expire); - - $value = $this->serialize($value); + $value = $this->serialize($value); if ($expire) { - $result = $this->handler->setex($key, $expire, $value); + $this->handler->setex($key, $expire, $value); } else { - $result = $this->handler->set($key, $value); + $this->handler->set($key, $value); } - isset($first) && $this->setTagItem($key); - - return $result; + return true; } /** * 自增缓存(针对数值缓存) * @access public - * @param string $name 缓存变量名 - * @param int $step 步长 + * @param string $name 缓存变量名 + * @param int $step 步长 * @return false|int */ - public function inc($name, $step = 1) + public function inc(string $name, int $step = 1) { $this->writeTimes++; - $key = $this->getCacheKey($name); return $this->handler->incrby($key, $step); @@ -168,14 +169,13 @@ class Redis extends Driver /** * 自减缓存(针对数值缓存) * @access public - * @param string $name 缓存变量名 - * @param int $step 步长 + * @param string $name 缓存变量名 + * @param int $step 步长 * @return false|int */ - public function dec($name, $step = 1) + public function dec(string $name, int $step = 1) { $this->writeTimes++; - $key = $this->getCacheKey($name); return $this->handler->decrby($key, $step); @@ -184,89 +184,66 @@ class Redis extends Driver /** * 删除缓存 * @access public - * @param string $name 缓存变量名 - * @return boolean + * @param string $name 缓存变量名 + * @return bool */ - public function rm($name) + public function delete($name): bool { $this->writeTimes++; - return $this->handler->del($this->getCacheKey($name)); + $key = $this->getCacheKey($name); + $result = $this->handler->del($key); + return $result > 0; } /** * 清除缓存 * @access public - * @param string $tag 标签名 - * @return boolean + * @return bool */ - public function clear($tag = null) + public function clear(): bool { - if ($tag) { - // 指定标签清除 - $keys = $this->getTagItem($tag); - - $this->handler->del($keys); - - $tagName = $this->getTagKey($tag); - $this->handler->del($tagName); - return true; - } - $this->writeTimes++; - - return $this->handler->flushDB(); + $this->handler->flushDB(); + return true; } /** - * 缓存标签 + * 删除缓存标签 * @access public - * @param string $name 标签名 - * @param string|array $keys 缓存标识 - * @param bool $overlay 是否覆盖 - * @return $this - */ - public function tag($name, $keys = null, $overlay = false) - { - if (is_null($keys)) { - $this->tag = $name; - } else { - $tagName = $this->getTagKey($name); - if ($overlay) { - $this->handler->del($tagName); - } - - foreach ($keys as $key) { - $this->handler->sAdd($tagName, $key); - } - } - - return $this; - } - - /** - * 更新标签 - * @access protected - * @param string $name 缓存标识 + * @param array $keys 缓存标识列表 * @return void */ - protected function setTagItem($name) + public function clearTag(array $keys): void { - if ($this->tag) { - $tagName = $this->getTagKey($this->tag); - $this->handler->sAdd($tagName, $name); - } + // 指定标签清除 + $this->handler->del($keys); + } + + /** + * 追加TagSet数据 + * @access public + * @param string $name 缓存标识 + * @param mixed $value 数据 + * @return void + */ + public function append(string $name, $value): void + { + $key = $this->getCacheKey($name); + $this->handler->sAdd($key, $value); } /** * 获取标签包含的缓存标识 - * @access protected - * @param string $tag 缓存标签 + * @access public + * @param string $tag 缓存标签 * @return array */ - protected function getTagItem($tag) + public function getTagItems(string $tag): array { - $tagName = $this->getTagKey($tag); - return $this->handler->sMembers($tagName); + $name = $this->getTagKey($tag); + $key = $this->getCacheKey($name); + return $this->handler->sMembers($key); } + } diff --git a/thinkphp/library/think/cache/driver/Wincache.php b/vendor/topthink/framework/src/think/cache/driver/Wincache.php old mode 100755 new mode 100644 similarity index 64% rename from thinkphp/library/think/cache/driver/Wincache.php rename to vendor/topthink/framework/src/think/cache/driver/Wincache.php index ef1578417..8b3e8b863 --- a/thinkphp/library/think/cache/driver/Wincache.php +++ b/vendor/topthink/framework/src/think/cache/driver/Wincache.php @@ -2,12 +2,13 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\cache\driver; @@ -15,23 +16,27 @@ use think\cache\Driver; /** * Wincache缓存驱动 - * @author liu21st */ class Wincache extends Driver { + /** + * 配置参数 + * @var array + */ protected $options = [ - 'prefix' => '', - 'expire' => 0, - 'serialize' => true, + 'prefix' => '', + 'expire' => 0, + 'tag_prefix' => 'tag:', + 'serialize' => [], ]; /** * 架构函数 * @access public - * @param array $options 缓存参数 + * @param array $options 缓存参数 * @throws \BadFunctionCallException */ - public function __construct($options = []) + public function __construct(array $options = []) { if (!function_exists('wincache_ucache_info')) { throw new \BadFunctionCallException('not support: WinCache'); @@ -45,10 +50,10 @@ class Wincache extends Driver /** * 判断缓存 * @access public - * @param string $name 缓存变量名 + * @param string $name 缓存变量名 * @return bool */ - public function has($name) + public function has($name): bool { $this->readTimes++; @@ -60,11 +65,11 @@ class Wincache extends Driver /** * 读取缓存 * @access public - * @param string $name 缓存变量名 - * @param mixed $default 默认值 + * @param string $name 缓存变量名 + * @param mixed $default 默认值 * @return mixed */ - public function get($name, $default = false) + public function get($name, $default = null) { $this->readTimes++; @@ -76,12 +81,12 @@ class Wincache extends Driver /** * 写入缓存 * @access public - * @param string $name 缓存变量名 - * @param mixed $value 存储数据 - * @param integer|\DateTime $expire 有效时间(秒) - * @return boolean + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param integer|\DateTime $expire 有效时间(秒) + * @return bool */ - public function set($name, $value, $expire = null) + public function set($name, $value, $expire = null): bool { $this->writeTimes++; @@ -93,12 +98,7 @@ class Wincache extends Driver $expire = $this->getExpireTime($expire); $value = $this->serialize($value); - if ($this->tag && !$this->has($name)) { - $first = true; - } - if (wincache_ucache_set($key, $value, $expire)) { - isset($first) && $this->setTagItem($key); return true; } @@ -108,11 +108,11 @@ class Wincache extends Driver /** * 自增缓存(针对数值缓存) * @access public - * @param string $name 缓存变量名 - * @param int $step 步长 + * @param string $name 缓存变量名 + * @param int $step 步长 * @return false|int */ - public function inc($name, $step = 1) + public function inc(string $name, int $step = 1) { $this->writeTimes++; @@ -124,11 +124,11 @@ class Wincache extends Driver /** * 自减缓存(针对数值缓存) * @access public - * @param string $name 缓存变量名 - * @param int $step 步长 + * @param string $name 缓存变量名 + * @param int $step 步长 * @return false|int */ - public function dec($name, $step = 1) + public function dec(string $name, int $step = 1) { $this->writeTimes++; @@ -140,10 +140,10 @@ class Wincache extends Driver /** * 删除缓存 * @access public - * @param string $name 缓存变量名 - * @return boolean + * @param string $name 缓存变量名 + * @return bool */ - public function rm($name) + public function delete($name): bool { $this->writeTimes++; @@ -153,23 +153,23 @@ class Wincache extends Driver /** * 清除缓存 * @access public - * @param string $tag 标签名 - * @return boolean + * @return bool */ - public function clear($tag = null) + public function clear(): bool { - if ($tag) { - $keys = $this->getTagItem($tag); - - wincache_ucache_delete($keys); - - $tagName = $this->getTagkey($tag); - $this->rm($tagName); - return true; - } - $this->writeTimes++; return wincache_ucache_clear(); } + /** + * 删除缓存标签 + * @access public + * @param array $keys 缓存标识列表 + * @return void + */ + public function clearTag(array $keys): void + { + wincache_ucache_delete($keys); + } + } diff --git a/thinkphp/library/think/console/Command.php b/vendor/topthink/framework/src/think/console/Command.php old mode 100755 new mode 100644 similarity index 68% rename from thinkphp/library/think/console/Command.php rename to vendor/topthink/framework/src/think/console/Command.php index a208e7b54..bd3fb209b --- a/thinkphp/library/think/console/Command.php +++ b/vendor/topthink/framework/src/think/console/Command.php @@ -8,20 +8,26 @@ // +---------------------------------------------------------------------- // | Author: yunwuxin <448901948@qq.com> // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\console; +use Exception; +use InvalidArgumentException; +use LogicException; +use think\App; use think\Console; use think\console\input\Argument; use think\console\input\Definition; use think\console\input\Option; -class Command +abstract class Command { /** @var Console */ private $console; private $name; + private $processTitle; private $aliases = []; private $definition; private $help; @@ -29,9 +35,8 @@ class Command private $ignoreValidationErrors = false; private $consoleDefinitionMerged = false; private $consoleDefinitionMergedWithArgs = false; - private $code; - private $synopsis = []; - private $usages = []; + private $synopsis = []; + private $usages = []; /** @var Input */ protected $input; @@ -39,31 +44,29 @@ class Command /** @var Output */ protected $output; + /** @var App */ + protected $app; + /** * 构造方法 - * @param string|null $name 命令名称,如果没有设置则比如在 configure() 里设置 - * @throws \LogicException + * @throws LogicException * @api */ - public function __construct($name = null) + public function __construct() { $this->definition = new Definition(); - if (null !== $name) { - $this->setName($name); - } - $this->configure(); if (!$this->name) { - throw new \LogicException(sprintf('The command defined in "%s" cannot have an empty name.', get_class($this))); + throw new LogicException(sprintf('The command defined in "%s" cannot have an empty name.', get_class($this))); } } /** * 忽略验证错误 */ - public function ignoreValidationErrors() + public function ignoreValidationErrors(): void { $this->ignoreValidationErrors = true; } @@ -72,7 +75,7 @@ class Command * 设置控制台 * @param Console $console */ - public function setConsole(Console $console = null) + public function setConsole(Console $console = null): void { $this->console = $console; } @@ -82,16 +85,34 @@ class Command * @return Console * @api */ - public function getConsole() + public function getConsole(): Console { return $this->console; } + /** + * 设置app + * @param App $app + */ + public function setApp(App $app) + { + $this->app = $app; + } + + /** + * 获取app + * @return App + */ + public function getApp() + { + return $this->app; + } + /** * 是否有效 * @return bool */ - public function isEnabled() + public function isEnabled(): bool { return true; } @@ -108,12 +129,12 @@ class Command * @param Input $input * @param Output $output * @return null|int - * @throws \LogicException + * @throws LogicException * @see setCode() */ protected function execute(Input $input, Output $output) { - throw new \LogicException('You must override the execute() method in the concrete command class.'); + return $this->app->invoke([$this, 'handle']); } /** @@ -139,11 +160,11 @@ class Command * @param Input $input * @param Output $output * @return int - * @throws \Exception + * @throws Exception * @see setCode() * @see execute() */ - public function run(Input $input, Output $output) + public function run(Input $input, Output $output): int { $this->input = $input; $this->output = $output; @@ -155,7 +176,7 @@ class Command try { $input->bind($this->definition); - } catch (\Exception $e) { + } catch (Exception $e) { if (!$this->ignoreValidationErrors) { throw $e; } @@ -163,51 +184,39 @@ class Command $this->initialize($input, $output); + if (null !== $this->processTitle) { + if (function_exists('cli_set_process_title')) { + if (false === @cli_set_process_title($this->processTitle)) { + if ('Darwin' === PHP_OS) { + $output->writeln('Running "cli_get_process_title" as an unprivileged user is not supported on MacOS.'); + } else { + $error = error_get_last(); + trigger_error($error['message'], E_USER_WARNING); + } + } + } elseif (function_exists('setproctitle')) { + setproctitle($this->processTitle); + } elseif (Output::VERBOSITY_VERY_VERBOSE === $output->getVerbosity()) { + $output->writeln('Install the proctitle PECL to be able to change the process title.'); + } + } + if ($input->isInteractive()) { $this->interact($input, $output); } $input->validate(); - if ($this->code) { - $statusCode = call_user_func($this->code, $input, $output); - } else { - $statusCode = $this->execute($input, $output); - } + $statusCode = $this->execute($input, $output); return is_numeric($statusCode) ? (int) $statusCode : 0; } - /** - * 设置执行代码 - * @param callable $code callable(InputInterface $input, OutputInterface $output) - * @return Command - * @throws \InvalidArgumentException - * @see execute() - */ - public function setCode(callable $code) - { - if (!is_callable($code)) { - throw new \InvalidArgumentException('Invalid callable provided to Command::setCode.'); - } - - if (PHP_VERSION_ID >= 50400 && $code instanceof \Closure) { - $r = new \ReflectionFunction($code); - if (null === $r->getClosureThis()) { - $code = \Closure::bind($code, $this); - } - } - - $this->code = $code; - - return $this; - } - /** * 合并参数定义 * @param bool $mergeArgs */ - public function mergeConsoleDefinition($mergeArgs = true) + public function mergeConsoleDefinition(bool $mergeArgs = true) { if (null === $this->console || (true === $this->consoleDefinitionMerged @@ -254,7 +263,7 @@ class Command * @return Definition * @api */ - public function getDefinition() + public function getDefinition(): Definition { return $this->definition; } @@ -263,7 +272,7 @@ class Command * 获取当前指令的参数定义 * @return Definition */ - public function getNativeDefinition() + public function getNativeDefinition(): Definition { return $this->getDefinition(); } @@ -276,7 +285,7 @@ class Command * @param mixed $default 默认值 * @return Command */ - public function addArgument($name, $mode = null, $description = '', $default = null) + public function addArgument(string $name, int $mode = null, string $description = '', $default = null) { $this->definition->addArgument(new Argument($name, $mode, $description, $default)); @@ -292,7 +301,7 @@ class Command * @param mixed $default 默认值 * @return Command */ - public function addOption($name, $shortcut = null, $mode = null, $description = '', $default = null) + public function addOption(string $name, string $shortcut = null, int $mode = null, string $description = '', $default = null) { $this->definition->addOption(new Option($name, $shortcut, $mode, $description, $default)); @@ -303,9 +312,9 @@ class Command * 设置指令名称 * @param string $name * @return Command - * @throws \InvalidArgumentException + * @throws InvalidArgumentException */ - public function setName($name) + public function setName(string $name) { $this->validateName($name); @@ -314,13 +323,29 @@ class Command return $this; } + /** + * 设置进程名称 + * + * PHP 5.5+ or the proctitle PECL library is required + * + * @param string $title The process title + * + * @return $this + */ + public function setProcessTitle($title) + { + $this->processTitle = $title; + + return $this; + } + /** * 获取指令名称 * @return string */ - public function getName() + public function getName(): string { - return $this->name; + return $this->name ?: ''; } /** @@ -328,7 +353,7 @@ class Command * @param string $description * @return Command */ - public function setDescription($description) + public function setDescription(string $description) { $this->description = $description; @@ -339,9 +364,9 @@ class Command * 获取描述 * @return string */ - public function getDescription() + public function getDescription(): string { - return $this->description; + return $this->description ?: ''; } /** @@ -349,7 +374,7 @@ class Command * @param string $help * @return Command */ - public function setHelp($help) + public function setHelp(string $help) { $this->help = $help; @@ -360,16 +385,16 @@ class Command * 获取帮助信息 * @return string */ - public function getHelp() + public function getHelp(): string { - return $this->help; + return $this->help ?: ''; } /** * 描述信息 * @return string */ - public function getProcessedHelp() + public function getProcessedHelp(): string { $name = $this->name; @@ -389,14 +414,10 @@ class Command * 设置别名 * @param string[] $aliases * @return Command - * @throws \InvalidArgumentException + * @throws InvalidArgumentException */ - public function setAliases($aliases) + public function setAliases(iterable $aliases) { - if (!is_array($aliases) && !$aliases instanceof \Traversable) { - throw new \InvalidArgumentException('$aliases must be an array or an instance of \Traversable'); - } - foreach ($aliases as $alias) { $this->validateName($alias); } @@ -410,7 +431,7 @@ class Command * 获取别名 * @return array */ - public function getAliases() + public function getAliases(): array { return $this->aliases; } @@ -420,7 +441,7 @@ class Command * @param bool $short 是否简单的 * @return string */ - public function getSynopsis($short = false) + public function getSynopsis(bool $short = false): string { $key = $short ? 'short' : 'long'; @@ -436,7 +457,7 @@ class Command * @param string $usage * @return $this */ - public function addUsage($usage) + public function addUsage(string $usage) { if (0 !== strpos($usage, $this->name)) { $usage = sprintf('%s %s', $this->name, $usage); @@ -451,7 +472,7 @@ class Command * 获取用法介绍 * @return array */ - public function getUsages() + public function getUsages(): array { return $this->usages; } @@ -459,12 +480,12 @@ class Command /** * 验证指令名称 * @param string $name - * @throws \InvalidArgumentException + * @throws InvalidArgumentException */ - private function validateName($name) + private function validateName(string $name) { if (!preg_match('/^[^\:]++(\:[^\:]++)*$/', $name)) { - throw new \InvalidArgumentException(sprintf('Command name "%s" is invalid.', $name)); + throw new InvalidArgumentException(sprintf('Command name "%s" is invalid.', $name)); } } @@ -473,10 +494,11 @@ class Command * @param Table $table * @return string */ - protected function table(Table $table) + protected function table(Table $table): string { $content = $table->render(); $this->output->writeln($content); return $content; } + } diff --git a/thinkphp/library/think/console/Input.php b/vendor/topthink/framework/src/think/console/Input.php old mode 100755 new mode 100644 similarity index 89% rename from thinkphp/library/think/console/Input.php rename to vendor/topthink/framework/src/think/console/Input.php index 2482dfdc0..9ae907758 --- a/thinkphp/library/think/console/Input.php +++ b/vendor/topthink/framework/src/think/console/Input.php @@ -8,6 +8,7 @@ // +---------------------------------------------------------------------- // | Author: yunwuxin <448901948@qq.com> // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\console; @@ -60,7 +61,7 @@ class Input * 绑定实例 * @param Definition $definition A InputDefinition instance */ - public function bind(Definition $definition) + public function bind(Definition $definition): void { $this->arguments = []; $this->options = []; @@ -72,7 +73,7 @@ class Input /** * 解析参数 */ - protected function parse() + protected function parse(): void { $parseOptions = true; $this->parsed = $this->tokens; @@ -95,7 +96,7 @@ class Input * 解析短选项 * @param string $token 当前的指令. */ - private function parseShortOption($token) + private function parseShortOption(string $token): void { $name = substr($token, 1); @@ -117,7 +118,7 @@ class Input * @param string $name 当前指令 * @throws \RuntimeException */ - private function parseShortOptionSet($name) + private function parseShortOptionSet(string $name): void { $len = strlen($name); for ($i = 0; $i < $len; ++$i) { @@ -140,7 +141,7 @@ class Input * 解析完整选项 * @param string $token 当前指令 */ - private function parseLongOption($token) + private function parseLongOption(string $token): void { $name = substr($token, 2); @@ -156,7 +157,7 @@ class Input * @param string $token 当前指令 * @throws \RuntimeException */ - private function parseArgument($token) + private function parseArgument(string $token): void { $c = count($this->arguments); @@ -180,7 +181,7 @@ class Input * @param mixed $value 值 * @throws \RuntimeException */ - private function addShortOption($shortcut, $value) + private function addShortOption(string $shortcut, $value): void { if (!$this->definition->hasShortcut($shortcut)) { throw new \RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut)); @@ -195,7 +196,7 @@ class Input * @param mixed $value 值 * @throws \RuntimeException */ - private function addLongOption($name, $value) + private function addLongOption(string $name, $value): void { if (!$this->definition->hasOption($name)) { throw new \RuntimeException(sprintf('The "--%s" option does not exist.', $name)); @@ -260,7 +261,7 @@ class Input * @param string|array $values 需要检查的值 * @return bool */ - public function hasParameterOption($values) + public function hasParameterOption($values): bool { $values = (array) $values; @@ -318,7 +319,7 @@ class Input * 检查输入是否是交互的 * @return bool */ - public function isInteractive() + public function isInteractive(): bool { return $this->interactive; } @@ -327,16 +328,16 @@ class Input * 设置输入的交互 * @param bool */ - public function setInteractive($interactive) + public function setInteractive(bool $interactive): void { - $this->interactive = (bool) $interactive; + $this->interactive = $interactive; } /** * 获取所有的参数 * @return Argument[] */ - public function getArguments() + public function getArguments(): array { return array_merge($this->definition->getArgumentDefaults(), $this->arguments); } @@ -347,13 +348,13 @@ class Input * @return mixed * @throws \InvalidArgumentException */ - public function getArgument($name) + public function getArgument(string $name) { if (!$this->definition->hasArgument($name)) { throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); } - return isset($this->arguments[$name]) ? $this->arguments[$name] : $this->definition->getArgument($name) + return $this->arguments[$name] ?? $this->definition->getArgument($name) ->getDefault(); } @@ -363,7 +364,7 @@ class Input * @param string $value 值 * @throws \InvalidArgumentException */ - public function setArgument($name, $value) + public function setArgument(string $name, $value) { if (!$this->definition->hasArgument($name)) { throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); @@ -377,7 +378,7 @@ class Input * @param string|int $name 参数名或位置 * @return bool */ - public function hasArgument($name) + public function hasArgument($name): bool { return $this->definition->hasArgument($name); } @@ -386,7 +387,7 @@ class Input * 获取所有的选项 * @return Option[] */ - public function getOptions() + public function getOptions(): array { return array_merge($this->definition->getOptionDefaults(), $this->options); } @@ -397,13 +398,13 @@ class Input * @return mixed * @throws \InvalidArgumentException */ - public function getOption($name) + public function getOption(string $name) { if (!$this->definition->hasOption($name)) { throw new \InvalidArgumentException(sprintf('The "%s" option does not exist.', $name)); } - return isset($this->options[$name]) ? $this->options[$name] : $this->definition->getOption($name)->getDefault(); + return $this->options[$name] ?? $this->definition->getOption($name)->getDefault(); } /** @@ -412,7 +413,7 @@ class Input * @param string|bool $value 值 * @throws \InvalidArgumentException */ - public function setOption($name, $value) + public function setOption(string $name, $value): void { if (!$this->definition->hasOption($name)) { throw new \InvalidArgumentException(sprintf('The "%s" option does not exist.', $name)); @@ -426,7 +427,7 @@ class Input * @param string $name 选项名 * @return bool */ - public function hasOption($name) + public function hasOption(string $name): bool { return $this->definition->hasOption($name) && isset($this->options[$name]); } @@ -436,7 +437,7 @@ class Input * @param string $token * @return string */ - public function escapeToken($token) + public function escapeToken(string $token): string { return preg_match('{^[\w-]+$}', $token) ? $token : escapeshellarg($token); } diff --git a/thinkphp/library/think/console/LICENSE b/vendor/topthink/framework/src/think/console/LICENSE old mode 100755 new mode 100644 similarity index 100% rename from thinkphp/library/think/console/LICENSE rename to vendor/topthink/framework/src/think/console/LICENSE diff --git a/thinkphp/library/think/console/Output.php b/vendor/topthink/framework/src/think/console/Output.php old mode 100755 new mode 100644 similarity index 82% rename from thinkphp/library/think/console/Output.php rename to vendor/topthink/framework/src/think/console/Output.php index 65dc9fb81..294c4b809 --- a/thinkphp/library/think/console/Output.php +++ b/vendor/topthink/framework/src/think/console/Output.php @@ -2,12 +2,13 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2020 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: yunwuxin <448901948@qq.com> // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\console; @@ -20,6 +21,7 @@ use think\console\output\driver\Nothing; use think\console\output\Question; use think\console\output\question\Choice; use think\console\output\question\Confirmation; +use Throwable; /** * Class Output @@ -40,16 +42,22 @@ use think\console\output\question\Confirmation; */ class Output { + // 不显示信息(静默) const VERBOSITY_QUIET = 0; + // 正常信息 const VERBOSITY_NORMAL = 1; + // 详细信息 const VERBOSITY_VERBOSE = 2; + // 非常详细的信息 const VERBOSITY_VERY_VERBOSE = 3; + // 调试信息 const VERBOSITY_DEBUG = 4; const OUTPUT_NORMAL = 0; const OUTPUT_RAW = 1; const OUTPUT_PLAIN = 2; + // 输出信息级别 private $verbosity = self::VERBOSITY_NORMAL; /** @var Buffer|Console|Nothing */ @@ -61,7 +69,7 @@ class Output 'comment', 'question', 'highlight', - 'warning' + 'warning', ]; public function __construct($driver = 'console') @@ -119,7 +127,7 @@ class Output return $answer; } - protected function block($style, $message) + protected function block(string $style, string $message): void { $this->writeln("<{$style}>{$message}"); } @@ -128,7 +136,7 @@ class Output * 输出空行 * @param int $count */ - public function newLine($count = 1) + public function newLine(int $count = 1): void { $this->write(str_repeat(PHP_EOL, $count)); } @@ -138,7 +146,7 @@ class Output * @param string $messages * @param int $type */ - public function writeln($messages, $type = self::OUTPUT_NORMAL) + public function writeln(string $messages, int $type = 0): void { $this->write($messages, true, $type); } @@ -149,53 +157,55 @@ class Output * @param bool $newline * @param int $type */ - public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL) + public function write(string $messages, bool $newline = false, int $type = 0): void { $this->handle->write($messages, $newline, $type); } - public function renderException(\Exception $e) + public function renderException(Throwable $e): void { $this->handle->renderException($e); } /** - * {@inheritdoc} + * 设置输出信息级别 + * @param int $level 输出信息级别 */ - public function setVerbosity($level) + public function setVerbosity(int $level) { - $this->verbosity = (int) $level; + $this->verbosity = $level; } /** - * {@inheritdoc} + * 获取输出信息级别 + * @return int */ - public function getVerbosity() + public function getVerbosity(): int { return $this->verbosity; } - public function isQuiet() + public function isQuiet(): bool { return self::VERBOSITY_QUIET === $this->verbosity; } - public function isVerbose() + public function isVerbose(): bool { return self::VERBOSITY_VERBOSE <= $this->verbosity; } - public function isVeryVerbose() + public function isVeryVerbose(): bool { return self::VERBOSITY_VERY_VERBOSE <= $this->verbosity; } - public function isDebug() + public function isDebug(): bool { return self::VERBOSITY_DEBUG <= $this->verbosity; } - public function describe($object, array $options = []) + public function describe($object, array $options = []): void { $descriptor = new Descriptor(); $options = array_merge([ @@ -218,5 +228,4 @@ class Output throw new Exception('method not exists:' . __CLASS__ . '->' . $method); } } - } diff --git a/thinkphp/library/think/console/Table.php b/vendor/topthink/framework/src/think/console/Table.php old mode 100755 new mode 100644 similarity index 79% rename from thinkphp/library/think/console/Table.php rename to vendor/topthink/framework/src/think/console/Table.php index 9e28e266b..5a861d7fe --- a/thinkphp/library/think/console/Table.php +++ b/vendor/topthink/framework/src/think/console/Table.php @@ -8,6 +8,7 @@ // +---------------------------------------------------------------------- // | Author: yunwuxin <448901948@qq.com> // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\console; @@ -108,7 +109,7 @@ class Table * @param int $align 对齐方式 默认1 ALGIN_LEFT 0 ALIGN_RIGHT 2 ALIGN_CENTER * @return void */ - public function setHeader(array $header, $align = self::ALIGN_LEFT) + public function setHeader(array $header, int $align = 1): void { $this->header = $header; $this->headerAlign = $align; @@ -123,7 +124,7 @@ class Table * @param int $align 对齐方式 默认1 ALGIN_LEFT 0 ALIGN_RIGHT 2 ALIGN_CENTER * @return void */ - public function setRows(array $rows, $align = self::ALIGN_LEFT) + public function setRows(array $rows, int $align = 1): void { $this->rows = $rows; $this->cellAlign = $align; @@ -133,18 +134,30 @@ class Table } } + /** + * 设置全局单元格对齐方式 + * @param int $align 对齐方式 默认1 ALGIN_LEFT 0 ALIGN_RIGHT 2 ALIGN_CENTER + * @return $this + */ + public function setCellAlign(int $align = 1) + { + $this->cellAlign = $align; + return $this; + } + /** * 检查列数据的显示宽度 * @access public * @param mixed $row 行数据 * @return void */ - protected function checkColWidth($row) + protected function checkColWidth($row): void { if (is_array($row)) { foreach ($row as $key => $cell) { - if (!isset($this->colWidth[$key]) || strlen($cell) > $this->colWidth[$key]) { - $this->colWidth[$key] = strlen($cell); + $width = mb_strwidth((string) $cell); + if (!isset($this->colWidth[$key]) || $width > $this->colWidth[$key]) { + $this->colWidth[$key] = $width; } } } @@ -157,7 +170,7 @@ class Table * @param bool $first 是否在开头插入 * @return void */ - public function addRow($row, $first = false) + public function addRow($row, bool $first = false): void { if ($first) { array_unshift($this->rows, $row); @@ -174,7 +187,7 @@ class Table * @param string $style 样式名 * @return void */ - public function setStyle($style) + public function setStyle(string $style): void { $this->style = isset($this->format[$style]) ? $style : 'default'; } @@ -185,7 +198,7 @@ class Table * @param string $pos 位置 * @return string */ - protected function renderSeparator($pos) + protected function renderSeparator(string $pos): string { $style = $this->getStyle($pos); $array = []; @@ -202,7 +215,7 @@ class Table * @access public * @return string */ - protected function renderHeader() + protected function renderHeader(): string { $style = $this->getStyle('cell'); $content = $this->renderSeparator('top'); @@ -214,7 +227,7 @@ class Table if (!empty($array)) { $content .= $style[0] . implode(' ' . $style[2], $array) . ' ' . $style[3] . PHP_EOL; - if ($this->rows) { + if (!empty($this->rows)) { $content .= $this->renderSeparator('middle'); } } @@ -222,7 +235,7 @@ class Table return $content; } - protected function getStyle($style) + protected function getStyle(string $style): array { if ($this->format[$this->style]) { $style = $this->format[$this->style][$style]; @@ -239,9 +252,9 @@ class Table * @param array $dataList 表格数据 * @return string */ - public function render($dataList = []) + public function render(array $dataList = []): string { - if ($dataList) { + if (!empty($dataList)) { $this->setRows($dataList); } @@ -249,15 +262,16 @@ class Table $content = $this->renderHeader(); $style = $this->getStyle('cell'); - if ($this->rows) { + if (!empty($this->rows)) { foreach ($this->rows as $row) { if (is_string($row) && '-' === $row) { $content .= $this->renderSeparator('middle'); } elseif (is_scalar($row)) { $content .= $this->renderSeparator('cross-top'); - $array = str_pad($row, 3 * (count($this->colWidth) - 1) + array_reduce($this->colWidth, function ($a, $b) { + $width = 3 * (count($this->colWidth) - 1) + array_reduce($this->colWidth, function ($a, $b) { return $a + $b; - })); + }); + $array = str_pad($row, $width); $content .= $style[0] . ' ' . $array . ' ' . $style[3] . PHP_EOL; $content .= $this->renderSeparator('cross-bottom'); @@ -265,11 +279,16 @@ class Table $array = []; foreach ($row as $key => $val) { - $array[] = ' ' . str_pad($val, $this->colWidth[$key], ' ', $this->cellAlign); + $width = $this->colWidth[$key]; + // form https://github.com/symfony/console/blob/20c9821c8d1c2189f287dcee709b2f86353ea08f/Helper/Table.php#L467 + // str_pad won't work properly with multi-byte strings, we need to fix the padding + if (false !== $encoding = mb_detect_encoding((string) $val, null, true)) { + $width += strlen((string) $val) - mb_strwidth((string) $val, $encoding); + } + $array[] = ' ' . str_pad((string) $val, $width, ' ', $this->cellAlign); } $content .= $style[0] . implode(' ' . $style[2], $array) . ' ' . $style[3] . PHP_EOL; - } } } diff --git a/thinkphp/library/think/console/bin/README.md b/vendor/topthink/framework/src/think/console/bin/README.md old mode 100755 new mode 100644 similarity index 100% rename from thinkphp/library/think/console/bin/README.md rename to vendor/topthink/framework/src/think/console/bin/README.md diff --git a/thinkphp/library/think/console/bin/hiddeninput.exe b/vendor/topthink/framework/src/think/console/bin/hiddeninput.exe old mode 100755 new mode 100644 similarity index 100% rename from thinkphp/library/think/console/bin/hiddeninput.exe rename to vendor/topthink/framework/src/think/console/bin/hiddeninput.exe diff --git a/vendor/topthink/framework/src/think/console/command/Clear.php b/vendor/topthink/framework/src/think/console/command/Clear.php new file mode 100644 index 000000000..da70b35d6 --- /dev/null +++ b/vendor/topthink/framework/src/think/console/command/Clear.php @@ -0,0 +1,85 @@ + +// +---------------------------------------------------------------------- +namespace think\console\command; + +use think\console\Command; +use think\console\Input; +use think\console\input\Option; +use think\console\Output; + +class Clear extends Command +{ + protected function configure() + { + // 指令配置 + $this->setName('clear') + ->addOption('path', 'd', Option::VALUE_OPTIONAL, 'path to clear', null) + ->addOption('cache', 'c', Option::VALUE_NONE, 'clear cache file') + ->addOption('log', 'l', Option::VALUE_NONE, 'clear log file') + ->addOption('dir', 'r', Option::VALUE_NONE, 'clear empty dir') + ->addOption('expire', 'e', Option::VALUE_NONE, 'clear cache file if cache has expired') + ->setDescription('Clear runtime file'); + } + + protected function execute(Input $input, Output $output) + { + $runtimePath = $this->app->getRootPath() . 'runtime' . DIRECTORY_SEPARATOR; + + if ($input->getOption('cache')) { + $path = $runtimePath . 'cache'; + } elseif ($input->getOption('log')) { + $path = $runtimePath . 'log'; + } else { + $path = $input->getOption('path') ?: $runtimePath; + } + + $rmdir = $input->getOption('dir') ? true : false; + // --expire 仅当 --cache 时生效 + $cache_expire = $input->getOption('expire') && $input->getOption('cache') ? true : false; + $this->clear(rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR, $rmdir, $cache_expire); + + $output->writeln("Clear Successed"); + } + + protected function clear(string $path, bool $rmdir, bool $cache_expire): void + { + $files = is_dir($path) ? scandir($path) : []; + + foreach ($files as $file) { + if ('.' != $file && '..' != $file && is_dir($path . $file)) { + $this->clear($path . $file . DIRECTORY_SEPARATOR, $rmdir, $cache_expire); + if ($rmdir) { + @rmdir($path . $file); + } + } elseif ('.gitignore' != $file && is_file($path . $file)) { + if ($cache_expire) { + if ($this->cacheHasExpired($path . $file)) { + unlink($path . $file); + } + } else { + unlink($path . $file); + } + } + } + } + + /** + * 缓存文件是否已过期 + * @param $filename string 文件路径 + * @return bool + */ + protected function cacheHasExpired($filename) { + $content = file_get_contents($filename); + $expire = (int) substr($content, 8, 12); + return 0 != $expire && time() - $expire > filemtime($filename); + } + +} diff --git a/thinkphp/library/think/console/command/Help.php b/vendor/topthink/framework/src/think/console/command/Help.php old mode 100755 new mode 100644 similarity index 96% rename from thinkphp/library/think/console/command/Help.php rename to vendor/topthink/framework/src/think/console/command/Help.php index f1b63b42e..2e4f2ca76 --- a/thinkphp/library/think/console/command/Help.php +++ b/vendor/topthink/framework/src/think/console/command/Help.php @@ -19,6 +19,7 @@ use think\console\Output; class Help extends Command { + private $command; /** @@ -31,7 +32,8 @@ class Help extends Command $this->setName('help')->setDefinition([ new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help'), new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command help'), - ])->setDescription('Displays help for a command')->setHelp(<<setDescription('Displays help for a command')->setHelp( + <<%command.name% command displays help for a given command: php %command.full_name% list @@ -45,7 +47,7 @@ EOF * Sets the command. * @param Command $command The command to set */ - public function setCommand(Command $command) + public function setCommand(Command $command): void { $this->command = $command; } diff --git a/thinkphp/library/think/console/command/Lists.php b/vendor/topthink/framework/src/think/console/command/Lists.php old mode 100755 new mode 100644 similarity index 91% rename from thinkphp/library/think/console/command/Lists.php rename to vendor/topthink/framework/src/think/console/command/Lists.php index 6eb856c26..d20fc751b --- a/thinkphp/library/think/console/command/Lists.php +++ b/vendor/topthink/framework/src/think/console/command/Lists.php @@ -25,7 +25,8 @@ class Lists extends Command */ protected function configure() { - $this->setName('list')->setDefinition($this->createDefinition())->setDescription('Lists commands')->setHelp(<<setName('list')->setDefinition($this->createDefinition())->setDescription('Lists commands')->setHelp( + <<%command.name% command lists all commands: php %command.full_name% @@ -44,7 +45,7 @@ EOF /** * {@inheritdoc} */ - public function getNativeDefinition() + public function getNativeDefinition(): InputDefinition { return $this->createDefinition(); } @@ -63,7 +64,7 @@ EOF /** * {@inheritdoc} */ - private function createDefinition() + private function createDefinition(): InputDefinition { return new InputDefinition([ new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name'), diff --git a/thinkphp/library/think/console/command/Make.php b/vendor/topthink/framework/src/think/console/command/Make.php old mode 100755 new mode 100644 similarity index 63% rename from thinkphp/library/think/console/command/Make.php rename to vendor/topthink/framework/src/think/console/command/Make.php index 2f20954ac..662b33721 --- a/thinkphp/library/think/console/command/Make.php +++ b/vendor/topthink/framework/src/think/console/command/Make.php @@ -15,9 +15,6 @@ use think\console\Command; use think\console\Input; use think\console\input\Argument; use think\console\Output; -use think\facade\App; -use think\facade\Config; -use think\facade\Env; abstract class Make extends Command { @@ -32,7 +29,6 @@ abstract class Make extends Command protected function execute(Input $input, Output $output) { - $name = trim($input->getArgument('name')); $classname = $this->getClassName($name); @@ -40,7 +36,7 @@ abstract class Make extends Command $pathname = $this->getPathName($classname); if (is_file($pathname)) { - $output->writeln('' . $this->type . ' already exists!'); + $output->writeln('' . $this->type . ':' . $classname . ' already exists!'); return false; } @@ -50,11 +46,10 @@ abstract class Make extends Command file_put_contents($pathname, $this->buildClass($classname)); - $output->writeln('' . $this->type . ' created successfully.'); - + $output->writeln('' . $this->type . ':' . $classname . ' created successfully.'); } - protected function buildClass($name) + protected function buildClass(string $name) { $stub = file_get_contents($this->getStub()); @@ -64,47 +59,41 @@ abstract class Make extends Command return str_replace(['{%className%}', '{%actionSuffix%}', '{%namespace%}', '{%app_namespace%}'], [ $class, - Config::get('action_suffix'), + $this->app->config->get('route.action_suffix'), $namespace, - App::getNamespace(), + $this->app->getNamespace(), ], $stub); } - protected function getPathName($name) + protected function getPathName(string $name): string { - $name = str_replace(App::getNamespace() . '\\', '', $name); + $name = str_replace('app\\', '', $name); - return Env::get('app_path') . ltrim(str_replace('\\', '/', $name), '/') . '.php'; + return $this->app->getBasePath() . ltrim(str_replace('\\', '/', $name), '/') . '.php'; } - protected function getClassName($name) + protected function getClassName(string $name): string { - $appNamespace = App::getNamespace(); - - if (strpos($name, $appNamespace . '\\') !== false) { + if (strpos($name, '\\') !== false) { return $name; } - if (Config::get('app_multi_module')) { - if (strpos($name, '/')) { - list($module, $name) = explode('/', $name, 2); - } else { - $module = 'common'; - } + if (strpos($name, '@')) { + [$app, $name] = explode('@', $name); } else { - $module = null; + $app = ''; } if (strpos($name, '/') !== false) { $name = str_replace('/', '\\', $name); } - return $this->getNamespace($appNamespace, $module) . '\\' . $name; + return $this->getNamespace($app) . '\\' . $name; } - protected function getNamespace($appNamespace, $module) + protected function getNamespace(string $app): string { - return $module ? ($appNamespace . '\\' . $module) : $appNamespace; + return 'app' . ($app ? '\\' . $app : ''); } } diff --git a/thinkphp/library/think/console/command/RouteList.php b/vendor/topthink/framework/src/think/console/command/RouteList.php old mode 100755 new mode 100644 similarity index 60% rename from thinkphp/library/think/console/command/RouteList.php rename to vendor/topthink/framework/src/think/console/command/RouteList.php index 0405c31b6..ed579b856 --- a/thinkphp/library/think/console/command/RouteList.php +++ b/vendor/topthink/framework/src/think/console/command/RouteList.php @@ -16,7 +16,7 @@ use think\console\input\Argument; use think\console\input\Option; use think\console\Output; use think\console\Table; -use think\Container; +use think\event\RouteLoaded; class RouteList extends Command { @@ -31,6 +31,7 @@ class RouteList extends Command protected function configure() { $this->setName('route:list') + ->addArgument('dir', Argument::OPTIONAL, 'dir name .') ->addArgument('style', Argument::OPTIONAL, "the style of the table.", 'default') ->addOption('sort', 's', Option::VALUE_OPTIONAL, 'order by rule name.', 0) ->addOption('more', 'm', Option::VALUE_NONE, 'show route options.') @@ -39,79 +40,77 @@ class RouteList extends Command protected function execute(Input $input, Output $output) { - $filename = Container::get('app')->getRuntimePath() . 'route_list.php'; + $dir = $input->getArgument('dir') ?: ''; + + $filename = $this->app->getRootPath() . 'runtime' . DIRECTORY_SEPARATOR . ($dir ? $dir . DIRECTORY_SEPARATOR : '') . 'route_list.php'; if (is_file($filename)) { unlink($filename); + } elseif (!is_dir(dirname($filename))) { + mkdir(dirname($filename), 0755); } - $content = $this->getRouteList(); + $content = $this->getRouteList($dir); file_put_contents($filename, 'Route List' . PHP_EOL . $content); } - protected function getRouteList() + protected function getRouteList(string $dir = null): string { - Container::get('route')->setTestMode(true); - // 路由检测 - $path = Container::get('app')->getRoutePath(); + $this->app->route->setTestMode(true); + $this->app->route->clear(); + + if ($dir) { + $path = $this->app->getRootPath() . 'route' . DIRECTORY_SEPARATOR . $dir . DIRECTORY_SEPARATOR; + } else { + $path = $this->app->getRootPath() . 'route' . DIRECTORY_SEPARATOR; + } $files = is_dir($path) ? scandir($path) : []; foreach ($files as $file) { if (strpos($file, '.php')) { - $filename = $path . DIRECTORY_SEPARATOR . $file; - // 导入路由配置 - $rules = include $filename; - - if (is_array($rules)) { - Container::get('route')->import($rules); - } + include $path . $file; } } - if (Container::get('config')->get('route_annotation')) { - $suffix = Container::get('config')->get('controller_suffix') || Container::get('config')->get('class_suffix'); - - include Container::get('build')->buildRoute($suffix); - } + //触发路由载入完成事件 + $this->app->event->trigger(RouteLoaded::class); $table = new Table(); if ($this->input->hasOption('more')) { $header = ['Rule', 'Route', 'Method', 'Name', 'Domain', 'Option', 'Pattern']; } else { - $header = ['Rule', 'Route', 'Method', 'Name', 'Domain']; + $header = ['Rule', 'Route', 'Method', 'Name']; } $table->setHeader($header); - $routeList = Container::get('route')->getRuleList(); + $routeList = $this->app->route->getRuleList(); $rows = []; - foreach ($routeList as $domain => $items) { - foreach ($items as $item) { - $item['route'] = $item['route'] instanceof \Closure ? '' : $item['route']; + foreach ($routeList as $item) { + $item['route'] = $item['route'] instanceof \Closure ? '' : $item['route']; - if ($this->input->hasOption('more')) { - $item = [$item['rule'], $item['route'], $item['method'], $item['name'], $domain, json_encode($item['option']), json_encode($item['pattern'])]; - } else { - $item = [$item['rule'], $item['route'], $item['method'], $item['name'], $domain]; - } - - $rows[] = $item; + if ($this->input->hasOption('more')) { + $item = [$item['rule'], $item['route'], $item['method'], $item['name'], $item['domain'], json_encode($item['option']), json_encode($item['pattern'])]; + } else { + $item = [$item['rule'], $item['route'], $item['method'], $item['name']]; } + + $rows[] = $item; } if ($this->input->getOption('sort')) { - $sort = $this->input->getOption('sort'); + $sort = strtolower($this->input->getOption('sort')); if (isset($this->sortBy[$sort])) { $sort = $this->sortBy[$sort]; } uasort($rows, function ($a, $b) use ($sort) { - $itemA = isset($a[$sort]) ? $a[$sort] : null; - $itemB = isset($b[$sort]) ? $b[$sort] : null; + $itemA = $a[$sort] ?? null; + $itemB = $b[$sort] ?? null; return strcasecmp($itemA, $itemB); }); diff --git a/thinkphp/library/think/console/command/RunServer.php b/vendor/topthink/framework/src/think/console/command/RunServer.php old mode 100755 new mode 100644 similarity index 65% rename from thinkphp/library/think/console/command/RunServer.php rename to vendor/topthink/framework/src/think/console/command/RunServer.php index 2e028dc6d..20a246627 --- a/thinkphp/library/think/console/command/RunServer.php +++ b/vendor/topthink/framework/src/think/console/command/RunServer.php @@ -8,25 +8,41 @@ // +---------------------------------------------------------------------- // | Author: Slince // +---------------------------------------------------------------------- +declare (strict_types = 1); + namespace think\console\command; use think\console\Command; use think\console\Input; use think\console\input\Option; use think\console\Output; -use think\facade\App; class RunServer extends Command { public function configure() { $this->setName('run') - ->addOption('host', 'H', Option::VALUE_OPTIONAL, - 'The host to server the application on', '127.0.0.1') - ->addOption('port', 'p', Option::VALUE_OPTIONAL, - 'The port to server the application on', 8000) - ->addOption('root', 'r', Option::VALUE_OPTIONAL, - 'The document root of the application', App::getRootPath() . 'public') + ->addOption( + 'host', + 'H', + Option::VALUE_OPTIONAL, + 'The host to server the application on', + '0.0.0.0' + ) + ->addOption( + 'port', + 'p', + Option::VALUE_OPTIONAL, + 'The port to server the application on', + 8000 + ) + ->addOption( + 'root', + 'r', + Option::VALUE_OPTIONAL, + 'The document root of the application', + '' + ) ->setDescription('PHP Built-in Server for ThinkPHP'); } @@ -35,6 +51,9 @@ class RunServer extends Command $host = $input->getOption('host'); $port = $input->getOption('port'); $root = $input->getOption('root'); + if (empty($root)) { + $root = $this->app->getRootPath() . 'public'; + } $command = sprintf( 'php -S %s:%d -t %s %s', @@ -44,7 +63,7 @@ class RunServer extends Command escapeshellarg($root . DIRECTORY_SEPARATOR . 'router.php') ); - $output->writeln(sprintf('ThinkPHP Development server is started On ', $host, $port)); + $output->writeln(sprintf('ThinkPHP Development server is started On ', '0.0.0.0' == $host ? '127.0.0.1' : $host, $port)); $output->writeln(sprintf('You can exit with `CTRL-C`')); $output->writeln(sprintf('Document root is: %s', $root)); passthru($command); diff --git a/vendor/topthink/framework/src/think/console/command/ServiceDiscover.php b/vendor/topthink/framework/src/think/console/command/ServiceDiscover.php new file mode 100644 index 000000000..e90f43398 --- /dev/null +++ b/vendor/topthink/framework/src/think/console/command/ServiceDiscover.php @@ -0,0 +1,52 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\console\command; + +use think\console\Command; +use think\console\Input; +use think\console\Output; + +class ServiceDiscover extends Command +{ + public function configure() + { + $this->setName('service:discover') + ->setDescription('Discover Services for ThinkPHP'); + } + + public function execute(Input $input, Output $output) + { + if (is_file($path = $this->app->getRootPath() . 'vendor/composer/installed.json')) { + $packages = json_decode(@file_get_contents($path), true); + // Compatibility with Composer 2.0 + if (isset($packages['packages'])) { + $packages = $packages['packages']; + } + + $services = []; + foreach ($packages as $package) { + if (!empty($package['extra']['think']['services'])) { + $services = array_merge($services, (array) $package['extra']['think']['services']); + } + } + + $header = '// This file is automatically generated at:' . date('Y-m-d H:i:s') . PHP_EOL . 'declare (strict_types = 1);' . PHP_EOL; + + $content = 'app->getRootPath() . 'vendor/services.php', $content); + + $output->writeln('Succeed!'); + } + } +} diff --git a/vendor/topthink/framework/src/think/console/command/VendorPublish.php b/vendor/topthink/framework/src/think/console/command/VendorPublish.php new file mode 100644 index 000000000..399876575 --- /dev/null +++ b/vendor/topthink/framework/src/think/console/command/VendorPublish.php @@ -0,0 +1,69 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\console\command; + +use think\console\Command; +use think\console\input\Option; + +class VendorPublish extends Command +{ + public function configure() + { + $this->setName('vendor:publish') + ->addOption('force', 'f', Option::VALUE_NONE, 'Overwrite any existing files') + ->setDescription('Publish any publishable assets from vendor packages'); + } + + public function handle() + { + + $force = $this->input->getOption('force'); + + if (is_file($path = $this->app->getRootPath() . 'vendor/composer/installed.json')) { + $packages = json_decode(@file_get_contents($path), true); + // Compatibility with Composer 2.0 + if (isset($packages['packages'])) { + $packages = $packages['packages']; + } + foreach ($packages as $package) { + //配置 + $configDir = $this->app->getConfigPath(); + + if (!empty($package['extra']['think']['config'])) { + + $installPath = $this->app->getRootPath() . 'vendor/' . $package['name'] . DIRECTORY_SEPARATOR; + + foreach ((array) $package['extra']['think']['config'] as $name => $file) { + + $target = $configDir . $name . '.php'; + $source = $installPath . $file; + + if (is_file($target) && !$force) { + $this->output->info("File {$target} exist!"); + continue; + } + + if (!is_file($source)) { + $this->output->info("File {$source} not exist!"); + continue; + } + + copy($source, $target); + } + } + } + + $this->output->writeln('Succeed!'); + } + } +} diff --git a/thinkphp/library/think/console/command/Version.php b/vendor/topthink/framework/src/think/console/command/Version.php old mode 100755 new mode 100644 similarity index 92% rename from thinkphp/library/think/console/command/Version.php rename to vendor/topthink/framework/src/think/console/command/Version.php index ee7eca9c9..beb49d2c6 --- a/thinkphp/library/think/console/command/Version.php +++ b/vendor/topthink/framework/src/think/console/command/Version.php @@ -8,12 +8,13 @@ // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); + namespace think\console\command; use think\console\Command; use think\console\Input; use think\console\Output; -use think\facade\App; class Version extends Command { @@ -26,6 +27,7 @@ class Version extends Command protected function execute(Input $input, Output $output) { - $output->writeln('v' . App::version()); + $output->writeln('v' . $this->app->version()); } + } diff --git a/thinkphp/library/think/console/command/make/Command.php b/vendor/topthink/framework/src/think/console/command/make/Command.php old mode 100755 new mode 100644 similarity index 81% rename from thinkphp/library/think/console/command/make/Command.php rename to vendor/topthink/framework/src/think/console/command/make/Command.php index b539eb236..9549a0215 --- a/thinkphp/library/think/console/command/make/Command.php +++ b/vendor/topthink/framework/src/think/console/command/make/Command.php @@ -2,18 +2,17 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2016 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- -// | Author: 刘志淳 +// | Author: liu21st // +---------------------------------------------------------------------- namespace think\console\command\make; use think\console\command\Make; use think\console\input\Argument; -use think\facade\App; class Command extends Make { @@ -27,7 +26,7 @@ class Command extends Make ->setDescription('Create a new command class'); } - protected function buildClass($name) + protected function buildClass(string $name): string { $commandName = $this->input->getArgument('commandName') ?: strtolower(basename($name)); $namespace = trim(implode('\\', array_slice(explode('\\', $name), 0, -1)), '\\'); @@ -39,18 +38,18 @@ class Command extends Make $commandName, $class, $namespace, - App::getNamespace(), + $this->app->getNamespace(), ], $stub); } - protected function getStub() + protected function getStub(): string { return __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'command.stub'; } - protected function getNamespace($appNamespace, $module) + protected function getNamespace(string $app): string { - return $appNamespace . '\\command'; + return parent::getNamespace($app) . '\\command'; } } diff --git a/thinkphp/library/think/console/command/make/Controller.php b/vendor/topthink/framework/src/think/console/command/make/Controller.php old mode 100755 new mode 100644 similarity index 75% rename from thinkphp/library/think/console/command/make/Controller.php rename to vendor/topthink/framework/src/think/console/command/make/Controller.php index 2a6ab770d..4a8d226c0 --- a/thinkphp/library/think/console/command/make/Controller.php +++ b/vendor/topthink/framework/src/think/console/command/make/Controller.php @@ -2,21 +2,21 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2016 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- -// | Author: 刘志淳 +// | Author: liu21st // +---------------------------------------------------------------------- namespace think\console\command\make; use think\console\command\Make; use think\console\input\Option; -use think\facade\Config; class Controller extends Make { + protected $type = "Controller"; protected function configure() @@ -28,7 +28,7 @@ class Controller extends Make ->setDescription('Create a new resource controller class'); } - protected function getStub() + protected function getStub(): string { $stubPath = __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR; @@ -43,14 +43,14 @@ class Controller extends Make return $stubPath . 'controller.stub'; } - protected function getClassName($name) + protected function getClassName(string $name): string { - return parent::getClassName($name) . (Config::get('controller_suffix') ? ucfirst(Config::get('url_controller_layer')) : ''); + return parent::getClassName($name) . ($this->app->config->get('route.controller_suffix') ? 'Controller' : ''); } - protected function getNamespace($appNamespace, $module) + protected function getNamespace(string $app): string { - return parent::getNamespace($appNamespace, $module) . '\controller'; + return parent::getNamespace($app) . '\\controller'; } } diff --git a/vendor/topthink/framework/src/think/console/command/make/Event.php b/vendor/topthink/framework/src/think/console/command/make/Event.php new file mode 100644 index 000000000..6b1668984 --- /dev/null +++ b/vendor/topthink/framework/src/think/console/command/make/Event.php @@ -0,0 +1,35 @@ + +// +---------------------------------------------------------------------- +namespace think\console\command\make; + +use think\console\command\Make; + +class Event extends Make +{ + protected $type = "Event"; + + protected function configure() + { + parent::configure(); + $this->setName('make:event') + ->setDescription('Create a new event class'); + } + + protected function getStub(): string + { + return __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'event.stub'; + } + + protected function getNamespace(string $app): string + { + return parent::getNamespace($app) . '\\event'; + } +} diff --git a/vendor/topthink/framework/src/think/console/command/make/Listener.php b/vendor/topthink/framework/src/think/console/command/make/Listener.php new file mode 100644 index 000000000..5c9267368 --- /dev/null +++ b/vendor/topthink/framework/src/think/console/command/make/Listener.php @@ -0,0 +1,35 @@ + +// +---------------------------------------------------------------------- +namespace think\console\command\make; + +use think\console\command\Make; + +class Listener extends Make +{ + protected $type = "Listener"; + + protected function configure() + { + parent::configure(); + $this->setName('make:listener') + ->setDescription('Create a new listener class'); + } + + protected function getStub(): string + { + return __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'listener.stub'; + } + + protected function getNamespace(string $app): string + { + return parent::getNamespace($app) . '\\listener'; + } +} diff --git a/thinkphp/library/think/console/command/make/Middleware.php b/vendor/topthink/framework/src/think/console/command/make/Middleware.php old mode 100755 new mode 100644 similarity index 73% rename from thinkphp/library/think/console/command/make/Middleware.php rename to vendor/topthink/framework/src/think/console/command/make/Middleware.php index bfe821b03..3b68b4a7f --- a/thinkphp/library/think/console/command/make/Middleware.php +++ b/vendor/topthink/framework/src/think/console/command/make/Middleware.php @@ -1,12 +1,12 @@ +// | Author: liu21st // +---------------------------------------------------------------------- namespace think\console\command\make; @@ -24,13 +24,13 @@ class Middleware extends Make ->setDescription('Create a new middleware class'); } - protected function getStub() + protected function getStub(): string { return __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'middleware.stub'; } - protected function getNamespace($appNamespace, $module) + protected function getNamespace(string $app): string { - return parent::getNamespace($appNamespace, 'http') . '\middleware'; + return parent::getNamespace($app) . '\\middleware'; } } diff --git a/thinkphp/library/think/console/command/make/Model.php b/vendor/topthink/framework/src/think/console/command/make/Model.php old mode 100755 new mode 100644 similarity index 73% rename from thinkphp/library/think/console/command/make/Model.php rename to vendor/topthink/framework/src/think/console/command/make/Model.php index 03e6b3fcd..cb7a23c4f --- a/thinkphp/library/think/console/command/make/Model.php +++ b/vendor/topthink/framework/src/think/console/command/make/Model.php @@ -1,12 +1,12 @@ +// | Author: liu21st // +---------------------------------------------------------------------- namespace think\console\command\make; @@ -24,13 +24,13 @@ class Model extends Make ->setDescription('Create a new model class'); } - protected function getStub() + protected function getStub(): string { return __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'model.stub'; } - protected function getNamespace($appNamespace, $module) + protected function getNamespace(string $app): string { - return parent::getNamespace($appNamespace, $module) . '\model'; + return parent::getNamespace($app) . '\\model'; } } diff --git a/vendor/topthink/framework/src/think/console/command/make/Service.php b/vendor/topthink/framework/src/think/console/command/make/Service.php new file mode 100644 index 000000000..c4bbaa0eb --- /dev/null +++ b/vendor/topthink/framework/src/think/console/command/make/Service.php @@ -0,0 +1,36 @@ + +// +---------------------------------------------------------------------- + +namespace think\console\command\make; + +use think\console\command\Make; + +class Service extends Make +{ + protected $type = "Service"; + + protected function configure() + { + parent::configure(); + $this->setName('make:service') + ->setDescription('Create a new Service class'); + } + + protected function getStub(): string + { + return __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'service.stub'; + } + + protected function getNamespace(string $app): string + { + return parent::getNamespace($app) . '\\service'; + } +} diff --git a/vendor/topthink/framework/src/think/console/command/make/Subscribe.php b/vendor/topthink/framework/src/think/console/command/make/Subscribe.php new file mode 100644 index 000000000..a1dc2a820 --- /dev/null +++ b/vendor/topthink/framework/src/think/console/command/make/Subscribe.php @@ -0,0 +1,35 @@ + +// +---------------------------------------------------------------------- +namespace think\console\command\make; + +use think\console\command\Make; + +class Subscribe extends Make +{ + protected $type = "Subscribe"; + + protected function configure() + { + parent::configure(); + $this->setName('make:subscribe') + ->setDescription('Create a new subscribe class'); + } + + protected function getStub(): string + { + return __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'subscribe.stub'; + } + + protected function getNamespace(string $app): string + { + return parent::getNamespace($app) . '\\subscribe'; + } +} diff --git a/thinkphp/library/think/console/command/make/Validate.php b/vendor/topthink/framework/src/think/console/command/make/Validate.php old mode 100755 new mode 100644 similarity index 77% rename from thinkphp/library/think/console/command/make/Validate.php rename to vendor/topthink/framework/src/think/console/command/make/Validate.php index 89830ad1d..8d3643161 --- a/thinkphp/library/think/console/command/make/Validate.php +++ b/vendor/topthink/framework/src/think/console/command/make/Validate.php @@ -2,11 +2,11 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2016 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- -// | Author: 刘志淳 +// | Author: liu21st // +---------------------------------------------------------------------- namespace think\console\command\make; @@ -24,16 +24,16 @@ class Validate extends Make ->setDescription('Create a validate class'); } - protected function getStub() + protected function getStub(): string { $stubPath = __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR; return $stubPath . 'validate.stub'; } - protected function getNamespace($appNamespace, $module) + protected function getNamespace(string $app): string { - return parent::getNamespace($appNamespace, $module) . '\validate'; + return parent::getNamespace($app) . '\\validate'; } } diff --git a/thinkphp/library/think/console/command/make/stubs/command.stub b/vendor/topthink/framework/src/think/console/command/make/stubs/command.stub old mode 100755 new mode 100644 similarity index 52% rename from thinkphp/library/think/console/command/make/stubs/command.stub rename to vendor/topthink/framework/src/think/console/command/make/stubs/command.stub index d2c7c1e7e..3ee2b1cf9 --- a/thinkphp/library/think/console/command/make/stubs/command.stub +++ b/vendor/topthink/framework/src/think/console/command/make/stubs/command.stub @@ -1,9 +1,12 @@ setName('{%commandName%}'); - // 设置参数 - + $this->setName('{%commandName%}') + ->setDescription('the {%commandName%} command'); } protected function execute(Input $input, Output $output) { - // 指令输出 - $output->writeln('{%commandName%}'); + // 指令输出 + $output->writeln('{%commandName%}'); } } diff --git a/thinkphp/library/think/console/command/make/stubs/controller.api.stub b/vendor/topthink/framework/src/think/console/command/make/stubs/controller.api.stub old mode 100755 new mode 100644 similarity index 94% rename from thinkphp/library/think/console/command/make/stubs/controller.api.stub rename to vendor/topthink/framework/src/think/console/command/make/stubs/controller.api.stub index 54ec0594e..5d3383d20 --- a/thinkphp/library/think/console/command/make/stubs/controller.api.stub +++ b/vendor/topthink/framework/src/think/console/command/make/stubs/controller.api.stub @@ -1,11 +1,11 @@ ['规则1','规则2'...] + * 格式:'字段名' => ['规则1','规则2'...] * * @var array - */ - protected $rule = []; - + */ + protected $rule = []; + /** * 定义错误信息 - * 格式:'字段名.规则名' => '错误信息' + * 格式:'字段名.规则名' => '错误信息' * * @var array - */ + */ protected $message = []; } diff --git a/thinkphp/library/think/console/command/optimize/Route.php b/vendor/topthink/framework/src/think/console/command/optimize/Route.php old mode 100755 new mode 100644 similarity index 53% rename from thinkphp/library/think/console/command/optimize/Route.php rename to vendor/topthink/framework/src/think/console/command/optimize/Route.php index f6dc63288..56f7f5a9b --- a/thinkphp/library/think/console/command/optimize/Route.php +++ b/vendor/topthink/framework/src/think/console/command/optimize/Route.php @@ -12,55 +12,55 @@ namespace think\console\command\optimize; use think\console\Command; use think\console\Input; +use think\console\input\Argument; use think\console\Output; -use think\Container; +use think\event\RouteLoaded; class Route extends Command { protected function configure() { $this->setName('optimize:route') - ->setDescription('Build route cache.'); + ->addArgument('dir', Argument::OPTIONAL, 'dir name .') + ->setDescription('Build app route cache.'); } protected function execute(Input $input, Output $output) { - $filename = Container::get('app')->getRuntimePath() . 'route.php'; + $dir = $input->getArgument('dir') ?: ''; + + $path = $this->app->getRootPath() . 'runtime' . DIRECTORY_SEPARATOR . ($dir ? $dir . DIRECTORY_SEPARATOR : ''); + + $filename = $path . 'route.php'; if (is_file($filename)) { unlink($filename); } - file_put_contents($filename, $this->buildRouteCache()); + + file_put_contents($filename, $this->buildRouteCache($dir)); $output->writeln('Succeed!'); } - protected function buildRouteCache() + protected function buildRouteCache(string $dir = null): string { - Container::get('route')->setName([]); - Container::get('route')->setTestMode(true); + $this->app->route->clear(); + $this->app->route->lazy(false); + // 路由检测 - $path = Container::get('app')->getRoutePath(); + $path = $this->app->getRootPath() . ($dir ? 'app' . DIRECTORY_SEPARATOR . $dir . DIRECTORY_SEPARATOR : '') . 'route' . DIRECTORY_SEPARATOR; $files = is_dir($path) ? scandir($path) : []; foreach ($files as $file) { if (strpos($file, '.php')) { - $filename = $path . DIRECTORY_SEPARATOR . $file; - // 导入路由配置 - $rules = include $filename; - if (is_array($rules)) { - Container::get('route')->import($rules); - } + include $path . $file; } } - if (Container::get('config')->get('route_annotation')) { - $suffix = Container::get('config')->get('controller_suffix') || Container::get('config')->get('class_suffix'); - include Container::get('build')->buildRoute($suffix); - } + //触发路由载入完成事件 + $this->app->event->trigger(RouteLoaded::class); + $rules = $this->app->route->getName(); - $content = 'getName(), true) . ';'; - return $content; + return ' +// +---------------------------------------------------------------------- +namespace think\console\command\optimize; + +use Exception; +use think\console\Command; +use think\console\Input; +use think\console\input\Argument; +use think\console\input\Option; +use think\console\Output; +use think\db\PDOConnection; + +class Schema extends Command +{ + protected function configure() + { + $this->setName('optimize:schema') + ->addArgument('dir', Argument::OPTIONAL, 'dir name .') + ->addOption('connection', null, Option::VALUE_REQUIRED, 'connection name .') + ->addOption('table', null, Option::VALUE_REQUIRED, 'table name .') + ->setDescription('Build database schema cache.'); + } + + protected function execute(Input $input, Output $output) + { + $dir = $input->getArgument('dir') ?: ''; + + if ($input->hasOption('table')) { + $connection = $this->app->db->connect($input->getOption('connection')); + if (!$connection instanceof PDOConnection) { + $output->error("only PDO connection support schema cache!"); + return; + } + $table = $input->getOption('table'); + if (false === strpos($table, '.')) { + $dbName = $connection->getConfig('database'); + } else { + [$dbName, $table] = explode('.', $table); + } + + if ($table == '*') { + $table = $connection->getTables($dbName); + } + + $this->buildDataBaseSchema($connection, (array) $table, $dbName); + } else { + if ($dir) { + $appPath = $this->app->getBasePath() . $dir . DIRECTORY_SEPARATOR; + $namespace = 'app\\' . $dir; + } else { + $appPath = $this->app->getBasePath(); + $namespace = 'app'; + } + + $path = $appPath . 'model'; + $list = is_dir($path) ? scandir($path) : []; + + foreach ($list as $file) { + if (0 === strpos($file, '.')) { + continue; + } + $class = '\\' . $namespace . '\\model\\' . pathinfo($file, PATHINFO_FILENAME); + $this->buildModelSchema($class); + } + } + + $output->writeln('Succeed!'); + } + + protected function buildModelSchema(string $class): void + { + $reflect = new \ReflectionClass($class); + if (!$reflect->isAbstract() && $reflect->isSubclassOf('\think\Model')) { + try { + /** @var \think\Model $model */ + $model = new $class; + $connection = $model->db()->getConnection(); + if ($connection instanceof PDOConnection) { + $table = $model->getTable(); + //预读字段信息 + $connection->getSchemaInfo($table, true); + } + } catch (Exception $e) { + + } + } + } + + protected function buildDataBaseSchema(PDOConnection $connection, array $tables, string $dbName): void + { + foreach ($tables as $table) { + //预读字段信息 + $connection->getSchemaInfo("{$dbName}.{$table}", true); + } + } +} diff --git a/thinkphp/library/think/console/input/Argument.php b/vendor/topthink/framework/src/think/console/input/Argument.php old mode 100755 new mode 100644 similarity index 82% rename from thinkphp/library/think/console/input/Argument.php rename to vendor/topthink/framework/src/think/console/input/Argument.php index 16223bbeb..86cca36cb --- a/thinkphp/library/think/console/input/Argument.php +++ b/vendor/topthink/framework/src/think/console/input/Argument.php @@ -13,14 +13,37 @@ namespace think\console\input; class Argument { - + // 必传参数 const REQUIRED = 1; + + // 可选参数 const OPTIONAL = 2; + + // 数组参数 const IS_ARRAY = 4; + /** + * 参数名 + * @var string + */ private $name; + + /** + * 参数类型 + * @var int + */ private $mode; + + /** + * 参数默认值 + * @var mixed + */ private $default; + + /** + * 参数描述 + * @var string + */ private $description; /** @@ -31,7 +54,7 @@ class Argument * @param mixed $default 默认值 (仅 self::OPTIONAL 类型有效) * @throws \InvalidArgumentException */ - public function __construct($name, $mode = null, $description = '', $default = null) + public function __construct(string $name, int $mode = null, string $description = '', $default = null) { if (null === $mode) { $mode = self::OPTIONAL; @@ -50,7 +73,7 @@ class Argument * 获取参数名 * @return string */ - public function getName() + public function getName(): string { return $this->name; } @@ -59,7 +82,7 @@ class Argument * 是否必须 * @return bool */ - public function isRequired() + public function isRequired(): bool { return self::REQUIRED === (self::REQUIRED & $this->mode); } @@ -68,7 +91,7 @@ class Argument * 该参数是否接受数组 * @return bool */ - public function isArray() + public function isArray(): bool { return self::IS_ARRAY === (self::IS_ARRAY & $this->mode); } @@ -78,7 +101,7 @@ class Argument * @param mixed $default 默认值 * @throws \LogicException */ - public function setDefault($default = null) + public function setDefault($default = null): void { if (self::REQUIRED === $this->mode && null !== $default) { throw new \LogicException('Cannot set a default value except for InputArgument::OPTIONAL mode.'); @@ -108,7 +131,7 @@ class Argument * 获取描述 * @return string */ - public function getDescription() + public function getDescription(): string { return $this->description; } diff --git a/thinkphp/library/think/console/input/Definition.php b/vendor/topthink/framework/src/think/console/input/Definition.php old mode 100755 new mode 100644 similarity index 88% rename from thinkphp/library/think/console/input/Definition.php rename to vendor/topthink/framework/src/think/console/input/Definition.php index c71977ec3..ccf02a0c7 --- a/thinkphp/library/think/console/input/Definition.php +++ b/vendor/topthink/framework/src/think/console/input/Definition.php @@ -43,7 +43,7 @@ class Definition * 设置指令的定义 * @param array $definition 定义的数组 */ - public function setDefinition(array $definition) + public function setDefinition(array $definition): void { $arguments = []; $options = []; @@ -63,7 +63,7 @@ class Definition * 设置参数 * @param Argument[] $arguments 参数数组 */ - public function setArguments($arguments = []) + public function setArguments(array $arguments = []): void { $this->arguments = []; $this->requiredCount = 0; @@ -77,7 +77,7 @@ class Definition * @param Argument[] $arguments 参数数组 * @api */ - public function addArguments($arguments = []) + public function addArguments(array $arguments = []): void { if (null !== $arguments) { foreach ($arguments as $argument) { @@ -91,7 +91,7 @@ class Definition * @param Argument $argument 参数 * @throws \LogicException */ - public function addArgument(Argument $argument) + public function addArgument(Argument $argument): void { if (isset($this->arguments[$argument->getName()])) { throw new \LogicException(sprintf('An argument with name "%s" already exists.', $argument->getName())); @@ -124,7 +124,7 @@ class Definition * @return Argument 参数 * @throws \InvalidArgumentException */ - public function getArgument($name) + public function getArgument($name): Argument { if (!$this->hasArgument($name)) { throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); @@ -141,7 +141,7 @@ class Definition * @return bool * @api */ - public function hasArgument($name) + public function hasArgument($name): bool { $arguments = is_int($name) ? array_values($this->arguments) : $this->arguments; @@ -152,7 +152,7 @@ class Definition * 获取所有的参数 * @return Argument[] 参数数组 */ - public function getArguments() + public function getArguments(): array { return $this->arguments; } @@ -161,7 +161,7 @@ class Definition * 获取参数数量 * @return int */ - public function getArgumentCount() + public function getArgumentCount(): int { return $this->hasAnArrayArgument ? PHP_INT_MAX : count($this->arguments); } @@ -170,7 +170,7 @@ class Definition * 获取必填的参数的数量 * @return int */ - public function getArgumentRequiredCount() + public function getArgumentRequiredCount(): int { return $this->requiredCount; } @@ -179,7 +179,7 @@ class Definition * 获取参数默认值 * @return array */ - public function getArgumentDefaults() + public function getArgumentDefaults(): array { $values = []; foreach ($this->arguments as $argument) { @@ -193,7 +193,7 @@ class Definition * 设置选项 * @param Option[] $options 选项数组 */ - public function setOptions($options = []) + public function setOptions(array $options = []): void { $this->options = []; $this->shortcuts = []; @@ -205,7 +205,7 @@ class Definition * @param Option[] $options 选项数组 * @api */ - public function addOptions($options = []) + public function addOptions(array $options = []): void { foreach ($options as $option) { $this->addOption($option); @@ -218,7 +218,7 @@ class Definition * @throws \LogicException * @api */ - public function addOption(Option $option) + public function addOption(Option $option): void { if (isset($this->options[$option->getName()]) && !$option->equals($this->options[$option->getName()])) { throw new \LogicException(sprintf('An option named "%s" already exists.', $option->getName())); @@ -249,7 +249,7 @@ class Definition * @throws \InvalidArgumentException * @api */ - public function getOption($name) + public function getOption(string $name): Option { if (!$this->hasOption($name)) { throw new \InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name)); @@ -264,7 +264,7 @@ class Definition * @return bool * @api */ - public function hasOption($name) + public function hasOption(string $name): bool { return isset($this->options[$name]); } @@ -274,7 +274,7 @@ class Definition * @return Option[] * @api */ - public function getOptions() + public function getOptions(): array { return $this->options; } @@ -284,7 +284,7 @@ class Definition * @param string $name 短名称 * @return bool */ - public function hasShortcut($name) + public function hasShortcut(string $name): bool { return isset($this->shortcuts[$name]); } @@ -294,7 +294,7 @@ class Definition * @param string $shortcut 短名称 * @return Option */ - public function getOptionForShortcut($shortcut) + public function getOptionForShortcut(string $shortcut): Option { return $this->getOption($this->shortcutToName($shortcut)); } @@ -303,7 +303,7 @@ class Definition * 获取所有选项的默认值 * @return array */ - public function getOptionDefaults() + public function getOptionDefaults(): array { $values = []; foreach ($this->options as $option) { @@ -319,7 +319,7 @@ class Definition * @return string * @throws \InvalidArgumentException */ - private function shortcutToName($shortcut) + private function shortcutToName(string $shortcut): string { if (!isset($this->shortcuts[$shortcut])) { throw new \InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut)); @@ -333,7 +333,7 @@ class Definition * @param bool $short 是否简洁介绍 * @return string */ - public function getSynopsis($short = false) + public function getSynopsis(bool $short = false): string { $elements = []; diff --git a/thinkphp/library/think/console/input/Option.php b/vendor/topthink/framework/src/think/console/input/Option.php old mode 100755 new mode 100644 similarity index 93% rename from thinkphp/library/think/console/input/Option.php rename to vendor/topthink/framework/src/think/console/input/Option.php index e5707c9ae..19c7e1e86 --- a/thinkphp/library/think/console/input/Option.php +++ b/vendor/topthink/framework/src/think/console/input/Option.php @@ -11,18 +11,49 @@ namespace think\console\input; +/** + * 命令行选项 + * @package think\console\input + */ class Option { - + // 无需传值 const VALUE_NONE = 1; + // 必须传值 const VALUE_REQUIRED = 2; + // 可选传值 const VALUE_OPTIONAL = 4; + // 传数组值 const VALUE_IS_ARRAY = 8; + /** + * 选项名 + * @var string + */ private $name; + + /** + * 选项短名称 + * @var string + */ private $shortcut; + + /** + * 选项类型 + * @var int + */ private $mode; + + /** + * 选项默认值 + * @var mixed + */ private $default; + + /** + * 选项描述 + * @var string + */ private $description; /** diff --git a/thinkphp/library/think/console/output/Ask.php b/vendor/topthink/framework/src/think/console/output/Ask.php old mode 100755 new mode 100644 similarity index 99% rename from thinkphp/library/think/console/output/Ask.php rename to vendor/topthink/framework/src/think/console/output/Ask.php index 3933eb296..56821c72d --- a/thinkphp/library/think/console/output/Ask.php +++ b/vendor/topthink/framework/src/think/console/output/Ask.php @@ -197,10 +197,6 @@ class Ask $value = rtrim(shell_exec($exe)); $this->output->writeln(''); - if (isset($tmpExe)) { - unlink($tmpExe); - } - return $value; } diff --git a/thinkphp/library/think/console/output/Descriptor.php b/vendor/topthink/framework/src/think/console/output/Descriptor.php old mode 100755 new mode 100644 similarity index 94% rename from thinkphp/library/think/console/output/Descriptor.php rename to vendor/topthink/framework/src/think/console/output/Descriptor.php index 6d98d53c7..e4a9e61b8 --- a/thinkphp/library/think/console/output/Descriptor.php +++ b/vendor/topthink/framework/src/think/console/output/Descriptor.php @@ -82,7 +82,7 @@ class Descriptor $default = ''; } - $totalWidth = isset($options['total_width']) ? $options['total_width'] : strlen($argument->getName()); + $totalWidth = $options['total_width'] ?? strlen($argument->getName()); $spacingWidth = $totalWidth - strlen($argument->getName()) + 2; $this->writeText(sprintf(" %s%s%s%s", $argument->getName(), str_repeat(' ', $spacingWidth), // + 17 = 2 spaces + + + 2 spaces @@ -115,7 +115,7 @@ class Descriptor } } - $totalWidth = isset($options['total_width']) ? $options['total_width'] : $this->calculateTotalWidthForOptions([$option]); + $totalWidth = $options['total_width'] ?? $this->calculateTotalWidthForOptions([$option]); $synopsis = sprintf('%s%s', $option->getShortcut() ? sprintf('-%s, ', $option->getShortcut()) : ' ', sprintf('--%s%s', $option->getName(), $value)); $spacingWidth = $totalWidth - strlen($synopsis) + 2; @@ -216,7 +216,7 @@ class Descriptor $description = new ConsoleDescription($console, $describedNamespace); if (isset($options['raw_text']) && $options['raw_text']) { - $width = $this->getColumnWidth($description->getCommands()); + $width = $this->getColumnWidth($description->getNamespaces()); foreach ($description->getCommands() as $command) { $this->writeText(sprintf("%-${width}s %s", $command->getName(), $command->getDescription()), $options); @@ -235,7 +235,7 @@ class Descriptor $this->writeText("\n"); $this->writeText("\n"); - $width = $this->getColumnWidth($description->getCommands()); + $width = $this->getColumnWidth($description->getNamespaces()); if ($describedNamespace) { $this->writeText(sprintf('Available commands for the "%s" namespace:', $describedNamespace), $options); @@ -282,14 +282,18 @@ class Descriptor } /** - * @param Command[] $commands + * @param Namespaces[] $namespaces * @return int */ - private function getColumnWidth(array $commands) + private function getColumnWidth(array $namespaces) { $width = 0; - foreach ($commands as $command) { - $width = strlen($command->getName()) > $width ? strlen($command->getName()) : $width; + foreach ($namespaces as $namespace) { + foreach ($namespace['commands'] as $name) { + if (strlen($name) > $width) { + $width = strlen($name); + } + } } return $width + 2; diff --git a/thinkphp/library/think/console/output/Formatter.php b/vendor/topthink/framework/src/think/console/output/Formatter.php old mode 100755 new mode 100644 similarity index 98% rename from thinkphp/library/think/console/output/Formatter.php rename to vendor/topthink/framework/src/think/console/output/Formatter.php index f8bee5527..1b97ca324 --- a/thinkphp/library/think/console/output/Formatter.php +++ b/vendor/topthink/framework/src/think/console/output/Formatter.php @@ -123,7 +123,7 @@ class Formatter if ($open = '/' != $text[1]) { $tag = $matches[1][$i][0]; } else { - $tag = isset($matches[3][$i][0]) ? $matches[3][$i][0] : ''; + $tag = $matches[3][$i][0] ?? ''; } if (!$open && !$tag) { diff --git a/thinkphp/library/think/console/output/Question.php b/vendor/topthink/framework/src/think/console/output/Question.php old mode 100755 new mode 100644 similarity index 100% rename from thinkphp/library/think/console/output/Question.php rename to vendor/topthink/framework/src/think/console/output/Question.php diff --git a/thinkphp/library/think/console/output/descriptor/Console.php b/vendor/topthink/framework/src/think/console/output/descriptor/Console.php old mode 100755 new mode 100644 similarity index 92% rename from thinkphp/library/think/console/output/descriptor/Console.php rename to vendor/topthink/framework/src/think/console/output/descriptor/Console.php index 8739c536e..ff9f4641e --- a/thinkphp/library/think/console/output/descriptor/Console.php +++ b/vendor/topthink/framework/src/think/console/output/descriptor/Console.php @@ -58,7 +58,7 @@ class Console /** * @return array */ - public function getNamespaces() + public function getNamespaces(): array { if (null === $this->namespaces) { $this->inspectConsole(); @@ -70,7 +70,7 @@ class Console /** * @return Command[] */ - public function getCommands() + public function getCommands(): array { if (null === $this->commands) { $this->inspectConsole(); @@ -84,16 +84,16 @@ class Console * @return Command * @throws \InvalidArgumentException */ - public function getCommand($name) + public function getCommand(string $name): Command { if (!isset($this->commands[$name]) && !isset($this->aliases[$name])) { throw new \InvalidArgumentException(sprintf('Command %s does not exist.', $name)); } - return isset($this->commands[$name]) ? $this->commands[$name] : $this->aliases[$name]; + return $this->commands[$name] ?? $this->aliases[$name]; } - private function inspectConsole() + private function inspectConsole(): void { $this->commands = []; $this->namespaces = []; @@ -129,7 +129,7 @@ class Console * @param array $commands * @return array */ - private function sortCommands(array $commands) + private function sortCommands(array $commands): array { $namespacedCommands = []; foreach ($commands as $name => $command) { diff --git a/thinkphp/library/think/console/output/driver/Buffer.php b/vendor/topthink/framework/src/think/console/output/driver/Buffer.php old mode 100755 new mode 100644 similarity index 89% rename from thinkphp/library/think/console/output/driver/Buffer.php rename to vendor/topthink/framework/src/think/console/output/driver/Buffer.php index c77a2ec4b..576f31ac3 --- a/thinkphp/library/think/console/output/driver/Buffer.php +++ b/vendor/topthink/framework/src/think/console/output/driver/Buffer.php @@ -32,7 +32,7 @@ class Buffer return $content; } - public function write($messages, $newline = false, $options = Output::OUTPUT_NORMAL) + public function write($messages, bool $newline = false, int $options = 0) { $messages = (array) $messages; @@ -44,7 +44,7 @@ class Buffer } } - public function renderException(\Exception $e) + public function renderException(\Throwable $e) { // do nothing } diff --git a/thinkphp/library/think/console/output/driver/Console.php b/vendor/topthink/framework/src/think/console/output/driver/Console.php old mode 100755 new mode 100644 similarity index 95% rename from thinkphp/library/think/console/output/driver/Console.php rename to vendor/topthink/framework/src/think/console/output/driver/Console.php index e041b5250..31bdf1f52 --- a/thinkphp/library/think/console/output/driver/Console.php +++ b/vendor/topthink/framework/src/think/console/output/driver/Console.php @@ -42,7 +42,7 @@ class Console $this->formatter->setDecorated($decorated); } - public function write($messages, $newline = false, $type = Output::OUTPUT_NORMAL, $stream = null) + public function write($messages, bool $newline = false, int $type = 0, $stream = null) { if (Output::VERBOSITY_QUIET === $this->output->getVerbosity()) { return; @@ -68,7 +68,7 @@ class Console } } - public function renderException(\Exception $e) + public function renderException(\Throwable $e) { $stderr = $this->openErrorStream(); $decorated = $this->hasColorSupport($stderr); @@ -162,7 +162,7 @@ class Console * 获取当前终端的尺寸 * @return array */ - public function getTerminalDimensions() + public function getTerminalDimensions(): array { if ($this->terminalDimensions) { return $this->terminalDimensions; @@ -237,7 +237,7 @@ class Console return; } - private function stringWidth($string) + private function stringWidth(string $string): int { if (!function_exists('mb_strwidth')) { return strlen($string); @@ -250,7 +250,7 @@ class Console return mb_strwidth($string, $encoding); } - private function splitStringByWidth($string, $width) + private function splitStringByWidth(string $string, int $width): array { if (!function_exists('mb_strwidth')) { return str_split($string, $width); @@ -280,7 +280,7 @@ class Console return $lines; } - private function isRunningOS400() + private function isRunningOS400(): bool { $checks = [ function_exists('php_uname') ? php_uname('s') : '', @@ -295,7 +295,7 @@ class Console * * @return bool */ - protected function hasStdoutSupport() + protected function hasStdoutSupport(): bool { return false === $this->isRunningOS400(); } @@ -305,7 +305,7 @@ class Console * * @return bool */ - protected function hasStderrSupport() + protected function hasStderrSupport(): bool { return false === $this->isRunningOS400(); } @@ -352,7 +352,7 @@ class Console * @param $stream * @return bool */ - protected function hasColorSupport($stream) + protected function hasColorSupport($stream): bool { if (DIRECTORY_SEPARATOR === '\\') { return diff --git a/thinkphp/library/think/console/output/driver/Nothing.php b/vendor/topthink/framework/src/think/console/output/driver/Nothing.php old mode 100755 new mode 100644 similarity index 85% rename from thinkphp/library/think/console/output/driver/Nothing.php rename to vendor/topthink/framework/src/think/console/output/driver/Nothing.php index 9a55f7779..a7cc49e24 --- a/thinkphp/library/think/console/output/driver/Nothing.php +++ b/vendor/topthink/framework/src/think/console/output/driver/Nothing.php @@ -21,12 +21,12 @@ class Nothing // do nothing } - public function write($messages, $newline = false, $options = Output::OUTPUT_NORMAL) + public function write($messages, bool $newline = false, int $options = 0) { // do nothing } - public function renderException(\Exception $e) + public function renderException(\Throwable $e) { // do nothing } diff --git a/thinkphp/library/think/console/output/formatter/Stack.php b/vendor/topthink/framework/src/think/console/output/formatter/Stack.php old mode 100755 new mode 100644 similarity index 92% rename from thinkphp/library/think/console/output/formatter/Stack.php rename to vendor/topthink/framework/src/think/console/output/formatter/Stack.php index 4864a3f29..536625991 --- a/thinkphp/library/think/console/output/formatter/Stack.php +++ b/vendor/topthink/framework/src/think/console/output/formatter/Stack.php @@ -37,7 +37,7 @@ class Stack /** * 重置堆栈 */ - public function reset() + public function reset(): void { $this->styles = []; } @@ -46,7 +46,7 @@ class Stack * 推一个样式进入堆栈 * @param Style $style */ - public function push(Style $style) + public function push(Style $style): void { $this->styles[] = $style; } @@ -57,7 +57,7 @@ class Stack * @return Style * @throws \InvalidArgumentException */ - public function pop(Style $style = null) + public function pop(Style $style = null): Style { if (empty($this->styles)) { return $this->emptyStyle; @@ -86,7 +86,7 @@ class Stack * 计算堆栈的当前样式。 * @return Style */ - public function getCurrent() + public function getCurrent(): Style { if (empty($this->styles)) { return $this->emptyStyle; @@ -109,7 +109,7 @@ class Stack /** * @return Style */ - public function getEmptyStyle() + public function getEmptyStyle(): Style { return $this->emptyStyle; } diff --git a/thinkphp/library/think/console/output/formatter/Style.php b/vendor/topthink/framework/src/think/console/output/formatter/Style.php old mode 100755 new mode 100644 similarity index 95% rename from thinkphp/library/think/console/output/formatter/Style.php rename to vendor/topthink/framework/src/think/console/output/formatter/Style.php index d9b099987..2aae76829 --- a/thinkphp/library/think/console/output/formatter/Style.php +++ b/vendor/topthink/framework/src/think/console/output/formatter/Style.php @@ -13,8 +13,7 @@ namespace think\console\output\formatter; class Style { - - private static $availableForegroundColors = [ + protected static $availableForegroundColors = [ 'black' => ['set' => 30, 'unset' => 39], 'red' => ['set' => 31, 'unset' => 39], 'green' => ['set' => 32, 'unset' => 39], @@ -24,7 +23,8 @@ class Style 'cyan' => ['set' => 36, 'unset' => 39], 'white' => ['set' => 37, 'unset' => 39], ]; - private static $availableBackgroundColors = [ + + protected static $availableBackgroundColors = [ 'black' => ['set' => 40, 'unset' => 49], 'red' => ['set' => 41, 'unset' => 49], 'green' => ['set' => 42, 'unset' => 49], @@ -34,7 +34,8 @@ class Style 'cyan' => ['set' => 46, 'unset' => 49], 'white' => ['set' => 47, 'unset' => 49], ]; - private static $availableOptions = [ + + protected static $availableOptions = [ 'bold' => ['set' => 1, 'unset' => 22], 'underscore' => ['set' => 4, 'unset' => 24], 'blink' => ['set' => 5, 'unset' => 25], @@ -114,7 +115,7 @@ class Style * @throws \InvalidArgumentException When the option name isn't defined * @api */ - public function setOption($option) + public function setOption(string $option): void { if (!isset(static::$availableOptions[$option])) { throw new \InvalidArgumentException(sprintf('Invalid option specified: "%s". Expected one of (%s)', $option, implode(', ', array_keys(static::$availableOptions)))); @@ -130,7 +131,7 @@ class Style * @param string $option 格式名 * @throws \InvalidArgumentException */ - public function unsetOption($option) + public function unsetOption(string $option): void { if (!isset(static::$availableOptions[$option])) { throw new \InvalidArgumentException(sprintf('Invalid option specified: "%s". Expected one of (%s)', $option, implode(', ', array_keys(static::$availableOptions)))); @@ -160,7 +161,7 @@ class Style * @param string $text 文字 * @return string */ - public function apply($text) + public function apply(string $text): string { $setCodes = []; $unsetCodes = []; diff --git a/thinkphp/library/think/console/output/question/Choice.php b/vendor/topthink/framework/src/think/console/output/question/Choice.php old mode 100755 new mode 100644 similarity index 94% rename from thinkphp/library/think/console/output/question/Choice.php rename to vendor/topthink/framework/src/think/console/output/question/Choice.php index cdc3b4e4a..1da1750cc --- a/thinkphp/library/think/console/output/question/Choice.php +++ b/vendor/topthink/framework/src/think/console/output/question/Choice.php @@ -40,7 +40,7 @@ class Choice extends Question * 可选项 * @return array */ - public function getChoices() + public function getChoices(): array { return $this->choices; } @@ -50,7 +50,7 @@ class Choice extends Question * @param bool $multiselect * @return self */ - public function setMultiselect($multiselect) + public function setMultiselect(bool $multiselect) { $this->multiselect = $multiselect; $this->setValidator($this->getDefaultValidator()); @@ -58,7 +58,7 @@ class Choice extends Question return $this; } - public function isMultiselect() + public function isMultiselect(): bool { return $this->multiselect; } @@ -67,7 +67,7 @@ class Choice extends Question * 获取提示 * @return string */ - public function getPrompt() + public function getPrompt(): string { return $this->prompt; } @@ -77,7 +77,7 @@ class Choice extends Question * @param string $prompt * @return self */ - public function setPrompt($prompt) + public function setPrompt(string $prompt) { $this->prompt = $prompt; @@ -89,7 +89,7 @@ class Choice extends Question * @param string $errorMessage * @return self */ - public function setErrorMessage($errorMessage) + public function setErrorMessage(string $errorMessage) { $this->errorMessage = $errorMessage; $this->setValidator($this->getDefaultValidator()); diff --git a/thinkphp/library/think/console/output/question/Confirmation.php b/vendor/topthink/framework/src/think/console/output/question/Confirmation.php old mode 100755 new mode 100644 similarity index 94% rename from thinkphp/library/think/console/output/question/Confirmation.php rename to vendor/topthink/framework/src/think/console/output/question/Confirmation.php index 6598f9b3e..bf71b5d6d --- a/thinkphp/library/think/console/output/question/Confirmation.php +++ b/vendor/topthink/framework/src/think/console/output/question/Confirmation.php @@ -24,7 +24,7 @@ class Confirmation extends Question * @param bool $default 默认答案 * @param string $trueAnswerRegex 验证正则 */ - public function __construct($question, $default = true, $trueAnswerRegex = '/^y/i') + public function __construct(string $question, bool $default = true, string $trueAnswerRegex = '/^y/i') { parent::__construct($question, (bool) $default); diff --git a/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php b/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php new file mode 100644 index 000000000..da5e69632 --- /dev/null +++ b/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php @@ -0,0 +1,88 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\contract; + +/** + * 缓存驱动接口 + */ +interface CacheHandlerInterface +{ + /** + * 判断缓存 + * @access public + * @param string $name 缓存变量名 + * @return bool + */ + public function has($name); + + /** + * 读取缓存 + * @access public + * @param string $name 缓存变量名 + * @param mixed $default 默认值 + * @return mixed + */ + public function get($name, $default = null); + + /** + * 写入缓存 + * @access public + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param integer|\DateTime $expire 有效时间(秒) + * @return bool + */ + public function set($name, $value, $expire = null); + + /** + * 自增缓存(针对数值缓存) + * @access public + * @param string $name 缓存变量名 + * @param int $step 步长 + * @return false|int + */ + public function inc(string $name, int $step = 1); + + /** + * 自减缓存(针对数值缓存) + * @access public + * @param string $name 缓存变量名 + * @param int $step 步长 + * @return false|int + */ + public function dec(string $name, int $step = 1); + + /** + * 删除缓存 + * @access public + * @param string $name 缓存变量名 + * @return bool + */ + public function delete($name); + + /** + * 清除缓存 + * @access public + * @return bool + */ + public function clear(); + + /** + * 删除缓存标签 + * @access public + * @param array $keys 缓存标识列表 + * @return void + */ + public function clearTag(array $keys); + +} diff --git a/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php b/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php new file mode 100644 index 000000000..896ac29db --- /dev/null +++ b/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php @@ -0,0 +1,28 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\contract; + +/** + * 日志驱动接口 + */ +interface LogHandlerInterface +{ + /** + * 日志写入接口 + * @access public + * @param array $log 日志信息 + * @return bool + */ + public function save(array $log): bool; + +} diff --git a/vendor/topthink/framework/src/think/contract/ModelRelationInterface.php b/vendor/topthink/framework/src/think/contract/ModelRelationInterface.php new file mode 100644 index 000000000..1f6f994e8 --- /dev/null +++ b/vendor/topthink/framework/src/think/contract/ModelRelationInterface.php @@ -0,0 +1,99 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\contract; + +use Closure; +use think\Collection; +use think\db\Query; +use think\Model; + +/** + * 模型关联接口 + */ +interface ModelRelationInterface +{ + /** + * 延迟获取关联数据 + * @access public + * @param array $subRelation 子关联 + * @param Closure $closure 闭包查询条件 + * @return Collection + */ + public function getRelation(array $subRelation = [], Closure $closure = null): Collection; + + /** + * 预载入关联查询 + * @access public + * @param array $resultSet 数据集 + * @param string $relation 当前关联名 + * @param array $subRelation 子关联名 + * @param Closure $closure 闭包条件 + * @return void + */ + public function eagerlyResultSet(array &$resultSet, string $relation, array $subRelation, Closure $closure = null): void; + + /** + * 预载入关联查询 + * @access public + * @param Model $result 数据对象 + * @param string $relation 当前关联名 + * @param array $subRelation 子关联名 + * @param Closure $closure 闭包条件 + * @return void + */ + public function eagerlyResult(Model $result, string $relation, array $subRelation = [], Closure $closure = null): void; + + /** + * 关联统计 + * @access public + * @param Model $result 模型对象 + * @param Closure $closure 闭包 + * @param string $aggregate 聚合查询方法 + * @param string $field 字段 + * @param string $name 统计字段别名 + * @return integer + */ + public function relationCount(Model $result, Closure $closure, string $aggregate = 'count', string $field = '*', string &$name = null); + + /** + * 创建关联统计子查询 + * @access public + * @param Closure $closure 闭包 + * @param string $aggregate 聚合查询方法 + * @param string $field 字段 + * @param string $name 统计字段别名 + * @return string + */ + public function getRelationCountQuery(Closure $closure = null, string $aggregate = 'count', string $field = '*', string &$name = null): string; + + /** + * 根据关联条件查询当前模型 + * @access public + * @param string $operator 比较操作符 + * @param integer $count 个数 + * @param string $id 关联表的统计字段 + * @param string $joinType JOIN类型 + * @return Query + */ + public function has(string $operator = '>=', int $count = 1, string $id = '*', string $joinType = 'INNER'): Query; + + /** + * 根据关联条件查询当前模型 + * @access public + * @param mixed $where 查询条件(数组或者闭包) + * @param mixed $fields 字段 + * @param string $joinType JOIN类型 + * @return Query + */ + public function hasWhere($where = [], $fields = null, string $joinType = ''): Query; +} diff --git a/thinkphp/library/think/config/driver/Json.php b/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php old mode 100755 new mode 100644 similarity index 57% rename from thinkphp/library/think/config/driver/Json.php rename to vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php index 0d77c8edc..0b2e41424 --- a/thinkphp/library/think/config/driver/Json.php +++ b/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php @@ -2,30 +2,22 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); -namespace think\config\driver; +namespace think\contract; -class Json +/** + * Session驱动接口 + */ +interface SessionHandlerInterface { - protected $config; - - public function __construct($config) - { - if (is_file($config)) { - $config = file_get_contents($config); - } - - $this->config = $config; - } - - public function parse() - { - return json_decode($this->config, true); - } + public function read(string $sessionId): string; + public function delete(string $sessionId): bool; + public function write(string $sessionId, string $data): bool; } diff --git a/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php b/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php new file mode 100644 index 000000000..9be93d2e4 --- /dev/null +++ b/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php @@ -0,0 +1,61 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\contract; + +/** + * 视图驱动接口 + */ +interface TemplateHandlerInterface +{ + /** + * 检测是否存在模板文件 + * @access public + * @param string $template 模板文件或者模板规则 + * @return bool + */ + public function exists(string $template): bool; + + /** + * 渲染模板文件 + * @access public + * @param string $template 模板文件 + * @param array $data 模板变量 + * @return void + */ + public function fetch(string $template, array $data = []): void; + + /** + * 渲染模板内容 + * @access public + * @param string $content 模板内容 + * @param array $data 模板变量 + * @return void + */ + public function display(string $content, array $data = []): void; + + /** + * 配置模板引擎 + * @access private + * @param array $config 参数 + * @return void + */ + public function config(array $config): void; + + /** + * 获取模板引擎配置 + * @access public + * @param string $name 参数名 + * @return void + */ + public function getConfig(string $name); +} diff --git a/thinkphp/library/think/route/dispatch/Response.php b/vendor/topthink/framework/src/think/event/AppInit.php old mode 100755 new mode 100644 similarity index 69% rename from thinkphp/library/think/route/dispatch/Response.php rename to vendor/topthink/framework/src/think/event/AppInit.php index 66f4e5abb..dda820b5e --- a/thinkphp/library/think/route/dispatch/Response.php +++ b/vendor/topthink/framework/src/think/event/AppInit.php @@ -2,22 +2,18 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); -namespace think\route\dispatch; +namespace think\event; -use think\route\Dispatch; - -class Response extends Dispatch -{ - public function exec() - { - return $this->dispatch; - } - -} +/** + * AppInit事件类 + */ +class AppInit +{} diff --git a/thinkphp/library/think/route/dispatch/Redirect.php b/vendor/topthink/framework/src/think/event/HttpEnd.php old mode 100755 new mode 100644 similarity index 64% rename from thinkphp/library/think/route/dispatch/Redirect.php rename to vendor/topthink/framework/src/think/event/HttpEnd.php index fae2c9a65..c40da57d7 --- a/thinkphp/library/think/route/dispatch/Redirect.php +++ b/vendor/topthink/framework/src/think/event/HttpEnd.php @@ -2,22 +2,18 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); -namespace think\route\dispatch; +namespace think\event; -use think\Response; -use think\route\Dispatch; - -class Redirect extends Dispatch -{ - public function exec() - { - return Response::create($this->dispatch, 'redirect')->code($this->code); - } -} +/** + * HttpEnd事件类 + */ +class HttpEnd +{} diff --git a/vendor/topthink/framework/src/think/event/HttpRun.php b/vendor/topthink/framework/src/think/event/HttpRun.php new file mode 100644 index 000000000..ce67e93e4 --- /dev/null +++ b/vendor/topthink/framework/src/think/event/HttpRun.php @@ -0,0 +1,19 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\event; + +/** + * HttpRun事件类 + */ +class HttpRun +{} diff --git a/vendor/topthink/framework/src/think/event/LogRecord.php b/vendor/topthink/framework/src/think/event/LogRecord.php new file mode 100644 index 000000000..237468dd5 --- /dev/null +++ b/vendor/topthink/framework/src/think/event/LogRecord.php @@ -0,0 +1,29 @@ + +// +---------------------------------------------------------------------- +namespace think\event; + +/** + * LogRecord事件类 + */ +class LogRecord +{ + /** @var string */ + public $type; + + /** @var string */ + public $message; + + public function __construct($type, $message) + { + $this->type = $type; + $this->message = $message; + } +} diff --git a/thinkphp/library/think/route/dispatch/View.php b/vendor/topthink/framework/src/think/event/LogWrite.php old mode 100755 new mode 100644 similarity index 59% rename from thinkphp/library/think/route/dispatch/View.php rename to vendor/topthink/framework/src/think/event/LogWrite.php index ea3ef11b0..a7873018d --- a/thinkphp/library/think/route/dispatch/View.php +++ b/vendor/topthink/framework/src/think/event/LogWrite.php @@ -2,25 +2,30 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); -namespace think\route\dispatch; +namespace think\event; -use think\Response; -use think\route\Dispatch; - -class View extends Dispatch +/** + * LogWrite事件类 + */ +class LogWrite { - public function exec() - { - // 渲染模板输出 - $vars = array_merge($this->request->param(), $this->param); + /** @var string */ + public $channel; - return Response::create($this->dispatch, 'view')->assign($vars); + /** @var array */ + public $log; + + public function __construct($channel, $log) + { + $this->channel = $channel; + $this->log = $log; } } diff --git a/vendor/topthink/framework/src/think/event/RouteLoaded.php b/vendor/topthink/framework/src/think/event/RouteLoaded.php new file mode 100644 index 000000000..ace7992f3 --- /dev/null +++ b/vendor/topthink/framework/src/think/event/RouteLoaded.php @@ -0,0 +1,21 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\event; + +/** + * 路由加载完成事件 + */ +class RouteLoaded +{ + +} diff --git a/thinkphp/library/think/exception/ClassNotFoundException.php b/vendor/topthink/framework/src/think/exception/ClassNotFoundException.php old mode 100755 new mode 100644 similarity index 67% rename from thinkphp/library/think/exception/ClassNotFoundException.php rename to vendor/topthink/framework/src/think/exception/ClassNotFoundException.php index eb22e7301..c4cda77d5 --- a/thinkphp/library/think/exception/ClassNotFoundException.php +++ b/vendor/topthink/framework/src/think/exception/ClassNotFoundException.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006-2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -11,13 +11,20 @@ namespace think\exception; -class ClassNotFoundException extends \RuntimeException +use Psr\Container\NotFoundExceptionInterface; +use RuntimeException; +use Throwable; + +class ClassNotFoundException extends RuntimeException implements NotFoundExceptionInterface { protected $class; - public function __construct($message, $class = '') + + public function __construct(string $message, string $class = '', Throwable $previous = null) { $this->message = $message; $this->class = $class; + + parent::__construct($message, 0, $previous); } /** diff --git a/thinkphp/library/think/exception/ErrorException.php b/vendor/topthink/framework/src/think/exception/ErrorException.php old mode 100755 new mode 100644 similarity index 89% rename from thinkphp/library/think/exception/ErrorException.php rename to vendor/topthink/framework/src/think/exception/ErrorException.php index 3143b8f70..d1a237803 --- a/thinkphp/library/think/exception/ErrorException.php +++ b/vendor/topthink/framework/src/think/exception/ErrorException.php @@ -2,12 +2,13 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: 麦当苗儿 // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\exception; @@ -35,7 +36,7 @@ class ErrorException extends Exception * @param string $file 出错文件路径 * @param integer $line 出错行号 */ - public function __construct($severity, $message, $file, $line) + public function __construct(int $severity, string $message, string $file, int $line) { $this->severity = $severity; $this->message = $message; diff --git a/vendor/topthink/framework/src/think/exception/FileException.php b/vendor/topthink/framework/src/think/exception/FileException.php new file mode 100644 index 000000000..228a1898c --- /dev/null +++ b/vendor/topthink/framework/src/think/exception/FileException.php @@ -0,0 +1,17 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\exception; + +class FileException extends \RuntimeException +{ +} diff --git a/vendor/topthink/framework/src/think/exception/FuncNotFoundException.php b/vendor/topthink/framework/src/think/exception/FuncNotFoundException.php new file mode 100644 index 000000000..ee2bcad2e --- /dev/null +++ b/vendor/topthink/framework/src/think/exception/FuncNotFoundException.php @@ -0,0 +1,30 @@ +message = $message; + $this->func = $func; + + parent::__construct($message, 0, $previous); + } + + /** + * 获取方法名 + * @access public + * @return string + */ + public function getFunc() + { + return $this->func; + } +} diff --git a/thinkphp/library/think/exception/Handle.php b/vendor/topthink/framework/src/think/exception/Handle.php old mode 100755 new mode 100644 similarity index 54% rename from thinkphp/library/think/exception/Handle.php rename to vendor/topthink/framework/src/think/exception/Handle.php index 02c85ec13..1f783bc52 --- a/thinkphp/library/think/exception/Handle.php +++ b/vendor/topthink/framework/src/think/exception/Handle.php @@ -2,44 +2,60 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006-2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: yunwuxin <448901948@qq.com> // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\exception; use Exception; +use think\App; use think\console\Output; -use think\Container; +use think\db\exception\DataNotFoundException; +use think\db\exception\ModelNotFoundException; +use think\Request; use think\Response; +use Throwable; +/** + * 系统异常处理类 + */ class Handle { - protected $render; + /** @var App */ + protected $app; + protected $ignoreReport = [ - '\\think\\exception\\HttpException', + HttpException::class, + HttpResponseException::class, + ModelNotFoundException::class, + DataNotFoundException::class, + ValidateException::class, ]; - public function setRender($render) + protected $isJson = false; + + public function __construct(App $app) { - $this->render = $render; + $this->app = $app; } /** * Report or log an exception. * * @access public - * @param \Exception $exception + * @param Throwable $exception * @return void */ - public function report(Exception $exception) + public function report(Throwable $exception): void { if (!$this->isIgnoreReport($exception)) { // 收集异常数据 - if (Container::get('app')->isDebug()) { + if ($this->app->isDebug()) { $data = [ 'file' => $exception->getFile(), 'line' => $exception->getLine(), @@ -55,15 +71,17 @@ class Handle $log = "[{$data['code']}]{$data['message']}"; } - if (Container::get('app')->config('log.record_trace')) { - $log .= "\r\n" . $exception->getTraceAsString(); + if ($this->app->config->get('log.record_trace')) { + $log .= PHP_EOL . $exception->getTraceAsString(); } - Container::get('log')->record($log, 'error'); + try { + $this->app->log->record($log, 'error'); + } catch (Exception $e) {} } } - protected function isIgnoreReport(Exception $exception) + protected function isIgnoreReport(Throwable $exception): bool { foreach ($this->ignoreReport as $class) { if ($exception instanceof $class) { @@ -78,20 +96,16 @@ class Handle * Render an exception into an HTTP response. * * @access public - * @param \Exception $e + * @param Request $request + * @param Throwable $e * @return Response */ - public function render(Exception $e) + public function render($request, Throwable $e): Response { - if ($this->render && $this->render instanceof \Closure) { - $result = call_user_func_array($this->render, [$e]); - - if ($result) { - return $result; - } - } - - if ($e instanceof HttpException) { + $this->isJson = $request->isJson(); + if ($e instanceof HttpResponseException) { + return $e->getResponse(); + } elseif ($e instanceof HttpException) { return $this->renderHttpException($e); } else { return $this->convertExceptionToResponse($e); @@ -100,12 +114,12 @@ class Handle /** * @access public - * @param Output $output - * @param Exception $e + * @param Output $output + * @param Throwable $e */ - public function renderForConsole(Output $output, Exception $e) + public function renderForConsole(Output $output, Throwable $e): void { - if (Container::get('app')->isDebug()) { + if ($this->app->isDebug()) { $output->setVerbosity(Output::VERBOSITY_DEBUG); } @@ -114,15 +128,15 @@ class Handle /** * @access protected - * @param HttpException $e + * @param HttpException $e * @return Response */ - protected function renderHttpException(HttpException $e) + protected function renderHttpException(HttpException $e): Response { $status = $e->getStatusCode(); - $template = Container::get('app')->config('http_exception_template'); + $template = $this->app->config->get('app.http_exception_template'); - if (!Container::get('app')->isDebug() && !empty($template[$status])) { + if (!$this->app->isDebug() && !empty($template[$status])) { return Response::create($template[$status], 'view', $status)->assign(['e' => $e]); } else { return $this->convertExceptionToResponse($e); @@ -130,33 +144,39 @@ class Handle } /** - * @access protected - * @param Exception $exception - * @return Response + * 收集异常数据 + * @param Throwable $exception + * @return array */ - protected function convertExceptionToResponse(Exception $exception) + protected function convertExceptionToArray(Throwable $exception): array { - // 收集异常数据 - if (Container::get('app')->isDebug()) { + if ($this->app->isDebug()) { // 调试模式,获取详细的错误信息 + $traces = []; + $nextException = $exception; + do { + $traces[] = [ + 'name' => get_class($nextException), + 'file' => $nextException->getFile(), + 'line' => $nextException->getLine(), + 'code' => $this->getCode($nextException), + 'message' => $this->getMessage($nextException), + 'trace' => $nextException->getTrace(), + 'source' => $this->getSourceCode($nextException), + ]; + } while ($nextException = $nextException->getPrevious()); $data = [ - 'name' => get_class($exception), - 'file' => $exception->getFile(), - 'line' => $exception->getLine(), - 'message' => $this->getMessage($exception), - 'trace' => $exception->getTrace(), 'code' => $this->getCode($exception), - 'source' => $this->getSourceCode($exception), + 'message' => $this->getMessage($exception), + 'traces' => $traces, 'datas' => $this->getExtendData($exception), 'tables' => [ - 'GET Data' => $_GET, - 'POST Data' => $_POST, - 'Files' => $_FILES, - 'Cookies' => $_COOKIE, - 'Session' => isset($_SESSION) ? $_SESSION : [], - 'Server/Request Data' => $_SERVER, - 'Environment Variables' => $_ENV, - 'ThinkPHP Constants' => $this->getConst(), + 'GET Data' => $this->app->request->get(), + 'POST Data' => $this->app->request->post(), + 'Files' => $this->app->request->file(), + 'Cookies' => $this->app->request->cookie(), + 'Session' => $this->app->exists('session') ? $this->app->session->all() : [], + 'Server/Request Data' => $this->app->request->server(), ], ]; } else { @@ -166,48 +186,54 @@ class Handle 'message' => $this->getMessage($exception), ]; - if (!Container::get('app')->config('show_error_msg')) { + if (!$this->app->config->get('app.show_error_msg')) { // 不显示详细错误信息 - $data['message'] = Container::get('app')->config('error_message'); + $data['message'] = $this->app->config->get('app.error_message'); } } - //保留一层 - while (ob_get_level() > 1) { - ob_end_clean(); + return $data; + } + + /** + * @access protected + * @param Throwable $exception + * @return Response + */ + protected function convertExceptionToResponse(Throwable $exception): Response + { + if (!$this->isJson) { + $response = Response::create($this->renderExceptionContent($exception)); + } else { + $response = Response::create($this->convertExceptionToArray($exception), 'json'); } - $data['echo'] = ob_get_clean(); - - ob_start(); - extract($data); - include Container::get('app')->config('exception_tmpl'); - - // 获取并清空缓存 - $content = ob_get_clean(); - $response = Response::create($content, 'html'); - if ($exception instanceof HttpException) { $statusCode = $exception->getStatusCode(); $response->header($exception->getHeaders()); } - if (!isset($statusCode)) { - $statusCode = 500; - } - $response->code($statusCode); + return $response->code($statusCode ?? 500); + } - return $response; + protected function renderExceptionContent(Throwable $exception): string + { + ob_start(); + $data = $this->convertExceptionToArray($exception); + extract($data); + include $this->app->config->get('app.exception_tmpl') ?: __DIR__ . '/../../tpl/think_exception.tpl'; + + return ob_get_clean(); } /** * 获取错误编码 * ErrorException则使用错误级别作为错误编码 * @access protected - * @param \Exception $exception + * @param Throwable $exception * @return integer 错误编码 */ - protected function getCode(Exception $exception) + protected function getCode(Throwable $exception) { $code = $exception->getCode(); @@ -222,18 +248,18 @@ class Handle * 获取错误信息 * ErrorException则使用错误级别作为错误编码 * @access protected - * @param \Exception $exception + * @param Throwable $exception * @return string 错误信息 */ - protected function getMessage(Exception $exception) + protected function getMessage(Throwable $exception): string { $message = $exception->getMessage(); - if (PHP_SAPI == 'cli') { + if ($this->app->runningInConsole()) { return $message; } - $lang = Container::get('lang'); + $lang = $this->app->lang; if (strpos($message, ':')) { $name = strstr($message, ':', true); @@ -252,17 +278,17 @@ class Handle * 获取出错文件内容 * 获取错误的前9行和后9行 * @access protected - * @param \Exception $exception + * @param Throwable $exception * @return array 错误文件内容 */ - protected function getSourceCode(Exception $exception) + protected function getSourceCode(Throwable $exception): array { // 读取前9行和后9行 $line = $exception->getLine(); $first = ($line - 9 > 0) ? $line - 9 : 1; try { - $contents = file($exception->getFile()); + $contents = file($exception->getFile()) ?: []; $source = [ 'first' => $first, 'source' => array_slice($contents, $first - 1, 19), @@ -278,10 +304,10 @@ class Handle * 获取异常扩展信息 * 用于非调试模式html返回类型显示 * @access protected - * @param \Exception $exception + * @param Throwable $exception * @return array 异常类定义的扩展数据 */ - protected function getExtendData(Exception $exception) + protected function getExtendData(Throwable $exception): array { $data = []; @@ -294,13 +320,13 @@ class Handle /** * 获取常量列表 - * @access private + * @access protected * @return array 常量列表 */ - private static function getConst() + protected function getConst(): array { $const = get_defined_constants(true); - return isset($const['user']) ? $const['user'] : []; + return $const['user'] ?? []; } } diff --git a/thinkphp/library/think/exception/HttpException.php b/vendor/topthink/framework/src/think/exception/HttpException.php old mode 100755 new mode 100644 similarity index 78% rename from thinkphp/library/think/exception/HttpException.php rename to vendor/topthink/framework/src/think/exception/HttpException.php index 01a27fc23..45302e587 --- a/thinkphp/library/think/exception/HttpException.php +++ b/vendor/topthink/framework/src/think/exception/HttpException.php @@ -2,21 +2,27 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006-2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: yunwuxin <448901948@qq.com> // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\exception; +use Exception; + +/** + * HTTP异常 + */ class HttpException extends \RuntimeException { private $statusCode; private $headers; - public function __construct($statusCode, $message = null, \Exception $previous = null, array $headers = [], $code = 0) + public function __construct(int $statusCode, string $message = '', Exception $previous = null, array $headers = [], $code = 0) { $this->statusCode = $statusCode; $this->headers = $headers; diff --git a/thinkphp/library/think/exception/HttpResponseException.php b/vendor/topthink/framework/src/think/exception/HttpResponseException.php old mode 100755 new mode 100644 similarity index 88% rename from thinkphp/library/think/exception/HttpResponseException.php rename to vendor/topthink/framework/src/think/exception/HttpResponseException.php index 52972867b..607813d97 --- a/thinkphp/library/think/exception/HttpResponseException.php +++ b/vendor/topthink/framework/src/think/exception/HttpResponseException.php @@ -2,17 +2,21 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006-2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: yunwuxin <448901948@qq.com> // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\exception; use think\Response; +/** + * HTTP响应异常 + */ class HttpResponseException extends \RuntimeException { /** diff --git a/vendor/topthink/framework/src/think/exception/InvalidArgumentException.php b/vendor/topthink/framework/src/think/exception/InvalidArgumentException.php new file mode 100644 index 000000000..8ccd6f6a7 --- /dev/null +++ b/vendor/topthink/framework/src/think/exception/InvalidArgumentException.php @@ -0,0 +1,22 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); +namespace think\exception; + +use Psr\Cache\InvalidArgumentException as Psr6CacheInvalidArgumentInterface; +use Psr\SimpleCache\InvalidArgumentException as SimpleCacheInvalidArgumentInterface; + +/** + * 非法数据异常 + */ +class InvalidArgumentException extends \InvalidArgumentException implements Psr6CacheInvalidArgumentInterface, SimpleCacheInvalidArgumentInterface +{ +} diff --git a/thinkphp/library/think/exception/RouteNotFoundException.php b/vendor/topthink/framework/src/think/exception/RouteNotFoundException.php old mode 100755 new mode 100644 similarity index 85% rename from thinkphp/library/think/exception/RouteNotFoundException.php rename to vendor/topthink/framework/src/think/exception/RouteNotFoundException.php index d22e3a637..7a2ee8790 --- a/thinkphp/library/think/exception/RouteNotFoundException.php +++ b/vendor/topthink/framework/src/think/exception/RouteNotFoundException.php @@ -2,15 +2,19 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006-2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: yunwuxin <448901948@qq.com> // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\exception; +/** + * 路由未定义异常 + */ class RouteNotFoundException extends HttpException { diff --git a/thinkphp/library/think/exception/ValidateException.php b/vendor/topthink/framework/src/think/exception/ValidateException.php old mode 100755 new mode 100644 similarity index 78% rename from thinkphp/library/think/exception/ValidateException.php rename to vendor/topthink/framework/src/think/exception/ValidateException.php index e3f843745..89b4e4d58 --- a/thinkphp/library/think/exception/ValidateException.php +++ b/vendor/topthink/framework/src/think/exception/ValidateException.php @@ -2,24 +2,27 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006-2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: yunwuxin <448901948@qq.com> // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\exception; +/** + * 数据验证异常 + */ class ValidateException extends \RuntimeException { protected $error; - public function __construct($error, $code = 0) + public function __construct($error) { $this->error = $error; - $this->message = is_array($error) ? implode("\n\r", $error) : $error; - $this->code = $code; + $this->message = is_array($error) ? implode(PHP_EOL, $error) : $error; } /** diff --git a/vendor/topthink/framework/src/think/facade/App.php b/vendor/topthink/framework/src/think/facade/App.php new file mode 100644 index 000000000..e9f81050e --- /dev/null +++ b/vendor/topthink/framework/src/think/facade/App.php @@ -0,0 +1,59 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\facade; + +use think\Facade; + +/** + * @see \think\App + * @package think\facade + * @mixin \think\App + * @method static \think\Service|null register(\think\Service|string $service, bool $force = false) 注册服务 + * @method static mixed bootService(\think\Service $service) 执行服务 + * @method static \think\Service|null getService(string|\think\Service $service) 获取服务 + * @method static \think\App debug(bool $debug = true) 开启应用调试模式 + * @method static bool isDebug() 是否为调试模式 + * @method static \think\App setNamespace(string $namespace) 设置应用命名空间 + * @method static string getNamespace() 获取应用类库命名空间 + * @method static string version() 获取框架版本 + * @method static string getRootPath() 获取应用根目录 + * @method static string getBasePath() 获取应用基础目录 + * @method static string getAppPath() 获取当前应用目录 + * @method static mixed setAppPath(string $path) 设置应用目录 + * @method static string getRuntimePath() 获取应用运行时目录 + * @method static void setRuntimePath(string $path) 设置runtime目录 + * @method static string getThinkPath() 获取核心框架目录 + * @method static string getConfigPath() 获取应用配置目录 + * @method static string getConfigExt() 获取配置后缀 + * @method static float getBeginTime() 获取应用开启时间 + * @method static integer getBeginMem() 获取应用初始内存占用 + * @method static \think\App initialize() 初始化应用 + * @method static bool initialized() 是否初始化过 + * @method static void loadLangPack(string $langset) 加载语言包 + * @method static void boot() 引导应用 + * @method static void loadEvent(array $event) 注册应用事件 + * @method static string parseClass(string $layer, string $name) 解析应用类的类名 + * @method static bool runningInConsole() 是否运行在命令行下 + */ +class App extends Facade +{ + /** + * 获取当前Facade对应类名(或者已经绑定的容器对象标识) + * @access protected + * @return string + */ + protected static function getFacadeClass() + { + return 'app'; + } +} diff --git a/vendor/topthink/framework/src/think/facade/Cache.php b/vendor/topthink/framework/src/think/facade/Cache.php new file mode 100644 index 000000000..aac105d44 --- /dev/null +++ b/vendor/topthink/framework/src/think/facade/Cache.php @@ -0,0 +1,48 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\facade; + +use think\cache\Driver; +use think\cache\TagSet; +use think\Facade; + +/** + * @see \think\Cache + * @package think\facade + * @mixin \think\Cache + * @method static string|null getDefaultDriver() 默认驱动 + * @method static mixed getConfig(null|string $name = null, mixed $default = null) 获取缓存配置 + * @method static array getStoreConfig(string $store, string $name = null, null $default = null) 获取驱动配置 + * @method static Driver store(string $name = null) 连接或者切换缓存 + * @method static bool clear() 清空缓冲池 + * @method static mixed get(string $key, mixed $default = null) 读取缓存 + * @method static bool set(string $key, mixed $value, int|\DateTime $ttl = null) 写入缓存 + * @method static bool delete(string $key) 删除缓存 + * @method static iterable getMultiple(iterable $keys, mixed $default = null) 读取缓存 + * @method static bool setMultiple(iterable $values, null|int|\DateInterval $ttl = null) 写入缓存 + * @method static bool deleteMultiple(iterable $keys) 删除缓存 + * @method static bool has(string $key) 判断缓存是否存在 + * @method static TagSet tag(string|array $name) 缓存标签 + */ +class Cache extends Facade +{ + /** + * 获取当前Facade对应类名(或者已经绑定的容器对象标识) + * @access protected + * @return string + */ + protected static function getFacadeClass() + { + return 'cache'; + } +} diff --git a/thinkphp/library/think/facade/Config.php b/vendor/topthink/framework/src/think/facade/Config.php old mode 100755 new mode 100644 similarity index 63% rename from thinkphp/library/think/facade/Config.php rename to vendor/topthink/framework/src/think/facade/Config.php index 8646d1271..4ce73dd6e --- a/thinkphp/library/think/facade/Config.php +++ b/vendor/topthink/framework/src/think/facade/Config.php @@ -2,12 +2,13 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\facade; @@ -15,12 +16,12 @@ use think\Facade; /** * @see \think\Config + * @package think\facade * @mixin \think\Config - * @method bool has(string $name) static 检测配置是否存在 - * @method array pull(string $name) static 获取一级配置 - * @method mixed get(string $name,mixed $default = null) static 获取配置参数 - * @method mixed set(string $name, mixed $value = null) static 设置配置参数 - * @method array reset(string $prefix ='') static 重置配置参数 + * @method static array load(string $file, string $name = '') 加载配置文件(多种格式) + * @method static bool has(string $name) 检测配置是否存在 + * @method static mixed get(string $name = null, mixed $default = null) 获取配置参数 为空则获取所有配置 + * @method static array set(array $config, string $name = null) 设置配置参数 name为数组则为批量设置 */ class Config extends Facade { diff --git a/vendor/topthink/framework/src/think/facade/Console.php b/vendor/topthink/framework/src/think/facade/Console.php new file mode 100644 index 000000000..30dd935e9 --- /dev/null +++ b/vendor/topthink/framework/src/think/facade/Console.php @@ -0,0 +1,56 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\facade; + +use think\console\Command; +use think\console\Input; +use think\console\input\Definition as InputDefinition; +use think\console\Output; +use think\console\output\driver\Buffer; +use think\Facade; + +/** + * Class Console + * @package think\facade + * @mixin \think\Console + * @method static Output|Buffer call(string $command, array $parameters = [], string $driver = 'buffer') + * @method static int run() 执行当前的指令 + * @method static int doRun(Input $input, Output $output) 执行指令 + * @method static void setDefinition(InputDefinition $definition) 设置输入参数定义 + * @method static InputDefinition The InputDefinition instance getDefinition() 获取输入参数定义 + * @method static string A help message. getHelp() Gets the help message. + * @method static void setCatchExceptions(bool $boolean) 是否捕获异常 + * @method static void setAutoExit(bool $boolean) 是否自动退出 + * @method static string getLongVersion() 获取完整的版本号 + * @method static void addCommands(array $commands) 添加指令集 + * @method static Command|void addCommand(string|Command $command, string $name = '') 添加一个指令 + * @method static Command getCommand(string $name) 获取指令 + * @method static bool hasCommand(string $name) 某个指令是否存在 + * @method static array getNamespaces() 获取所有的命名空间 + * @method static string findNamespace(string $namespace) 查找注册命名空间中的名称或缩写。 + * @method static Command find(string $name) 查找指令 + * @method static Command[] all(string $namespace = null) 获取所有的指令 + * @method static string extractNamespace(string $name, int $limit = 0) 返回命名空间部分 + */ +class Console extends Facade +{ + /** + * 获取当前Facade对应类名(或者已经绑定的容器对象标识) + * @access protected + * @return string + */ + protected static function getFacadeClass() + { + return 'console'; + } +} diff --git a/thinkphp/library/think/facade/Cookie.php b/vendor/topthink/framework/src/think/facade/Cookie.php old mode 100755 new mode 100644 similarity index 55% rename from thinkphp/library/think/facade/Cookie.php rename to vendor/topthink/framework/src/think/facade/Cookie.php index 4d7cea250..960f4a3df --- a/thinkphp/library/think/facade/Cookie.php +++ b/vendor/topthink/framework/src/think/facade/Cookie.php @@ -2,12 +2,13 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\facade; @@ -15,15 +16,15 @@ use think\Facade; /** * @see \think\Cookie + * @package think\facade * @mixin \think\Cookie - * @method void init(array $config = []) static 初始化 - * @method bool has(string $name,string $prefix = null) static 判断Cookie数据 - * @method mixed prefix(string $prefix = '') static 设置或者获取cookie作用域(前缀) - * @method mixed get(string $name,string $prefix = null) static Cookie获取 - * @method mixed set(string $name, mixed $value = null, mixed $option = null) static 设置Cookie - * @method void forever(string $name, mixed $value = null, mixed $option = null) static 永久保存Cookie数据 - * @method void delete(string $name, string $prefix = null) static Cookie删除 - * @method void clear($prefix = null) static Cookie清空 + * @method static mixed get(mixed $name = '', string $default = null) 获取cookie + * @method static bool has(string $name) 是否存在Cookie参数 + * @method static void set(string $name, string $value, mixed $option = null) Cookie 设置 + * @method static void forever(string $name, string $value = '', mixed $option = null) 永久保存Cookie数据 + * @method static void delete(string $name) Cookie删除 + * @method static array getCookie() 获取cookie保存数据 + * @method static void save() 保存Cookie */ class Cookie extends Facade { diff --git a/vendor/topthink/framework/src/think/facade/Env.php b/vendor/topthink/framework/src/think/facade/Env.php new file mode 100644 index 000000000..bed253805 --- /dev/null +++ b/vendor/topthink/framework/src/think/facade/Env.php @@ -0,0 +1,44 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\facade; + +use think\Facade; + +/** + * @see \think\Env + * @package think\facade + * @mixin \think\Env + * @method static void load(string $file) 读取环境变量定义文件 + * @method static mixed get(string $name = null, mixed $default = null) 获取环境变量值 + * @method static void set(string|array $env, mixed $value = null) 设置环境变量值 + * @method static bool has(string $name) 检测是否存在环境变量 + * @method static void __set(string $name, mixed $value) 设置环境变量 + * @method static mixed __get(string $name) 获取环境变量 + * @method static bool __isset(string $name) 检测是否存在环境变量 + * @method static void offsetSet($name, $value) + * @method static bool offsetExists($name) + * @method static mixed offsetUnset($name) + * @method static mixed offsetGet($name) + */ +class Env extends Facade +{ + /** + * 获取当前Facade对应类名(或者已经绑定的容器对象标识) + * @access protected + * @return string + */ + protected static function getFacadeClass() + { + return 'env'; + } +} diff --git a/vendor/topthink/framework/src/think/facade/Event.php b/vendor/topthink/framework/src/think/facade/Event.php new file mode 100644 index 000000000..c09d81667 --- /dev/null +++ b/vendor/topthink/framework/src/think/facade/Event.php @@ -0,0 +1,42 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\facade; + +use think\Facade; + +/** + * @see \think\Event + * @package think\facade + * @mixin \think\Event + * @method static \think\Event listenEvents(array $events) 批量注册事件监听 + * @method static \think\Event listen(string $event, mixed $listener, bool $first = false) 注册事件监听 + * @method static bool hasListener(string $event) 是否存在事件监听 + * @method static void remove(string $event) 移除事件监听 + * @method static \think\Event bind(array $events) 指定事件别名标识 便于调用 + * @method static \think\Event subscribe(mixed $subscriber) 注册事件订阅者 + * @method static \think\Event observe(string|object $observer, null|string $prefix = '') 自动注册事件观察者 + * @method static mixed trigger(string|object $event, mixed $params = null, bool $once = false) 触发事件 + * @method static mixed until($event, $params = null) 触发事件(只获取一个有效返回值) + */ +class Event extends Facade +{ + /** + * 获取当前Facade对应类名(或者已经绑定的容器对象标识) + * @access protected + * @return string + */ + protected static function getFacadeClass() + { + return 'event'; + } +} diff --git a/vendor/topthink/framework/src/think/facade/Filesystem.php b/vendor/topthink/framework/src/think/facade/Filesystem.php new file mode 100644 index 000000000..53706a841 --- /dev/null +++ b/vendor/topthink/framework/src/think/facade/Filesystem.php @@ -0,0 +1,33 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\facade; + +use think\Facade; +use think\filesystem\Driver; + +/** + * Class Filesystem + * @package think\facade + * @mixin \think\Filesystem + * @method static Driver disk(string $name = null) ,null|string + * @method static mixed getConfig(null|string $name = null, mixed $default = null) 获取缓存配置 + * @method static array getDiskConfig(string $disk, null $name = null, null $default = null) 获取磁盘配置 + * @method static string|null getDefaultDriver() 默认驱动 + */ +class Filesystem extends Facade +{ + protected static function getFacadeClass() + { + return 'filesystem'; + } +} diff --git a/vendor/topthink/framework/src/think/facade/Lang.php b/vendor/topthink/framework/src/think/facade/Lang.php new file mode 100644 index 000000000..b460fe2f9 --- /dev/null +++ b/vendor/topthink/framework/src/think/facade/Lang.php @@ -0,0 +1,41 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\facade; + +use think\Facade; + +/** + * @see \think\Lang + * @package think\facade + * @mixin \think\Lang + * @method static void setLangSet(string $lang) 设置当前语言 + * @method static string getLangSet() 获取当前语言 + * @method static string defaultLangSet() 获取默认语言 + * @method static array load(string|array $file, string $range = '') 加载语言定义(不区分大小写) + * @method static bool has(string|null $name, string $range = '') 判断是否存在语言定义(不区分大小写) + * @method static mixed get(string|null $name = null, array $vars = [], string $range = '') 获取语言定义(不区分大小写) + * @method static string detect(\think\Request $request) 自动侦测设置获取语言选择 + * @method static void saveToCookie(\think\Cookie $cookie) 保存当前语言到Cookie + */ +class Lang extends Facade +{ + /** + * 获取当前Facade对应类名(或者已经绑定的容器对象标识) + * @access protected + * @return string + */ + protected static function getFacadeClass() + { + return 'lang'; + } +} diff --git a/vendor/topthink/framework/src/think/facade/Log.php b/vendor/topthink/framework/src/think/facade/Log.php new file mode 100644 index 000000000..7c43d37e7 --- /dev/null +++ b/vendor/topthink/framework/src/think/facade/Log.php @@ -0,0 +1,58 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\facade; + +use think\Facade; +use think\log\Channel; +use think\log\ChannelSet; + +/** + * @see \think\Log + * @package think\facade + * @mixin \think\Log + * @method static string|null getDefaultDriver() 默认驱动 + * @method static mixed getConfig(null|string $name = null, mixed $default = null) 获取日志配置 + * @method static array getChannelConfig(string $channel, null $name = null, null $default = null) 获取渠道配置 + * @method static Channel|ChannelSet channel(string|array $name = null) driver() 的别名 + * @method static mixed createDriver(string $name) + * @method static \think\Log clear(string|array $channel = '*') 清空日志信息 + * @method static \think\Log close(string|array $channel = '*') 关闭本次请求日志写入 + * @method static array getLog(string $channel = null) 获取日志信息 + * @method static bool save() 保存日志信息 + * @method static \think\Log record(mixed $msg, string $type = 'info', array $context = [], bool $lazy = true) 记录日志信息 + * @method static \think\Log write(mixed $msg, string $type = 'info', array $context = []) 实时写入日志信息 + * @method static Event listen($listener) 注册日志写入事件监听 + * @method static void log(string $level, mixed $message, array $context = []) 记录日志信息 + * @method static void emergency(mixed $message, array $context = []) 记录emergency信息 + * @method static void alert(mixed $message, array $context = []) 记录警报信息 + * @method static void critical(mixed $message, array $context = []) 记录紧急情况 + * @method static void error(mixed $message, array $context = []) 记录错误信息 + * @method static void warning(mixed $message, array $context = []) 记录warning信息 + * @method static void notice(mixed $message, array $context = []) 记录notice信息 + * @method static void info(mixed $message, array $context = []) 记录一般信息 + * @method static void debug(mixed $message, array $context = []) 记录调试信息 + * @method static void sql(mixed $message, array $context = []) 记录sql信息 + * @method static mixed __call($method, $parameters) + */ +class Log extends Facade +{ + /** + * 获取当前Facade对应类名(或者已经绑定的容器对象标识) + * @access protected + * @return string + */ + protected static function getFacadeClass() + { + return 'log'; + } +} diff --git a/thinkphp/library/think/facade/Middleware.php b/vendor/topthink/framework/src/think/facade/Middleware.php old mode 100755 new mode 100644 similarity index 50% rename from thinkphp/library/think/facade/Middleware.php rename to vendor/topthink/framework/src/think/facade/Middleware.php index 5e4cac747..4203f821e --- a/thinkphp/library/think/facade/Middleware.php +++ b/vendor/topthink/framework/src/think/facade/Middleware.php @@ -2,12 +2,13 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\facade; @@ -15,12 +16,17 @@ use think\Facade; /** * @see \think\Middleware + * @package think\facade * @mixin \think\Middleware - * @method void import(array $middlewares = []) static 批量设置中间件 - * @method void add(mixed $middleware) static 添加中间件到队列 - * @method void unshift(mixed $middleware) static 添加中间件到队列开头 - * @method array all() static 获取中间件队列 - * @method \think\Response dispatch(\think\Request $request) static 执行中间件调度 + * @method static void import(array $middlewares = [], string $type = 'global') 导入中间件 + * @method static void add(mixed $middleware, string $type = 'global') 注册中间件 + * @method static void route(mixed $middleware) 注册路由中间件 + * @method static void controller(mixed $middleware) 注册控制器中间件 + * @method static mixed unshift(mixed $middleware, string $type = 'global') 注册中间件到开始位置 + * @method static array all(string $type = 'global') 获取注册的中间件 + * @method static Pipeline pipeline(string $type = 'global') 调度管道 + * @method static mixed end(\think\Response $response) 结束调度 + * @method static \think\Response handleException(\think\Request $passable, \Throwable $e) 异常处理 */ class Middleware extends Facade { diff --git a/vendor/topthink/framework/src/think/facade/Request.php b/vendor/topthink/framework/src/think/facade/Request.php new file mode 100644 index 000000000..6531f4678 --- /dev/null +++ b/vendor/topthink/framework/src/think/facade/Request.php @@ -0,0 +1,134 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\facade; + +use think\Facade; +use think\file\UploadedFile; +use think\route\Rule; + +/** + * @see \think\Request + * @package think\facade + * @mixin \think\Request + * @method static \think\Request setDomain(string $domain) 设置当前包含协议的域名 + * @method static string domain(bool $port = false) 获取当前包含协议的域名 + * @method static string rootDomain() 获取当前根域名 + * @method static \think\Request setSubDomain(string $domain) 设置当前泛域名的值 + * @method static string subDomain() 获取当前子域名 + * @method static \think\Request setPanDomain(string $domain) 设置当前泛域名的值 + * @method static string panDomain() 获取当前泛域名的值 + * @method static \think\Request setUrl(string $url) 设置当前完整URL 包括QUERY_STRING + * @method static string url(bool $complete = false) 获取当前完整URL 包括QUERY_STRING + * @method static \think\Request setBaseUrl(string $url) 设置当前URL 不含QUERY_STRING + * @method static string baseUrl(bool $complete = false) 获取当前URL 不含QUERY_STRING + * @method static string baseFile(bool $complete = false) 获取当前执行的文件 SCRIPT_NAME + * @method static \think\Request setRoot(string $url) 设置URL访问根地址 + * @method static string root(bool $complete = false) 获取URL访问根地址 + * @method static string rootUrl() 获取URL访问根目录 + * @method static \think\Request setPathinfo(string $pathinfo) 设置当前请求的pathinfo + * @method static string pathinfo() 获取当前请求URL的pathinfo信息(含URL后缀) + * @method static string ext() 当前URL的访问后缀 + * @method static integer|float time(bool $float = false) 获取当前请求的时间 + * @method static string type() 当前请求的资源类型 + * @method static void mimeType(string|array $type, string $val = '') 设置资源类型 + * @method static \think\Request setMethod(string $method) 设置请求类型 + * @method static string method(bool $origin = false) 当前的请求类型 + * @method static bool isGet() 是否为GET请求 + * @method static bool isPost() 是否为POST请求 + * @method static bool isPut() 是否为PUT请求 + * @method static bool isDelete() 是否为DELTE请求 + * @method static bool isHead() 是否为HEAD请求 + * @method static bool isPatch() 是否为PATCH请求 + * @method static bool isOptions() 是否为OPTIONS请求 + * @method static bool isCli() 是否为cli + * @method static bool isCgi() 是否为cgi + * @method static mixed param(string|array $name = '', mixed $default = null, string|array $filter = '') 获取当前请求的参数 + * @method static \think\Request setRule(Rule $rule) 设置路由变量 + * @method static Rule|null rule() 获取当前路由对象 + * @method static \think\Request setRoute(array $route) 设置路由变量 + * @method static mixed route(string|array $name = '', mixed $default = null, string|array $filter = '') 获取路由参数 + * @method static mixed get(string|array $name = '', mixed $default = null, string|array $filter = '') 获取GET参数 + * @method static mixed middleware(mixed $name, mixed $default = null) 获取中间件传递的参数 + * @method static mixed post(string|array $name = '', mixed $default = null, string|array $filter = '') 获取POST参数 + * @method static mixed put(string|array $name = '', mixed $default = null, string|array $filter = '') 获取PUT参数 + * @method static mixed delete(mixed $name = '', mixed $default = null, string|array $filter = '') 设置获取DELETE参数 + * @method static mixed patch(mixed $name = '', mixed $default = null, string|array $filter = '') 设置获取PATCH参数 + * @method static mixed request(string|array $name = '', mixed $default = null, string|array $filter = '') 获取request变量 + * @method static mixed env(string $name = '', string $default = null) 获取环境变量 + * @method static mixed session(string $name = '', string $default = null) 获取session数据 + * @method static mixed cookie(mixed $name = '', string $default = null, string|array $filter = '') 获取cookie参数 + * @method static mixed server(string $name = '', string $default = '') 获取server参数 + * @method static null|array|UploadedFile file(string $name = '') 获取上传的文件信息 + * @method static string|array header(string $name = '', string $default = null) 设置或者获取当前的Header + * @method static mixed input(array $data = [], string|false $name = '', mixed $default = null, string|array $filter = '') 获取变量 支持过滤和默认值 + * @method static mixed filter(mixed $filter = null) 设置或获取当前的过滤规则 + * @method static mixed filterValue(mixed &$value, mixed $key, array $filters) 递归过滤给定的值 + * @method static bool has(string $name, string $type = 'param', bool $checkEmpty = false) 是否存在某个请求参数 + * @method static array only(array $name, mixed $data = 'param', string|array $filter = '') 获取指定的参数 + * @method static mixed except(array $name, string $type = 'param') 排除指定参数获取 + * @method static bool isSsl() 当前是否ssl + * @method static bool isJson() 当前是否JSON请求 + * @method static bool isAjax(bool $ajax = false) 当前是否Ajax请求 + * @method static bool isPjax(bool $pjax = false) 当前是否Pjax请求 + * @method static string ip() 获取客户端IP地址 + * @method static boolean isValidIP(string $ip, string $type = '') 检测是否是合法的IP地址 + * @method static string ip2bin(string $ip) 将IP地址转换为二进制字符串 + * @method static bool isMobile() 检测是否使用手机访问 + * @method static string scheme() 当前URL地址中的scheme参数 + * @method static string query() 当前请求URL地址中的query参数 + * @method static \think\Request setHost(string $host) 设置当前请求的host(包含端口) + * @method static string host(bool $strict = false) 当前请求的host + * @method static int port() 当前请求URL地址中的port参数 + * @method static string protocol() 当前请求 SERVER_PROTOCOL + * @method static int remotePort() 当前请求 REMOTE_PORT + * @method static string contentType() 当前请求 HTTP_CONTENT_TYPE + * @method static string secureKey() 获取当前请求的安全Key + * @method static \think\Request setController(string $controller) 设置当前的控制器名 + * @method static \think\Request setAction(string $action) 设置当前的操作名 + * @method static string controller(bool $convert = false) 获取当前的控制器名 + * @method static string action(bool $convert = false) 获取当前的操作名 + * @method static string getContent() 设置或者获取当前请求的content + * @method static string getInput() 获取当前请求的php://input + * @method static string buildToken(string $name = '__token__', mixed $type = 'md5') 生成请求令牌 + * @method static bool checkToken(string $token = '__token__', array $data = []) 检查请求令牌 + * @method static \think\Request withMiddleware(array $middleware) 设置在中间件传递的数据 + * @method static \think\Request withGet(array $get) 设置GET数据 + * @method static \think\Request withPost(array $post) 设置POST数据 + * @method static \think\Request withCookie(array $cookie) 设置COOKIE数据 + * @method static \think\Request withSession(Session $session) 设置SESSION数据 + * @method static \think\Request withServer(array $server) 设置SERVER数据 + * @method static \think\Request withHeader(array $header) 设置HEADER数据 + * @method static \think\Request withEnv(Env $env) 设置ENV数据 + * @method static \think\Request withInput(string $input) 设置php://input数据 + * @method static \think\Request withFiles(array $files) 设置文件上传数据 + * @method static \think\Request withRoute(array $route) 设置ROUTE变量 + * @method static mixed __set(string $name, mixed $value) 设置中间传递数据 + * @method static mixed __get(string $name) 获取中间传递数据的值 + * @method static boolean __isset(string $name) 检测中间传递数据的值 + * @method static bool offsetExists($name) + * @method static mixed offsetGet($name) + * @method static mixed offsetSet($name, $value) + * @method static mixed offsetUnset($name) + */ +class Request extends Facade +{ + /** + * 获取当前Facade对应类名(或者已经绑定的容器对象标识) + * @access protected + * @return string + */ + protected static function getFacadeClass() + { + return 'request'; + } +} diff --git a/vendor/topthink/framework/src/think/facade/Route.php b/vendor/topthink/framework/src/think/facade/Route.php new file mode 100644 index 000000000..46bd7469c --- /dev/null +++ b/vendor/topthink/framework/src/think/facade/Route.php @@ -0,0 +1,83 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\facade; + +use think\Facade; +use think\route\Dispatch; +use think\route\Domain; +use think\route\Rule; +use think\route\RuleGroup; +use think\route\RuleItem; +use think\route\RuleName; +use think\route\Url as UrlBuild; + +/** + * @see \think\Route + * @package think\facade + * @mixin \think\Route + * @method static mixed config(string $name = null) + * @method static \think\Route lazy(bool $lazy = true) 设置路由域名及分组(包括资源路由)是否延迟解析 + * @method static void setTestMode(bool $test) 设置路由为测试模式 + * @method static bool isTest() 检查路由是否为测试模式 + * @method static \think\Route mergeRuleRegex(bool $merge = true) 设置路由域名及分组(包括资源路由)是否合并解析 + * @method static void setGroup(RuleGroup $group) 设置当前分组 + * @method static RuleGroup getGroup(string $name = null) 获取指定标识的路由分组 不指定则获取当前分组 + * @method static \think\Route pattern(array $pattern) 注册变量规则 + * @method static \think\Route option(array $option) 注册路由参数 + * @method static Domain domain(string|array $name, mixed $rule = null) 注册域名路由 + * @method static array getDomains() 获取域名 + * @method static RuleName getRuleName() 获取RuleName对象 + * @method static \think\Route bind(string $bind, string $domain = null) 设置路由绑定 + * @method static array getBind() 读取路由绑定信息 + * @method static string|null getDomainBind(string $domain = null) 读取路由绑定 + * @method static RuleItem[] getName(string $name = null, string $domain = null, string $method = '*') 读取路由标识 + * @method static void import(array $name) 批量导入路由标识 + * @method static void setName(string $name, RuleItem $ruleItem, bool $first = false) 注册路由标识 + * @method static void setRule(string $rule, RuleItem $ruleItem = null) 保存路由规则 + * @method static RuleItem[] getRule(string $rule) 读取路由 + * @method static array getRuleList() 读取路由列表 + * @method static void clear() 清空路由规则 + * @method static RuleItem rule(string $rule, mixed $route = null, string $method = '*') 注册路由规则 + * @method static \think\Route setCrossDomainRule(Rule $rule, string $method = '*') 设置跨域有效路由规则 + * @method static RuleGroup group(string|\Closure $name, mixed $route = null) 注册路由分组 + * @method static RuleItem any(string $rule, mixed $route) 注册路由 + * @method static RuleItem get(string $rule, mixed $route) 注册GET路由 + * @method static RuleItem post(string $rule, mixed $route) 注册POST路由 + * @method static RuleItem put(string $rule, mixed $route) 注册PUT路由 + * @method static RuleItem delete(string $rule, mixed $route) 注册DELETE路由 + * @method static RuleItem patch(string $rule, mixed $route) 注册PATCH路由 + * @method static RuleItem options(string $rule, mixed $route) 注册OPTIONS路由 + * @method static Resource resource(string $rule, string $route) 注册资源路由 + * @method static RuleItem view(string $rule, string $template = '', array $vars = []) 注册视图路由 + * @method static RuleItem redirect(string $rule, string $route = '', int $status = 301) 注册重定向路由 + * @method static \think\Route rest(string|array $name, array|bool $resource = []) rest方法定义和修改 + * @method static array|null getRest(string $name = null) 获取rest方法定义的参数 + * @method static RuleItem miss(string|Closure $route, string $method = '*') 注册未匹配路由规则后的处理 + * @method static Response dispatch(\think\Request $request, Closure|bool $withRoute = true) 路由调度 + * @method static Dispatch|false check() 检测URL路由 + * @method static Dispatch url(string $url) 默认URL解析 + * @method static UrlBuild buildUrl(string $url = '', array $vars = []) URL生成 支持路由反射 + * @method static RuleGroup __call(string $method, array $args) 设置全局的路由分组参数 + */ +class Route extends Facade +{ + /** + * 获取当前Facade对应类名(或者已经绑定的容器对象标识) + * @access protected + * @return string + */ + protected static function getFacadeClass() + { + return 'route'; + } +} diff --git a/thinkphp/library/think/facade/Env.php b/vendor/topthink/framework/src/think/facade/Session.php old mode 100755 new mode 100644 similarity index 66% rename from thinkphp/library/think/facade/Env.php rename to vendor/topthink/framework/src/think/facade/Session.php index 5d0472443..68bf99362 --- a/thinkphp/library/think/facade/Env.php +++ b/vendor/topthink/framework/src/think/facade/Session.php @@ -2,25 +2,26 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\facade; use think\Facade; /** - * @see \think\Env - * @mixin \think\Env - * @method void load(string $file) static 读取环境变量定义文件 - * @method mixed get(string $name = null, mixed $default = null) static 获取环境变量值 - * @method void set(mixed $env, string $value = null) static 设置环境变量值 + * @see \think\Session + * @package think\facade + * @mixin \think\Session + * @method static mixed getConfig(null|string $name = null, mixed $default = null) 获取Session配置 + * @method static string|null getDefaultDriver() 默认驱动 */ -class Env extends Facade +class Session extends Facade { /** * 获取当前Facade对应类名(或者已经绑定的容器对象标识) @@ -29,6 +30,6 @@ class Env extends Facade */ protected static function getFacadeClass() { - return 'env'; + return 'session'; } } diff --git a/vendor/topthink/framework/src/think/facade/Validate.php b/vendor/topthink/framework/src/think/facade/Validate.php new file mode 100644 index 000000000..6db6d34a4 --- /dev/null +++ b/vendor/topthink/framework/src/think/facade/Validate.php @@ -0,0 +1,95 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\facade; + +use think\Facade; + +/** + * @see \think\Validate + * @package think\facade + * @mixin \think\Validate + * @method static void setLang(\think\Lang $lang) 设置Lang对象 + * @method static void setDb(\think\Db $db) 设置Db对象 + * @method static void setRequest(\think\Request $request) 设置Request对象 + * @method static \think\Validate rule(string|array $name, mixed $rule = '') 添加字段验证规则 + * @method static \think\Validate extend(string $type, callable $callback = null, string $message = null) 注册验证(类型)规则 + * @method static void setTypeMsg(string|array $type, string $msg = null) 设置验证规则的默认提示信息 + * @method static Validate message(array $message) 设置提示信息 + * @method static \think\Validate scene(string $name) 设置验证场景 + * @method static bool hasScene(string $name) 判断是否存在某个验证场景 + * @method static \think\Validate batch(bool $batch = true) 设置批量验证 + * @method static \think\Validate failException(bool $fail = true) 设置验证失败后是否抛出异常 + * @method static \think\Validate only(array $fields) 指定需要验证的字段列表 + * @method static \think\Validate remove(string|array $field, mixed $rule = null) 移除某个字段的验证规则 + * @method static \think\Validate append(string|array $field, mixed $rule = null) 追加某个字段的验证规则 + * @method static bool check(array $data, array $rules = []) 数据自动验证 + * @method static bool checkRule(mixed $value, mixed $rules) 根据验证规则验证数据 + * @method static bool confirm(mixed $value, mixed $rule, array $data = [], string $field = '') 验证是否和某个字段的值一致 + * @method static bool different(mixed $value, mixed $rule, array $data = []) 验证是否和某个字段的值是否不同 + * @method static bool egt(mixed $value, mixed $rule, array $data = []) 验证是否大于等于某个值 + * @method static bool gt(mixed $value, mixed $rule, array $data = []) 验证是否大于某个值 + * @method static bool elt(mixed $value, mixed $rule, array $data = []) 验证是否小于等于某个值 + * @method static bool lt(mixed $value, mixed $rule, array $data = []) 验证是否小于某个值 + * @method static bool eq(mixed $value, mixed $rule) 验证是否等于某个值 + * @method static bool must(mixed $value, mixed $rule = null) 必须验证 + * @method static bool is(mixed $value, string $rule, array $data = []) 验证字段值是否为有效格式 + * @method static bool token(mixed $value, mixed $rule, array $data) 验证表单令牌 + * @method static bool activeUrl(mixed $value, mixed $rule = 'MX') 验证是否为合格的域名或者IP 支持A,MX,NS,SOA,PTR,CNAME,AAAA,A6, SRV,NAPTR,TXT 或者 ANY类型 + * @method static bool ip(mixed $value, mixed $rule = 'ipv4') 验证是否有效IP + * @method static bool fileExt(mixed $file, mixed $rule) 验证上传文件后缀 + * @method static bool fileMime(mixed $file, mixed $rule) 验证上传文件类型 + * @method static bool fileSize(mixed $file, mixed $rule) 验证上传文件大小 + * @method static bool image(mixed $file, mixed $rule) 验证图片的宽高及类型 + * @method static bool dateFormat(mixed $value, mixed $rule) 验证时间和日期是否符合指定格式 + * @method static bool unique(mixed $value, mixed $rule, array $data = [], string $field = '') 验证是否唯一 + * @method static bool filter(mixed $value, mixed $rule) 使用filter_var方式验证 + * @method static bool requireIf(mixed $value, mixed $rule, array $data = []) 验证某个字段等于某个值的时候必须 + * @method static bool requireCallback(mixed $value, mixed $rule, array $data = []) 通过回调方法验证某个字段是否必须 + * @method static bool requireWith(mixed $value, mixed $rule, array $data = []) 验证某个字段有值的情况下必须 + * @method static bool requireWithout(mixed $value, mixed $rule, array $data = []) 验证某个字段没有值的情况下必须 + * @method static bool in(mixed $value, mixed $rule) 验证是否在范围内 + * @method static bool notIn(mixed $value, mixed $rule) 验证是否不在某个范围 + * @method static bool between(mixed $value, mixed $rule) between验证数据 + * @method static bool notBetween(mixed $value, mixed $rule) 使用notbetween验证数据 + * @method static bool length(mixed $value, mixed $rule) 验证数据长度 + * @method static bool max(mixed $value, mixed $rule) 验证数据最大长度 + * @method static bool min(mixed $value, mixed $rule) 验证数据最小长度 + * @method static bool after(mixed $value, mixed $rule, array $data = []) 验证日期 + * @method static bool before(mixed $value, mixed $rule, array $data = []) 验证日期 + * @method static bool afterWith(mixed $value, mixed $rule, array $data = []) 验证日期 + * @method static bool beforeWith(mixed $value, mixed $rule, array $data = []) 验证日期 + * @method static bool expire(mixed $value, mixed $rule) 验证有效期 + * @method static bool allowIp(mixed $value, mixed $rule) 验证IP许可 + * @method static bool denyIp(mixed $value, mixed $rule) 验证IP禁用 + * @method static bool regex(mixed $value, mixed $rule) 使用正则验证数据 + * @method static array|string getError() 获取错误信息 + * @method static bool __call(string $method, array $args) 动态方法 直接调用is方法进行验证 + */ +class Validate extends Facade +{ + /** + * 始终创建新的对象实例 + * @var bool + */ + protected static $alwaysNewInstance = true; + + /** + * 获取当前Facade对应类名(或者已经绑定的容器对象标识) + * @access protected + * @return string + */ + protected static function getFacadeClass() + { + return 'validate'; + } +} diff --git a/vendor/topthink/framework/src/think/facade/View.php b/vendor/topthink/framework/src/think/facade/View.php new file mode 100644 index 000000000..acde3b577 --- /dev/null +++ b/vendor/topthink/framework/src/think/facade/View.php @@ -0,0 +1,42 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\facade; + +use think\Facade; + +/** + * @see \think\View + * @package think\facade + * @mixin \think\View + * @method static \think\View engine(string $type = null) 获取模板引擎 + * @method static \think\View assign(string|array $name, mixed $value = null) 模板变量赋值 + * @method static \think\View filter(\think\Callable $filter = null) 视图过滤 + * @method static string fetch(string $template = '', array $vars = []) 解析和获取模板内容 用于输出 + * @method static string display(string $content, array $vars = []) 渲染内容输出 + * @method static mixed __set(string $name, mixed $value) 模板变量赋值 + * @method static mixed __get(string $name) 取得模板显示变量的值 + * @method static bool __isset(string $name) 检测模板变量是否设置 + * @method static string|null getDefaultDriver() 默认驱动 + */ +class View extends Facade +{ + /** + * 获取当前Facade对应类名(或者已经绑定的容器对象标识) + * @access protected + * @return string + */ + protected static function getFacadeClass() + { + return 'view'; + } +} diff --git a/vendor/topthink/framework/src/think/file/UploadedFile.php b/vendor/topthink/framework/src/think/file/UploadedFile.php new file mode 100644 index 000000000..7dff766e1 --- /dev/null +++ b/vendor/topthink/framework/src/think/file/UploadedFile.php @@ -0,0 +1,143 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\file; + +use think\exception\FileException; +use think\File; + +class UploadedFile extends File +{ + + private $test = false; + private $originalName; + private $mimeType; + private $error; + + public function __construct(string $path, string $originalName, string $mimeType = null, int $error = null, bool $test = false) + { + $this->originalName = $originalName; + $this->mimeType = $mimeType ?: 'application/octet-stream'; + $this->test = $test; + $this->error = $error ?: UPLOAD_ERR_OK; + + parent::__construct($path, UPLOAD_ERR_OK === $this->error); + } + + public function isValid(): bool + { + $isOk = UPLOAD_ERR_OK === $this->error; + + return $this->test ? $isOk : $isOk && is_uploaded_file($this->getPathname()); + } + + /** + * 上传文件 + * @access public + * @param string $directory 保存路径 + * @param string|null $name 保存的文件名 + * @return File + */ + public function move(string $directory, string $name = null): File + { + if ($this->isValid()) { + if ($this->test) { + return parent::move($directory, $name); + } + + $target = $this->getTargetFile($directory, $name); + + set_error_handler(function ($type, $msg) use (&$error) { + $error = $msg; + }); + + $moved = move_uploaded_file($this->getPathname(), (string) $target); + restore_error_handler(); + if (!$moved) { + throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s)', $this->getPathname(), $target, strip_tags($error))); + } + + @chmod((string) $target, 0666 & ~umask()); + + return $target; + } + + throw new FileException($this->getErrorMessage()); + } + + /** + * 获取错误信息 + * @access public + * @return string + */ + protected function getErrorMessage(): string + { + switch ($this->error) { + case 1: + case 2: + $message = 'upload File size exceeds the maximum value'; + break; + case 3: + $message = 'only the portion of file is uploaded'; + break; + case 4: + $message = 'no file to uploaded'; + break; + case 6: + $message = 'upload temp dir not found'; + break; + case 7: + $message = 'file write error'; + break; + default: + $message = 'unknown upload error'; + } + + return $message; + } + + /** + * 获取上传文件类型信息 + * @return string + */ + public function getOriginalMime(): string + { + return $this->mimeType; + } + + /** + * 上传文件名 + * @return string + */ + public function getOriginalName(): string + { + return $this->originalName; + } + + /** + * 获取上传文件扩展名 + * @return string + */ + public function getOriginalExtension(): string + { + return pathinfo($this->originalName, PATHINFO_EXTENSION); + } + + /** + * 获取文件扩展名 + * @return string + */ + public function extension(): string + { + return $this->getOriginalExtension(); + } +} diff --git a/vendor/topthink/framework/src/think/filesystem/CacheStore.php b/vendor/topthink/framework/src/think/filesystem/CacheStore.php new file mode 100644 index 000000000..0a62399e0 --- /dev/null +++ b/vendor/topthink/framework/src/think/filesystem/CacheStore.php @@ -0,0 +1,54 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\filesystem; + +use League\Flysystem\Cached\Storage\AbstractCache; +use Psr\SimpleCache\CacheInterface; + +class CacheStore extends AbstractCache +{ + protected $store; + + protected $key; + + protected $expire; + + public function __construct(CacheInterface $store, $key = 'flysystem', $expire = null) + { + $this->key = $key; + $this->store = $store; + $this->expire = $expire; + } + + /** + * Store the cache. + */ + public function save() + { + $contents = $this->getForStorage(); + + $this->store->set($this->key, $contents, $this->expire); + } + + /** + * Load the cache. + */ + public function load() + { + $contents = $this->store->get($this->key); + + if (!is_null($contents)) { + $this->setFromStorage($contents); + } + } +} diff --git a/vendor/topthink/framework/src/think/filesystem/Driver.php b/vendor/topthink/framework/src/think/filesystem/Driver.php new file mode 100644 index 000000000..67129592c --- /dev/null +++ b/vendor/topthink/framework/src/think/filesystem/Driver.php @@ -0,0 +1,133 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\filesystem; + +use League\Flysystem\AdapterInterface; +use League\Flysystem\Adapter\AbstractAdapter; +use League\Flysystem\Cached\CachedAdapter; +use League\Flysystem\Cached\Storage\Memory as MemoryStore; +use League\Flysystem\Filesystem; +use think\Cache; +use think\File; + +/** + * Class Driver + * @package think\filesystem + * @mixin Filesystem + */ +abstract class Driver +{ + + /** @var Cache */ + protected $cache; + + /** @var Filesystem */ + protected $filesystem; + + /** + * 配置参数 + * @var array + */ + protected $config = []; + + public function __construct(Cache $cache, array $config) + { + $this->cache = $cache; + $this->config = array_merge($this->config, $config); + + $adapter = $this->createAdapter(); + $this->filesystem = $this->createFilesystem($adapter); + } + + protected function createCacheStore($config) + { + if (true === $config) { + return new MemoryStore; + } + + return new CacheStore( + $this->cache->store($config['store']), + $config['prefix'] ?? 'flysystem', + $config['expire'] ?? null + ); + } + + abstract protected function createAdapter(): AdapterInterface; + + protected function createFilesystem(AdapterInterface $adapter): Filesystem + { + if (!empty($this->config['cache'])) { + $adapter = new CachedAdapter($adapter, $this->createCacheStore($this->config['cache'])); + } + + $config = array_intersect_key($this->config, array_flip(['visibility', 'disable_asserts', 'url'])); + + return new Filesystem($adapter, count($config) > 0 ? $config : null); + } + + /** + * 获取文件完整路径 + * @param string $path + * @return string + */ + public function path(string $path): string + { + $adapter = $this->filesystem->getAdapter(); + + if ($adapter instanceof AbstractAdapter) { + return $adapter->applyPathPrefix($path); + } + + return $path; + } + + /** + * 保存文件 + * @param string $path 路径 + * @param File $file 文件 + * @param null|string|\Closure $rule 文件名规则 + * @param array $options 参数 + * @return bool|string + */ + public function putFile(string $path, File $file, $rule = null, array $options = []) + { + return $this->putFileAs($path, $file, $file->hashName($rule), $options); + } + + /** + * 指定文件名保存文件 + * @param string $path 路径 + * @param File $file 文件 + * @param string $name 文件名 + * @param array $options 参数 + * @return bool|string + */ + public function putFileAs(string $path, File $file, string $name, array $options = []) + { + $stream = fopen($file->getRealPath(), 'r'); + $path = trim($path . '/' . $name, '/'); + + $result = $this->putStream($path, $stream, $options); + + if (is_resource($stream)) { + fclose($stream); + } + + return $result ? $path : false; + } + + public function __call($method, $parameters) + { + return $this->filesystem->$method(...$parameters); + } +} diff --git a/vendor/topthink/framework/src/think/filesystem/driver/Local.php b/vendor/topthink/framework/src/think/filesystem/driver/Local.php new file mode 100644 index 000000000..c10ccc3b6 --- /dev/null +++ b/vendor/topthink/framework/src/think/filesystem/driver/Local.php @@ -0,0 +1,44 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\filesystem\driver; + +use League\Flysystem\AdapterInterface; +use League\Flysystem\Adapter\Local as LocalAdapter; +use think\filesystem\Driver; + +class Local extends Driver +{ + /** + * 配置参数 + * @var array + */ + protected $config = [ + 'root' => '', + ]; + + protected function createAdapter(): AdapterInterface + { + $permissions = $this->config['permissions'] ?? []; + + $links = ($this->config['links'] ?? null) === 'skip' + ? LocalAdapter::SKIP_LINKS + : LocalAdapter::DISALLOW_LINKS; + + return new LocalAdapter( + $this->config['root'], + LOCK_EX, + $links, + $permissions + ); + } +} diff --git a/vendor/topthink/framework/src/think/initializer/BootService.php b/vendor/topthink/framework/src/think/initializer/BootService.php new file mode 100644 index 000000000..bab6d3904 --- /dev/null +++ b/vendor/topthink/framework/src/think/initializer/BootService.php @@ -0,0 +1,26 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\initializer; + +use think\App; + +/** + * 启动系统服务 + */ +class BootService +{ + public function init(App $app) + { + $app->boot(); + } +} diff --git a/vendor/topthink/framework/src/think/initializer/Error.php b/vendor/topthink/framework/src/think/initializer/Error.php new file mode 100644 index 000000000..201d94732 --- /dev/null +++ b/vendor/topthink/framework/src/think/initializer/Error.php @@ -0,0 +1,117 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\initializer; + +use think\App; +use think\console\Output as ConsoleOutput; +use think\exception\ErrorException; +use think\exception\Handle; +use Throwable; + +/** + * 错误和异常处理 + */ +class Error +{ + /** @var App */ + protected $app; + + /** + * 注册异常处理 + * @access public + * @param App $app + * @return void + */ + public function init(App $app) + { + $this->app = $app; + error_reporting(E_ALL); + set_error_handler([$this, 'appError']); + set_exception_handler([$this, 'appException']); + register_shutdown_function([$this, 'appShutdown']); + } + + /** + * Exception Handler + * @access public + * @param \Throwable $e + */ + public function appException(Throwable $e): void + { + $handler = $this->getExceptionHandler(); + + $handler->report($e); + + if ($this->app->runningInConsole()) { + $handler->renderForConsole(new ConsoleOutput, $e); + } else { + $handler->render($this->app->request, $e)->send(); + } + } + + /** + * Error Handler + * @access public + * @param integer $errno 错误编号 + * @param string $errstr 详细错误信息 + * @param string $errfile 出错的文件 + * @param integer $errline 出错行号 + * @throws ErrorException + */ + public function appError(int $errno, string $errstr, string $errfile = '', int $errline = 0): void + { + $exception = new ErrorException($errno, $errstr, $errfile, $errline); + + if (error_reporting() & $errno) { + // 将错误信息托管至 think\exception\ErrorException + throw $exception; + } + } + + /** + * Shutdown Handler + * @access public + */ + public function appShutdown(): void + { + if (!is_null($error = error_get_last()) && $this->isFatal($error['type'])) { + // 将错误信息托管至think\ErrorException + $exception = new ErrorException($error['type'], $error['message'], $error['file'], $error['line']); + + $this->appException($exception); + } + } + + /** + * 确定错误类型是否致命 + * + * @access protected + * @param int $type + * @return bool + */ + protected function isFatal(int $type): bool + { + return in_array($type, [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE]); + } + + /** + * Get an instance of the exception handler. + * + * @access protected + * @return Handle + */ + protected function getExceptionHandler() + { + return $this->app->make(Handle::class); + } +} diff --git a/vendor/topthink/framework/src/think/initializer/RegisterService.php b/vendor/topthink/framework/src/think/initializer/RegisterService.php new file mode 100644 index 000000000..b682a0b0e --- /dev/null +++ b/vendor/topthink/framework/src/think/initializer/RegisterService.php @@ -0,0 +1,48 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\initializer; + +use think\App; +use think\service\ModelService; +use think\service\PaginatorService; +use think\service\ValidateService; + +/** + * 注册系统服务 + */ +class RegisterService +{ + + protected $services = [ + PaginatorService::class, + ValidateService::class, + ModelService::class, + ]; + + public function init(App $app) + { + $file = $app->getRootPath() . 'vendor/services.php'; + + $services = $this->services; + + if (is_file($file)) { + $services = array_merge($services, include $file); + } + + foreach ($services as $service) { + if (class_exists($service)) { + $app->register($service); + } + } + } +} diff --git a/vendor/topthink/framework/src/think/log/Channel.php b/vendor/topthink/framework/src/think/log/Channel.php new file mode 100644 index 000000000..1de96f1a5 --- /dev/null +++ b/vendor/topthink/framework/src/think/log/Channel.php @@ -0,0 +1,286 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\log; + +use Psr\Log\LoggerInterface; +use think\contract\LogHandlerInterface; +use think\Event; +use think\event\LogRecord; +use think\event\LogWrite; + +class Channel implements LoggerInterface +{ + protected $name; + protected $logger; + protected $event; + + protected $lazy = true; + /** + * 日志信息 + * @var array + */ + protected $log = []; + + /** + * 关闭日志 + * @var array + */ + protected $close = false; + + /** + * 允许写入类型 + * @var array + */ + protected $allow = []; + + public function __construct(string $name, LogHandlerInterface $logger, array $allow, bool $lazy = true, Event $event = null) + { + $this->name = $name; + $this->logger = $logger; + $this->allow = $allow; + $this->lazy = $lazy; + $this->event = $event; + } + + /** + * 关闭通道 + */ + public function close() + { + $this->clear(); + $this->close = true; + } + + /** + * 清空日志 + */ + public function clear() + { + $this->log = []; + } + + /** + * 记录日志信息 + * @access public + * @param mixed $msg 日志信息 + * @param string $type 日志级别 + * @param array $context 替换内容 + * @param bool $lazy + * @return $this + */ + public function record($msg, string $type = 'info', array $context = [], bool $lazy = true) + { + if ($this->close || (!empty($this->allow) && !in_array($type, $this->allow))) { + return $this; + } + + if (is_string($msg) && !empty($context)) { + $replace = []; + foreach ($context as $key => $val) { + $replace['{' . $key . '}'] = $val; + } + + $msg = strtr($msg, $replace); + } + + if (!empty($msg) || 0 === $msg) { + $this->log[$type][] = $msg; + if ($this->event) { + $this->event->trigger(new LogRecord($type, $msg)); + } + } + + if (!$this->lazy || !$lazy) { + $this->save(); + } + + return $this; + } + + /** + * 实时写入日志信息 + * @access public + * @param mixed $msg 调试信息 + * @param string $type 日志级别 + * @param array $context 替换内容 + * @return $this + */ + public function write($msg, string $type = 'info', array $context = []) + { + return $this->record($msg, $type, $context, false); + } + + /** + * 获取日志信息 + * @return array + */ + public function getLog(): array + { + return $this->log; + } + + /** + * 保存日志 + * @return bool + */ + public function save(): bool + { + $log = $this->log; + if ($this->event) { + $event = new LogWrite($this->name, $log); + $this->event->trigger($event); + $log = $event->log; + } + + if ($this->logger->save($log)) { + $this->clear(); + return true; + } + + return false; + } + + /** + * System is unusable. + * + * @param string $message + * @param array $context + * + * @return void + */ + public function emergency($message, array $context = []) + { + $this->log(__FUNCTION__, $message, $context); + } + + /** + * Action must be taken immediately. + * + * Example: Entire website down, database unavailable, etc. This should + * trigger the SMS alerts and wake you up. + * + * @param string $message + * @param array $context + * + * @return void + */ + public function alert($message, array $context = []) + { + $this->log(__FUNCTION__, $message, $context); + } + + /** + * Critical conditions. + * + * Example: Application component unavailable, unexpected exception. + * + * @param string $message + * @param array $context + * + * @return void + */ + public function critical($message, array $context = []) + { + $this->log(__FUNCTION__, $message, $context); + } + + /** + * Runtime errors that do not require immediate action but should typically + * be logged and monitored. + * + * @param string $message + * @param array $context + * + * @return void + */ + public function error($message, array $context = []) + { + $this->log(__FUNCTION__, $message, $context); + } + + /** + * Exceptional occurrences that are not errors. + * + * Example: Use of deprecated APIs, poor use of an API, undesirable things + * that are not necessarily wrong. + * + * @param string $message + * @param array $context + * + * @return void + */ + public function warning($message, array $context = []) + { + $this->log(__FUNCTION__, $message, $context); + } + + /** + * Normal but significant events. + * + * @param string $message + * @param array $context + * + * @return void + */ + public function notice($message, array $context = []) + { + $this->log(__FUNCTION__, $message, $context); + } + + /** + * Interesting events. + * + * Example: User logs in, SQL logs. + * + * @param string $message + * @param array $context + * + * @return void + */ + public function info($message, array $context = []) + { + $this->log(__FUNCTION__, $message, $context); + } + + /** + * Detailed debug information. + * + * @param string $message + * @param array $context + * + * @return void + */ + public function debug($message, array $context = []) + { + $this->log(__FUNCTION__, $message, $context); + } + + /** + * Logs with an arbitrary level. + * + * @param mixed $level + * @param string $message + * @param array $context + * + * @return void + */ + public function log($level, $message, array $context = []) + { + $this->record($message, $level, $context); + } + + public function __call($method, $parameters) + { + $this->log($method, ...$parameters); + } +} diff --git a/vendor/topthink/framework/src/think/log/ChannelSet.php b/vendor/topthink/framework/src/think/log/ChannelSet.php new file mode 100644 index 000000000..6dcb0bdb0 --- /dev/null +++ b/vendor/topthink/framework/src/think/log/ChannelSet.php @@ -0,0 +1,39 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\log; + +use think\Log; + +/** + * Class ChannelSet + * @package think\log + * @mixin Channel + */ +class ChannelSet +{ + protected $log; + protected $channels; + + public function __construct(Log $log, array $channels) + { + $this->log = $log; + $this->channels = $channels; + } + + public function __call($method, $arguments) + { + foreach ($this->channels as $channel) { + $this->log->channel($channel)->{$method}(...$arguments); + } + } +} diff --git a/vendor/topthink/framework/src/think/log/driver/File.php b/vendor/topthink/framework/src/think/log/driver/File.php new file mode 100644 index 000000000..e5682fc00 --- /dev/null +++ b/vendor/topthink/framework/src/think/log/driver/File.php @@ -0,0 +1,205 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\log\driver; + +use think\App; +use think\contract\LogHandlerInterface; + +/** + * 本地化调试输出到文件 + */ +class File implements LogHandlerInterface +{ + /** + * 配置参数 + * @var array + */ + protected $config = [ + 'time_format' => 'c', + 'single' => false, + 'file_size' => 2097152, + 'path' => '', + 'apart_level' => [], + 'max_files' => 0, + 'json' => false, + 'json_options' => JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES, + 'format' => '[%s][%s] %s', + ]; + + // 实例化并传入参数 + public function __construct(App $app, $config = []) + { + if (is_array($config)) { + $this->config = array_merge($this->config, $config); + } + + if (empty($this->config['format'])) { + $this->config['format'] = '[%s][%s] %s'; + } + + if (empty($this->config['path'])) { + $this->config['path'] = $app->getRuntimePath() . 'log'; + } + + if (substr($this->config['path'], -1) != DIRECTORY_SEPARATOR) { + $this->config['path'] .= DIRECTORY_SEPARATOR; + } + } + + /** + * 日志写入接口 + * @access public + * @param array $log 日志信息 + * @return bool + */ + public function save(array $log): bool + { + $destination = $this->getMasterLogFile(); + + $path = dirname($destination); + !is_dir($path) && mkdir($path, 0755, true); + + $info = []; + + // 日志信息封装 + $time = \DateTime::createFromFormat('0.u00 U', microtime())->setTimezone(new \DateTimeZone(date_default_timezone_get()))->format($this->config['time_format']); + + foreach ($log as $type => $val) { + $message = []; + foreach ($val as $msg) { + if (!is_string($msg)) { + $msg = var_export($msg, true); + } + + $message[] = $this->config['json'] ? + json_encode(['time' => $time, 'type' => $type, 'msg' => $msg], $this->config['json_options']) : + sprintf($this->config['format'], $time, $type, $msg); + } + + if (true === $this->config['apart_level'] || in_array($type, $this->config['apart_level'])) { + // 独立记录的日志级别 + $filename = $this->getApartLevelFile($path, $type); + $this->write($message, $filename); + continue; + } + + $info[$type] = $message; + } + + if ($info) { + return $this->write($info, $destination); + } + + return true; + } + + /** + * 日志写入 + * @access protected + * @param array $message 日志信息 + * @param string $destination 日志文件 + * @return bool + */ + protected function write(array $message, string $destination): bool + { + // 检测日志文件大小,超过配置大小则备份日志文件重新生成 + $this->checkLogSize($destination); + + $info = []; + + foreach ($message as $type => $msg) { + $info[$type] = is_array($msg) ? implode(PHP_EOL, $msg) : $msg; + } + + $message = implode(PHP_EOL, $info) . PHP_EOL; + + return error_log($message, 3, $destination); + } + + /** + * 获取主日志文件名 + * @access public + * @return string + */ + protected function getMasterLogFile(): string + { + + if ($this->config['max_files']) { + $files = glob($this->config['path'] . '*.log'); + + try { + if (count($files) > $this->config['max_files']) { + unlink($files[0]); + } + } catch (\Exception $e) { + // + } + } + + if ($this->config['single']) { + $name = is_string($this->config['single']) ? $this->config['single'] : 'single'; + $destination = $this->config['path'] . $name . '.log'; + } else { + + if ($this->config['max_files']) { + $filename = date('Ymd') . '.log'; + } else { + $filename = date('Ym') . DIRECTORY_SEPARATOR . date('d') . '.log'; + } + + $destination = $this->config['path'] . $filename; + } + + return $destination; + } + + /** + * 获取独立日志文件名 + * @access public + * @param string $path 日志目录 + * @param string $type 日志类型 + * @return string + */ + protected function getApartLevelFile(string $path, string $type): string + { + + if ($this->config['single']) { + $name = is_string($this->config['single']) ? $this->config['single'] : 'single'; + + $name .= '_' . $type; + } elseif ($this->config['max_files']) { + $name = date('Ymd') . '_' . $type; + } else { + $name = date('d') . '_' . $type; + } + + return $path . DIRECTORY_SEPARATOR . $name . '.log'; + } + + /** + * 检查日志文件大小并自动生成备份文件 + * @access protected + * @param string $destination 日志文件 + * @return void + */ + protected function checkLogSize(string $destination): void + { + if (is_file($destination) && floor($this->config['file_size']) <= filesize($destination)) { + try { + rename($destination, dirname($destination) . DIRECTORY_SEPARATOR . time() . '-' . basename($destination)); + } catch (\Exception $e) { + // + } + } + } +} diff --git a/thinkphp/library/think/log/driver/Socket.php b/vendor/topthink/framework/src/think/log/driver/Socket.php old mode 100755 new mode 100644 similarity index 53% rename from thinkphp/library/think/log/driver/Socket.php rename to vendor/topthink/framework/src/think/log/driver/Socket.php index 5e4f8bfd8..2cfb94339 --- a/thinkphp/library/think/log/driver/Socket.php +++ b/vendor/topthink/framework/src/think/log/driver/Socket.php @@ -2,36 +2,50 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006-2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: luofei614 // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\log\driver; +use Psr\Container\NotFoundExceptionInterface; use think\App; +use think\contract\LogHandlerInterface; /** * github: https://github.com/luofei614/SocketLog * @author luofei614 */ -class Socket +class Socket implements LogHandlerInterface { - public $port = 1116; //SocketLog 服务的http的端口号 + protected $app; protected $config = [ // socket服务器地址 'host' => 'localhost', + // socket服务器端口 + 'port' => 1116, // 是否显示加载的文件列表 'show_included_files' => false, // 日志强制记录到配置的client_id 'force_client_ids' => [], // 限制允许读取日志的client_id 'allow_client_ids' => [], - //输出到浏览器默认展开的日志级别 + // 调试开关 + 'debug' => false, + // 输出到浏览器时默认展开的日志级别 'expand_level' => ['debug'], + // 日志头渲染回调 + 'format_head' => null, + // curl opt + 'curl_opt' => [ + CURLOPT_CONNECTTIMEOUT => 1, + CURLOPT_TIMEOUT => 10, + ], ]; protected $css = [ @@ -43,12 +57,14 @@ class Socket ]; protected $allowForceClientIds = []; //配置强制推送且被授权的client_id - protected $app; + + protected $clientArg = []; /** * 架构函数 * @access public - * @param array $config 缓存参数 + * @param App $app + * @param array $config 缓存参数 */ public function __construct(App $app, array $config = []) { @@ -57,15 +73,19 @@ class Socket if (!empty($config)) { $this->config = array_merge($this->config, $config); } + + if (!isset($config['debug'])) { + $this->config['debug'] = $app->isDebug(); + } } /** * 调试输出接口 * @access public - * @param array $log 日志信息 + * @param array $log 日志信息 * @return bool */ - public function save(array $log = [], $append = false) + public function save(array $log = []): bool { if (!$this->check()) { return false; @@ -73,33 +93,36 @@ class Socket $trace = []; - if ($this->app->isDebug()) { - $runtime = round(microtime(true) - $this->app->getBeginTime(), 10); - $reqs = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞'; - $time_str = ' [运行时间:' . number_format($runtime, 6) . 's][吞吐率:' . $reqs . 'req/s]'; - $memory_use = number_format((memory_get_usage() - $this->app->getBeginMem()) / 1024, 2); - $memory_str = ' [内存消耗:' . $memory_use . 'kb]'; - $file_load = ' [文件加载:' . count(get_included_files()) . ']'; - - if (isset($_SERVER['HTTP_HOST'])) { - $current_uri = $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; + if ($this->config['debug']) { + if ($this->app->exists('request')) { + $currentUri = $this->app->request->url(true); } else { - $current_uri = 'cmd:' . implode(' ', $_SERVER['argv']); + $currentUri = 'cmd:' . implode(' ', $_SERVER['argv'] ?? []); + } + + if (!empty($this->config['format_head'])) { + try { + $currentUri = $this->app->invoke($this->config['format_head'], [$currentUri]); + } catch (NotFoundExceptionInterface $notFoundException) { + // Ignore exception + } } // 基本信息 $trace[] = [ 'type' => 'group', - 'msg' => $current_uri . $time_str . $memory_str . $file_load, + 'msg' => $currentUri, 'css' => $this->css['page'], ]; } + $expandLevel = array_flip($this->config['expand_level']); + foreach ($log as $type => $val) { $trace[] = [ - 'type' => in_array($type, $this->config['expand_level']) ? 'group' : 'groupCollapsed', + 'type' => isset($expandLevel[$type]) ? 'group' : 'groupCollapsed', 'msg' => '[ ' . $type . ' ]', - 'css' => isset($this->css[$type]) ? $this->css[$type] : '', + 'css' => $this->css[$type] ?? '', ]; foreach ($val as $msg) { @@ -148,18 +171,18 @@ class Socket $tabid = $this->getClientArg('tabid'); - if (!$client_id = $this->getClientArg('client_id')) { - $client_id = ''; + if (!$clientId = $this->getClientArg('client_id')) { + $clientId = ''; } if (!empty($this->allowForceClientIds)) { //强制推送到多个client_id - foreach ($this->allowForceClientIds as $force_client_id) { - $client_id = $force_client_id; - $this->sendToClient($tabid, $client_id, $trace, $force_client_id); + foreach ($this->allowForceClientIds as $forceClientId) { + $clientId = $forceClientId; + $this->sendToClient($tabid, $clientId, $trace, $forceClientId); } } else { - $this->sendToClient($tabid, $client_id, $trace, ''); + $this->sendToClient($tabid, $clientId, $trace, ''); } return true; @@ -170,25 +193,30 @@ class Socket * @access protected * @author Zjmainstay * @param $tabid - * @param $client_id + * @param $clientId * @param $logs - * @param $force_client_id + * @param $forceClientId */ - protected function sendToClient($tabid, $client_id, $logs, $force_client_id) + protected function sendToClient($tabid, $clientId, $logs, $forceClientId) { $logs = [ 'tabid' => $tabid, - 'client_id' => $client_id, + 'client_id' => $clientId, 'logs' => $logs, - 'force_client_id' => $force_client_id, + 'force_client_id' => $forceClientId, ]; - $msg = @json_encode($logs); - $address = '/' . $client_id; //将client_id作为地址, server端通过地址判断将日志发布给谁 + $msg = json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PARTIAL_OUTPUT_ON_ERROR); + $address = '/' . $clientId; //将client_id作为地址, server端通过地址判断将日志发布给谁 - $this->send($this->config['host'], $msg, $address); + $this->send($this->config['host'], $this->config['port'], $msg, $address); } + /** + * 检测客户授权 + * @access protected + * @return bool + */ protected function check() { $tabid = $this->getClientArg('tabid'); @@ -199,17 +227,17 @@ class Socket } //用户认证 - $allow_client_ids = $this->config['allow_client_ids']; + $allowClientIds = $this->config['allow_client_ids']; - if (!empty($allow_client_ids)) { + if (!empty($allowClientIds)) { //通过数组交集得出授权强制推送的client_id - $this->allowForceClientIds = array_intersect($allow_client_ids, $this->config['force_client_ids']); + $this->allowForceClientIds = array_intersect($allowClientIds, $this->config['force_client_ids']); if (!$tabid && count($this->allowForceClientIds)) { return true; } - $client_id = $this->getClientArg('client_id'); - if (!in_array($client_id, $allow_client_ids)) { + $clientId = $this->getClientArg('client_id'); + if (!in_array($clientId, $allowClientIds)) { return false; } } else { @@ -219,53 +247,58 @@ class Socket return true; } - protected function getClientArg($name) + /** + * 获取客户参数 + * @access protected + * @param string $name + * @return string + */ + protected function getClientArg(string $name) { - static $args = []; - - $key = 'HTTP_USER_AGENT'; - - if (isset($_SERVER['HTTP_SOCKETLOG'])) { - $key = 'HTTP_SOCKETLOG'; + if (!$this->app->exists('request')) { + return ''; } - if (!isset($_SERVER[$key])) { - return; - } - - if (empty($args)) { - if (!preg_match('/SocketLog\((.*?)\)/', $_SERVER[$key], $match)) { - $args = ['tabid' => null]; - return; + if (empty($this->clientArg)) { + if (empty($socketLog = $this->app->request->header('socketlog'))) { + if (empty($socketLog = $this->app->request->header('User-Agent'))) { + return ''; + } } - parse_str($match[1], $args); + + if (!preg_match('/SocketLog\((.*?)\)/', $socketLog, $match)) { + $this->clientArg = ['tabid' => null, 'client_id' => null]; + return ''; + } + parse_str($match[1] ?? '', $this->clientArg); } - if (isset($args[$name])) { - return $args[$name]; + if (isset($this->clientArg[$name])) { + return $this->clientArg[$name]; } - return; + return ''; } /** * @access protected - * @param string $host - $host of socket server - * @param string $message - 发送的消息 - * @param string $address - 地址 + * @param string $host - $host of socket server + * @param int $port - $port of socket server + * @param string $message - 发送的消息 + * @param string $address - 地址 * @return bool */ - protected function send($host, $message = '', $address = '/') + protected function send($host, $port, $message = '', $address = '/') { - $url = 'http://' . $host . ':' . $this->port . $address; + $url = 'http://' . $host . ':' . $port . $address; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $message); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 1); - curl_setopt($ch, CURLOPT_TIMEOUT, 10); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->config['curl_opt'][CURLOPT_CONNECTTIMEOUT] ?? 1); + curl_setopt($ch, CURLOPT_TIMEOUT, $this->config['curl_opt'][CURLOPT_TIMEOUT] ?? 10); $headers = [ "Content-Type: application/json;charset=UTF-8", @@ -275,5 +308,4 @@ class Socket return curl_exec($ch); } - } diff --git a/vendor/topthink/framework/src/think/middleware/AllowCrossDomain.php b/vendor/topthink/framework/src/think/middleware/AllowCrossDomain.php new file mode 100644 index 000000000..b7ab842c4 --- /dev/null +++ b/vendor/topthink/framework/src/think/middleware/AllowCrossDomain.php @@ -0,0 +1,63 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\middleware; + +use Closure; +use think\Config; +use think\Request; +use think\Response; + +/** + * 跨域请求支持 + */ +class AllowCrossDomain +{ + protected $cookieDomain; + + protected $header = [ + 'Access-Control-Allow-Credentials' => 'true', + 'Access-Control-Max-Age' => 1800, + 'Access-Control-Allow-Methods' => 'GET, POST, PATCH, PUT, DELETE, OPTIONS', + 'Access-Control-Allow-Headers' => 'Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-CSRF-TOKEN, X-Requested-With', + ]; + + public function __construct(Config $config) + { + $this->cookieDomain = $config->get('cookie.domain', ''); + } + + /** + * 允许跨域请求 + * @access public + * @param Request $request + * @param Closure $next + * @param array $header + * @return Response + */ + public function handle($request, Closure $next, ? array $header = []) + { + $header = !empty($header) ? array_merge($this->header, $header) : $this->header; + + if (!isset($header['Access-Control-Allow-Origin'])) { + $origin = $request->header('origin'); + + if ($origin && ('' == $this->cookieDomain || strpos($origin, $this->cookieDomain))) { + $header['Access-Control-Allow-Origin'] = $origin; + } else { + $header['Access-Control-Allow-Origin'] = '*'; + } + } + + return $next($request)->header($header); + } +} diff --git a/vendor/topthink/framework/src/think/middleware/CheckRequestCache.php b/vendor/topthink/framework/src/think/middleware/CheckRequestCache.php new file mode 100644 index 000000000..b1143519c --- /dev/null +++ b/vendor/topthink/framework/src/think/middleware/CheckRequestCache.php @@ -0,0 +1,183 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\middleware; + +use Closure; +use think\Cache; +use think\Config; +use think\Request; +use think\Response; + +/** + * 请求缓存处理 + */ +class CheckRequestCache +{ + /** + * 缓存对象 + * @var Cache + */ + protected $cache; + + /** + * 配置参数 + * @var array + */ + protected $config = [ + // 请求缓存规则 true为自动规则 + 'request_cache_key' => true, + // 请求缓存有效期 + 'request_cache_expire' => null, + // 全局请求缓存排除规则 + 'request_cache_except' => [], + // 请求缓存的Tag + 'request_cache_tag' => '', + ]; + + public function __construct(Cache $cache, Config $config) + { + $this->cache = $cache; + $this->config = array_merge($this->config, $config->get('route')); + } + + /** + * 设置当前地址的请求缓存 + * @access public + * @param Request $request + * @param Closure $next + * @param mixed $cache + * @return Response + */ + public function handle($request, Closure $next, $cache = null) + { + if ($request->isGet() && false !== $cache) { + if (false === $this->config['request_cache_key']) { + // 关闭当前缓存 + $cache = false; + } + + $cache = $cache ?? $this->getRequestCache($request); + + if ($cache) { + if (is_array($cache)) { + [$key, $expire, $tag] = array_pad($cache, 3, null); + } else { + $key = md5($request->url(true)); + $expire = $cache; + $tag = null; + } + + $key = $this->parseCacheKey($request, $key); + + if (strtotime($request->server('HTTP_IF_MODIFIED_SINCE', '')) + $expire > $request->server('REQUEST_TIME')) { + // 读取缓存 + return Response::create()->code(304); + } elseif (($hit = $this->cache->get($key)) !== null) { + [$content, $header, $when] = $hit; + if (null === $expire || $when + $expire > $request->server('REQUEST_TIME')) { + return Response::create($content)->header($header); + } + } + } + } + + $response = $next($request); + + if (isset($key) && 200 == $response->getCode() && $response->isAllowCache()) { + $header = $response->getHeader(); + $header['Cache-Control'] = 'max-age=' . $expire . ',must-revalidate'; + $header['Last-Modified'] = gmdate('D, d M Y H:i:s') . ' GMT'; + $header['Expires'] = gmdate('D, d M Y H:i:s', time() + $expire) . ' GMT'; + + $this->cache->tag($tag)->set($key, [$response->getContent(), $header, time()], $expire); + } + + return $response; + } + + /** + * 读取当前地址的请求缓存信息 + * @access protected + * @param Request $request + * @return mixed + */ + protected function getRequestCache($request) + { + $key = $this->config['request_cache_key']; + $expire = $this->config['request_cache_expire']; + $except = $this->config['request_cache_except']; + $tag = $this->config['request_cache_tag']; + + foreach ($except as $rule) { + if (0 === stripos($request->url(), $rule)) { + return; + } + } + + return [$key, $expire, $tag]; + } + + /** + * 读取当前地址的请求缓存信息 + * @access protected + * @param Request $request + * @param mixed $key + * @return null|string + */ + protected function parseCacheKey($request, $key) + { + if ($key instanceof \Closure) { + $key = call_user_func($key, $request); + } + + if (false === $key) { + // 关闭当前缓存 + return; + } + + if (true === $key) { + // 自动缓存功能 + $key = '__URL__'; + } elseif (strpos($key, '|')) { + [$key, $fun] = explode('|', $key); + } + + // 特殊规则替换 + if (false !== strpos($key, '__')) { + $key = str_replace(['__CONTROLLER__', '__ACTION__', '__URL__'], [$request->controller(), $request->action(), md5($request->url(true))], $key); + } + + if (false !== strpos($key, ':')) { + $param = $request->param(); + + foreach ($param as $item => $val) { + if (is_string($val) && false !== strpos($key, ':' . $item)) { + $key = str_replace(':' . $item, (string) $val, $key); + } + } + } elseif (strpos($key, ']')) { + if ('[' . $request->ext() . ']' == $key) { + // 缓存某个后缀的请求 + $key = md5($request->url()); + } else { + return; + } + } + + if (isset($fun)) { + $key = $fun($key); + } + + return $key; + } +} diff --git a/vendor/topthink/framework/src/think/middleware/FormTokenCheck.php b/vendor/topthink/framework/src/think/middleware/FormTokenCheck.php new file mode 100644 index 000000000..efbb77b17 --- /dev/null +++ b/vendor/topthink/framework/src/think/middleware/FormTokenCheck.php @@ -0,0 +1,45 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\middleware; + +use Closure; +use think\exception\ValidateException; +use think\Request; +use think\Response; + +/** + * 表单令牌支持 + */ +class FormTokenCheck +{ + + /** + * 表单令牌检测 + * @access public + * @param Request $request + * @param Closure $next + * @param string $token 表单令牌Token名称 + * @return Response + */ + public function handle(Request $request, Closure $next, string $token = null) + { + $check = $request->checkToken($token ?: '__token__'); + + if (false === $check) { + throw new ValidateException('invalid token'); + } + + return $next($request); + } + +} diff --git a/vendor/topthink/framework/src/think/middleware/LoadLangPack.php b/vendor/topthink/framework/src/think/middleware/LoadLangPack.php new file mode 100644 index 000000000..478e29c90 --- /dev/null +++ b/vendor/topthink/framework/src/think/middleware/LoadLangPack.php @@ -0,0 +1,61 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\middleware; + +use Closure; +use think\App; +use think\Lang; +use think\Request; +use think\Response; + +/** + * 多语言加载 + */ +class LoadLangPack +{ + protected $app; + + protected $lang; + + public function __construct(App $app, Lang $lang) + { + $this->app = $app; + $this->lang = $lang; + } + + /** + * 路由初始化(路由规则注册) + * @access public + * @param Request $request + * @param Closure $next + * @return Response + */ + public function handle($request, Closure $next) + { + // 自动侦测当前语言 + $langset = $this->lang->detect($request); + + if ($this->lang->defaultLangSet() != $langset) { + // 加载系统语言包 + $this->lang->load([ + $this->app->getThinkPath() . 'lang' . DIRECTORY_SEPARATOR . $langset . '.php', + ]); + + $this->app->LoadLangPack($langset); + } + + $this->lang->saveToCookie($this->app->cookie); + + return $next($request); + } +} diff --git a/vendor/topthink/framework/src/think/middleware/SessionInit.php b/vendor/topthink/framework/src/think/middleware/SessionInit.php new file mode 100644 index 000000000..3cb2fad96 --- /dev/null +++ b/vendor/topthink/framework/src/think/middleware/SessionInit.php @@ -0,0 +1,80 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\middleware; + +use Closure; +use think\App; +use think\Request; +use think\Response; +use think\Session; + +/** + * Session初始化 + */ +class SessionInit +{ + + /** @var App */ + protected $app; + + /** @var Session */ + protected $session; + + public function __construct(App $app, Session $session) + { + $this->app = $app; + $this->session = $session; + } + + /** + * Session初始化 + * @access public + * @param Request $request + * @param Closure $next + * @return Response + */ + public function handle($request, Closure $next) + { + // Session初始化 + $varSessionId = $this->app->config->get('session.var_session_id'); + $cookieName = $this->session->getName(); + + if ($varSessionId && $request->request($varSessionId)) { + $sessionId = $request->request($varSessionId); + } else { + $sessionId = $request->cookie($cookieName); + } + + if ($sessionId) { + $this->session->setId($sessionId); + } + + $this->session->init(); + + $request->withSession($this->session); + + /** @var Response $response */ + $response = $next($request); + + $response->setSession($this->session); + + $this->app->cookie->set($cookieName, $this->session->getId()); + + return $response; + } + + public function end(Response $response) + { + $this->session->save(); + } +} diff --git a/thinkphp/library/think/response/Download.php b/vendor/topthink/framework/src/think/response/File.php old mode 100755 new mode 100644 similarity index 77% rename from thinkphp/library/think/response/Download.php rename to vendor/topthink/framework/src/think/response/File.php index d5fcb444c..1e45f2f48 --- a/thinkphp/library/think/response/Download.php +++ b/vendor/topthink/framework/src/think/response/File.php @@ -2,25 +2,35 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\response; use think\Exception; use think\Response; -class Download extends Response +/** + * File Response + */ +class File extends Response { protected $expire = 360; protected $name; protected $mimeType; protected $isContent = false; - protected $openinBrower = false; + protected $force = true; + + public function __construct($data = '', int $code = 200) + { + $this->init($data, $code); + } + /** * 处理数据 * @access protected @@ -34,7 +44,9 @@ class Download extends Response throw new Exception('file not exists:' . $data); } - ob_end_clean(); + while (ob_get_level() > 0) { + ob_end_clean(); + } if (!empty($this->name)) { $name = $this->name; @@ -53,15 +65,14 @@ class Download extends Response $this->header['Pragma'] = 'public'; $this->header['Content-Type'] = $mimeType ?: 'application/octet-stream'; $this->header['Cache-control'] = 'max-age=' . $this->expire; - $this->header['Content-Disposition'] = $this->openinBrower ? 'inline' : 'attachment; filename="' . $name . '"'; + $this->header['Content-Disposition'] = ($this->force ? 'attachment; ' : '') . 'filename="' . $name . '"'; $this->header['Content-Length'] = $size; $this->header['Content-Transfer-Encoding'] = 'binary'; $this->header['Expires'] = gmdate("D, d M Y H:i:s", time() + $this->expire) . ' GMT'; $this->lastModified(gmdate('D, d M Y H:i:s', time()) . ' GMT'); - $data = $this->isContent ? $data : file_get_contents($data); - return $data; + return $this->isContent ? $data : file_get_contents($data); } /** @@ -70,7 +81,7 @@ class Download extends Response * @param bool $content * @return $this */ - public function isContent($content = true) + public function isContent(bool $content = true) { $this->isContent = $content; return $this; @@ -82,7 +93,7 @@ class Download extends Response * @param integer $expire 有效期 * @return $this */ - public function expire($expire) + public function expire(int $expire) { $this->expire = $expire; return $this; @@ -94,19 +105,31 @@ class Download extends Response * @param string $filename 文件名 * @return $this */ - public function mimeType($mimeType) + public function mimeType(string $mimeType) { $this->mimeType = $mimeType; return $this; } + /** + * 设置文件强制下载 + * @access public + * @param bool $force 强制浏览器下载 + * @return $this + */ + public function force(bool $force) + { + $this->force = $force; + return $this; + } + /** * 获取文件类型信息 * @access public * @param string $filename 文件名 * @return string */ - protected function getMimeType($filename) + protected function getMimeType(string $filename): string { if (!empty($this->mimeType)) { return $this->mimeType; @@ -124,7 +147,7 @@ class Download extends Response * @param bool $extension 后缀自动识别 * @return $this */ - public function name($filename, $extension = true) + public function name(string $filename, bool $extension = true) { $this->name = $filename; @@ -134,15 +157,4 @@ class Download extends Response return $this; } - - /** - * 设置是否在浏览器中显示文件 - * @access public - * @param bool $openinBrower 是否在浏览器中显示文件 - * @return $this - */ - public function openinBrower($openinBrower) { - $this->openinBrower = $openinBrower; - return $this; - } } diff --git a/thinkphp/library/think/response/Jump.php b/vendor/topthink/framework/src/think/response/Html.php old mode 100755 new mode 100644 similarity index 63% rename from thinkphp/library/think/response/Jump.php rename to vendor/topthink/framework/src/think/response/Html.php index 258448ca4..c158f7815 --- a/thinkphp/library/think/response/Jump.php +++ b/vendor/topthink/framework/src/think/response/Html.php @@ -2,31 +2,33 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\response; +use think\Cookie; use think\Response; -class Jump extends Response +/** + * Html Response + */ +class Html extends Response { + /** + * 输出type + * @var string + */ protected $contentType = 'text/html'; - /** - * 处理数据 - * @access protected - * @param mixed $data 要处理的数据 - * @return mixed - * @throws \Exception - */ - protected function output($data) + public function __construct(Cookie $cookie, $data = '', int $code = 200) { - $data = $this->app['view']->fetch($this->options['jump_template'], $data); - return $data; + $this->init($data, $code); + $this->cookie = $cookie; } } diff --git a/thinkphp/library/think/response/Json.php b/vendor/topthink/framework/src/think/response/Json.php old mode 100755 new mode 100644 similarity index 79% rename from thinkphp/library/think/response/Json.php rename to vendor/topthink/framework/src/think/response/Json.php index aa5bbd6fa..a84501f55 --- a/thinkphp/library/think/response/Json.php +++ b/vendor/topthink/framework/src/think/response/Json.php @@ -2,17 +2,22 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\response; +use think\Cookie; use think\Response; +/** + * Json Response + */ class Json extends Response { // 输出参数 @@ -22,14 +27,20 @@ class Json extends Response protected $contentType = 'application/json'; + public function __construct(Cookie $cookie, $data = '', int $code = 200) + { + $this->init($data, $code); + $this->cookie = $cookie; + } + /** * 处理数据 * @access protected * @param mixed $data 要处理的数据 - * @return mixed + * @return string * @throws \Exception */ - protected function output($data) + protected function output($data): string { try { // 返回JSON数据格式到客户端 包含状态信息 diff --git a/thinkphp/library/think/response/Jsonp.php b/vendor/topthink/framework/src/think/response/Jsonp.php old mode 100755 new mode 100644 similarity index 71% rename from thinkphp/library/think/response/Jsonp.php rename to vendor/topthink/framework/src/think/response/Jsonp.php index f69e88e1d..81d3a06e1 --- a/thinkphp/library/think/response/Jsonp.php +++ b/vendor/topthink/framework/src/think/response/Jsonp.php @@ -2,17 +2,23 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\response; +use think\Cookie; +use think\Request; use think\Response; +/** + * Jsonp Response + */ class Jsonp extends Response { // 输出参数 @@ -24,19 +30,29 @@ class Jsonp extends Response protected $contentType = 'application/javascript'; + protected $request; + + public function __construct(Cookie $cookie, Request $request, $data = '', int $code = 200) + { + $this->init($data, $code); + + $this->cookie = $cookie; + $this->request = $request; + } + /** * 处理数据 * @access protected * @param mixed $data 要处理的数据 - * @return mixed + * @return string * @throws \Exception */ - protected function output($data) + protected function output($data): string { try { // 返回JSON数据格式到客户端 包含状态信息 [当url_common_param为false时是无法获取到$_GET的数据的,故使用Request来获取] - $var_jsonp_handler = $this->app['request']->param($this->options['var_jsonp_handler'], ""); - $handler = !empty($var_jsonp_handler) ? $var_jsonp_handler : $this->options['default_jsonp_handler']; + $varJsonpHandler = $this->request->param($this->options['var_jsonp_handler'], ""); + $handler = !empty($varJsonpHandler) ? $varJsonpHandler : $this->options['default_jsonp_handler']; $data = json_encode($data, $this->options['json_encode_param']); diff --git a/thinkphp/library/think/response/Redirect.php b/vendor/topthink/framework/src/think/response/Redirect.php old mode 100755 new mode 100644 similarity index 51% rename from thinkphp/library/think/response/Redirect.php rename to vendor/topthink/framework/src/think/response/Redirect.php index 73729ce88..1f38764c9 --- a/thinkphp/library/think/response/Redirect.php +++ b/vendor/topthink/framework/src/think/response/Redirect.php @@ -2,28 +2,36 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\response; +use think\Cookie; +use think\Request; use think\Response; +use think\Session; +/** + * Redirect Response + */ class Redirect extends Response { - protected $options = []; + protected $request; - // URL参数 - protected $params = []; - - public function __construct($data = '', $code = 302, array $header = [], array $options = []) + public function __construct(Cookie $cookie, Request $request, Session $session, $data = '', int $code = 302) { - parent::__construct($data, $code, $header, $options); + $this->init((string) $data, $code); + + $this->cookie = $cookie; + $this->request = $request; + $this->session = $session; $this->cacheControl('no-cache,must-revalidate'); } @@ -32,13 +40,13 @@ class Redirect extends Response * 处理数据 * @access protected * @param mixed $data 要处理的数据 - * @return mixed + * @return string */ - protected function output($data) + protected function output($data): string { - $this->header['Location'] = $this->getTargetUrl(); + $this->header['Location'] = $data; - return; + return ''; } /** @@ -50,40 +58,17 @@ class Redirect extends Response */ public function with($name, $value = null) { - $session = $this->app['session']; - if (is_array($name)) { foreach ($name as $key => $val) { - $session->flash($key, $val); + $this->session->flash($key, $val); } } else { - $session->flash($name, $value); + $this->session->flash($name, $value); } return $this; } - /** - * 获取跳转地址 - * @access public - * @return string - */ - public function getTargetUrl() - { - if (strpos($this->data, '://') || (0 === strpos($this->data, '/') && empty($this->params))) { - return $this->data; - } else { - return $this->app['url']->build($this->data, $this->params); - } - } - - public function params($params = []) - { - $this->params = $params; - - return $this; - } - /** * 记住当前url后跳转 * @access public @@ -91,7 +76,7 @@ class Redirect extends Response */ public function remember() { - $this->app['session']->set('redirect_url', $this->app['request']->url()); + $this->session->set('redirect_url', $this->request->url()); return $this; } @@ -99,18 +84,13 @@ class Redirect extends Response /** * 跳转到上次记住的url * @access public - * @param string $url 闪存数据不存在时的跳转地址 * @return $this */ - public function restore($url = null) + public function restore() { - $session = $this->app['session']; - - if ($session->has('redirect_url')) { - $this->data = $session->get('redirect_url'); - $session->delete('redirect_url'); - } elseif ($url) { - $this->data = $url; + if ($this->session->has('redirect_url')) { + $this->data = $this->session->get('redirect_url'); + $this->session->delete('redirect_url'); } return $this; diff --git a/vendor/topthink/framework/src/think/response/View.php b/vendor/topthink/framework/src/think/response/View.php new file mode 100644 index 000000000..2c116c778 --- /dev/null +++ b/vendor/topthink/framework/src/think/response/View.php @@ -0,0 +1,151 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\response; + +use think\Cookie; +use think\Response; +use think\View as BaseView; + +/** + * View Response + */ +class View extends Response +{ + /** + * 输出参数 + * @var array + */ + protected $options = []; + + /** + * 输出变量 + * @var array + */ + protected $vars = []; + + /** + * 输出过滤 + * @var mixed + */ + protected $filter; + + /** + * 输出type + * @var string + */ + protected $contentType = 'text/html'; + + /** + * View对象 + * @var BaseView + */ + protected $view; + + /** + * 是否内容渲染 + * @var bool + */ + protected $isContent = false; + + public function __construct(Cookie $cookie, BaseView $view, $data = '', int $code = 200) + { + $this->init($data, $code); + + $this->cookie = $cookie; + $this->view = $view; + } + + /** + * 设置是否为内容渲染 + * @access public + * @param bool $content + * @return $this + */ + public function isContent(bool $content = true) + { + $this->isContent = $content; + return $this; + } + + /** + * 处理数据 + * @access protected + * @param mixed $data 要处理的数据 + * @return string + */ + protected function output($data): string + { + // 渲染模板输出 + $this->view->filter($this->filter); + return $this->isContent ? + $this->view->display($data, $this->vars) : + $this->view->fetch($data, $this->vars); + } + + /** + * 获取视图变量 + * @access public + * @param string $name 模板变量 + * @return mixed + */ + public function getVars(string $name = null) + { + if (is_null($name)) { + return $this->vars; + } else { + return $this->vars[$name] ?? null; + } + } + + /** + * 模板变量赋值 + * @access public + * @param string|array $name 模板变量 + * @param mixed $value 变量值 + * @return $this + */ + public function assign($name, $value = null) + { + if (is_array($name)) { + $this->vars = array_merge($this->vars, $name); + } else { + $this->vars[$name] = $value; + } + + return $this; + } + + /** + * 视图内容过滤 + * @access public + * @param callable $filter + * @return $this + */ + public function filter(callable $filter = null) + { + $this->filter = $filter; + return $this; + } + + /** + * 检查模板是否存在 + * @access public + * @param string $name 模板名 + * @return bool + */ + public function exists(string $name): bool + { + return $this->view->exists($name); + } + +} diff --git a/thinkphp/library/think/response/Xml.php b/vendor/topthink/framework/src/think/response/Xml.php old mode 100755 new mode 100644 similarity index 85% rename from thinkphp/library/think/response/Xml.php rename to vendor/topthink/framework/src/think/response/Xml.php index 9c1681a4a..bddbb48b5 --- a/thinkphp/library/think/response/Xml.php +++ b/vendor/topthink/framework/src/think/response/Xml.php @@ -2,19 +2,24 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\response; use think\Collection; +use think\Cookie; use think\Model; use think\Response; +/** + * XML Response + */ class Xml extends Response { // 输出参数 @@ -33,13 +38,19 @@ class Xml extends Response protected $contentType = 'text/xml'; + public function __construct(Cookie $cookie, $data = '', int $code = 200) + { + $this->init($data, $code); + $this->cookie = $cookie; + } + /** * 处理数据 * @access protected * @param mixed $data 要处理的数据 * @return mixed */ - protected function output($data) + protected function output($data): string { if (is_string($data)) { if (0 !== strpos($data, ' +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\route; + +use think\App; +use think\Container; +use think\Request; +use think\Response; +use think\Validate; + +/** + * 路由调度基础类 + */ +abstract class Dispatch +{ + /** + * 应用对象 + * @var \think\App + */ + protected $app; + + /** + * 请求对象 + * @var Request + */ + protected $request; + + /** + * 路由规则 + * @var Rule + */ + protected $rule; + + /** + * 调度信息 + * @var mixed + */ + protected $dispatch; + + /** + * 路由变量 + * @var array + */ + protected $param; + + public function __construct(Request $request, Rule $rule, $dispatch, array $param = []) + { + $this->request = $request; + $this->rule = $rule; + $this->dispatch = $dispatch; + $this->param = $param; + } + + public function init(App $app) + { + $this->app = $app; + + // 执行路由后置操作 + $this->doRouteAfter(); + } + + /** + * 执行路由调度 + * @access public + * @return mixed + */ + public function run(): Response + { + if ($this->rule instanceof RuleItem && $this->request->method() == 'OPTIONS' && $this->rule->isAutoOptions()) { + $rules = $this->rule->getRouter()->getRule($this->rule->getRule()); + $allow = []; + foreach ($rules as $item) { + $allow[] = strtoupper($item->getMethod()); + } + + return Response::create('', 'html', 204)->header(['Allow' => implode(', ', $allow)]); + } + + $data = $this->exec(); + return $this->autoResponse($data); + } + + protected function autoResponse($data): Response + { + if ($data instanceof Response) { + $response = $data; + } elseif (!is_null($data)) { + // 默认自动识别响应输出类型 + $type = $this->request->isJson() ? 'json' : 'html'; + $response = Response::create($data, $type); + } else { + $data = ob_get_clean(); + + $content = false === $data ? '' : $data; + $status = '' === $content && $this->request->isJson() ? 204 : 200; + $response = Response::create($content, 'html', $status); + } + + return $response; + } + + /** + * 检查路由后置操作 + * @access protected + * @return void + */ + protected function doRouteAfter(): void + { + $option = $this->rule->getOption(); + + // 添加中间件 + if (!empty($option['middleware'])) { + $this->app->middleware->import($option['middleware'], 'route'); + } + + if (!empty($option['append'])) { + $this->param = array_merge($this->param, $option['append']); + } + + // 绑定模型数据 + if (!empty($option['model'])) { + $this->createBindModel($option['model'], $this->param); + } + + // 记录当前请求的路由规则 + $this->request->setRule($this->rule); + + // 记录路由变量 + $this->request->setRoute($this->param); + + // 数据自动验证 + if (isset($option['validate'])) { + $this->autoValidate($option['validate']); + } + } + + /** + * 路由绑定模型实例 + * @access protected + * @param array $bindModel 绑定模型 + * @param array $matches 路由变量 + * @return void + */ + protected function createBindModel(array $bindModel, array $matches): void + { + foreach ($bindModel as $key => $val) { + if ($val instanceof \Closure) { + $result = $this->app->invokeFunction($val, $matches); + } else { + $fields = explode('&', $key); + + if (is_array($val)) { + [$model, $exception] = $val; + } else { + $model = $val; + $exception = true; + } + + $where = []; + $match = true; + + foreach ($fields as $field) { + if (!isset($matches[$field])) { + $match = false; + break; + } else { + $where[] = [$field, '=', $matches[$field]]; + } + } + + if ($match) { + $result = $model::where($where)->failException($exception)->find(); + } + } + + if (!empty($result)) { + // 注入容器 + $this->app->instance(get_class($result), $result); + } + } + } + + /** + * 验证数据 + * @access protected + * @param array $option + * @return void + * @throws \think\exception\ValidateException + */ + protected function autoValidate(array $option): void + { + [$validate, $scene, $message, $batch] = $option; + + if (is_array($validate)) { + // 指定验证规则 + $v = new Validate(); + $v->rule($validate); + } else { + // 调用验证器 + $class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate); + + $v = new $class(); + + if (!empty($scene)) { + $v->scene($scene); + } + } + + /** @var Validate $v */ + $v->message($message) + ->batch($batch) + ->failException(true) + ->check($this->request->param()); + } + + public function getDispatch() + { + return $this->dispatch; + } + + public function getParam(): array + { + return $this->param; + } + + abstract public function exec(); + + public function __sleep() + { + return ['rule', 'dispatch', 'param', 'controller', 'actionName']; + } + + public function __wakeup() + { + $this->app = Container::pull('app'); + $this->request = $this->app->request; + } + + public function __debugInfo() + { + return [ + 'dispatch' => $this->dispatch, + 'param' => $this->param, + 'rule' => $this->rule, + ]; + } +} diff --git a/thinkphp/library/think/route/Domain.php b/vendor/topthink/framework/src/think/route/Domain.php old mode 100755 new mode 100644 similarity index 57% rename from thinkphp/library/think/route/Domain.php rename to vendor/topthink/framework/src/think/route/Domain.php index 80950dc28..84f1d463b --- a/thinkphp/library/think/route/Domain.php +++ b/vendor/topthink/framework/src/think/route/Domain.php @@ -2,22 +2,25 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\route; -use think\Container; -use think\Loader; +use think\helper\Str; +use think\Request; use think\Route; use think\route\dispatch\Callback as CallbackDispatch; use think\route\dispatch\Controller as ControllerDispatch; -use think\route\dispatch\Module as ModuleDispatch; +/** + * 域名路由 + */ class Domain extends RuleGroup { /** @@ -26,16 +29,12 @@ class Domain extends RuleGroup * @param Route $router 路由对象 * @param string $name 路由域名 * @param mixed $rule 域名路由 - * @param array $option 路由参数 - * @param array $pattern 变量规则 */ - public function __construct(Route $router, $name = '', $rule = null, $option = [], $pattern = []) + public function __construct(Route $router, string $name = null, $rule = null) { - $this->router = $router; - $this->domain = $name; - $this->option = $option; - $this->rule = $rule; - $this->pattern = $pattern; + $this->router = $router; + $this->domain = $name; + $this->rule = $rule; } /** @@ -46,20 +45,13 @@ class Domain extends RuleGroup * @param bool $completeMatch 路由是否完全匹配 * @return Dispatch|false */ - public function check($request, $url, $completeMatch = false) + public function check(Request $request, string $url, bool $completeMatch = false) { - // 检测别名路由 - $result = $this->checkRouteAlias($request, $url); - - if (false !== $result) { - return $result; - } - // 检测URL绑定 $result = $this->checkUrlBind($request, $url); if (!empty($this->option['append'])) { - $request->setRouteVars($this->option['append']); + $request->setRoute($this->option['append']); unset($this->option['append']); } @@ -67,12 +59,6 @@ class Domain extends RuleGroup return $result; } - // 添加域名中间件 - if (!empty($this->option['middleware'])) { - Container::get('middleware')->import($this->option['middleware']); - unset($this->option['middleware']); - } - return parent::check($request, $url, $completeMatch); } @@ -82,28 +68,13 @@ class Domain extends RuleGroup * @param string $bind 绑定信息 * @return $this */ - public function bind($bind) + public function bind(string $bind) { $this->router->bind($bind, $this->domain); + return $this; } - /** - * 检测路由别名 - * @access private - * @param Request $request - * @param string $url URL地址 - * @return Dispatch|false - */ - private function checkRouteAlias($request, $url) - { - $alias = strpos($url, '|') ? strstr($url, '|', true) : $url; - - $item = $this->router->getAlias($alias); - - return $item ? $item->check($request, $url) : false; - } - /** * 检测URL绑定 * @access private @@ -111,16 +82,13 @@ class Domain extends RuleGroup * @param string $url URL地址 * @return Dispatch|false */ - private function checkUrlBind($request, $url) + private function checkUrlBind(Request $request, string $url) { - $bind = $this->router->getBind($this->domain); + $bind = $this->router->getDomainBind($this->domain); - if (!empty($bind)) { + if ($bind) { $this->parseBindAppendParam($bind); - // 记录绑定信息 - Container::get('app')->log('[ BIND ] ' . var_export($bind, true)); - // 如果有URL绑定 则进行绑定检测 $type = substr($bind, 0, 1); $bind = substr($bind, 1); @@ -139,10 +107,10 @@ class Domain extends RuleGroup return false; } - protected function parseBindAppendParam(&$bind) + protected function parseBindAppendParam(string &$bind): void { if (false !== strpos($bind, '?')) { - list($bind, $query) = explode('?', $bind); + [$bind, $query] = explode('?', $bind); parse_str($query, $vars); $this->append($vars); } @@ -156,14 +124,14 @@ class Domain extends RuleGroup * @param string $class 类名(带命名空间) * @return CallbackDispatch */ - protected function bindToClass($request, $url, $class) + protected function bindToClass(Request $request, string $url, string $class): CallbackDispatch { $array = explode('|', $url, 2); $action = !empty($array[0]) ? $array[0] : $this->router->config('default_action'); $param = []; if (!empty($array[1])) { - $this->parseUrlParams($request, $array[1], $param); + $this->parseUrlParams($array[1], $param); } return new CallbackDispatch($request, $this, [$class, $action], $param); @@ -177,7 +145,7 @@ class Domain extends RuleGroup * @param string $namespace 命名空间 * @return CallbackDispatch */ - protected function bindToNamespace($request, $url, $namespace) + protected function bindToNamespace(Request $request, string $url, string $namespace): CallbackDispatch { $array = explode('|', $url, 3); $class = !empty($array[0]) ? $array[0] : $this->router->config('default_controller'); @@ -185,52 +153,31 @@ class Domain extends RuleGroup $param = []; if (!empty($array[2])) { - $this->parseUrlParams($request, $array[2], $param); + $this->parseUrlParams($array[2], $param); } - return new CallbackDispatch($request, $this, [$namespace . '\\' . Loader::parseName($class, 1), $method], $param); + return new CallbackDispatch($request, $this, [$namespace . '\\' . Str::studly($class), $method], $param); } /** - * 绑定到控制器类 + * 绑定到控制器 * @access protected * @param Request $request * @param string $url URL地址 - * @param string $controller 控制器名 (支持带模块名 index/user ) + * @param string $controller 控制器名 * @return ControllerDispatch */ - protected function bindToController($request, $url, $controller) + protected function bindToController(Request $request, string $url, string $controller): ControllerDispatch { $array = explode('|', $url, 2); $action = !empty($array[0]) ? $array[0] : $this->router->config('default_action'); $param = []; if (!empty($array[1])) { - $this->parseUrlParams($request, $array[1], $param); + $this->parseUrlParams($array[1], $param); } return new ControllerDispatch($request, $this, $controller . '/' . $action, $param); } - /** - * 绑定到模块/控制器 - * @access protected - * @param Request $request - * @param string $url URL地址 - * @param string $controller 控制器类名(带命名空间) - * @return ModuleDispatch - */ - protected function bindToModule($request, $url, $controller) - { - $array = explode('|', $url, 2); - $action = !empty($array[0]) ? $array[0] : $this->router->config('default_action'); - $param = []; - - if (!empty($array[1])) { - $this->parseUrlParams($request, $array[1], $param); - } - - return new ModuleDispatch($request, $this, $controller . '/' . $action, $param); - } - } diff --git a/vendor/topthink/framework/src/think/route/Resource.php b/vendor/topthink/framework/src/think/route/Resource.php new file mode 100644 index 000000000..bb37cb6d9 --- /dev/null +++ b/vendor/topthink/framework/src/think/route/Resource.php @@ -0,0 +1,251 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\route; + +use think\Route; + +/** + * 资源路由类 + */ +class Resource extends RuleGroup +{ + /** + * 资源路由名称 + * @var string + */ + protected $resource; + + /** + * 资源路由地址 + * @var string + */ + protected $route; + + /** + * REST方法定义 + * @var array + */ + protected $rest = []; + + /** + * 模型绑定 + * @var array + */ + protected $model = []; + + /** + * 数据验证 + * @var array + */ + protected $validate = []; + + /** + * 中间件 + * @var array + */ + protected $middleware = []; + + /** + * 架构函数 + * @access public + * @param Route $router 路由对象 + * @param RuleGroup $parent 上级对象 + * @param string $name 资源名称 + * @param string $route 路由地址 + * @param array $rest 资源定义 + */ + public function __construct(Route $router, RuleGroup $parent = null, string $name = '', string $route = '', array $rest = []) + { + $name = ltrim($name, '/'); + $this->router = $router; + $this->parent = $parent; + $this->resource = $name; + $this->route = $route; + $this->name = strpos($name, '.') ? strstr($name, '.', true) : $name; + + $this->setFullName(); + + // 资源路由默认为完整匹配 + $this->option['complete_match'] = true; + + $this->rest = $rest; + + if ($this->parent) { + $this->domain = $this->parent->getDomain(); + $this->parent->addRuleItem($this); + } + + if ($router->isTest()) { + $this->buildResourceRule(); + } + } + + /** + * 生成资源路由规则 + * @access protected + * @return void + */ + protected function buildResourceRule(): void + { + $rule = $this->resource; + $option = $this->option; + $origin = $this->router->getGroup(); + $this->router->setGroup($this); + + if (strpos($rule, '.')) { + // 注册嵌套资源路由 + $array = explode('.', $rule); + $last = array_pop($array); + $item = []; + + foreach ($array as $val) { + $item[] = $val . '/<' . ($option['var'][$val] ?? $val . '_id') . '>'; + } + + $rule = implode('/', $item) . '/' . $last; + } + + $prefix = substr($rule, strlen($this->name) + 1); + + // 注册资源路由 + foreach ($this->rest as $key => $val) { + if ((isset($option['only']) && !in_array($key, $option['only'])) + || (isset($option['except']) && in_array($key, $option['except']))) { + continue; + } + + if (isset($last) && strpos($val[1], '') && isset($option['var'][$last])) { + $val[1] = str_replace('', '<' . $option['var'][$last] . '>', $val[1]); + } elseif (strpos($val[1], '') && isset($option['var'][$rule])) { + $val[1] = str_replace('', '<' . $option['var'][$rule] . '>', $val[1]); + } + + $ruleItem = $this->addRule(trim($prefix . $val[1], '/'), $this->route . '/' . $val[2], $val[0]); + + foreach (['model', 'validate', 'middleware', 'pattern'] as $name) { + if (isset($this->$name[$key])) { + call_user_func_array([$ruleItem, $name], (array) $this->$name[$key]); + } + + } + } + + $this->router->setGroup($origin); + } + + /** + * 设置资源允许 + * @access public + * @param array $only 资源允许 + * @return $this + */ + public function only(array $only) + { + return $this->setOption('only', $only); + } + + /** + * 设置资源排除 + * @access public + * @param array $except 排除资源 + * @return $this + */ + public function except(array $except) + { + return $this->setOption('except', $except); + } + + /** + * 设置资源路由的变量 + * @access public + * @param array $vars 资源变量 + * @return $this + */ + public function vars(array $vars) + { + return $this->setOption('var', $vars); + } + + /** + * 绑定资源验证 + * @access public + * @param array|string $name 资源类型或者验证信息 + * @param array|string $validate 验证信息 + * @return $this + */ + public function withValidate($name, $validate = []) + { + if (is_array($name)) { + $this->validate = array_merge($this->validate, $name); + } else { + $this->validate[$name] = $validate; + } + + return $this; + } + + /** + * 绑定资源模型 + * @access public + * @param array|string $name 资源类型或者模型绑定 + * @param array|string $model 模型绑定 + * @return $this + */ + public function withModel($name, $model = []) + { + if (is_array($name)) { + $this->model = array_merge($this->model, $name); + } else { + $this->model[$name] = $model; + } + + return $this; + } + + /** + * 绑定资源模型 + * @access public + * @param array|string $name 资源类型或者中间件定义 + * @param array|string $middleware 中间件定义 + * @return $this + */ + public function withMiddleware($name, $middleware = []) + { + if (is_array($name)) { + $this->middleware = array_merge($this->middleware, $name); + } else { + $this->middleware[$name] = $middleware; + } + + return $this; + } + + /** + * rest方法定义和修改 + * @access public + * @param array|string $name 方法名称 + * @param array|bool $resource 资源 + * @return $this + */ + public function rest($name, $resource = []) + { + if (is_array($name)) { + $this->rest = $resource ? $name : array_merge($this->rest, $name); + } else { + $this->rest[$name] = $resource; + } + + return $this; + } + +} diff --git a/vendor/topthink/framework/src/think/route/Rule.php b/vendor/topthink/framework/src/think/route/Rule.php new file mode 100644 index 000000000..31b2e0e59 --- /dev/null +++ b/vendor/topthink/framework/src/think/route/Rule.php @@ -0,0 +1,905 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\route; + +use Closure; +use think\Container; +use think\middleware\AllowCrossDomain; +use think\middleware\CheckRequestCache; +use think\middleware\FormTokenCheck; +use think\Request; +use think\Route; +use think\route\dispatch\Callback as CallbackDispatch; +use think\route\dispatch\Controller as ControllerDispatch; + +/** + * 路由规则基础类 + */ +abstract class Rule +{ + /** + * 路由标识 + * @var string + */ + protected $name; + + /** + * 所在域名 + * @var string + */ + protected $domain; + + /** + * 路由对象 + * @var Route + */ + protected $router; + + /** + * 路由所属分组 + * @var RuleGroup + */ + protected $parent; + + /** + * 路由规则 + * @var mixed + */ + protected $rule; + + /** + * 路由地址 + * @var string|Closure + */ + protected $route; + + /** + * 请求类型 + * @var string + */ + protected $method; + + /** + * 路由变量 + * @var array + */ + protected $vars = []; + + /** + * 路由参数 + * @var array + */ + protected $option = []; + + /** + * 路由变量规则 + * @var array + */ + protected $pattern = []; + + /** + * 需要和分组合并的路由参数 + * @var array + */ + protected $mergeOptions = ['model', 'append', 'middleware']; + + abstract public function check(Request $request, string $url, bool $completeMatch = false); + + /** + * 设置路由参数 + * @access public + * @param array $option 参数 + * @return $this + */ + public function option(array $option) + { + $this->option = array_merge($this->option, $option); + + return $this; + } + + /** + * 设置单个路由参数 + * @access public + * @param string $name 参数名 + * @param mixed $value 值 + * @return $this + */ + public function setOption(string $name, $value) + { + $this->option[$name] = $value; + + return $this; + } + + /** + * 注册变量规则 + * @access public + * @param array $pattern 变量规则 + * @return $this + */ + public function pattern(array $pattern) + { + $this->pattern = array_merge($this->pattern, $pattern); + + return $this; + } + + /** + * 设置标识 + * @access public + * @param string $name 标识名 + * @return $this + */ + public function name(string $name) + { + $this->name = $name; + + return $this; + } + + /** + * 获取路由对象 + * @access public + * @return Route + */ + public function getRouter(): Route + { + return $this->router; + } + + /** + * 获取Name + * @access public + * @return string + */ + public function getName(): string + { + return $this->name ?: ''; + } + + /** + * 获取当前路由规则 + * @access public + * @return mixed + */ + public function getRule() + { + return $this->rule; + } + + /** + * 获取当前路由地址 + * @access public + * @return mixed + */ + public function getRoute() + { + return $this->route; + } + + /** + * 获取当前路由的变量 + * @access public + * @return array + */ + public function getVars(): array + { + return $this->vars; + } + + /** + * 获取Parent对象 + * @access public + * @return $this|null + */ + public function getParent() + { + return $this->parent; + } + + /** + * 获取路由所在域名 + * @access public + * @return string + */ + public function getDomain(): string + { + return $this->domain ?: $this->parent->getDomain(); + } + + /** + * 获取路由参数 + * @access public + * @param string $name 变量名 + * @return mixed + */ + public function config(string $name = '') + { + return $this->router->config($name); + } + + /** + * 获取变量规则定义 + * @access public + * @param string $name 变量名 + * @return mixed + */ + public function getPattern(string $name = '') + { + $pattern = $this->pattern; + + if ($this->parent) { + $pattern = array_merge($this->parent->getPattern(), $pattern); + } + + if ('' === $name) { + return $pattern; + } + + return $pattern[$name] ?? null; + } + + /** + * 获取路由参数定义 + * @access public + * @param string $name 参数名 + * @param mixed $default 默认值 + * @return mixed + */ + public function getOption(string $name = '', $default = null) + { + $option = $this->option; + + if ($this->parent) { + $parentOption = $this->parent->getOption(); + + // 合并分组参数 + foreach ($this->mergeOptions as $item) { + if (isset($parentOption[$item]) && isset($option[$item])) { + $option[$item] = array_merge($parentOption[$item], $option[$item]); + } + } + + $option = array_merge($parentOption, $option); + } + + if ('' === $name) { + return $option; + } + + return $option[$name] ?? $default; + } + + /** + * 获取当前路由的请求类型 + * @access public + * @return string + */ + public function getMethod(): string + { + return strtolower($this->method); + } + + /** + * 设置路由请求类型 + * @access public + * @param string $method 请求类型 + * @return $this + */ + public function method(string $method) + { + return $this->setOption('method', strtolower($method)); + } + + /** + * 检查后缀 + * @access public + * @param string $ext URL后缀 + * @return $this + */ + public function ext(string $ext = '') + { + return $this->setOption('ext', $ext); + } + + /** + * 检查禁止后缀 + * @access public + * @param string $ext URL后缀 + * @return $this + */ + public function denyExt(string $ext = '') + { + return $this->setOption('deny_ext', $ext); + } + + /** + * 检查域名 + * @access public + * @param string $domain 域名 + * @return $this + */ + public function domain(string $domain) + { + $this->domain = $domain; + return $this->setOption('domain', $domain); + } + + /** + * 设置参数过滤检查 + * @access public + * @param array $filter 参数过滤 + * @return $this + */ + public function filter(array $filter) + { + $this->option['filter'] = $filter; + + return $this; + } + + /** + * 绑定模型 + * @access public + * @param array|string|Closure $var 路由变量名 多个使用 & 分割 + * @param string|Closure $model 绑定模型类 + * @param bool $exception 是否抛出异常 + * @return $this + */ + public function model($var, $model = null, bool $exception = true) + { + if ($var instanceof Closure) { + $this->option['model'][] = $var; + } elseif (is_array($var)) { + $this->option['model'] = $var; + } elseif (is_null($model)) { + $this->option['model']['id'] = [$var, true]; + } else { + $this->option['model'][$var] = [$model, $exception]; + } + + return $this; + } + + /** + * 附加路由隐式参数 + * @access public + * @param array $append 追加参数 + * @return $this + */ + public function append(array $append = []) + { + $this->option['append'] = $append; + + return $this; + } + + /** + * 绑定验证 + * @access public + * @param mixed $validate 验证器类 + * @param string $scene 验证场景 + * @param array $message 验证提示 + * @param bool $batch 批量验证 + * @return $this + */ + public function validate($validate, string $scene = null, array $message = [], bool $batch = false) + { + $this->option['validate'] = [$validate, $scene, $message, $batch]; + + return $this; + } + + /** + * 指定路由中间件 + * @access public + * @param string|array|Closure $middleware 中间件 + * @param mixed $params 参数 + * @return $this + */ + public function middleware($middleware, ...$params) + { + if (empty($params) && is_array($middleware)) { + $this->option['middleware'] = $middleware; + } else { + foreach ((array) $middleware as $item) { + $this->option['middleware'][] = [$item, $params]; + } + } + + return $this; + } + + /** + * 允许跨域 + * @access public + * @param array $header 自定义Header + * @return $this + */ + public function allowCrossDomain(array $header = []) + { + return $this->middleware(AllowCrossDomain::class, $header); + } + + /** + * 表单令牌验证 + * @access public + * @param string $token 表单令牌token名称 + * @return $this + */ + public function token(string $token = '__token__') + { + return $this->middleware(FormTokenCheck::class, $token); + } + + /** + * 设置路由缓存 + * @access public + * @param array|string $cache 缓存 + * @return $this + */ + public function cache($cache) + { + return $this->middleware(CheckRequestCache::class, $cache); + } + + /** + * 检查URL分隔符 + * @access public + * @param string $depr URL分隔符 + * @return $this + */ + public function depr(string $depr) + { + return $this->setOption('param_depr', $depr); + } + + /** + * 设置需要合并的路由参数 + * @access public + * @param array $option 路由参数 + * @return $this + */ + public function mergeOptions(array $option = []) + { + $this->mergeOptions = array_merge($this->mergeOptions, $option); + return $this; + } + + /** + * 检查是否为HTTPS请求 + * @access public + * @param bool $https 是否为HTTPS + * @return $this + */ + public function https(bool $https = true) + { + return $this->setOption('https', $https); + } + + /** + * 检查是否为JSON请求 + * @access public + * @param bool $json 是否为JSON + * @return $this + */ + public function json(bool $json = true) + { + return $this->setOption('json', $json); + } + + /** + * 检查是否为AJAX请求 + * @access public + * @param bool $ajax 是否为AJAX + * @return $this + */ + public function ajax(bool $ajax = true) + { + return $this->setOption('ajax', $ajax); + } + + /** + * 检查是否为PJAX请求 + * @access public + * @param bool $pjax 是否为PJAX + * @return $this + */ + public function pjax(bool $pjax = true) + { + return $this->setOption('pjax', $pjax); + } + + /** + * 路由到一个模板地址 需要额外传入的模板变量 + * @access public + * @param array $view 视图 + * @return $this + */ + public function view(array $view = []) + { + return $this->setOption('view', $view); + } + + /** + * 设置路由完整匹配 + * @access public + * @param bool $match 是否完整匹配 + * @return $this + */ + public function completeMatch(bool $match = true) + { + return $this->setOption('complete_match', $match); + } + + /** + * 是否去除URL最后的斜线 + * @access public + * @param bool $remove 是否去除最后斜线 + * @return $this + */ + public function removeSlash(bool $remove = true) + { + return $this->setOption('remove_slash', $remove); + } + + /** + * 设置路由规则全局有效 + * @access public + * @return $this + */ + public function crossDomainRule() + { + if ($this instanceof RuleGroup) { + $method = '*'; + } else { + $method = $this->method; + } + + $this->router->setCrossDomainRule($this, $method); + + return $this; + } + + /** + * 解析匹配到的规则路由 + * @access public + * @param Request $request 请求对象 + * @param string $rule 路由规则 + * @param mixed $route 路由地址 + * @param string $url URL地址 + * @param array $option 路由参数 + * @param array $matches 匹配的变量 + * @return Dispatch + */ + public function parseRule(Request $request, string $rule, $route, string $url, array $option = [], array $matches = []): Dispatch + { + if (is_string($route) && isset($option['prefix'])) { + // 路由地址前缀 + $route = $option['prefix'] . $route; + } + + // 替换路由地址中的变量 + $extraParams = true; + $search = $replace = []; + $depr = $this->router->config('pathinfo_depr'); + foreach ($matches as $key => $value) { + $search[] = '<' . $key . '>'; + $replace[] = $value; + + $search[] = ':' . $key; + $replace[] = $value; + + if (strpos($value, $depr)) { + $extraParams = false; + } + } + + if (is_string($route)) { + $route = str_replace($search, $replace, $route); + } + + // 解析额外参数 + if ($extraParams) { + $count = substr_count($rule, '/'); + $url = array_slice(explode('|', $url), $count + 1); + $this->parseUrlParams(implode('|', $url), $matches); + } + + $this->vars = $matches; + + // 发起路由调度 + return $this->dispatch($request, $route, $option); + } + + /** + * 发起路由调度 + * @access protected + * @param Request $request Request对象 + * @param mixed $route 路由地址 + * @param array $option 路由参数 + * @return Dispatch + */ + protected function dispatch(Request $request, $route, array $option): Dispatch + { + if (is_subclass_of($route, Dispatch::class)) { + $result = new $route($request, $this, $route, $this->vars); + } elseif ($route instanceof Closure) { + // 执行闭包 + $result = new CallbackDispatch($request, $this, $route, $this->vars); + } elseif (false !== strpos($route, '@') || false !== strpos($route, '::') || false !== strpos($route, '\\')) { + // 路由到类的方法 + $route = str_replace('::', '@', $route); + $result = $this->dispatchMethod($request, $route); + } else { + // 路由到控制器/操作 + $result = $this->dispatchController($request, $route); + } + + return $result; + } + + /** + * 解析URL地址为 模块/控制器/操作 + * @access protected + * @param Request $request Request对象 + * @param string $route 路由地址 + * @return CallbackDispatch + */ + protected function dispatchMethod(Request $request, string $route): CallbackDispatch + { + $path = $this->parseUrlPath($route); + + $route = str_replace('/', '@', implode('/', $path)); + $method = strpos($route, '@') ? explode('@', $route) : $route; + + return new CallbackDispatch($request, $this, $method, $this->vars); + } + + /** + * 解析URL地址为 模块/控制器/操作 + * @access protected + * @param Request $request Request对象 + * @param string $route 路由地址 + * @return ControllerDispatch + */ + protected function dispatchController(Request $request, string $route): ControllerDispatch + { + $path = $this->parseUrlPath($route); + + $action = array_pop($path); + $controller = !empty($path) ? array_pop($path) : null; + + // 路由到模块/控制器/操作 + return new ControllerDispatch($request, $this, [$controller, $action], $this->vars); + } + + /** + * 路由检查 + * @access protected + * @param array $option 路由参数 + * @param Request $request Request对象 + * @return bool + */ + protected function checkOption(array $option, Request $request): bool + { + // 请求类型检测 + if (!empty($option['method'])) { + if (is_string($option['method']) && false === stripos($option['method'], $request->method())) { + return false; + } + } + + // AJAX PJAX 请求检查 + foreach (['ajax', 'pjax', 'json'] as $item) { + if (isset($option[$item])) { + $call = 'is' . $item; + if ($option[$item] && !$request->$call() || !$option[$item] && $request->$call()) { + return false; + } + } + } + + // 伪静态后缀检测 + if ($request->url() != '/' && ((isset($option['ext']) && false === stripos('|' . $option['ext'] . '|', '|' . $request->ext() . '|')) + || (isset($option['deny_ext']) && false !== stripos('|' . $option['deny_ext'] . '|', '|' . $request->ext() . '|')))) { + return false; + } + + // 域名检查 + if ((isset($option['domain']) && !in_array($option['domain'], [$request->host(true), $request->subDomain()]))) { + return false; + } + + // HTTPS检查 + if ((isset($option['https']) && $option['https'] && !$request->isSsl()) + || (isset($option['https']) && !$option['https'] && $request->isSsl())) { + return false; + } + + // 请求参数检查 + if (isset($option['filter'])) { + foreach ($option['filter'] as $name => $value) { + if ($request->param($name, '', null) != $value) { + return false; + } + } + } + + return true; + } + + /** + * 解析URL地址中的参数Request对象 + * @access protected + * @param string $rule 路由规则 + * @param array $var 变量 + * @return void + */ + protected function parseUrlParams(string $url, array &$var = []): void + { + if ($url) { + preg_replace_callback('/(\w+)\|([^\|]+)/', function ($match) use (&$var) { + $var[$match[1]] = strip_tags($match[2]); + }, $url); + } + } + + /** + * 解析URL的pathinfo参数 + * @access public + * @param string $url URL地址 + * @return array + */ + public function parseUrlPath(string $url): array + { + // 分隔符替换 确保路由定义使用统一的分隔符 + $url = str_replace('|', '/', $url); + $url = trim($url, '/'); + + if (strpos($url, '/')) { + // [控制器/操作] + $path = explode('/', $url); + } else { + $path = [$url]; + } + + return $path; + } + + /** + * 生成路由的正则规则 + * @access protected + * @param string $rule 路由规则 + * @param array $match 匹配的变量 + * @param array $pattern 路由变量规则 + * @param array $option 路由参数 + * @param bool $completeMatch 路由是否完全匹配 + * @param string $suffix 路由正则变量后缀 + * @return string + */ + protected function buildRuleRegex(string $rule, array $match, array $pattern = [], array $option = [], bool $completeMatch = false, string $suffix = ''): string + { + foreach ($match as $name) { + $value = $this->buildNameRegex($name, $pattern, $suffix); + if ($value) { + $origin[] = $name; + $replace[] = $value; + } + } + + // 是否区分 / 地址访问 + if ('/' != $rule) { + if (!empty($option['remove_slash'])) { + $rule = rtrim($rule, '/'); + } elseif (substr($rule, -1) == '/') { + $rule = rtrim($rule, '/'); + $hasSlash = true; + } + } + + $regex = isset($replace) ? str_replace($origin, $replace, $rule) : $rule; + $regex = str_replace([')?/', ')?-'], [')/', ')-'], $regex); + + if (isset($hasSlash)) { + $regex .= '/'; + } + + return $regex . ($completeMatch ? '$' : ''); + } + + /** + * 生成路由变量的正则规则 + * @access protected + * @param string $name 路由变量 + * @param array $pattern 变量规则 + * @param string $suffix 路由正则变量后缀 + * @return string + */ + protected function buildNameRegex(string $name, array $pattern, string $suffix): string + { + $optional = ''; + $slash = substr($name, 0, 1); + + if (in_array($slash, ['/', '-'])) { + $prefix = $slash; + $name = substr($name, 1); + $slash = substr($name, 0, 1); + } else { + $prefix = ''; + } + + if ('<' != $slash) { + return ''; + } + + if (strpos($name, '?')) { + $name = substr($name, 1, -2); + $optional = '?'; + } elseif (strpos($name, '>')) { + $name = substr($name, 1, -1); + } + + if (isset($pattern[$name])) { + $nameRule = $pattern[$name]; + if (0 === strpos($nameRule, '/') && '/' == substr($nameRule, -1)) { + $nameRule = substr($nameRule, 1, -1); + } + } else { + $nameRule = $this->router->config('default_route_pattern'); + } + + return '(' . $prefix . '(?<' . $name . $suffix . '>' . $nameRule . '))' . $optional; + } + + /** + * 设置路由参数 + * @access public + * @param string $method 方法名 + * @param array $args 调用参数 + * @return $this + */ + public function __call($method, $args) + { + if (count($args) > 1) { + $args[0] = $args; + } + array_unshift($args, $method); + + return call_user_func_array([$this, 'setOption'], $args); + } + + public function __sleep() + { + return ['name', 'rule', 'route', 'method', 'vars', 'option', 'pattern']; + } + + public function __wakeup() + { + $this->router = Container::pull('route'); + } + + public function __debugInfo() + { + return [ + 'name' => $this->name, + 'rule' => $this->rule, + 'route' => $this->route, + 'method' => $this->method, + 'vars' => $this->vars, + 'option' => $this->option, + 'pattern' => $this->pattern, + ]; + } +} diff --git a/thinkphp/library/think/route/RuleGroup.php b/vendor/topthink/framework/src/think/route/RuleGroup.php old mode 100755 new mode 100644 similarity index 53% rename from thinkphp/library/think/route/RuleGroup.php rename to vendor/topthink/framework/src/think/route/RuleGroup.php index 36be2f444..cd9ddbd1b --- a/thinkphp/library/think/route/RuleGroup.php +++ b/vendor/topthink/framework/src/think/route/RuleGroup.php @@ -2,67 +2,71 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\route; +use Closure; use think\Container; use think\Exception; use think\Request; -use think\Response; use think\Route; -use think\route\dispatch\Response as ResponseDispatch; -use think\route\dispatch\Url as UrlDispatch; +/** + * 路由分组类 + */ class RuleGroup extends Rule { - // 分组路由(包括子分组) - protected $rules = [ - '*' => [], - 'get' => [], - 'post' => [], - 'put' => [], - 'patch' => [], - 'delete' => [], - 'head' => [], - 'options' => [], - ]; + /** + * 分组路由(包括子分组) + * @var array + */ + protected $rules = []; - // MISS路由 + /** + * 分组路由规则 + * @var mixed + */ + protected $rule; + + /** + * MISS路由 + * @var RuleItem + */ protected $miss; - // 自动路由 - protected $auto; - - // 完整名称 + /** + * 完整名称 + * @var string + */ protected $fullName; - // 所在域名 - protected $domain; + /** + * 分组别名 + * @var string + */ + protected $alias; /** * 架构函数 * @access public - * @param Route $router 路由对象 - * @param RuleGroup $parent 上级对象 - * @param string $name 分组名称 - * @param mixed $rule 分组路由 - * @param array $option 路由参数 - * @param array $pattern 变量规则 + * @param Route $router 路由对象 + * @param RuleGroup $parent 上级对象 + * @param string $name 分组名称 + * @param mixed $rule 分组路由 */ - public function __construct(Route $router, RuleGroup $parent = null, $name = '', $rule = [], $option = [], $pattern = []) + public function __construct(Route $router, RuleGroup $parent = null, string $name = '', $rule = null) { - $this->router = $router; - $this->parent = $parent; - $this->rule = $rule; - $this->name = trim($name, '/'); - $this->option = $option; - $this->pattern = $pattern; + $this->router = $router; + $this->parent = $parent; + $this->rule = $rule; + $this->name = trim($name, '/'); $this->setFullName(); @@ -71,10 +75,6 @@ class RuleGroup extends Rule $this->parent->addRuleItem($this); } - if (!empty($option['cross_domain'])) { - $this->router->setCrossDomainRule($this); - } - if ($router->isTest()) { $this->lazy(false); } @@ -85,7 +85,7 @@ class RuleGroup extends Rule * @access public * @return void */ - protected function setFullName() + protected function setFullName(): void { if (false !== strpos($this->name, ':')) { $this->name = preg_replace(['/\[\:(\w+)\]/', '/\:(\w+)/'], ['<\1?>', '<\1>'], $this->name); @@ -96,6 +96,10 @@ class RuleGroup extends Rule } else { $this->fullName = $this->name; } + + if ($this->name) { + $this->router->getRuleName()->setGroup($this->name, $this); + } } /** @@ -103,70 +107,53 @@ class RuleGroup extends Rule * @access public * @return string */ - public function getDomain() + public function getDomain(): string { - return $this->domain; + return $this->domain ?: '-'; + } + + /** + * 获取分组别名 + * @access public + * @return string + */ + public function getAlias(): string + { + return $this->alias ?: ''; } /** * 检测分组路由 * @access public - * @param Request $request 请求对象 - * @param string $url 访问地址 - * @param bool $completeMatch 路由是否完全匹配 + * @param Request $request 请求对象 + * @param string $url 访问地址 + * @param bool $completeMatch 路由是否完全匹配 * @return Dispatch|false */ - public function check($request, $url, $completeMatch = false) + public function check(Request $request, string $url, bool $completeMatch = false) { - if ($dispatch = $this->checkCrossDomain($request)) { - // 跨域OPTIONS请求 - return $dispatch; - } - // 检查分组有效性 if (!$this->checkOption($this->option, $request) || !$this->checkUrl($url)) { return false; } - // 检查前置行为 - if (isset($this->option['before'])) { - if (false === $this->checkBefore($this->option['before'])) { - return false; - } - unset($this->option['before']); - } - // 解析分组路由 if ($this instanceof Resource) { $this->buildResourceRule(); - } elseif ($this->rule) { - if ($this->rule instanceof Response) { - return new ResponseDispatch($request, $this, $this->rule); - } - + } else { $this->parseGroupRule($this->rule); } // 获取当前路由规则 $method = strtolower($request->method()); - $rules = $this->getMethodRules($method); + $rules = $this->getRules($method); + $option = $this->getOption(); - if (count($rules) == 0) { - return false; + if (isset($option['complete_match'])) { + $completeMatch = $option['complete_match']; } - if ($this->parent) { - // 合并分组参数 - $this->mergeGroupOptions(); - // 合并分组变量规则 - $this->pattern = array_merge($this->parent->getPattern(), $this->pattern); - } - - if (isset($this->option['complete_match'])) { - $completeMatch = $this->option['complete_match']; - } - - if (!empty($this->option['merge_rule_regex'])) { + if (!empty($option['merge_rule_regex'])) { // 合并路由正则规则进行路由匹配检查 $result = $this->checkMergeRuleRegex($request, $rules, $url, $completeMatch); @@ -177,19 +164,18 @@ class RuleGroup extends Rule // 检查分组路由 foreach ($rules as $key => $item) { - $result = $item->check($request, $url, $completeMatch); + $result = $item[1]->check($request, $url, $completeMatch); if (false !== $result) { return $result; } } - if ($this->auto) { - // 自动解析URL地址 - $result = new UrlDispatch($request, $this, $this->auto . '/' . $url, ['auto_search' => false]); + if (!empty($option['dispatcher'])) { + $result = $this->parseRule($request, '', $option['dispatcher'], $url, $option); } elseif ($this->miss && in_array($this->miss->getMethod(), ['*', $method])) { // 未匹配所有路由的路由规则处理 - $result = $this->miss->parseRule($request, '', $this->miss->getRoute(), $url, $this->miss->mergeGroupOptions()); + $result = $this->parseRule($request, '', $this->miss->getRoute(), $url, $this->miss->getOption()); } else { $result = false; } @@ -197,24 +183,13 @@ class RuleGroup extends Rule return $result; } - /** - * 获取当前请求的路由规则(包括子分组、资源路由) - * @access protected - * @param string $method - * @return array - */ - protected function getMethodRules($method) - { - return array_merge($this->rules[$method], $this->rules['*']); - } - /** * 分组URL匹配检查 * @access protected - * @param string $url + * @param string $url URL * @return bool */ - protected function checkUrl($url) + protected function checkUrl(string $url): bool { if ($this->fullName) { $pos = strpos($this->fullName, '<'); @@ -234,12 +209,26 @@ class RuleGroup extends Rule } /** - * 延迟解析分组的路由规则 + * 设置路由分组别名 * @access public - * @param bool $lazy 路由是否延迟解析 + * @param string $alias 路由分组别名 * @return $this */ - public function lazy($lazy = true) + public function alias(string $alias) + { + $this->alias = $alias; + $this->router->getRuleName()->setGroup($alias, $this); + + return $this; + } + + /** + * 延迟解析分组的路由规则 + * @access public + * @param bool $lazy 路由是否延迟解析 + * @return $this + */ + public function lazy(bool $lazy = true) { if (!$lazy) { $this->parseGroupRule($this->rule); @@ -252,18 +241,21 @@ class RuleGroup extends Rule /** * 解析分组和域名的路由规则及绑定 * @access public - * @param mixed $rule 路由规则 + * @param mixed $rule 路由规则 * @return void */ - public function parseGroupRule($rule) + public function parseGroupRule($rule): void { + if (is_string($rule) && is_subclass_of($rule, Dispatch::class)) { + $this->dispatcher($rule); + return; + } + $origin = $this->router->getGroup(); $this->router->setGroup($this); if ($rule instanceof \Closure) { Container::getInstance()->invokeFunction($rule); - } elseif (is_array($rule)) { - $this->addRules($rule); } elseif (is_string($rule) && $rule) { $this->router->bind($rule, $this->domain); } @@ -274,18 +266,21 @@ class RuleGroup extends Rule /** * 检测分组路由 * @access public - * @param Request $request 请求对象 - * @param array $rules 路由规则 - * @param string $url 访问地址 - * @param bool $completeMatch 路由是否完全匹配 + * @param Request $request 请求对象 + * @param array $rules 路由规则 + * @param string $url 访问地址 + * @param bool $completeMatch 路由是否完全匹配 * @return Dispatch|false */ - protected function checkMergeRuleRegex($request, &$rules, $url, $completeMatch) + protected function checkMergeRuleRegex(Request $request, array &$rules, string $url, bool $completeMatch) { - $depr = $this->router->config('pathinfo_depr'); - $url = $depr . str_replace('|', $depr, $url); + $depr = $this->router->config('pathinfo_depr'); + $url = $depr . str_replace('|', $depr, $url); + $regex = []; + $items = []; - foreach ($rules as $key => $item) { + foreach ($rules as $key => $val) { + $item = $val[1]; if ($item instanceof RuleItem) { $rule = $depr . str_replace('/', $depr, $item->getRule()); if ($depr == $rule && $depr != $url) { @@ -293,7 +288,7 @@ class RuleGroup extends Rule continue; } - $complete = null !== $item->getOption('complete_match') ? $item->getOption('complete_match') : $completeMatch; + $complete = $item->getOption('complete_match', $completeMatch); if (false === strpos($rule, '<')) { if (0 === strcasecmp($rule, $url) || (!$complete && 0 === strncasecmp($rule, $url, strlen($rule)))) { @@ -329,7 +324,7 @@ class RuleGroup extends Rule } try { - $result = preg_match('/^(?:' . implode('|', $regex) . ')/u', $url, $match); + $result = preg_match('~^(?:' . implode('|', $regex) . ')~u', $url, $match); } catch (\Exception $e) { throw new Exception('route pattern error'); } @@ -338,7 +333,7 @@ class RuleGroup extends Rule $var = []; foreach ($match as $key => $val) { if (is_string($key) && '' !== $val) { - list($name, $pos) = explode('_THINK_', $key); + [$name, $pos] = explode('_THINK_', $key); $var[$name] = $val; } @@ -375,67 +370,41 @@ class RuleGroup extends Rule * @access public * @return RuleItem|null */ - public function getMissRule() + public function getMissRule(): ? RuleItem { return $this->miss; } - /** - * 获取分组的自动路由 - * @access public - * @return string - */ - public function getAutoRule() - { - return $this->auto; - } - - /** - * 注册自动路由 - * @access public - * @param string $route 路由规则 - * @return void - */ - public function addAutoRule($route) - { - $this->auto = $route; - } - /** * 注册MISS路由 * @access public - * @param string $route 路由地址 - * @param string $method 请求类型 - * @param array $option 路由参数 + * @param string|Closure $route 路由地址 + * @param string $method 请求类型 * @return RuleItem */ - public function addMissRule($route, $method = '*', $option = []) + public function miss($route, string $method = '*') : RuleItem { // 创建路由规则实例 - $ruleItem = new RuleItem($this->router, $this, null, '', $route, strtolower($method), $option); + $ruleItem = new RuleItem($this->router, $this, null, '', $route, strtolower($method)); + $ruleItem->setMiss(); $this->miss = $ruleItem; return $ruleItem; } /** - * 添加分组下的路由规则或者子分组 + * 添加分组下的路由规则 * @access public - * @param string $rule 路由规则 - * @param string $route 路由地址 - * @param string $method 请求类型 - * @param array $option 路由参数 - * @param array $pattern 变量规则 - * @return $this + * @param string $rule 路由规则 + * @param mixed $route 路由地址 + * @param string $method 请求类型 + * @return RuleItem */ - public function addRule($rule, $route, $method = '*', $option = [], $pattern = []) + public function addRule(string $rule, $route = null, string $method = '*'): RuleItem { // 读取路由标识 - if (is_array($rule)) { - $name = $rule[0]; - $rule = $rule[1]; - } elseif (is_string($route)) { + if (is_string($route)) { $name = $route; } else { $name = null; @@ -443,17 +412,12 @@ class RuleGroup extends Rule $method = strtolower($method); - if ('/' === $rule || '' === $rule) { - // 首页自动完整匹配 + if ('' === $rule || '/' === $rule) { $rule .= '$'; } // 创建路由规则实例 - $ruleItem = new RuleItem($this->router, $this, $name, $rule, $route, $method, $option, $pattern); - - if (!empty($option['cross_domain'])) { - $this->router->setCrossDomainRule($ruleItem, $method); - } + $ruleItem = new RuleItem($this->router, $this, $name, $rule, $route, $method); $this->addRuleItem($ruleItem, $method); @@ -461,41 +425,24 @@ class RuleGroup extends Rule } /** - * 批量注册路由规则 + * 注册分组下的路由规则 * @access public - * @param array $rules 路由规则 - * @param string $method 请求类型 - * @param array $option 路由参数 - * @param array $pattern 变量规则 - * @return void + * @param Rule $rule 路由规则 + * @param string $method 请求类型 + * @return $this */ - public function addRules($rules, $method = '*', $option = [], $pattern = []) - { - foreach ($rules as $key => $val) { - if (is_numeric($key)) { - $key = array_shift($val); - } - - if (is_array($val)) { - $route = array_shift($val); - $option = $val ? array_shift($val) : []; - $pattern = $val ? array_shift($val) : []; - } else { - $route = $val; - } - - $this->addRule($key, $route, $method, $option, $pattern); - } - } - - public function addRuleItem($rule, $method = '*') + public function addRuleItem(Rule $rule, string $method = '*') { if (strpos($method, '|')) { $rule->method($method); $method = '*'; } - $this->rules[$method][] = $rule; + $this->rules[] = [$method, $rule]; + + if ($rule instanceof RuleItem && 'options' != $method) { + $this->rules[] = ['options', $rule->setAutoOptions()]; + } return $this; } @@ -503,60 +450,38 @@ class RuleGroup extends Rule /** * 设置分组的路由前缀 * @access public - * @param string $prefix + * @param string $prefix 路由前缀 * @return $this */ - public function prefix($prefix) + public function prefix(string $prefix) { if ($this->parent && $this->parent->getOption('prefix')) { $prefix = $this->parent->getOption('prefix') . $prefix; } - return $this->option('prefix', $prefix); - } - - /** - * 设置资源允许 - * @access public - * @param array $only - * @return $this - */ - public function only($only) - { - return $this->option('only', $only); - } - - /** - * 设置资源排除 - * @access public - * @param array $except - * @return $this - */ - public function except($except) - { - return $this->option('except', $except); - } - - /** - * 设置资源路由的变量 - * @access public - * @param array $vars - * @return $this - */ - public function vars($vars) - { - return $this->option('var', $vars); + return $this->setOption('prefix', $prefix); } /** * 合并分组的路由规则正则 * @access public - * @param bool $merge + * @param bool $merge 是否合并 * @return $this */ - public function mergeRuleRegex($merge = true) + public function mergeRuleRegex(bool $merge = true) { - return $this->option('merge_rule_regex', $merge); + return $this->setOption('merge_rule_regex', $merge); + } + + /** + * 设置分组的Dispatch调度 + * @access public + * @param string $dispatch 调度类 + * @return $this + */ + public function dispatcher(string $dispatch) + { + return $this->setOption('dispatcher', $dispatch); } /** @@ -564,24 +489,26 @@ class RuleGroup extends Rule * @access public * @return string */ - public function getFullName() + public function getFullName(): string { - return $this->fullName; + return $this->fullName ?: ''; } /** * 获取分组的路由规则 * @access public - * @param string $method + * @param string $method 请求类型 * @return array */ - public function getRules($method = '') + public function getRules(string $method = ''): array { if ('' === $method) { return $this->rules; } - return isset($this->rules[strtolower($method)]) ? $this->rules[strtolower($method)] : []; + return array_filter($this->rules, function ($item) use ($method) { + return $method == $item[0] || '*' == $item[0]; + }); } /** @@ -589,17 +516,8 @@ class RuleGroup extends Rule * @access public * @return void */ - public function clear() + public function clear(): void { - $this->rules = [ - '*' => [], - 'get' => [], - 'post' => [], - 'put' => [], - 'patch' => [], - 'delete' => [], - 'head' => [], - 'options' => [], - ]; + $this->rules = []; } } diff --git a/thinkphp/library/think/route/RuleItem.php b/vendor/topthink/framework/src/think/route/RuleItem.php old mode 100755 new mode 100644 similarity index 63% rename from thinkphp/library/think/route/RuleItem.php rename to vendor/topthink/framework/src/think/route/RuleItem.php index e4bddd90c..1f9aa52a1 --- a/thinkphp/library/think/route/RuleItem.php +++ b/vendor/topthink/framework/src/think/route/RuleItem.php @@ -2,22 +2,36 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\route; -use think\Container; use think\Exception; +use think\Request; use think\Route; +/** + * 路由规则类 + */ class RuleItem extends Rule { - protected $hasSetRule; + /** + * 是否为MISS规则 + * @var bool + */ + protected $miss = false; + + /** + * 是否为额外自动注册的OPTIONS规则 + * @var bool + */ + protected $autoOption = false; /** * 架构函数 @@ -25,27 +39,81 @@ class RuleItem extends Rule * @param Route $router 路由实例 * @param RuleGroup $parent 上级对象 * @param string $name 路由标识 - * @param string|array $rule 路由规则 + * @param string $rule 路由规则 * @param string|\Closure $route 路由地址 * @param string $method 请求类型 - * @param array $option 路由参数 - * @param array $pattern 变量规则 */ - public function __construct(Route $router, RuleGroup $parent, $name, $rule, $route, $method = '*', $option = [], $pattern = []) + public function __construct(Route $router, RuleGroup $parent, string $name = null, string $rule = '', $route = null, string $method = '*') { - $this->router = $router; - $this->parent = $parent; - $this->name = $name; - $this->route = $route; - $this->method = $method; - $this->option = $option; - $this->pattern = $pattern; + $this->router = $router; + $this->parent = $parent; + $this->name = $name; + $this->route = $route; + $this->method = $method; $this->setRule($rule); - if (!empty($option['cross_domain'])) { - $this->router->setCrossDomainRule($this, $method); + $this->router->setRule($this->rule, $this); + } + + /** + * 设置当前路由规则为MISS路由 + * @access public + * @return $this + */ + public function setMiss() + { + $this->miss = true; + return $this; + } + + /** + * 判断当前路由规则是否为MISS路由 + * @access public + * @return bool + */ + public function isMiss(): bool + { + return $this->miss; + } + + /** + * 设置当前路由为自动注册OPTIONS + * @access public + * @return $this + */ + public function setAutoOptions() + { + $this->autoOption = true; + return $this; + } + + /** + * 判断当前路由规则是否为自动注册的OPTIONS路由 + * @access public + * @return bool + */ + public function isAutoOptions(): bool + { + return $this->autoOption; + } + + /** + * 获取当前路由的URL后缀 + * @access public + * @return string|null + */ + public function getSuffix() + { + if (isset($this->option['ext'])) { + $suffix = $this->option['ext']; + } elseif ($this->parent->getOption('ext')) { + $suffix = $this->parent->getOption('ext'); + } else { + $suffix = null; } + + return $suffix; } /** @@ -54,7 +122,7 @@ class RuleItem extends Rule * @param string $rule 路由规则 * @return void */ - public function setRule($rule) + public function setRule(string $rule): void { if ('$' == substr($rule, -1, 1)) { // 是否完整匹配 @@ -79,27 +147,13 @@ class RuleItem extends Rule $this->setRuleName(); } - /** - * 检查后缀 - * @access public - * @param string $ext - * @return $this - */ - public function ext($ext = '') - { - $this->option('ext', $ext); - $this->setRuleName(true); - - return $this; - } - /** * 设置别名 * @access public * @param string $name * @return $this */ - public function name($name) + public function name(string $name) { $this->name = $name; $this->setRuleName(true); @@ -110,31 +164,13 @@ class RuleItem extends Rule /** * 设置路由标识 用于URL反解生成 * @access protected - * @param bool $first 是否插入开头 + * @param bool $first 是否插入开头 * @return void */ - protected function setRuleName($first = false) + protected function setRuleName(bool $first = false): void { if ($this->name) { - $vars = $this->parseVar($this->rule); - $name = strtolower($this->name); - - if (isset($this->option['ext'])) { - $suffix = $this->option['ext']; - } elseif ($this->parent->getOption('ext')) { - $suffix = $this->parent->getOption('ext'); - } else { - $suffix = null; - } - - $value = [$this->rule, $vars, $this->parent->getDomain(), $suffix, $this->method]; - - Container::get('rule_name')->set($name, $value, $first); - } - - if (!$this->hasSetRule) { - Container::get('rule_name')->setRule($this->rule, $this); - $this->hasSetRule = true; + $this->router->setName($this->name, $this, $first); } } @@ -147,33 +183,23 @@ class RuleItem extends Rule * @param bool $completeMatch 路由是否完全匹配 * @return Dispatch|false */ - public function checkRule($request, $url, $match = null, $completeMatch = false) + public function checkRule(Request $request, string $url, $match = null, bool $completeMatch = false) { - if ($dispatch = $this->checkCrossDomain($request)) { - // 允许跨域 - return $dispatch; - } - // 检查参数有效性 if (!$this->checkOption($this->option, $request)) { return false; } // 合并分组参数 - $option = $this->mergeGroupOptions(); - - $url = $this->urlSuffixCheck($request, $url, $option); + $option = $this->getOption(); + $pattern = $this->getPattern(); + $url = $this->urlSuffixCheck($request, $url, $option); if (is_null($match)) { - $match = $this->match($url, $option, $completeMatch); + $match = $this->match($url, $option, $pattern, $completeMatch); } if (false !== $match) { - // 检查前置行为 - if (isset($option['before']) && false === $this->checkBefore($option['before'])) { - return false; - } - return $this->parseRule($request, $this->rule, $this->route, $url, $option, $match); } @@ -185,11 +211,10 @@ class RuleItem extends Rule * @access public * @param Request $request 请求对象 * @param string $url 访问地址 - * @param string $depr 路径分隔符 * @param bool $completeMatch 路由是否完全匹配 * @return Dispatch|false */ - public function check($request, $url, $completeMatch = false) + public function check(Request $request, string $url, bool $completeMatch = false) { return $this->checkRule($request, $url, null, $completeMatch); } @@ -202,7 +227,7 @@ class RuleItem extends Rule * @param array $option 路由参数 * @return string */ - protected function urlSuffixCheck($request, $url, $option = []) + protected function urlSuffixCheck(Request $request, string $url, array $option = []): string { // 是否区分 / 地址访问 if (!empty($option['remove_slash']) && '/' != $this->rule) { @@ -223,20 +248,20 @@ class RuleItem extends Rule * @access private * @param string $url URL地址 * @param array $option 路由参数 - * @param bool $completeMatch 路由是否完全匹配 + * @param array $pattern 变量规则 + * @param bool $completeMatch 是否完全匹配 * @return array|false */ - private function match($url, $option, $completeMatch) + private function match(string $url, array $option, array $pattern, bool $completeMatch) { if (isset($option['complete_match'])) { $completeMatch = $option['complete_match']; } - $pattern = array_merge($this->parent->getPattern(), $this->pattern); - $depr = $this->router->config('pathinfo_depr'); + $depr = $this->router->config('pathinfo_depr'); // 检查完整规则定义 - if (isset($pattern['__url__']) && !preg_match(0 === strpos($pattern['__url__'], '/') ? $pattern['__url__'] : '/^' . $pattern['__url__'] . '/', str_replace('|', $depr, $url))) { + if (isset($pattern['__url__']) && !preg_match(0 === strpos($pattern['__url__'], '/') ? $pattern['__url__'] : '/^' . $pattern['__url__'] . ($completeMatch ? '$' : '') . '/', str_replace('|', $depr, $url))) { return false; } @@ -267,7 +292,7 @@ class RuleItem extends Rule $regex = $this->buildRuleRegex($rule, $matches[0], $pattern, $option, $completeMatch); try { - if (!preg_match('/^' . $regex . ($completeMatch ? '$' : '') . '/u', $url, $match)) { + if (!preg_match('~^' . $regex . '~u', $url, $match)) { return false; } } catch (\Exception $e) { @@ -285,4 +310,21 @@ class RuleItem extends Rule return $var; } + /** + * 设置路由所属分组(用于注解路由) + * @access public + * @param string $name 分组名称或者标识 + * @return $this + */ + public function group(string $name) + { + $group = $this->router->getRuleName()->getGroup($name); + + if ($group) { + $this->parent = $group; + $this->setRule($this->rule); + } + + return $this; + } } diff --git a/vendor/topthink/framework/src/think/route/RuleName.php b/vendor/topthink/framework/src/think/route/RuleName.php new file mode 100644 index 000000000..0684367cd --- /dev/null +++ b/vendor/topthink/framework/src/think/route/RuleName.php @@ -0,0 +1,211 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\route; + +/** + * 路由标识管理类 + */ +class RuleName +{ + /** + * 路由标识 + * @var array + */ + protected $item = []; + + /** + * 路由规则 + * @var array + */ + protected $rule = []; + + /** + * 路由分组 + * @var array + */ + protected $group = []; + + /** + * 注册路由标识 + * @access public + * @param string $name 路由标识 + * @param RuleItem $ruleItem 路由规则 + * @param bool $first 是否优先 + * @return void + */ + public function setName(string $name, RuleItem $ruleItem, bool $first = false): void + { + $name = strtolower($name); + $item = $this->getRuleItemInfo($ruleItem); + if ($first && isset($this->item[$name])) { + array_unshift($this->item[$name], $item); + } else { + $this->item[$name][] = $item; + } + } + + /** + * 注册路由分组标识 + * @access public + * @param string $name 路由分组标识 + * @param RuleGroup $group 路由分组 + * @return void + */ + public function setGroup(string $name, RuleGroup $group): void + { + $this->group[strtolower($name)] = $group; + } + + /** + * 注册路由规则 + * @access public + * @param string $rule 路由规则 + * @param RuleItem $ruleItem 路由 + * @return void + */ + public function setRule(string $rule, RuleItem $ruleItem): void + { + $route = $ruleItem->getRoute(); + + if (is_string($route)) { + $this->rule[$rule][$route] = $ruleItem; + } else { + $this->rule[$rule][] = $ruleItem; + } + } + + /** + * 根据路由规则获取路由对象(列表) + * @access public + * @param string $rule 路由标识 + * @return RuleItem[] + */ + public function getRule(string $rule): array + { + return $this->rule[$rule] ?? []; + } + + /** + * 根据路由分组标识获取分组 + * @access public + * @param string $name 路由分组标识 + * @return RuleGroup|null + */ + public function getGroup(string $name) + { + return $this->group[strtolower($name)] ?? null; + } + + /** + * 清空路由规则 + * @access public + * @return void + */ + public function clear(): void + { + $this->item = []; + $this->rule = []; + } + + /** + * 获取全部路由列表 + * @access public + * @return array + */ + public function getRuleList(): array + { + $list = []; + + foreach ($this->rule as $rule => $rules) { + foreach ($rules as $item) { + $val = []; + + foreach (['method', 'rule', 'name', 'route', 'domain', 'pattern', 'option'] as $param) { + $call = 'get' . $param; + $val[$param] = $item->$call(); + } + + if ($item->isMiss()) { + $val['rule'] .= ''; + } + + $list[] = $val; + } + } + + return $list; + } + + /** + * 导入路由标识 + * @access public + * @param array $item 路由标识 + * @return void + */ + public function import(array $item): void + { + $this->item = $item; + } + + /** + * 根据路由标识获取路由信息(用于URL生成) + * @access public + * @param string $name 路由标识 + * @param string $domain 域名 + * @param string $method 请求类型 + * @return array + */ + public function getName(string $name = null, string $domain = null, string $method = '*'): array + { + if (is_null($name)) { + return $this->item; + } + + $name = strtolower($name); + $method = strtolower($method); + $result = []; + + if (isset($this->item[$name])) { + if (is_null($domain)) { + $result = $this->item[$name]; + } else { + foreach ($this->item[$name] as $item) { + $itemDomain = $item['domain']; + $itemMethod = $item['method']; + + if (($itemDomain == $domain || '-' == $itemDomain) && ('*' == $itemMethod || '*' == $method || $method == $itemMethod)) { + $result[] = $item; + } + } + } + } + + return $result; + } + + /** + * 获取路由信息 + * @access protected + * @param RuleItem $item 路由规则 + * @return array + */ + protected function getRuleItemInfo(RuleItem $item): array + { + return [ + 'rule' => $item->getRule(), + 'domain' => $item->getDomain(), + 'method' => $item->getMethod(), + 'suffix' => $item->getSuffix(), + ]; + } +} diff --git a/vendor/topthink/framework/src/think/route/Url.php b/vendor/topthink/framework/src/think/route/Url.php new file mode 100644 index 000000000..8dd410cbe --- /dev/null +++ b/vendor/topthink/framework/src/think/route/Url.php @@ -0,0 +1,517 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\route; + +use think\App; +use think\Route; + +/** + * 路由地址生成 + */ +class Url +{ + /** + * 应用对象 + * @var App + */ + protected $app; + + /** + * 路由对象 + * @var Route + */ + protected $route; + + /** + * URL变量 + * @var array + */ + protected $vars = []; + + /** + * 路由URL + * @var string + */ + protected $url; + + /** + * URL 根地址 + * @var string + */ + protected $root = ''; + + /** + * HTTPS + * @var bool + */ + protected $https; + + /** + * URL后缀 + * @var string|bool + */ + protected $suffix = true; + + /** + * URL域名 + * @var string|bool + */ + protected $domain = false; + + /** + * 架构函数 + * @access public + * @param string $url URL地址 + * @param array $vars 参数 + */ + public function __construct(Route $route, App $app, string $url = '', array $vars = []) + { + $this->route = $route; + $this->app = $app; + $this->url = $url; + $this->vars = $vars; + } + + /** + * 设置URL参数 + * @access public + * @param array $vars URL参数 + * @return $this + */ + public function vars(array $vars = []) + { + $this->vars = $vars; + return $this; + } + + /** + * 设置URL后缀 + * @access public + * @param string|bool $suffix URL后缀 + * @return $this + */ + public function suffix($suffix) + { + $this->suffix = $suffix; + return $this; + } + + /** + * 设置URL域名(或者子域名) + * @access public + * @param string|bool $domain URL域名 + * @return $this + */ + public function domain($domain) + { + $this->domain = $domain; + return $this; + } + + /** + * 设置URL 根地址 + * @access public + * @param string $root URL root + * @return $this + */ + public function root(string $root) + { + $this->root = $root; + return $this; + } + + /** + * 设置是否使用HTTPS + * @access public + * @param bool $https + * @return $this + */ + public function https(bool $https = true) + { + $this->https = $https; + return $this; + } + + /** + * 检测域名 + * @access protected + * @param string $url URL + * @param string|true $domain 域名 + * @return string + */ + protected function parseDomain(string &$url, $domain): string + { + if (!$domain) { + return ''; + } + + $request = $this->app->request; + $rootDomain = $request->rootDomain(); + + if (true === $domain) { + // 自动判断域名 + $domain = $request->host(); + $domains = $this->route->getDomains(); + + if (!empty($domains)) { + $routeDomain = array_keys($domains); + foreach ($routeDomain as $domainPrefix) { + if (0 === strpos($domainPrefix, '*.') && strpos($domain, ltrim($domainPrefix, '*.')) !== false) { + foreach ($domains as $key => $rule) { + $rule = is_array($rule) ? $rule[0] : $rule; + if (is_string($rule) && false === strpos($key, '*') && 0 === strpos($url, $rule)) { + $url = ltrim($url, $rule); + $domain = $key; + + // 生成对应子域名 + if (!empty($rootDomain)) { + $domain .= $rootDomain; + } + break; + } elseif (false !== strpos($key, '*')) { + if (!empty($rootDomain)) { + $domain .= $rootDomain; + } + + break; + } + } + } + } + } + } elseif (false === strpos($domain, '.') && 0 !== strpos($domain, $rootDomain)) { + $domain .= '.' . $rootDomain; + } + + if (false !== strpos($domain, '://')) { + $scheme = ''; + } else { + $scheme = $this->https || $request->isSsl() ? 'https://' : 'http://'; + } + + return $scheme . $domain; + } + + /** + * 解析URL后缀 + * @access protected + * @param string|bool $suffix 后缀 + * @return string + */ + protected function parseSuffix($suffix): string + { + if ($suffix) { + $suffix = true === $suffix ? $this->route->config('url_html_suffix') : $suffix; + + if (is_string($suffix) && $pos = strpos($suffix, '|')) { + $suffix = substr($suffix, 0, $pos); + } + } + + return (empty($suffix) || 0 === strpos($suffix, '.')) ? (string) $suffix : '.' . $suffix; + } + + /** + * 直接解析URL地址 + * @access protected + * @param string $url URL + * @param string|bool $domain Domain + * @return string + */ + protected function parseUrl(string $url, &$domain): string + { + $request = $this->app->request; + + if (0 === strpos($url, '/')) { + // 直接作为路由地址解析 + $url = substr($url, 1); + } elseif (false !== strpos($url, '\\')) { + // 解析到类 + $url = ltrim(str_replace('\\', '/', $url), '/'); + } elseif (0 === strpos($url, '@')) { + // 解析到控制器 + $url = substr($url, 1); + } elseif ('' === $url) { + $url = $request->controller() . '/' . $request->action(); + } else { + $controller = $request->controller(); + + $path = explode('/', $url); + $action = array_pop($path); + $controller = empty($path) ? $controller : array_pop($path); + + $url = $controller . '/' . $action; + } + + return $url; + } + + /** + * 分析路由规则中的变量 + * @access protected + * @param string $rule 路由规则 + * @return array + */ + protected function parseVar(string $rule): array + { + // 提取路由规则中的变量 + $var = []; + + if (preg_match_all('/<\w+\??>/', $rule, $matches)) { + foreach ($matches[0] as $name) { + $optional = false; + + if (strpos($name, '?')) { + $name = substr($name, 1, -2); + $optional = true; + } else { + $name = substr($name, 1, -1); + } + + $var[$name] = $optional ? 2 : 1; + } + } + + return $var; + } + + /** + * 匹配路由地址 + * @access protected + * @param array $rule 路由规则 + * @param array $vars 路由变量 + * @param mixed $allowDomain 允许域名 + * @return array + */ + protected function getRuleUrl(array $rule, array &$vars = [], $allowDomain = ''): array + { + $request = $this->app->request; + if (is_string($allowDomain) && false === strpos($allowDomain, '.')) { + $allowDomain .= '.' . $request->rootDomain(); + } + $port = $request->port(); + + foreach ($rule as $item) { + $url = $item['rule']; + $pattern = $this->parseVar($url); + $domain = $item['domain']; + $suffix = $item['suffix']; + + if ('-' == $domain) { + $domain = is_string($allowDomain) ? $allowDomain : $request->host(true); + } + + if (is_string($allowDomain) && $domain != $allowDomain) { + continue; + } + + if ($port && !in_array($port, [80, 443])) { + $domain .= ':' . $port; + } + + if (empty($pattern)) { + return [rtrim($url, '?/-'), $domain, $suffix]; + } + + $type = $this->route->config('url_common_param'); + $keys = []; + + foreach ($pattern as $key => $val) { + if (isset($vars[$key])) { + $url = str_replace(['[:' . $key . ']', '<' . $key . '?>', ':' . $key, '<' . $key . '>'], $type ? (string) $vars[$key] : urlencode((string) $vars[$key]), $url); + $keys[] = $key; + $url = str_replace(['/?', '-?'], ['/', '-'], $url); + $result = [rtrim($url, '?/-'), $domain, $suffix]; + } elseif (2 == $val) { + $url = str_replace(['/[:' . $key . ']', '[:' . $key . ']', '<' . $key . '?>'], '', $url); + $url = str_replace(['/?', '-?'], ['/', '-'], $url); + $result = [rtrim($url, '?/-'), $domain, $suffix]; + } else { + $result = null; + $keys = []; + break; + } + } + + $vars = array_diff_key($vars, array_flip($keys)); + + if (isset($result)) { + return $result; + } + } + + return []; + } + + /** + * 生成URL地址 + * @access public + * @return string + */ + public function build() + { + // 解析URL + $url = $this->url; + $suffix = $this->suffix; + $domain = $this->domain; + $request = $this->app->request; + $vars = $this->vars; + + if (0 === strpos($url, '[') && $pos = strpos($url, ']')) { + // [name] 表示使用路由命名标识生成URL + $name = substr($url, 1, $pos - 1); + $url = 'name' . substr($url, $pos + 1); + } + + if (false === strpos($url, '://') && 0 !== strpos($url, '/')) { + $info = parse_url($url); + $url = !empty($info['path']) ? $info['path'] : ''; + + if (isset($info['fragment'])) { + // 解析锚点 + $anchor = $info['fragment']; + + if (false !== strpos($anchor, '?')) { + // 解析参数 + [$anchor, $info['query']] = explode('?', $anchor, 2); + } + + if (false !== strpos($anchor, '@')) { + // 解析域名 + [$anchor, $domain] = explode('@', $anchor, 2); + } + } elseif (strpos($url, '@') && false === strpos($url, '\\')) { + // 解析域名 + [$url, $domain] = explode('@', $url, 2); + } + } + + if ($url) { + $checkName = isset($name) ? $name : $url . (isset($info['query']) ? '?' . $info['query'] : ''); + $checkDomain = $domain && is_string($domain) ? $domain : null; + + $rule = $this->route->getName($checkName, $checkDomain); + + if (empty($rule) && isset($info['query'])) { + $rule = $this->route->getName($url, $checkDomain); + // 解析地址里面参数 合并到vars + parse_str($info['query'], $params); + $vars = array_merge($params, $vars); + unset($info['query']); + } + } + + if (!empty($rule) && $match = $this->getRuleUrl($rule, $vars, $domain)) { + // 匹配路由命名标识 + $url = $match[0]; + + if ($domain && !empty($match[1])) { + $domain = $match[1]; + } + + if (!is_null($match[2])) { + $suffix = $match[2]; + } + } elseif (!empty($rule) && isset($name)) { + throw new \InvalidArgumentException('route name not exists:' . $name); + } else { + // 检测URL绑定 + $bind = $this->route->getDomainBind($domain && is_string($domain) ? $domain : null); + + if ($bind && 0 === strpos($url, $bind)) { + $url = substr($url, strlen($bind) + 1); + } else { + $binds = $this->route->getBind(); + + foreach ($binds as $key => $val) { + if (is_string($val) && 0 === strpos($url, $val) && substr_count($val, '/') > 1) { + $url = substr($url, strlen($val) + 1); + $domain = $key; + break; + } + } + } + + // 路由标识不存在 直接解析 + $url = $this->parseUrl($url, $domain); + + if (isset($info['query'])) { + // 解析地址里面参数 合并到vars + parse_str($info['query'], $params); + $vars = array_merge($params, $vars); + } + } + + // 还原URL分隔符 + $depr = $this->route->config('pathinfo_depr'); + $url = str_replace('/', $depr, $url); + + $file = $request->baseFile(); + if ($file && 0 !== strpos($request->url(), $file)) { + $file = str_replace('\\', '/', dirname($file)); + } + + $url = rtrim($file, '/') . '/' . $url; + + // URL后缀 + if ('/' == substr($url, -1) || '' == $url) { + $suffix = ''; + } else { + $suffix = $this->parseSuffix($suffix); + } + + // 锚点 + $anchor = !empty($anchor) ? '#' . $anchor : ''; + + // 参数组装 + if (!empty($vars)) { + // 添加参数 + if ($this->route->config('url_common_param')) { + $vars = http_build_query($vars); + $url .= $suffix . ($vars ? '?' . $vars : '') . $anchor; + } else { + foreach ($vars as $var => $val) { + $val = (string) $val; + if ('' !== $val) { + $url .= $depr . $var . $depr . urlencode($val); + } + } + + $url .= $suffix . $anchor; + } + } else { + $url .= $suffix . $anchor; + } + + // 检测域名 + $domain = $this->parseDomain($url, $domain); + + // URL组装 + return $domain . rtrim($this->root, '/') . '/' . ltrim($url, '/'); + } + + public function __toString() + { + return $this->build(); + } + + public function __debugInfo() + { + return [ + 'url' => $this->url, + 'vars' => $this->vars, + 'suffix' => $this->suffix, + 'domain' => $this->domain, + ]; + } +} diff --git a/thinkphp/library/think/route/dispatch/Callback.php b/vendor/topthink/framework/src/think/route/dispatch/Callback.php old mode 100755 new mode 100644 similarity index 87% rename from thinkphp/library/think/route/dispatch/Callback.php rename to vendor/topthink/framework/src/think/route/dispatch/Callback.php index ca76fc993..2044ef8e7 --- a/thinkphp/library/think/route/dispatch/Callback.php +++ b/vendor/topthink/framework/src/think/route/dispatch/Callback.php @@ -2,17 +2,21 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\route\dispatch; use think\route\Dispatch; +/** + * Callback Dispatcher + */ class Callback extends Dispatch { public function exec() diff --git a/vendor/topthink/framework/src/think/route/dispatch/Controller.php b/vendor/topthink/framework/src/think/route/dispatch/Controller.php new file mode 100644 index 000000000..611101bde --- /dev/null +++ b/vendor/topthink/framework/src/think/route/dispatch/Controller.php @@ -0,0 +1,183 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\route\dispatch; + +use ReflectionClass; +use ReflectionException; +use ReflectionMethod; +use think\App; +use think\exception\ClassNotFoundException; +use think\exception\HttpException; +use think\helper\Str; +use think\route\Dispatch; + +/** + * Controller Dispatcher + */ +class Controller extends Dispatch +{ + /** + * 控制器名 + * @var string + */ + protected $controller; + + /** + * 操作名 + * @var string + */ + protected $actionName; + + public function init(App $app) + { + parent::init($app); + + $result = $this->dispatch; + + if (is_string($result)) { + $result = explode('/', $result); + } + + // 获取控制器名 + $controller = strip_tags($result[0] ?: $this->rule->config('default_controller')); + + if (strpos($controller, '.')) { + $pos = strrpos($controller, '.'); + $this->controller = substr($controller, 0, $pos) . '.' . Str::studly(substr($controller, $pos + 1)); + } else { + $this->controller = Str::studly($controller); + } + + // 获取操作名 + $this->actionName = strip_tags($result[1] ?: $this->rule->config('default_action')); + + // 设置当前请求的控制器、操作 + $this->request + ->setController($this->controller) + ->setAction($this->actionName); + } + + public function exec() + { + try { + // 实例化控制器 + $instance = $this->controller($this->controller); + } catch (ClassNotFoundException $e) { + throw new HttpException(404, 'controller not exists:' . $e->getClass()); + } + + // 注册控制器中间件 + $this->registerControllerMiddleware($instance); + + return $this->app->middleware->pipeline('controller') + ->send($this->request) + ->then(function () use ($instance) { + // 获取当前操作名 + $suffix = $this->rule->config('action_suffix'); + $action = $this->actionName . $suffix; + + if (is_callable([$instance, $action])) { + $vars = $this->request->param(); + try { + $reflect = new ReflectionMethod($instance, $action); + // 严格获取当前操作方法名 + $actionName = $reflect->getName(); + if ($suffix) { + $actionName = substr($actionName, 0, -strlen($suffix)); + } + + $this->request->setAction($actionName); + } catch (ReflectionException $e) { + $reflect = new ReflectionMethod($instance, '__call'); + $vars = [$action, $vars]; + $this->request->setAction($action); + } + } else { + // 操作不存在 + throw new HttpException(404, 'method not exists:' . get_class($instance) . '->' . $action . '()'); + } + + $data = $this->app->invokeReflectMethod($instance, $reflect, $vars); + + return $this->autoResponse($data); + }); + } + + /** + * 使用反射机制注册控制器中间件 + * @access public + * @param object $controller 控制器实例 + * @return void + */ + protected function registerControllerMiddleware($controller): void + { + $class = new ReflectionClass($controller); + + if ($class->hasProperty('middleware')) { + $reflectionProperty = $class->getProperty('middleware'); + $reflectionProperty->setAccessible(true); + + $middlewares = $reflectionProperty->getValue($controller); + + foreach ($middlewares as $key => $val) { + if (!is_int($key)) { + if (isset($val['only']) && !in_array($this->request->action(true), array_map(function ($item) { + return strtolower($item); + }, is_string($val['only']) ? explode(",", $val['only']) : $val['only']))) { + continue; + } elseif (isset($val['except']) && in_array($this->request->action(true), array_map(function ($item) { + return strtolower($item); + }, is_string($val['except']) ? explode(',', $val['except']) : $val['except']))) { + continue; + } else { + $val = $key; + } + } + + if (is_string($val) && strpos($val, ':')) { + $val = explode(':', $val); + if (count($val) > 1) { + $val = [$val[0], array_slice($val, 1)]; + } + } + + $this->app->middleware->controller($val); + } + } + } + + /** + * 实例化访问控制器 + * @access public + * @param string $name 资源地址 + * @return object + * @throws ClassNotFoundException + */ + public function controller(string $name) + { + $suffix = $this->rule->config('controller_suffix') ? 'Controller' : ''; + + $controllerLayer = $this->rule->config('controller_layer') ?: 'controller'; + $emptyController = $this->rule->config('empty_controller') ?: 'Error'; + + $class = $this->app->parseClass($controllerLayer, $name . $suffix); + + if (class_exists($class)) { + return $this->app->make($class, [], true); + } elseif ($emptyController && class_exists($emptyClass = $this->app->parseClass($controllerLayer, $emptyController . $suffix))) { + return $this->app->make($emptyClass, [], true); + } + + throw new ClassNotFoundException('class not exists:' . $class, $class); + } +} diff --git a/vendor/topthink/framework/src/think/route/dispatch/Url.php b/vendor/topthink/framework/src/think/route/dispatch/Url.php new file mode 100644 index 000000000..147f5cb75 --- /dev/null +++ b/vendor/topthink/framework/src/think/route/dispatch/Url.php @@ -0,0 +1,118 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\route\dispatch; + +use think\exception\HttpException; +use think\helper\Str; +use think\Request; +use think\route\Rule; + +/** + * Url Dispatcher + */ +class Url extends Controller +{ + + public function __construct(Request $request, Rule $rule, $dispatch) + { + $this->request = $request; + $this->rule = $rule; + // 解析默认的URL规则 + $dispatch = $this->parseUrl($dispatch); + + parent::__construct($request, $rule, $dispatch, $this->param); + } + + /** + * 解析URL地址 + * @access protected + * @param string $url URL + * @return array + */ + protected function parseUrl(string $url): array + { + $depr = $this->rule->config('pathinfo_depr'); + $bind = $this->rule->getRouter()->getDomainBind(); + + if ($bind && preg_match('/^[a-z]/is', $bind)) { + $bind = str_replace('/', $depr, $bind); + // 如果有域名绑定 + $url = $bind . ('.' != substr($bind, -1) ? $depr : '') . ltrim($url, $depr); + } + + $path = $this->rule->parseUrlPath($url); + if (empty($path)) { + return [null, null]; + } + + // 解析控制器 + $controller = !empty($path) ? array_shift($path) : null; + + if ($controller && !preg_match('/^[A-Za-z0-9][\w|\.]*$/', $controller)) { + throw new HttpException(404, 'controller not exists:' . $controller); + } + + // 解析操作 + $action = !empty($path) ? array_shift($path) : null; + $var = []; + + // 解析额外参数 + if ($path) { + preg_replace_callback('/(\w+)\|([^\|]+)/', function ($match) use (&$var) { + $var[$match[1]] = strip_tags($match[2]); + }, implode('|', $path)); + } + + $panDomain = $this->request->panDomain(); + if ($panDomain && $key = array_search('*', $var)) { + // 泛域名赋值 + $var[$key] = $panDomain; + } + + // 设置当前请求的参数 + $this->param = $var; + + // 封装路由 + $route = [$controller, $action]; + + if ($this->hasDefinedRoute($route)) { + throw new HttpException(404, 'invalid request:' . str_replace('|', $depr, $url)); + } + + return $route; + } + + /** + * 检查URL是否已经定义过路由 + * @access protected + * @param array $route 路由信息 + * @return bool + */ + protected function hasDefinedRoute(array $route): bool + { + [$controller, $action] = $route; + + // 检查地址是否被定义过路由 + $name = strtolower(Str::studly($controller) . '/' . $action); + + $host = $this->request->host(true); + $method = $this->request->method(); + + if ($this->rule->getRouter()->getName($name, $host, $method)) { + return true; + } + + return false; + } + +} diff --git a/vendor/topthink/framework/src/think/service/ModelService.php b/vendor/topthink/framework/src/think/service/ModelService.php new file mode 100644 index 000000000..87cfaf980 --- /dev/null +++ b/vendor/topthink/framework/src/think/service/ModelService.php @@ -0,0 +1,47 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\service; + +use think\Model; +use think\Service; + +/** + * 模型服务类 + */ +class ModelService extends Service +{ + public function boot() + { + Model::setDb($this->app->db); + Model::setEvent($this->app->event); + Model::setInvoker([$this->app, 'invoke']); + Model::maker(function (Model $model) { + $config = $this->app->config; + + $isAutoWriteTimestamp = $model->getAutoWriteTimestamp(); + + if (is_null($isAutoWriteTimestamp)) { + // 自动写入时间戳 + $model->isAutoWriteTimestamp($config->get('database.auto_timestamp', 'timestamp')); + } + + $dateFormat = $model->getDateFormat(); + + if (is_null($dateFormat)) { + // 设置时间戳格式 + $model->setDateFormat($config->get('database.datetime_format', 'Y-m-d H:i:s')); + } + + }); + } +} diff --git a/vendor/topthink/framework/src/think/service/PaginatorService.php b/vendor/topthink/framework/src/think/service/PaginatorService.php new file mode 100644 index 000000000..a01977d01 --- /dev/null +++ b/vendor/topthink/framework/src/think/service/PaginatorService.php @@ -0,0 +1,52 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\service; + +use think\Paginator; +use think\paginator\driver\Bootstrap; +use think\Service; + +/** + * 分页服务类 + */ +class PaginatorService extends Service +{ + public function register() + { + if (!$this->app->bound(Paginator::class)) { + $this->app->bind(Paginator::class, Bootstrap::class); + } + } + + public function boot() + { + Paginator::maker(function (...$args) { + return $this->app->make(Paginator::class, $args, true); + }); + + Paginator::currentPathResolver(function () { + return $this->app->request->baseUrl(); + }); + + Paginator::currentPageResolver(function ($varPage = 'page') { + + $page = $this->app->request->param($varPage); + + if (filter_var($page, FILTER_VALIDATE_INT) !== false && (int) $page >= 1) { + return (int) $page; + } + + return 1; + }); + } +} diff --git a/vendor/topthink/framework/src/think/service/ValidateService.php b/vendor/topthink/framework/src/think/service/ValidateService.php new file mode 100644 index 000000000..94d7638a6 --- /dev/null +++ b/vendor/topthink/framework/src/think/service/ValidateService.php @@ -0,0 +1,31 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\service; + +use think\Service; +use think\Validate; + +/** + * 验证服务类 + */ +class ValidateService extends Service +{ + public function boot() + { + Validate::maker(function (Validate $validate) { + $validate->setLang($this->app->lang); + $validate->setDb($this->app->db); + $validate->setRequest($this->app->request); + }); + } +} diff --git a/vendor/topthink/framework/src/think/session/Store.php b/vendor/topthink/framework/src/think/session/Store.php new file mode 100644 index 000000000..49e1ba909 --- /dev/null +++ b/vendor/topthink/framework/src/think/session/Store.php @@ -0,0 +1,340 @@ + +// +---------------------------------------------------------------------- + +namespace think\session; + +use think\contract\SessionHandlerInterface; +use think\helper\Arr; + +class Store +{ + + /** + * Session数据 + * @var array + */ + protected $data = []; + + /** + * 是否初始化 + * @var bool + */ + protected $init = null; + + /** + * 记录Session name + * @var string + */ + protected $name = 'PHPSESSID'; + + /** + * 记录Session Id + * @var string + */ + protected $id; + + /** + * @var SessionHandlerInterface + */ + protected $handler; + + /** @var array */ + protected $serialize = []; + + public function __construct($name, SessionHandlerInterface $handler, array $serialize = null) + { + $this->name = $name; + $this->handler = $handler; + + if (!empty($serialize)) { + $this->serialize = $serialize; + } + + $this->setId(); + } + + /** + * 设置数据 + * @access public + * @param array $data + * @return void + */ + public function setData(array $data): void + { + $this->data = $data; + } + + /** + * session初始化 + * @access public + * @return void + */ + public function init(): void + { + // 读取缓存数据 + $data = $this->handler->read($this->getId()); + + if (!empty($data)) { + $this->data = array_merge($this->data, $this->unserialize($data)); + } + + $this->init = true; + } + + /** + * 设置SessionName + * @access public + * @param string $name session_name + * @return void + */ + public function setName(string $name): void + { + $this->name = $name; + } + + /** + * 获取sessionName + * @access public + * @return string + */ + public function getName(): string + { + return $this->name; + } + + /** + * session_id设置 + * @access public + * @param string $id session_id + * @return void + */ + public function setId($id = null): void + { + $this->id = is_string($id) && strlen($id) === 32 && ctype_alnum($id) ? $id : md5(microtime(true) . session_create_id()); + } + + /** + * 获取session_id + * @access public + * @return string + */ + public function getId(): string + { + return $this->id; + } + + /** + * 获取所有数据 + * @return array + */ + public function all(): array + { + return $this->data; + } + + /** + * session设置 + * @access public + * @param string $name session名称 + * @param mixed $value session值 + * @return void + */ + public function set(string $name, $value): void + { + Arr::set($this->data, $name, $value); + } + + /** + * session获取 + * @access public + * @param string $name session名称 + * @param mixed $default 默认值 + * @return mixed + */ + public function get(string $name, $default = null) + { + return Arr::get($this->data, $name, $default); + } + + /** + * session获取并删除 + * @access public + * @param string $name session名称 + * @return mixed + */ + public function pull(string $name) + { + return Arr::pull($this->data, $name); + } + + /** + * 添加数据到一个session数组 + * @access public + * @param string $key + * @param mixed $value + * @return void + */ + public function push(string $key, $value): void + { + $array = $this->get($key, []); + + $array[] = $value; + + $this->set($key, $array); + } + + /** + * 判断session数据 + * @access public + * @param string $name session名称 + * @return bool + */ + public function has(string $name): bool + { + return Arr::has($this->data, $name); + } + + /** + * 删除session数据 + * @access public + * @param string $name session名称 + * @return void + */ + public function delete(string $name): void + { + Arr::forget($this->data, $name); + } + + /** + * 清空session数据 + * @access public + * @return void + */ + public function clear(): void + { + $this->data = []; + } + + /** + * 销毁session + */ + public function destroy(): void + { + $this->clear(); + + $this->regenerate(true); + } + + /** + * 重新生成session id + * @param bool $destroy + */ + public function regenerate(bool $destroy = false): void + { + if ($destroy) { + $this->handler->delete($this->getId()); + } + + $this->setId(); + } + + /** + * 保存session数据 + * @access public + * @return void + */ + public function save(): void + { + $this->clearFlashData(); + + $sessionId = $this->getId(); + + if (!empty($this->data)) { + $data = $this->serialize($this->data); + + $this->handler->write($sessionId, $data); + } else { + $this->handler->delete($sessionId); + } + + $this->init = false; + } + + /** + * session设置 下一次请求有效 + * @access public + * @param string $name session名称 + * @param mixed $value session值 + * @return void + */ + public function flash(string $name, $value): void + { + $this->set($name, $value); + $this->push('__flash__.__next__', $name); + $this->set('__flash__.__current__', Arr::except($this->get('__flash__.__current__', []), $name)); + } + + /** + * 将本次闪存数据推迟到下次请求 + * + * @return void + */ + public function reflash(): void + { + $keys = $this->get('__flash__.__current__', []); + $values = array_unique(array_merge($this->get('__flash__.__next__', []), $keys)); + $this->set('__flash__.__next__', $values); + $this->set('__flash__.__current__', []); + } + + /** + * 清空当前请求的session数据 + * @access public + * @return void + */ + public function clearFlashData(): void + { + Arr::forget($this->data, $this->get('__flash__.__current__', [])); + if (!empty($next = $this->get('__flash__.__next__', []))) { + $this->set('__flash__.__current__', $next); + } else { + $this->delete('__flash__.__current__'); + } + $this->delete('__flash__.__next__'); + } + + /** + * 序列化数据 + * @access protected + * @param mixed $data + * @return string + */ + protected function serialize($data): string + { + $serialize = $this->serialize[0] ?? 'serialize'; + + return $serialize($data); + } + + /** + * 反序列化数据 + * @access protected + * @param string $data + * @return array + */ + protected function unserialize(string $data): array + { + $unserialize = $this->serialize[1] ?? 'unserialize'; + + return (array) $unserialize($data); + } + +} diff --git a/vendor/topthink/framework/src/think/session/driver/Cache.php b/vendor/topthink/framework/src/think/session/driver/Cache.php new file mode 100644 index 000000000..4fabc799a --- /dev/null +++ b/vendor/topthink/framework/src/think/session/driver/Cache.php @@ -0,0 +1,50 @@ + +// +---------------------------------------------------------------------- +namespace think\session\driver; + +use Psr\SimpleCache\CacheInterface; +use think\contract\SessionHandlerInterface; +use think\helper\Arr; + +class Cache implements SessionHandlerInterface +{ + + /** @var CacheInterface */ + protected $handler; + + /** @var integer */ + protected $expire; + + /** @var string */ + protected $prefix; + + public function __construct(\think\Cache $cache, array $config = []) + { + $this->handler = $cache->store(Arr::get($config, 'store')); + $this->expire = Arr::get($config, 'expire', 1440); + $this->prefix = Arr::get($config, 'prefix', ''); + } + + public function read(string $sessionId): string + { + return (string) $this->handler->get($this->prefix . $sessionId); + } + + public function delete(string $sessionId): bool + { + return $this->handler->delete($this->prefix . $sessionId); + } + + public function write(string $sessionId, string $data): bool + { + return $this->handler->set($this->prefix . $sessionId, $data, $this->expire); + } +} diff --git a/vendor/topthink/framework/src/think/session/driver/File.php b/vendor/topthink/framework/src/think/session/driver/File.php new file mode 100644 index 000000000..788f3230e --- /dev/null +++ b/vendor/topthink/framework/src/think/session/driver/File.php @@ -0,0 +1,249 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\session\driver; + +use Closure; +use Exception; +use FilesystemIterator; +use Generator; +use SplFileInfo; +use think\App; +use think\contract\SessionHandlerInterface; + +/** + * Session 文件驱动 + */ +class File implements SessionHandlerInterface +{ + protected $config = [ + 'path' => '', + 'expire' => 1440, + 'prefix' => '', + 'data_compress' => false, + 'gc_probability' => 1, + 'gc_divisor' => 100, + ]; + + public function __construct(App $app, array $config = []) + { + $this->config = array_merge($this->config, $config); + + if (empty($this->config['path'])) { + $this->config['path'] = $app->getRuntimePath() . 'session' . DIRECTORY_SEPARATOR; + } elseif (substr($this->config['path'], -1) != DIRECTORY_SEPARATOR) { + $this->config['path'] .= DIRECTORY_SEPARATOR; + } + + $this->init(); + } + + /** + * 打开Session + * @access protected + * @throws Exception + */ + protected function init(): void + { + try { + !is_dir($this->config['path']) && mkdir($this->config['path'], 0755, true); + } catch (\Exception $e) { + // 写入失败 + } + + // 垃圾回收 + if (random_int(1, $this->config['gc_divisor']) <= $this->config['gc_probability']) { + $this->gc(); + } + } + + /** + * Session 垃圾回收 + * @access public + * @return void + */ + public function gc(): void + { + $lifetime = $this->config['expire']; + $now = time(); + + $files = $this->findFiles($this->config['path'], function (SplFileInfo $item) use ($lifetime, $now) { + return $now - $lifetime > $item->getMTime(); + }); + + foreach ($files as $file) { + $this->unlink($file->getPathname()); + } + } + + /** + * 查找文件 + * @param string $root + * @param Closure $filter + * @return Generator + */ + protected function findFiles(string $root, Closure $filter) + { + $items = new FilesystemIterator($root); + + /** @var SplFileInfo $item */ + foreach ($items as $item) { + if ($item->isDir() && !$item->isLink()) { + yield from $this->findFiles($item->getPathname(), $filter); + } else { + if ($filter($item)) { + yield $item; + } + } + } + } + + /** + * 取得变量的存储文件名 + * @access protected + * @param string $name 缓存变量名 + * @param bool $auto 是否自动创建目录 + * @return string + */ + protected function getFileName(string $name, bool $auto = false): string + { + if ($this->config['prefix']) { + // 使用子目录 + $name = $this->config['prefix'] . DIRECTORY_SEPARATOR . 'sess_' . $name; + } else { + $name = 'sess_' . $name; + } + + $filename = $this->config['path'] . $name; + $dir = dirname($filename); + + if ($auto && !is_dir($dir)) { + try { + mkdir($dir, 0755, true); + } catch (\Exception $e) { + // 创建失败 + } + } + + return $filename; + } + + /** + * 读取Session + * @access public + * @param string $sessID + * @return string + */ + public function read(string $sessID): string + { + $filename = $this->getFileName($sessID); + + if (is_file($filename) && filemtime($filename) >= time() - $this->config['expire']) { + $content = $this->readFile($filename); + + if ($this->config['data_compress'] && function_exists('gzcompress')) { + //启用数据压缩 + $content = (string) gzuncompress($content); + } + + return $content; + } + + return ''; + } + + /** + * 写文件(加锁) + * @param $path + * @param $content + * @return bool + */ + protected function writeFile($path, $content): bool + { + return (bool) file_put_contents($path, $content, LOCK_EX); + } + + /** + * 读取文件内容(加锁) + * @param $path + * @return string + */ + protected function readFile($path): string + { + $contents = ''; + + $handle = fopen($path, 'rb'); + + if ($handle) { + try { + if (flock($handle, LOCK_SH)) { + clearstatcache(true, $path); + + $contents = fread($handle, filesize($path) ?: 1); + + flock($handle, LOCK_UN); + } + } finally { + fclose($handle); + } + } + + return $contents; + } + + /** + * 写入Session + * @access public + * @param string $sessID + * @param string $sessData + * @return bool + */ + public function write(string $sessID, string $sessData): bool + { + $filename = $this->getFileName($sessID, true); + $data = $sessData; + + if ($this->config['data_compress'] && function_exists('gzcompress')) { + //数据压缩 + $data = gzcompress($data, 3); + } + + return $this->writeFile($filename, $data); + } + + /** + * 删除Session + * @access public + * @param string $sessID + * @return bool + */ + public function delete(string $sessID): bool + { + try { + return $this->unlink($this->getFileName($sessID)); + } catch (\Exception $e) { + return false; + } + } + + /** + * 判断文件是否存在后,删除 + * @access private + * @param string $file + * @return bool + */ + private function unlink(string $file): bool + { + return is_file($file) && unlink($file); + } + +} diff --git a/thinkphp/library/think/validate/ValidateRule.php b/vendor/topthink/framework/src/think/validate/ValidateRule.php old mode 100755 new mode 100644 similarity index 95% rename from thinkphp/library/think/validate/ValidateRule.php rename to vendor/topthink/framework/src/think/validate/ValidateRule.php index 7cd701747..b741f5301 --- a/thinkphp/library/think/validate/ValidateRule.php +++ b/vendor/topthink/framework/src/think/validate/ValidateRule.php @@ -2,12 +2,13 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\validate; @@ -90,7 +91,7 @@ class ValidateRule * @param string $msg 提示信息 * @return $this */ - protected function addItem($name, $rule = null, $msg = '') + protected function addItem(string $name, $rule = null, string $msg = '') { if ($rule || 0 === $rule) { $this->rule[$name] = $rule; @@ -108,7 +109,7 @@ class ValidateRule * @access public * @return array */ - public function getRule() + public function getRule(): array { return $this->rule; } @@ -118,9 +119,9 @@ class ValidateRule * @access public * @return string */ - public function getTitle() + public function getTitle(): string { - return $this->title; + return $this->title ?: ''; } /** @@ -128,7 +129,7 @@ class ValidateRule * @access public * @return array */ - public function getMsg() + public function getMsg(): array { return $this->message; } @@ -138,7 +139,7 @@ class ValidateRule * @access public * @return $this */ - public function title($title) + public function title(string $title) { $this->title = $title; diff --git a/vendor/topthink/framework/src/think/view/driver/Php.php b/vendor/topthink/framework/src/think/view/driver/Php.php new file mode 100644 index 000000000..9e6e54aa3 --- /dev/null +++ b/vendor/topthink/framework/src/think/view/driver/Php.php @@ -0,0 +1,191 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\view\driver; + +use RuntimeException; +use think\App; +use think\contract\TemplateHandlerInterface; +use think\helper\Str; + +/** + * PHP原生模板驱动 + */ +class Php implements TemplateHandlerInterface +{ + protected $template; + protected $content; + protected $app; + + // 模板引擎参数 + protected $config = [ + // 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写 3 保持操作方法 + 'auto_rule' => 1, + // 视图目录名 + 'view_dir_name' => 'view', + // 应用模板路径 + 'view_path' => '', + // 模板文件后缀 + 'view_suffix' => 'php', + // 模板文件名分隔符 + 'view_depr' => DIRECTORY_SEPARATOR, + ]; + + public function __construct(App $app, array $config = []) + { + $this->app = $app; + $this->config = array_merge($this->config, (array) $config); + } + + /** + * 检测是否存在模板文件 + * @access public + * @param string $template 模板文件或者模板规则 + * @return bool + */ + public function exists(string $template): bool + { + if ('' == pathinfo($template, PATHINFO_EXTENSION)) { + // 获取模板文件名 + $template = $this->parseTemplate($template); + } + + return is_file($template); + } + + /** + * 渲染模板文件 + * @access public + * @param string $template 模板文件 + * @param array $data 模板变量 + * @return void + */ + public function fetch(string $template, array $data = []): void + { + if ('' == pathinfo($template, PATHINFO_EXTENSION)) { + // 获取模板文件名 + $template = $this->parseTemplate($template); + } + + // 模板不存在 抛出异常 + if (!is_file($template)) { + throw new RuntimeException('template not exists:' . $template); + } + + $this->template = $template; + + extract($data, EXTR_OVERWRITE); + + include $this->template; + } + + /** + * 渲染模板内容 + * @access public + * @param string $content 模板内容 + * @param array $data 模板变量 + * @return void + */ + public function display(string $content, array $data = []): void + { + $this->content = $content; + + extract($data, EXTR_OVERWRITE); + eval('?>' . $this->content); + } + + /** + * 自动定位模板文件 + * @access private + * @param string $template 模板文件规则 + * @return string + */ + private function parseTemplate(string $template): string + { + $request = $this->app->request; + + // 获取视图根目录 + if (strpos($template, '@')) { + // 跨应用调用 + [$app, $template] = explode('@', $template); + } + + if ($this->config['view_path'] && !isset($app)) { + $path = $this->config['view_path']; + } else { + $appName = isset($app) ? $app : $this->app->http->getName(); + $view = $this->config['view_dir_name']; + + if (is_dir($this->app->getAppPath() . $view)) { + $path = isset($app) ? $this->app->getBasePath() . ($appName ? $appName . DIRECTORY_SEPARATOR : '') . $view . DIRECTORY_SEPARATOR : $this->app->getAppPath() . $view . DIRECTORY_SEPARATOR; + } else { + $path = $this->app->getRootPath() . $view . DIRECTORY_SEPARATOR . ($appName ? $appName . DIRECTORY_SEPARATOR : ''); + } + } + + $depr = $this->config['view_depr']; + + if (0 !== strpos($template, '/')) { + $template = str_replace(['/', ':'], $depr, $template); + $controller = $request->controller(); + if (strpos($controller, '.')) { + $pos = strrpos($controller, '.'); + $controller = substr($controller, 0, $pos) . '.' . Str::snake(substr($controller, $pos + 1)); + } else { + $controller = Str::snake($controller); + } + + if ($controller) { + if ('' == $template) { + // 如果模板文件名为空 按照默认规则定位 + if (2 == $this->config['auto_rule']) { + $template = $request->action(true); + } elseif (3 == $this->config['auto_rule']) { + $template = $request->action(); + } else { + $template = Str::snake($request->action()); + } + + $template = str_replace('.', DIRECTORY_SEPARATOR, $controller) . $depr . $template; + } elseif (false === strpos($template, $depr)) { + $template = str_replace('.', DIRECTORY_SEPARATOR, $controller) . $depr . $template; + } + } + } else { + $template = str_replace(['/', ':'], $depr, substr($template, 1)); + } + + return $path . ltrim($template, '/') . '.' . ltrim($this->config['view_suffix'], '.'); + } + + /** + * 配置模板引擎 + * @access private + * @param array $config 参数 + * @return void + */ + public function config(array $config): void + { + $this->config = array_merge($this->config, $config); + } + + /** + * 获取模板引擎配置 + * @access public + * @param string $name 参数名 + * @return mixed + */ + public function getConfig(string $name) + { + return $this->config[$name] ?? null; + } +} diff --git a/vendor/topthink/framework/src/tpl/think_exception.tpl b/vendor/topthink/framework/src/tpl/think_exception.tpl new file mode 100644 index 000000000..7766caf57 --- /dev/null +++ b/vendor/topthink/framework/src/tpl/think_exception.tpl @@ -0,0 +1,502 @@ +'.end($names).''; + } +} + +if (!function_exists('parse_file')) { + function parse_file($file, $line) + { + return ''.basename($file)." line {$line}".''; + } +} + +if (!function_exists('parse_args')) { + function parse_args($args) + { + $result = []; + foreach ($args as $key => $item) { + switch (true) { + case is_object($item): + $value = sprintf('object(%s)', parse_class(get_class($item))); + break; + case is_array($item): + if (count($item) > 3) { + $value = sprintf('[%s, ...]', parse_args(array_slice($item, 0, 3))); + } else { + $value = sprintf('[%s]', parse_args($item)); + } + break; + case is_string($item): + if (strlen($item) > 20) { + $value = sprintf( + '\'%s...\'', + htmlentities($item), + htmlentities(substr($item, 0, 20)) + ); + } else { + $value = sprintf("'%s'", htmlentities($item)); + } + break; + case is_int($item): + case is_float($item): + $value = $item; + break; + case is_null($item): + $value = 'null'; + break; + case is_bool($item): + $value = '' . ($item ? 'true' : 'false') . ''; + break; + case is_resource($item): + $value = 'resource'; + break; + default: + $value = htmlentities(str_replace("\n", '', var_export(strval($item), true))); + break; + } + + $result[] = is_int($key) ? $value : "'{$key}' => {$value}"; + } + + return implode(', ', $result); + } +} +if (!function_exists('echo_value')) { + function echo_value($val) + { + if (is_array($val) || is_object($val)) { + echo htmlentities(json_encode($val, JSON_PRETTY_PRINT)); + } elseif (is_bool($val)) { + echo $val ? 'true' : 'false'; + } elseif (is_scalar($val)) { + echo htmlentities($val); + } else { + echo 'Resource'; + } + } +} +?> + + + + + 系统发生错误 + + + + + + $trace) { ?> +
    +
    +
    +
    +

    +
    +

    +
    +
    + +
    +
      $value) { ?>
    1. ">
    +
    + +
    +

    Call Stack

    +
      +
    1. + +
    2. + +
    3. + +
    +
    +
    + + +
    +

    +
    + + + +
    +

    Exception Datas

    + $value) { ?> +
    empty
    - -
    + + + + + + $val) { ?> + + + + + + + +
    empty
    + +
    + + + +
    +

    Environment Variables

    + $value) { ?> + + + + + + + $val) { ?> + + + + + + + +
    empty
    + +
    + + + + + + + + diff --git a/vendor/topthink/framework/tests/AppTest.php b/vendor/topthink/framework/tests/AppTest.php new file mode 100644 index 000000000..6b8601521 --- /dev/null +++ b/vendor/topthink/framework/tests/AppTest.php @@ -0,0 +1,215 @@ + 'class', + ]; + + public function register() + { + + } + + public function boot() + { + + } +} + +/** + * @property array initializers + */ +class AppTest extends TestCase +{ + /** @var App */ + protected $app; + + protected function setUp() + { + $this->app = new App(); + } + + protected function tearDown(): void + { + m::close(); + } + + public function testService() + { + $this->app->register(stdClass::class); + + $this->assertInstanceOf(stdClass::class, $this->app->getService(stdClass::class)); + + $service = m::mock(SomeService::class); + + $service->shouldReceive('register')->once(); + + $this->app->register($service); + + $this->assertEquals($service, $this->app->getService(SomeService::class)); + + $service2 = m::mock(SomeService::class); + + $service2->shouldReceive('register')->once(); + + $this->app->register($service2); + + $this->assertEquals($service, $this->app->getService(SomeService::class)); + + $this->app->register($service2, true); + + $this->assertEquals($service2, $this->app->getService(SomeService::class)); + + $service->shouldReceive('boot')->once(); + $service2->shouldReceive('boot')->once(); + + $this->app->boot(); + } + + public function testDebug() + { + $this->app->debug(false); + + $this->assertFalse($this->app->isDebug()); + + $this->app->debug(true); + + $this->assertTrue($this->app->isDebug()); + } + + public function testNamespace() + { + $namespace = 'test'; + + $this->app->setNamespace($namespace); + + $this->assertEquals($namespace, $this->app->getNamespace()); + } + + public function testVersion() + { + $this->assertEquals(App::VERSION, $this->app->version()); + } + + public function testPath() + { + $rootPath = __DIR__ . DIRECTORY_SEPARATOR; + + $app = new App($rootPath); + + $this->assertEquals($rootPath, $app->getRootPath()); + + $this->assertEquals(dirname(__DIR__) . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR, $app->getThinkPath()); + + $this->assertEquals($rootPath . 'app' . DIRECTORY_SEPARATOR, $app->getAppPath()); + + $appPath = $rootPath . 'app' . DIRECTORY_SEPARATOR . 'admin' . DIRECTORY_SEPARATOR; + $app->setAppPath($appPath); + $this->assertEquals($appPath, $app->getAppPath()); + + $this->assertEquals($rootPath . 'app' . DIRECTORY_SEPARATOR, $app->getBasePath()); + + $this->assertEquals($rootPath . 'config' . DIRECTORY_SEPARATOR, $app->getConfigPath()); + + $this->assertEquals($rootPath . 'runtime' . DIRECTORY_SEPARATOR, $app->getRuntimePath()); + + $runtimePath = $rootPath . 'runtime' . DIRECTORY_SEPARATOR . 'admin' . DIRECTORY_SEPARATOR; + $app->setRuntimePath($runtimePath); + $this->assertEquals($runtimePath, $app->getRuntimePath()); + } + + /** + * @param vfsStreamDirectory $root + * @param bool $debug + * @return App + */ + protected function prepareAppForInitialize(vfsStreamDirectory $root, $debug = true) + { + $rootPath = $root->url() . DIRECTORY_SEPARATOR; + + $app = new App($rootPath); + + $initializer = m::mock(); + $initializer->shouldReceive('init')->once()->with($app); + + $app->instance($initializer->mockery_getName(), $initializer); + + (function () use ($initializer) { + $this->initializers = [$initializer->mockery_getName()]; + })->call($app); + + $env = m::mock(Env::class); + $env->shouldReceive('load')->once()->with($rootPath . '.env'); + $env->shouldReceive('get')->once()->with('config_ext', '.php')->andReturn('.php'); + $env->shouldReceive('get')->once()->with('app_debug')->andReturn($debug); + + $event = m::mock(Event::class); + $event->shouldReceive('trigger')->once()->with(AppInit::class); + $event->shouldReceive('bind')->once()->with([]); + $event->shouldReceive('listenEvents')->once()->with([]); + $event->shouldReceive('subscribe')->once()->with([]); + + $app->instance('env', $env); + $app->instance('event', $event); + + return $app; + } + + public function testInitialize() + { + $root = vfsStream::setup('rootDir', null, [ + '.env' => '', + 'app' => [ + 'common.php' => '', + 'event.php' => '[],"listen"=>[],"subscribe"=>[]];', + 'provider.php' => ' [ + 'app.php' => 'prepareAppForInitialize($root, true); + + $app->debug(false); + + $app->initialize(); + + $this->assertIsInt($app->getBeginMem()); + $this->assertIsFloat($app->getBeginTime()); + + $this->assertTrue($app->initialized()); + } + + public function testFactory() + { + $this->assertInstanceOf(stdClass::class, App::factory(stdClass::class)); + + $this->expectException(ClassNotFoundException::class); + + App::factory('SomeClass'); + } + + public function testParseClass() + { + $this->assertEquals('app\\controller\\SomeClass', $this->app->parseClass('controller', 'some_class')); + $this->app->setNamespace('app2'); + $this->assertEquals('app2\\controller\\SomeClass', $this->app->parseClass('controller', 'some_class')); + } + +} diff --git a/vendor/topthink/framework/tests/CacheTest.php b/vendor/topthink/framework/tests/CacheTest.php new file mode 100644 index 000000000..5b5a13cbc --- /dev/null +++ b/vendor/topthink/framework/tests/CacheTest.php @@ -0,0 +1,149 @@ +app = m::mock(App::class)->makePartial(); + + Container::setInstance($this->app); + $this->app->shouldReceive('make')->with(App::class)->andReturn($this->app); + $this->config = m::mock(Config::class)->makePartial(); + $this->app->shouldReceive('get')->with('config')->andReturn($this->config); + + $this->cache = new Cache($this->app); + } + + public function testGetConfig() + { + $config = [ + 'default' => 'file', + ]; + + $this->config->shouldReceive('get')->with('cache')->andReturn($config); + + $this->assertEquals($config, $this->cache->getConfig()); + + $this->expectException(InvalidArgumentException::class); + $this->cache->getStoreConfig('foo'); + } + + public function testCacheManagerInstances() + { + $this->config->shouldReceive('get')->with("cache.stores.single", null)->andReturn(['type' => 'file']); + + $channel1 = $this->cache->store('single'); + $channel2 = $this->cache->store('single'); + + $this->assertSame($channel1, $channel2); + } + + public function testFileCache() + { + $root = vfsStream::setup(); + + $this->config->shouldReceive('get')->with("cache.default", null)->andReturn('file'); + + $this->config->shouldReceive('get')->with("cache.stores.file", null)->andReturn(['type' => 'file', 'path' => $root->url()]); + + $this->cache->set('foo', 5); + $this->cache->inc('foo'); + $this->assertEquals(6, $this->cache->get('foo')); + $this->cache->dec('foo', 2); + $this->assertEquals(4, $this->cache->get('foo')); + + $this->cache->set('bar', true); + $this->assertTrue($this->cache->get('bar')); + + $this->cache->set('baz', null); + $this->assertNull($this->cache->get('baz')); + + $this->assertTrue($this->cache->has('baz')); + $this->cache->delete('baz'); + $this->assertFalse($this->cache->has('baz')); + $this->assertNull($this->cache->get('baz')); + $this->assertFalse($this->cache->get('baz', false)); + + $this->assertTrue($root->hasChildren()); + $this->cache->clear(); + $this->assertFalse($root->hasChildren()); + + //tags + $this->cache->tag('foo')->set('bar', 'foobar'); + $this->assertEquals('foobar', $this->cache->get('bar')); + $this->cache->tag('foo')->clear(); + $this->assertFalse($this->cache->has('bar')); + + //multiple + $this->cache->setMultiple(['foo' => ['foobar', 'bar'], 'foobar' => ['foo', 'bar']]); + $this->assertEquals(['foo' => ['foobar', 'bar'], 'foobar' => ['foo', 'bar']], $this->cache->getMultiple(['foo', 'foobar'])); + $this->assertTrue($this->cache->deleteMultiple(['foo', 'foobar'])); + } + + public function testRedisCache() + { + if (extension_loaded('redis')) { + return; + } + $this->config->shouldReceive('get')->with("cache.default", null)->andReturn('redis'); + $this->config->shouldReceive('get')->with("cache.stores.redis", null)->andReturn(['type' => 'redis']); + + $redis = m::mock('overload:\Predis\Client'); + + $redis->shouldReceive("set")->once()->with('foo', 5)->andReturnTrue(); + $redis->shouldReceive("incrby")->once()->with('foo', 1)->andReturnTrue(); + $redis->shouldReceive("decrby")->once()->with('foo', 2)->andReturnTrue(); + $redis->shouldReceive("get")->once()->with('foo')->andReturn('6'); + $redis->shouldReceive("get")->once()->with('foo')->andReturn('4'); + $redis->shouldReceive("set")->once()->with('bar', serialize(true))->andReturnTrue(); + $redis->shouldReceive("set")->once()->with('baz', serialize(null))->andReturnTrue(); + $redis->shouldReceive("del")->once()->with('baz')->andReturnTrue(); + $redis->shouldReceive("flushDB")->once()->andReturnTrue(); + $redis->shouldReceive("set")->once()->with('bar', serialize('foobar'))->andReturnTrue(); + $redis->shouldReceive("sAdd")->once()->with('tag:' . md5('foo'), 'bar')->andReturnTrue(); + $redis->shouldReceive("sMembers")->once()->with('tag:' . md5('foo'))->andReturn(['bar']); + $redis->shouldReceive("del")->once()->with(['bar'])->andReturnTrue(); + $redis->shouldReceive("del")->once()->with('tag:' . md5('foo'))->andReturnTrue(); + + $this->cache->set('foo', 5); + $this->cache->inc('foo'); + $this->assertEquals(6, $this->cache->get('foo')); + $this->cache->dec('foo', 2); + $this->assertEquals(4, $this->cache->get('foo')); + + $this->cache->set('bar', true); + $this->cache->set('baz', null); + $this->cache->delete('baz'); + $this->cache->clear(); + + //tags + $this->cache->tag('foo')->set('bar', 'foobar'); + $this->cache->tag('foo')->clear(); + } +} diff --git a/vendor/topthink/framework/tests/ConfigTest.php b/vendor/topthink/framework/tests/ConfigTest.php new file mode 100644 index 000000000..271a34fc3 --- /dev/null +++ b/vendor/topthink/framework/tests/ConfigTest.php @@ -0,0 +1,46 @@ +setContent(" 'value1','key2'=>'value2'];"); + $root->addChild($file); + + $config = new Config(); + + $config->load($file->url(), 'test'); + + $this->assertEquals('value1', $config->get('test.key1')); + $this->assertEquals('value2', $config->get('test.key2')); + + $this->assertSame(['key1' => 'value1', 'key2' => 'value2'], $config->get('test')); + } + + public function testSetAndGet() + { + $config = new Config(); + + $config->set([ + 'key1' => 'value1', + 'key2' => [ + 'key3' => 'value3', + ], + ], 'test'); + + $this->assertTrue($config->has('test.key1')); + $this->assertEquals('value1', $config->get('test.key1')); + $this->assertEquals('value3', $config->get('test.key2.key3')); + + $this->assertEquals(['key3' => 'value3'], $config->get('test.key2')); + $this->assertFalse($config->has('test.key3')); + $this->assertEquals('none', $config->get('test.key3', 'none')); + } +} diff --git a/vendor/topthink/framework/tests/ContainerTest.php b/vendor/topthink/framework/tests/ContainerTest.php new file mode 100644 index 000000000..e27deb088 --- /dev/null +++ b/vendor/topthink/framework/tests/ContainerTest.php @@ -0,0 +1,314 @@ +name = $name; + } + + public function some(Container $container) + { + } + + protected function protectionFun() + { + return true; + } + + public static function test(Container $container) + { + return $container; + } + + public static function __make() + { + return new self('Taylor'); + } +} + +class SomeClass +{ + public $container; + + public $count = 0; + + public function __construct(Container $container) + { + $this->container = $container; + } +} + +class ContainerTest extends TestCase +{ + protected function tearDown(): void + { + Container::setInstance(null); + } + + public function testClosureResolution() + { + $container = new Container; + + Container::setInstance($container); + + $container->bind('name', function () { + return 'Taylor'; + }); + + $this->assertEquals('Taylor', $container->make('name')); + + $this->assertEquals('Taylor', Container::pull('name')); + } + + public function testGet() + { + $container = new Container; + + $this->expectException(ClassNotFoundException::class); + $this->expectExceptionMessage('class not exists: name'); + $container->get('name'); + + $container->bind('name', function () { + return 'Taylor'; + }); + + $this->assertSame('Taylor', $container->get('name')); + } + + public function testExist() + { + $container = new Container; + + $container->bind('name', function () { + return 'Taylor'; + }); + + $this->assertFalse($container->exists("name")); + + $container->make('name'); + + $this->assertTrue($container->exists('name')); + } + + public function testInstance() + { + $container = new Container; + + $container->bind('name', function () { + return 'Taylor'; + }); + + $this->assertEquals('Taylor', $container->get('name')); + + $container->bind('name2', Taylor::class); + + $object = new stdClass(); + + $this->assertFalse($container->exists('name2')); + + $container->instance('name2', $object); + + $this->assertTrue($container->exists('name2')); + + $this->assertTrue($container->exists(Taylor::class)); + + $this->assertEquals($object, $container->make(Taylor::class)); + + unset($container->name1); + + $this->assertFalse($container->exists('name1')); + + $container->delete('name2'); + + $this->assertFalse($container->exists('name2')); + + foreach ($container as $class => $instance) { + + } + } + + public function testBind() + { + $container = new Container; + + $object = new stdClass(); + + $container->bind(['name' => Taylor::class]); + + $container->bind('name2', $object); + + $container->bind('name3', Taylor::class); + $container->bind('name3', Taylor::class); + + $container->name4 = $object; + + $container['name5'] = $object; + + $this->assertTrue(isset($container->name4)); + + $this->assertTrue(isset($container['name5'])); + + $this->assertInstanceOf(Taylor::class, $container->get('name')); + + $this->assertSame($object, $container->get('name2')); + + $this->assertSame($object, $container->name4); + + $this->assertSame($object, $container['name5']); + + $this->assertInstanceOf(Taylor::class, $container->get('name3')); + + unset($container['name']); + + $this->assertFalse(isset($container['name'])); + + unset($container->name3); + + $this->assertFalse(isset($container->name3)); + } + + public function testAutoConcreteResolution() + { + $container = new Container; + + $taylor = $container->make(Taylor::class); + + $this->assertInstanceOf(Taylor::class, $taylor); + $this->assertAttributeSame('Taylor', 'name', $taylor); + } + + public function testGetAndSetInstance() + { + $this->assertInstanceOf(Container::class, Container::getInstance()); + + $object = new stdClass(); + + Container::setInstance($object); + + $this->assertSame($object, Container::getInstance()); + + Container::setInstance(function () { + return $this; + }); + + $this->assertSame($this, Container::getInstance()); + } + + public function testResolving() + { + $container = new Container(); + $container->bind(Container::class, $container); + + $container->resolving(function (SomeClass $taylor, Container $container) { + $taylor->count++; + }); + $container->resolving(SomeClass::class, function (SomeClass $taylor, Container $container) { + $taylor->count++; + }); + + /** @var SomeClass $someClass */ + $someClass = $container->invokeClass(SomeClass::class); + $this->assertEquals(2, $someClass->count); + } + + public function testInvokeFunctionWithoutMethodThrowsException() + { + $this->expectException(FuncNotFoundException::class); + $this->expectExceptionMessage('function not exists: ContainerTestCallStub()'); + $container = new Container(); + $container->invokeFunction('ContainerTestCallStub', []); + } + + public function testInvokeProtectionMethod() + { + $container = new Container(); + $this->assertTrue($container->invokeMethod([Taylor::class, 'protectionFun'], [], true)); + } + + public function testInvoke() + { + $container = new Container(); + + Container::setInstance($container); + + $container->bind(Container::class, $container); + + $stub = $this->createMock(Taylor::class); + + $stub->expects($this->once())->method('some')->with($container)->will($this->returnSelf()); + + $container->invokeMethod([$stub, 'some']); + + $this->assertEquals('48', $container->invoke('ord', ['0'])); + + $this->assertSame($container, $container->invoke(Taylor::class . '::test', [])); + + $this->assertSame($container, $container->invokeMethod(Taylor::class . '::test')); + + $reflect = new ReflectionMethod($container, 'exists'); + + $this->assertTrue($container->invokeReflectMethod($container, $reflect, [Container::class])); + + $this->assertSame($container, $container->invoke(function (Container $container) { + return $container; + })); + + $this->assertSame($container, $container->invoke(Taylor::class . '::test')); + + $object = $container->invokeClass(SomeClass::class); + $this->assertInstanceOf(SomeClass::class, $object); + $this->assertSame($container, $object->container); + + $stdClass = new stdClass(); + + $container->invoke(function (Container $container, stdClass $stdObject, $key1, $lowKey, $key2 = 'default') use ($stdClass) { + $this->assertEquals('value1', $key1); + $this->assertEquals('default', $key2); + $this->assertEquals('value2', $lowKey); + $this->assertSame($stdClass, $stdObject); + return $container; + }, ['some' => $stdClass, 'key1' => 'value1', 'low_key' => 'value2']); + } + + public function testInvokeMethodNotExists() + { + $container = $this->resolveContainer(); + $this->expectException(FuncNotFoundException::class); + + $container->invokeMethod([SomeClass::class, 'any']); + } + + public function testInvokeClassNotExists() + { + $container = new Container(); + + Container::setInstance($container); + + $container->bind(Container::class, $container); + + $this->expectExceptionObject(new ClassNotFoundException('class not exists: SomeClass')); + + $container->invokeClass('SomeClass'); + } + + protected function resolveContainer() + { + $container = new Container(); + + Container::setInstance($container); + return $container; + } + +} diff --git a/vendor/topthink/framework/tests/DbTest.php b/vendor/topthink/framework/tests/DbTest.php new file mode 100644 index 000000000..3bd0c1e9d --- /dev/null +++ b/vendor/topthink/framework/tests/DbTest.php @@ -0,0 +1,49 @@ +shouldReceive('get')->with('database.cache_store', null)->andReturn(null); + $cache->shouldReceive('store')->with(null)->andReturn($store); + + $db = Db::__make($event, $config, $log, $cache); + + $config->shouldReceive('get')->with('database.foo', null)->andReturn('foo'); + $this->assertEquals('foo', $db->getConfig('foo')); + + $config->shouldReceive('get')->with('database', [])->andReturn([]); + $this->assertEquals([], $db->getConfig()); + + $callback = function () { + }; + $event->shouldReceive('listen')->with('db.some', $callback); + $db->event('some', $callback); + + $event->shouldReceive('trigger')->with('db.some', null, false); + $db->trigger('some'); + } + +} diff --git a/vendor/topthink/framework/tests/EnvTest.php b/vendor/topthink/framework/tests/EnvTest.php new file mode 100644 index 000000000..cf2e65f85 --- /dev/null +++ b/vendor/topthink/framework/tests/EnvTest.php @@ -0,0 +1,82 @@ +setContent("key1=value1\nkey2=value2"); + $root->addChild($envFile); + + $env = new Env(); + + $env->load($envFile->url()); + + $this->assertEquals('value1', $env->get('key1')); + $this->assertEquals('value2', $env->get('key2')); + + $this->assertSame(['KEY1' => 'value1', 'KEY2' => 'value2'], $env->get()); + } + + public function testServerEnv() + { + $env = new Env(); + + $this->assertEquals('value2', $env->get('key2', 'value2')); + + putenv('PHP_KEY7=value7'); + putenv('PHP_KEY8=false'); + putenv('PHP_KEY9=true'); + + $this->assertEquals('value7', $env->get('key7')); + $this->assertFalse($env->get('KEY8')); + $this->assertTrue($env->get('key9')); + } + + public function testSetEnv() + { + $env = new Env(); + + $env->set([ + 'key1' => 'value1', + 'key2' => [ + 'key1' => 'value1-2', + ], + ]); + + $env->set('key3', 'value3'); + + $env->key4 = 'value4'; + + $env['key5'] = 'value5'; + + $this->assertEquals('value1', $env->get('key1')); + $this->assertEquals('value1-2', $env->get('key2.key1')); + + $this->assertEquals('value3', $env->get('key3')); + + $this->assertEquals('value4', $env->key4); + + $this->assertEquals('value5', $env['key5']); + + $this->expectException(Exception::class); + + unset($env['key5']); + } + + public function testHasEnv() + { + $env = new Env(); + $env->set(['foo' => 'bar']); + $this->assertTrue($env->has('foo')); + $this->assertTrue(isset($env->foo)); + $this->assertTrue($env->offsetExists('foo')); + } +} diff --git a/vendor/topthink/framework/tests/EventTest.php b/vendor/topthink/framework/tests/EventTest.php new file mode 100644 index 000000000..ded5a36d5 --- /dev/null +++ b/vendor/topthink/framework/tests/EventTest.php @@ -0,0 +1,134 @@ +app = m::mock(App::class)->makePartial(); + + Container::setInstance($this->app); + $this->app->shouldReceive('make')->with(App::class)->andReturn($this->app); + $this->config = m::mock(Config::class)->makePartial(); + $this->app->shouldReceive('get')->with('config')->andReturn($this->config); + + $this->event = new Event($this->app); + } + + public function testBasic() + { + $this->event->bind(['foo' => 'baz']); + + $this->event->listen('foo', function ($bar) { + $this->assertEquals('bar', $bar); + }); + + $this->assertTrue($this->event->hasListener('foo')); + + $this->event->trigger('baz', 'bar'); + + $this->event->remove('foo'); + + $this->assertFalse($this->event->hasListener('foo')); + } + + public function testOnceEvent() + { + $this->event->listen('AppInit', function ($bar) { + $this->assertEquals('bar', $bar); + return 'foo'; + }); + + $this->assertEquals('foo', $this->event->trigger('AppInit', 'bar', true)); + $this->assertEquals(['foo'], $this->event->trigger('AppInit', 'bar')); + } + + public function testClassListener() + { + $listener = m::mock("overload:SomeListener", TestListener::class); + + $listener->shouldReceive('handle')->andReturnTrue(); + + $this->event->listen('some', "SomeListener"); + + $this->assertTrue($this->event->until('some')); + } + + public function testSubscribe() + { + $listener = m::mock("overload:SomeListener", TestListener::class); + + $listener->shouldReceive('subscribe')->andReturnUsing(function (Event $event) use ($listener) { + + $listener->shouldReceive('onBar')->once()->andReturnFalse(); + + $event->listenEvents(['SomeListener::onBar' => [[$listener, 'onBar']]]); + }); + + $this->event->subscribe('SomeListener'); + + $this->assertTrue($this->event->hasListener('SomeListener::onBar')); + + $this->event->trigger('SomeListener::onBar'); + } + + public function testAutoObserve() + { + $listener = m::mock("overload:SomeListener", TestListener::class); + + $listener->shouldReceive('onBar')->once(); + + $this->app->shouldReceive('make')->with('SomeListener')->andReturn($listener); + + $this->event->observe('SomeListener'); + + $this->event->trigger('bar'); + } + +} + +class TestListener +{ + public function handle() + { + + } + + public function onBar() + { + + } + + public function onFoo() + { + + } + + public function subscribe() + { + + } +} diff --git a/vendor/topthink/framework/tests/FilesystemTest.php b/vendor/topthink/framework/tests/FilesystemTest.php new file mode 100644 index 000000000..df5ffe209 --- /dev/null +++ b/vendor/topthink/framework/tests/FilesystemTest.php @@ -0,0 +1,131 @@ +app = m::mock(App::class)->makePartial(); + Container::setInstance($this->app); + $this->app->shouldReceive('make')->with(App::class)->andReturn($this->app); + $this->config = m::mock(Config::class); + $this->config->shouldReceive('get')->with('filesystem.default', null)->andReturn('local'); + $this->app->shouldReceive('get')->with('config')->andReturn($this->config); + $this->filesystem = new Filesystem($this->app); + + $this->root = vfsStream::setup('rootDir'); + } + + protected function tearDown(): void + { + m::close(); + } + + public function testDisk() + { + $this->config->shouldReceive('get')->with('filesystem.disks.local', null)->andReturn([ + 'type' => 'local', + 'root' => $this->root->url(), + ]); + + $this->config->shouldReceive('get')->with('filesystem.disks.foo', null)->andReturn([ + 'type' => 'local', + 'root' => $this->root->url(), + ]); + + $this->assertInstanceOf(Local::class, $this->filesystem->disk()); + + $this->assertInstanceOf(Local::class, $this->filesystem->disk('foo')); + } + + public function testCache() + { + $this->config->shouldReceive('get')->with('filesystem.disks.local', null)->andReturn([ + 'type' => 'local', + 'root' => $this->root->url(), + 'cache' => true, + ]); + + $this->assertInstanceOf(Local::class, $this->filesystem->disk()); + + $this->config->shouldReceive('get')->with('filesystem.disks.cache', null)->andReturn([ + 'type' => NullDriver::class, + 'root' => $this->root->url(), + 'cache' => [ + 'store' => 'flysystem', + ], + ]); + + $cache = m::mock(Cache::class); + + $cacheDriver = m::mock(File::class); + + $cache->shouldReceive('store')->once()->with('flysystem')->andReturn($cacheDriver); + + $this->app->shouldReceive('make')->with(Cache::class)->andReturn($cache); + + $cacheDriver->shouldReceive('get')->with('flysystem')->once()->andReturn(null); + + $cacheDriver->shouldReceive('set')->withAnyArgs(); + + $this->filesystem->disk('cache')->put('test.txt', 'aa'); + } + + public function testPutFile() + { + $root = vfsStream::setup('rootDir', null, [ + 'foo.jpg' => 'hello', + ]); + + $this->config->shouldReceive('get')->with('filesystem.disks.local', null)->andReturn([ + 'type' => NullDriver::class, + 'root' => $root->url(), + 'cache' => true, + ]); + + $file = m::mock(\think\File::class); + + $file->shouldReceive('hashName')->with(null)->once()->andReturn('foo.jpg'); + + $file->shouldReceive('getRealPath')->once()->andReturn($root->getChild('foo.jpg')->url()); + + $this->filesystem->putFile('test', $file); + } +} + +class NullDriver extends Driver +{ + protected function createAdapter(): AdapterInterface + { + return new NullAdapter(); + } +} diff --git a/vendor/topthink/framework/tests/HttpTest.php b/vendor/topthink/framework/tests/HttpTest.php new file mode 100644 index 000000000..c3e0abd33 --- /dev/null +++ b/vendor/topthink/framework/tests/HttpTest.php @@ -0,0 +1,155 @@ +app = m::mock(App::class)->makePartial(); + + $this->http = m::mock(Http::class, [$this->app])->shouldAllowMockingProtectedMethods()->makePartial(); + } + + protected function prepareApp($request, $response) + { + $this->app->shouldReceive('instance')->once()->with('request', $request); + $this->app->shouldReceive('initialized')->once()->andReturnFalse(); + $this->app->shouldReceive('initialize')->once(); + $this->app->shouldReceive('get')->with('request')->andReturn($request); + + $route = m::mock(Route::class); + + $route->shouldReceive('dispatch')->withArgs(function ($req, $withRoute) use ($request) { + if ($withRoute) { + $withRoute(); + } + return $req === $request; + })->andReturn($response); + + $route->shouldReceive('config')->with('route_annotation')->andReturn(true); + + $this->app->shouldReceive('get')->with('route')->andReturn($route); + + $console = m::mock(Console::class); + + $console->shouldReceive('call'); + + $this->app->shouldReceive('get')->with('console')->andReturn($console); + } + + public function testRun() + { + $root = vfsStream::setup('rootDir', null, [ + 'app' => [ + 'controller' => [], + 'middleware.php' => ' [ + 'route.php' => 'app->shouldReceive('getBasePath')->andReturn($root->getChild('app')->url() . DIRECTORY_SEPARATOR); + $this->app->shouldReceive('getRootPath')->andReturn($root->url() . DIRECTORY_SEPARATOR); + + $request = m::mock(Request::class)->makePartial(); + $response = m::mock(Response::class)->makePartial(); + + $this->prepareApp($request, $response); + + $this->assertEquals($response, $this->http->run($request)); + } + + public function multiAppRunProvider() + { + $request1 = m::mock(Request::class)->makePartial(); + $request1->shouldReceive('subDomain')->andReturn('www'); + $request1->shouldReceive('host')->andReturn('www.domain.com'); + + $request2 = m::mock(Request::class)->makePartial(); + $request2->shouldReceive('subDomain')->andReturn('app2'); + $request2->shouldReceive('host')->andReturn('app2.domain.com'); + + $request3 = m::mock(Request::class)->makePartial(); + $request3->shouldReceive('pathinfo')->andReturn('some1/a/b/c'); + + $request4 = m::mock(Request::class)->makePartial(); + $request4->shouldReceive('pathinfo')->andReturn('app3/a/b/c'); + + $request5 = m::mock(Request::class)->makePartial(); + $request5->shouldReceive('pathinfo')->andReturn('some2/a/b/c'); + + return [ + [$request1, true, 'app1'], + [$request2, true, 'app2'], + [$request3, true, 'app3'], + [$request4, true, null], + [$request5, true, 'some2', 'path'], + [$request1, false, 'some3'], + ]; + } + + public function testRunWithException() + { + $request = m::mock(Request::class); + $response = m::mock(Response::class); + + $this->app->shouldReceive('instance')->once()->with('request', $request); + $this->app->shouldReceive('initialize')->once(); + + $exception = new Exception(); + + $this->http->shouldReceive('runWithRequest')->once()->with($request)->andThrow($exception); + + $handle = m::mock(Handle::class); + + $handle->shouldReceive('report')->once()->with($exception); + $handle->shouldReceive('render')->once()->with($request, $exception)->andReturn($response); + + $this->app->shouldReceive('make')->with(Handle::class)->andReturn($handle); + + $this->assertEquals($response, $this->http->run($request)); + } + + public function testEnd() + { + $response = m::mock(Response::class); + $event = m::mock(Event::class); + $event->shouldReceive('trigger')->once()->with(HttpEnd::class, $response); + $this->app->shouldReceive('get')->once()->with('event')->andReturn($event); + $log = m::mock(Log::class); + $log->shouldReceive('save')->once(); + $this->app->shouldReceive('get')->once()->with('log')->andReturn($log); + + $this->http->end($response); + } + +} diff --git a/vendor/topthink/framework/tests/InteractsWithApp.php b/vendor/topthink/framework/tests/InteractsWithApp.php new file mode 100644 index 000000000..f4fcf73f7 --- /dev/null +++ b/vendor/topthink/framework/tests/InteractsWithApp.php @@ -0,0 +1,30 @@ +app = m::mock(App::class)->makePartial(); + Container::setInstance($this->app); + $this->app->shouldReceive('make')->with(App::class)->andReturn($this->app); + $this->app->shouldReceive('isDebug')->andReturnTrue(); + $this->config = m::mock(Config::class)->makePartial(); + $this->config->shouldReceive('get')->with('app.show_error_msg')->andReturnTrue(); + $this->app->shouldReceive('get')->with('config')->andReturn($this->config); + $this->app->shouldReceive('runningInConsole')->andReturn(false); + } +} diff --git a/vendor/topthink/framework/tests/LogTest.php b/vendor/topthink/framework/tests/LogTest.php new file mode 100644 index 000000000..981110f56 --- /dev/null +++ b/vendor/topthink/framework/tests/LogTest.php @@ -0,0 +1,130 @@ +prepareApp(); + + $this->log = new Log($this->app); + } + + public function testGetConfig() + { + $config = [ + 'default' => 'file', + ]; + + $this->config->shouldReceive('get')->with('log')->andReturn($config); + + $this->assertEquals($config, $this->log->getConfig()); + + $this->expectException(InvalidArgumentException::class); + $this->log->getChannelConfig('foo'); + } + + public function testChannel() + { + $this->assertInstanceOf(ChannelSet::class, $this->log->channel(['file', 'mail'])); + } + + public function testLogManagerInstances() + { + $this->config->shouldReceive('get')->with("log.channels.single", null)->andReturn(['type' => 'file']); + + $channel1 = $this->log->channel('single'); + $channel2 = $this->log->channel('single'); + + $this->assertSame($channel1, $channel2); + } + + public function testFileLog() + { + $root = vfsStream::setup(); + + $this->config->shouldReceive('get')->with("log.default", null)->andReturn('file'); + + $this->config->shouldReceive('get')->with("log.channels.file", null)->andReturn(['type' => 'file', 'path' => $root->url()]); + + $this->log->info('foo'); + + $this->assertEquals($this->log->getLog(), ['info' => ['foo']]); + + $this->log->clear(); + + $this->assertEmpty($this->log->getLog()); + + $this->log->error('foo'); + $this->assertArrayHasKey('error', $this->log->getLog()); + + $this->log->emergency('foo'); + $this->assertArrayHasKey('emergency', $this->log->getLog()); + + $this->log->alert('foo'); + $this->assertArrayHasKey('alert', $this->log->getLog()); + + $this->log->critical('foo'); + $this->assertArrayHasKey('critical', $this->log->getLog()); + + $this->log->warning('foo'); + $this->assertArrayHasKey('warning', $this->log->getLog()); + + $this->log->notice('foo'); + $this->assertArrayHasKey('notice', $this->log->getLog()); + + $this->log->debug('foo'); + $this->assertArrayHasKey('debug', $this->log->getLog()); + + $this->log->sql('foo'); + $this->assertArrayHasKey('sql', $this->log->getLog()); + + $this->log->custom('foo'); + $this->assertArrayHasKey('custom', $this->log->getLog()); + + $this->log->write('foo'); + $this->assertTrue($root->hasChildren()); + $this->assertEmpty($this->log->getLog()); + + $this->log->close(); + + $this->log->info('foo'); + + $this->assertEmpty($this->log->getLog()); + } + + public function testSave() + { + $root = vfsStream::setup(); + + $this->config->shouldReceive('get')->with("log.default", null)->andReturn('file'); + + $this->config->shouldReceive('get')->with("log.channels.file", null)->andReturn(['type' => 'file', 'path' => $root->url()]); + + $this->log->info('foo'); + + $this->log->save(); + + $this->assertTrue($root->hasChildren()); + } + +} diff --git a/vendor/topthink/framework/tests/MiddlewareTest.php b/vendor/topthink/framework/tests/MiddlewareTest.php new file mode 100644 index 000000000..aa53059c0 --- /dev/null +++ b/vendor/topthink/framework/tests/MiddlewareTest.php @@ -0,0 +1,108 @@ +prepareApp(); + + $this->middleware = new Middleware($this->app); + } + + public function testSetMiddleware() + { + $this->middleware->add('BarMiddleware', 'bar'); + + $this->assertEquals(1, count($this->middleware->all('bar'))); + + $this->middleware->controller('BarMiddleware'); + $this->assertEquals(1, count($this->middleware->all('controller'))); + + $this->middleware->import(['FooMiddleware']); + $this->assertEquals(1, count($this->middleware->all())); + + $this->middleware->unshift(['BazMiddleware', 'baz']); + $this->assertEquals(2, count($this->middleware->all())); + $this->assertEquals([['BazMiddleware', 'handle'], 'baz'], $this->middleware->all()[0]); + + $this->config->shouldReceive('get')->with('middleware.alias', [])->andReturn(['foo' => ['FooMiddleware', 'FarMiddleware']]); + + $this->middleware->add('foo'); + $this->assertEquals(3, count($this->middleware->all())); + $this->middleware->add(function () { + }); + $this->middleware->add(function () { + }); + $this->assertEquals(5, count($this->middleware->all())); + } + + public function testPipelineAndEnd() + { + $bar = m::mock("overload:BarMiddleware"); + $foo = m::mock("overload:FooMiddleware", Foo::class); + + $request = m::mock(Request::class); + $response = m::mock(Response::class); + + $e = new Exception(); + + $handle = m::mock(Handle::class); + $handle->shouldReceive('report')->with($e)->andReturnNull(); + $handle->shouldReceive('render')->with($request, $e)->andReturn($response); + + $foo->shouldReceive('handle')->once()->andReturnUsing(function ($request, $next) { + return $next($request); + }); + $bar->shouldReceive('handle')->once()->andReturnUsing(function ($request, $next) use ($e) { + $next($request); + throw $e; + }); + + $foo->shouldReceive('end')->once()->with($response)->andReturnNull(); + + $this->app->shouldReceive('make')->with(Handle::class)->andReturn($handle); + + $this->config->shouldReceive('get')->once()->with('middleware.priority', [])->andReturn(['FooMiddleware', 'BarMiddleware']); + + $this->middleware->import([function ($request, $next) { + return $next($request); + }, 'BarMiddleware', 'FooMiddleware']); + + $this->assertInstanceOf(Pipeline::class, $pipeline = $this->middleware->pipeline()); + + $pipeline->send($request)->then(function ($request) use ($e, $response) { + throw $e; + }); + + $this->middleware->end($response); + } +} + +class Foo +{ + public function end(Response $response) + { + } +} diff --git a/vendor/topthink/framework/tests/RouteTest.php b/vendor/topthink/framework/tests/RouteTest.php new file mode 100644 index 000000000..e992d0fed --- /dev/null +++ b/vendor/topthink/framework/tests/RouteTest.php @@ -0,0 +1,286 @@ +prepareApp(); + $this->route = new Route($this->app); + } + + /** + * @param $path + * @param string $method + * @param string $host + * @return m\Mock|Request + */ + protected function makeRequest($path, $method = 'GET', $host = 'localhost') + { + $request = m::mock(Request::class)->makePartial(); + $request->shouldReceive('host')->andReturn($host); + $request->shouldReceive('pathinfo')->andReturn($path); + $request->shouldReceive('url')->andReturn('/' . $path); + $request->shouldReceive('method')->andReturn(strtoupper($method)); + return $request; + } + + public function testSimpleRequest() + { + $this->route->get('foo', function () { + return 'get-foo'; + }); + + $this->route->put('foo', function () { + return 'put-foo'; + }); + + $this->route->group(function () { + $this->route->post('foo', function () { + return 'post-foo'; + }); + }); + + $request = $this->makeRequest('foo', 'post'); + $response = $this->route->dispatch($request); + $this->assertEquals(200, $response->getCode()); + $this->assertEquals('post-foo', $response->getContent()); + + $request = $this->makeRequest('foo', 'get'); + $response = $this->route->dispatch($request); + $this->assertEquals(200, $response->getCode()); + $this->assertEquals('get-foo', $response->getContent()); + } + + public function testOptionsRequest() + { + $this->route->get('foo', function () { + return 'get-foo'; + }); + + $this->route->put('foo', function () { + return 'put-foo'; + }); + + $this->route->group(function () { + $this->route->post('foo', function () { + return 'post-foo'; + }); + }); + $this->route->group('abc', function () { + $this->route->post('foo/:id', function () { + return 'post-abc-foo'; + }); + }); + + $this->route->post('foo/:id', function () { + return 'post-abc-foo'; + }); + + $this->route->resource('bar', 'SomeClass'); + + $request = $this->makeRequest('foo', 'options'); + $response = $this->route->dispatch($request); + $this->assertEquals(204, $response->getCode()); + $this->assertEquals('GET, PUT, POST', $response->getHeader('Allow')); + + $request = $this->makeRequest('bar', 'options'); + $response = $this->route->dispatch($request); + $this->assertEquals(204, $response->getCode()); + $this->assertEquals('GET, POST', $response->getHeader('Allow')); + + $request = $this->makeRequest('bar/1', 'options'); + $response = $this->route->dispatch($request); + $this->assertEquals(204, $response->getCode()); + $this->assertEquals('GET, PUT, DELETE', $response->getHeader('Allow')); + + $request = $this->makeRequest('xxxx', 'options'); + $response = $this->route->dispatch($request); + $this->assertEquals(204, $response->getCode()); + $this->assertEquals('GET, POST, PUT, DELETE', $response->getHeader('Allow')); + } + + public function testAllowCrossDomain() + { + $this->route->get('foo', function () { + return 'get-foo'; + })->allowCrossDomain(['some' => 'bar']); + + $request = $this->makeRequest('foo', 'get'); + $response = $this->route->dispatch($request); + + $this->assertEquals('bar', $response->getHeader('some')); + $this->assertArrayHasKey('Access-Control-Allow-Credentials', $response->getHeader()); + + $request = $this->makeRequest('foo2', 'options'); + $response = $this->route->dispatch($request); + + $this->assertEquals(204, $response->getCode()); + $this->assertArrayHasKey('Access-Control-Allow-Credentials', $response->getHeader()); + $this->assertEquals('GET, POST, PUT, DELETE', $response->getHeader('Allow')); + } + + public function testControllerDispatch() + { + $this->route->get('foo', 'foo/bar'); + + $controller = m::Mock(\stdClass::class); + + $this->app->shouldReceive('parseClass')->with('controller', 'Foo')->andReturn($controller->mockery_getName()); + $this->app->shouldReceive('make')->with($controller->mockery_getName(), [], true)->andReturn($controller); + + $controller->shouldReceive('bar')->andReturn('bar'); + + $request = $this->makeRequest('foo'); + $response = $this->route->dispatch($request); + $this->assertEquals('bar', $response->getContent()); + } + + public function testEmptyControllerDispatch() + { + $this->route->get('foo', 'foo/bar'); + + $controller = m::Mock(\stdClass::class); + + $this->app->shouldReceive('parseClass')->with('controller', 'Error')->andReturn($controller->mockery_getName()); + $this->app->shouldReceive('make')->with($controller->mockery_getName(), [], true)->andReturn($controller); + + $controller->shouldReceive('bar')->andReturn('bar'); + + $request = $this->makeRequest('foo'); + $response = $this->route->dispatch($request); + $this->assertEquals('bar', $response->getContent()); + } + + protected function createMiddleware($times = 1) + { + $middleware = m::mock(Str::random(5)); + $middleware->shouldReceive('handle')->times($times)->andReturnUsing(function ($request, Closure $next) { + return $next($request); + }); + $this->app->shouldReceive('make')->with($middleware->mockery_getName())->andReturn($middleware); + + return $middleware; + } + + public function testControllerWithMiddleware() + { + $this->route->get('foo', 'foo/bar'); + + $controller = m::mock(FooClass::class); + + $controller->middleware = [ + $this->createMiddleware()->mockery_getName() . ":params1:params2", + $this->createMiddleware(0)->mockery_getName() => ['except' => 'bar'], + $this->createMiddleware()->mockery_getName() => ['only' => 'bar'], + ]; + + $this->app->shouldReceive('parseClass')->with('controller', 'Foo')->andReturn($controller->mockery_getName()); + $this->app->shouldReceive('make')->with($controller->mockery_getName(), [], true)->andReturn($controller); + + $controller->shouldReceive('bar')->once()->andReturn('bar'); + + $request = $this->makeRequest('foo'); + $response = $this->route->dispatch($request); + $this->assertEquals('bar', $response->getContent()); + } + + public function testUrlDispatch() + { + $controller = m::mock(FooClass::class); + $controller->shouldReceive('index')->andReturn('bar'); + + $this->app->shouldReceive('parseClass')->once()->with('controller', 'Foo')->andReturn($controller->mockery_getName()); + $this->app->shouldReceive('make')->with($controller->mockery_getName(), [], true)->andReturn($controller); + + $request = $this->makeRequest('foo'); + $response = $this->route->dispatch($request); + $this->assertEquals('bar', $response->getContent()); + } + + public function testRedirectDispatch() + { + $this->route->redirect('foo', 'http://localhost', 302); + + $request = $this->makeRequest('foo'); + $this->app->shouldReceive('make')->with(Request::class)->andReturn($request); + $response = $this->route->dispatch($request); + + $this->assertInstanceOf(Redirect::class, $response); + $this->assertEquals(302, $response->getCode()); + $this->assertEquals('http://localhost', $response->getData()); + } + + public function testViewDispatch() + { + $this->route->view('foo', 'index/hello', ['city' => 'shanghai']); + + $request = $this->makeRequest('foo'); + $response = $this->route->dispatch($request); + + $this->assertInstanceOf(View::class, $response); + $this->assertEquals(['city' => 'shanghai'], $response->getVars()); + $this->assertEquals('index/hello', $response->getData()); + } + + public function testResponseDispatch() + { + $this->route->get('hello/:name', response() + ->data('Hello,ThinkPHP') + ->code(200) + ->contentType('text/plain')); + + $request = $this->makeRequest('hello/some'); + $response = $this->route->dispatch($request); + + $this->assertEquals('Hello,ThinkPHP', $response->getContent()); + $this->assertEquals(200, $response->getCode()); + } + + public function testDomainBindResponse() + { + $this->route->domain('test', function () { + $this->route->get('/', function () { + return 'Hello,ThinkPHP'; + }); + }); + + $request = $this->makeRequest('', 'get', 'test.domain.com'); + $response = $this->route->dispatch($request); + + $this->assertEquals('Hello,ThinkPHP', $response->getContent()); + $this->assertEquals(200, $response->getCode()); + } + +} + +class FooClass +{ + public $middleware = []; + + public function bar() + { + + } +} diff --git a/vendor/topthink/framework/tests/SessionTest.php b/vendor/topthink/framework/tests/SessionTest.php new file mode 100644 index 000000000..b3b48a70d --- /dev/null +++ b/vendor/topthink/framework/tests/SessionTest.php @@ -0,0 +1,225 @@ +app = m::mock(App::class)->makePartial(); + Container::setInstance($this->app); + + $this->app->shouldReceive('make')->with(App::class)->andReturn($this->app); + $this->config = m::mock(Config::class)->makePartial(); + + $this->app->shouldReceive('get')->with('config')->andReturn($this->config); + $handlerClass = "\\think\\session\\driver\\Test" . Str::random(10); + $this->config->shouldReceive("get")->with("session.type", "file")->andReturn($handlerClass); + $this->session = new Session($this->app); + + $this->handler = m::mock('overload:' . $handlerClass, SessionHandlerInterface::class); + } + + public function testLoadData() + { + $data = [ + "bar" => 'foo', + ]; + + $id = md5(uniqid()); + + $this->handler->shouldReceive("read")->once()->with($id)->andReturn(serialize($data)); + + $this->session->setId($id); + $this->session->init(); + + $this->assertEquals('foo', $this->session->get('bar')); + $this->assertTrue($this->session->has('bar')); + $this->assertFalse($this->session->has('foo')); + + $this->session->set('foo', 'bar'); + $this->assertTrue($this->session->has('foo')); + + $this->assertEquals('bar', $this->session->pull('foo')); + $this->assertFalse($this->session->has('foo')); + } + + public function testSave() + { + + $id = md5(uniqid()); + + $this->handler->shouldReceive('read')->once()->with($id)->andReturn(""); + + $this->handler->shouldReceive('write')->once()->with($id, serialize([ + "bar" => 'foo', + ]))->andReturnTrue(); + + $this->session->setId($id); + $this->session->init(); + + $this->session->set('bar', 'foo'); + + $this->session->save(); + } + + public function testFlash() + { + $this->session->flash('foo', 'bar'); + $this->session->flash('bar', 0); + $this->session->flash('baz', true); + + $this->assertTrue($this->session->has('foo')); + $this->assertEquals('bar', $this->session->get('foo')); + $this->assertEquals(0, $this->session->get('bar')); + $this->assertTrue($this->session->get('baz')); + + $this->session->clearFlashData(); + + $this->assertTrue($this->session->has('foo')); + $this->assertEquals('bar', $this->session->get('foo')); + $this->assertEquals(0, $this->session->get('bar')); + + $this->session->clearFlashData(); + + $this->assertFalse($this->session->has('foo')); + $this->assertNull($this->session->get('foo')); + + $this->session->flash('foo', 'bar'); + $this->assertTrue($this->session->has('foo')); + $this->session->clearFlashData(); + $this->session->reflash(); + $this->session->clearFlashData(); + + $this->assertTrue($this->session->has('foo')); + } + + public function testClear() + { + $this->session->set('bar', 'foo'); + $this->assertEquals('foo', $this->session->get('bar')); + $this->session->clear(); + $this->assertFalse($this->session->has('foo')); + } + + public function testSetName() + { + $this->session->setName('foo'); + $this->assertEquals('foo', $this->session->getName()); + } + + public function testDestroy() + { + $id = md5(uniqid()); + + $this->handler->shouldReceive('read')->once()->with($id)->andReturn(""); + $this->handler->shouldReceive('delete')->once()->with($id)->andReturnTrue(); + + $this->session->setId($id); + $this->session->init(); + + $this->session->set('bar', 'foo'); + + $this->session->destroy(); + + $this->assertFalse($this->session->has('bar')); + + $this->assertNotEquals($id, $this->session->getId()); + } + + public function testFileHandler() + { + $root = vfsStream::setup(); + + vfsStream::newFile('bar') + ->at($root) + ->lastModified(time()); + + vfsStream::newFile('bar') + ->at(vfsStream::newDirectory("foo")->at($root)) + ->lastModified(100); + + $this->assertTrue($root->hasChild("bar")); + $this->assertTrue($root->hasChild("foo/bar")); + + $handler = new TestFileHandle($this->app, [ + 'path' => $root->url(), + 'gc_probability' => 1, + 'gc_divisor' => 1, + ]); + + $this->assertTrue($root->hasChild("bar")); + $this->assertFalse($root->hasChild("foo/bar")); + + $id = md5(uniqid()); + $handler->write($id, "bar"); + + $this->assertTrue($root->hasChild("sess_{$id}")); + + $this->assertEquals("bar", $handler->read($id)); + + $handler->delete($id); + + $this->assertFalse($root->hasChild("sess_{$id}")); + } + + public function testCacheHandler() + { + $id = md5(uniqid()); + + $cache = m::mock(\think\Cache::class); + + $store = m::mock(Driver::class); + + $cache->shouldReceive('store')->once()->with('redis')->andReturn($store); + + $handler = new Cache($cache, ['store' => 'redis']); + + $store->shouldReceive("set")->with($id, "bar", 1440)->once()->andReturnTrue(); + $handler->write($id, "bar"); + + $store->shouldReceive("get")->with($id)->once()->andReturn("bar"); + $this->assertEquals("bar", $handler->read($id)); + + $store->shouldReceive("delete")->with($id)->once()->andReturnTrue(); + $handler->delete($id); + } +} + +class TestFileHandle extends File +{ + protected function writeFile($path, $content): bool + { + return (bool) file_put_contents($path, $content); + } +} diff --git a/vendor/topthink/framework/tests/ViewTest.php b/vendor/topthink/framework/tests/ViewTest.php new file mode 100644 index 000000000..e4135109a --- /dev/null +++ b/vendor/topthink/framework/tests/ViewTest.php @@ -0,0 +1,127 @@ +app = m::mock(App::class)->makePartial(); + Container::setInstance($this->app); + + $this->app->shouldReceive('make')->with(App::class)->andReturn($this->app); + $this->config = m::mock(Config::class)->makePartial(); + $this->app->shouldReceive('get')->with('config')->andReturn($this->config); + + $this->view = new View($this->app); + } + + public function testAssignData() + { + $this->view->assign('foo', 'bar'); + $this->view->assign(['baz' => 'boom']); + $this->view->qux = "corge"; + + $this->assertEquals('bar', $this->view->foo); + $this->assertEquals('boom', $this->view->baz); + $this->assertEquals('corge', $this->view->qux); + $this->assertTrue(isset($this->view->qux)); + } + + public function testRender() + { + $this->config->shouldReceive("get")->with("view.type", 'php')->andReturn(TestTemplate::class); + + $this->view->filter(function ($content) { + return $content; + }); + + $this->assertEquals("fetch", $this->view->fetch('foo')); + $this->assertEquals("display", $this->view->display('foo')); + } + +} + +class TestTemplate implements TemplateHandlerInterface +{ + + /** + * 检测是否存在模板文件 + * @access public + * @param string $template 模板文件或者模板规则 + * @return bool + */ + public function exists(string $template): bool + { + return true; + } + + /** + * 渲染模板文件 + * @access public + * @param string $template 模板文件 + * @param array $data 模板变量 + * @return void + */ + public function fetch(string $template, array $data = []): void + { + echo "fetch"; + } + + /** + * 渲染模板内容 + * @access public + * @param string $content 模板内容 + * @param array $data 模板变量 + * @return void + */ + public function display(string $content, array $data = []): void + { + echo "display"; + } + + /** + * 配置模板引擎 + * @access private + * @param array $config 参数 + * @return void + */ + public function config(array $config): void + { + // TODO: Implement config() method. + } + + /** + * 获取模板引擎配置 + * @access public + * @param string $name 参数名 + * @return void + */ + public function getConfig(string $name) + { + // TODO: Implement getConfig() method. + } +} diff --git a/vendor/topthink/framework/tests/bootstrap.php b/vendor/topthink/framework/tests/bootstrap.php new file mode 100644 index 000000000..34590612e --- /dev/null +++ b/vendor/topthink/framework/tests/bootstrap.php @@ -0,0 +1,3 @@ + 以下类库都在`\\think\\helper`命名空间下 + +## Str + +> 字符串操作 + +``` +// 检查字符串中是否包含某些字符串 +Str::contains($haystack, $needles) + +// 检查字符串是否以某些字符串结尾 +Str::endsWith($haystack, $needles) + +// 获取指定长度的随机字母数字组合的字符串 +Str::random($length = 16) + +// 字符串转小写 +Str::lower($value) + +// 字符串转大写 +Str::upper($value) + +// 获取字符串的长度 +Str::length($value) + +// 截取字符串 +Str::substr($string, $start, $length = null) + +``` \ No newline at end of file diff --git a/vendor/topthink/think-helper/composer.json b/vendor/topthink/think-helper/composer.json new file mode 100644 index 000000000..b68c43b51 --- /dev/null +++ b/vendor/topthink/think-helper/composer.json @@ -0,0 +1,22 @@ +{ + "name": "topthink/think-helper", + "description": "The ThinkPHP6 Helper Package", + "license": "Apache-2.0", + "authors": [ + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "require": { + "php": ">=7.1.0" + }, + "autoload": { + "psr-4": { + "think\\": "src" + }, + "files": [ + "src/helper.php" + ] + } +} diff --git a/thinkphp/library/think/Collection.php b/vendor/topthink/think-helper/src/Collection.php old mode 100755 new mode 100644 similarity index 64% rename from thinkphp/library/think/Collection.php rename to vendor/topthink/think-helper/src/Collection.php index d58c8999b..fa408c25a --- a/thinkphp/library/think/Collection.php +++ b/vendor/topthink/think-helper/src/Collection.php @@ -2,12 +2,13 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: zhangyajun <448901948@qq.com> // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think; @@ -16,8 +17,14 @@ use ArrayIterator; use Countable; use IteratorAggregate; use JsonSerializable; +use think\contract\Arrayable; +use think\contract\Jsonable; +use think\helper\Arr; -class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable +/** + * 数据集管理类 + */ +class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable, Arrayable, Jsonable { /** * 数据集数据 @@ -40,19 +47,19 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria * @access public * @return bool */ - public function isEmpty() + public function isEmpty(): bool { return empty($this->items); } - public function toArray() + public function toArray(): array { return array_map(function ($value) { - return ($value instanceof Model || $value instanceof self) ? $value->toArray() : $value; + return $value instanceof Arrayable ? $value->toArray() : $value; }, $this->items); } - public function all() + public function all(): array { return $this->items; } @@ -61,7 +68,7 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria * 合并数组 * * @access public - * @param mixed $items + * @param mixed $items 数据 * @return static */ public function merge($items) @@ -69,28 +76,17 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria return new static(array_merge($this->items, $this->convertToArray($items))); } - /** - * 交换数组中的键和值 - * - * @access public - * @return static - */ - public function flip() - { - return new static(array_flip($this->items)); - } - /** * 按指定键整理数据 * * @access public - * @param mixed $items 数据 - * @param string $indexKey 键名 + * @param mixed $items 数据 + * @param string $indexKey 键名 * @return array */ - public function dictionary($items = null, &$indexKey = null) + public function dictionary($items = null, string &$indexKey = null) { - if ($items instanceof self || $items instanceof Paginator) { + if ($items instanceof self) { $items = $items->all(); } @@ -111,11 +107,11 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria * 比较数组,返回差集 * * @access public - * @param mixed $items 数据 - * @param string $indexKey 指定比较的键名 + * @param mixed $items 数据 + * @param string $indexKey 指定比较的键名 * @return static */ - public function diff($items, $indexKey = null) + public function diff($items, string $indexKey = null) { if ($this->isEmpty() || is_scalar($this->items[0])) { return new static(array_diff($this->items, $this->convertToArray($items))); @@ -139,11 +135,11 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria * 比较数组,返回交集 * * @access public - * @param mixed $items 数据 - * @param string $indexKey 指定比较的键名 + * @param mixed $items 数据 + * @param string $indexKey 指定比较的键名 * @return static */ - public function intersect($items, $indexKey = null) + public function intersect($items, string $indexKey = null) { if ($this->isEmpty() || is_scalar($this->items[0])) { return new static(array_diff($this->items, $this->convertToArray($items))); @@ -163,25 +159,36 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria return new static($intersect); } + /** + * 交换数组中的键和值 + * + * @access public + * @return static + */ + public function flip() + { + return new static(array_flip($this->items)); + } + /** * 返回数组中所有的键名 * * @access public - * @return array + * @return static */ public function keys() { - $current = current($this->items); + return new static(array_keys($this->items)); + } - if (is_scalar($current)) { - $array = $this->items; - } elseif (is_array($current)) { - $array = $current; - } else { - $array = $current->toArray(); - } - - return array_keys($array); + /** + * 返回数组中所有的值组成的新 Collection 实例 + * @access public + * @return static + */ + public function values() + { + return new static(array_values($this->items)); } /** @@ -199,8 +206,8 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria * 通过使用用户自定义函数,以字符串返回数组 * * @access public - * @param callable $callback - * @param mixed $initial + * @param callable $callback 调用方法 + * @param mixed $initial * @return mixed */ public function reduce(callable $callback, $initial = null) @@ -233,28 +240,30 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria /** * 在数组结尾插入一个元素 * @access public - * @param mixed $value - * @param mixed $key - * @return void + * @param mixed $value 元素 + * @param string $key KEY + * @return $this */ - public function push($value, $key = null) + public function push($value, string $key = null) { if (is_null($key)) { $this->items[] = $value; } else { $this->items[$key] = $value; } + + return $this; } /** * 把一个数组分割为新的数组块. * * @access public - * @param int $size - * @param bool $preserveKeys + * @param int $size 块大小 + * @param bool $preserveKeys * @return static */ - public function chunk($size, $preserveKeys = false) + public function chunk(int $size, bool $preserveKeys = false) { $chunks = []; @@ -268,24 +277,26 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria /** * 在数组开头插入一个元素 * @access public - * @param mixed $value - * @param mixed $key - * @return void + * @param mixed $value 元素 + * @param string $key KEY + * @return $this */ - public function unshift($value, $key = null) + public function unshift($value, string $key = null) { if (is_null($key)) { array_unshift($this->items, $value); } else { $this->items = [$key => $value] + $this->items; } + + return $this; } /** * 给每个元素执行个回调 * * @access public - * @param callable $callback + * @param callable $callback 回调 * @return $this */ public function each(callable $callback) @@ -306,7 +317,7 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria /** * 用回调函数处理数组中的元素 * @access public - * @param callable|null $callback + * @param callable|null $callback 回调 * @return static */ public function map(callable $callback) @@ -317,7 +328,7 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria /** * 用回调函数过滤数组中的元素 * @access public - * @param callable|null $callback + * @param callable|null $callback 回调 * @return static */ public function filter(callable $callback = null) @@ -332,12 +343,12 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria /** * 根据字段条件过滤数组中的元素 * @access public - * @param string $field 字段名 - * @param mixed $operator 操作符 - * @param mixed $value 数据 + * @param string $field 字段名 + * @param mixed $operator 操作符 + * @param mixed $value 数据 * @return static */ - public function where($field, $operator, $value = null) + public function where(string $field, $operator, $value = null) { if (is_null($value)) { $value = $operator; @@ -346,14 +357,14 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria return $this->filter(function ($data) use ($field, $operator, $value) { if (strpos($field, '.')) { - list($field, $relation) = explode('.', $field); + [$field, $relation] = explode('.', $field); - $result = isset($data[$field][$relation]) ? $data[$field][$relation] : null; + $result = $data[$field][$relation] ?? null; } else { - $result = isset($data[$field]) ? $data[$field] : null; + $result = $data[$field] ?? null; } - switch ($operator) { + switch (strtolower($operator)) { case '===': return $result === $value; case '!==': @@ -378,10 +389,10 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria case 'not in': return is_scalar($result) && !in_array($result, $value, true); case 'between': - list($min, $max) = is_string($value) ? explode(',', $value) : $value; + [$min, $max] = is_string($value) ? explode(',', $value) : $value; return is_scalar($result) && $result >= $min && $result <= $max; case 'not between': - list($min, $max) = is_string($value) ? explode(',', $value) : $value; + [$min, $max] = is_string($value) ? explode(',', $value) : $value; return is_scalar($result) && $result > $max || $result < $min; case '==': case '=': @@ -391,14 +402,86 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria }); } + /** + * LIKE过滤 + * @access public + * @param string $field 字段名 + * @param string $value 数据 + * @return static + */ + public function whereLike(string $field, string $value) + { + return $this->where($field, 'like', $value); + } + + /** + * NOT LIKE过滤 + * @access public + * @param string $field 字段名 + * @param string $value 数据 + * @return static + */ + public function whereNotLike(string $field, string $value) + { + return $this->where($field, 'not like', $value); + } + + /** + * IN过滤 + * @access public + * @param string $field 字段名 + * @param array $value 数据 + * @return static + */ + public function whereIn(string $field, array $value) + { + return $this->where($field, 'in', $value); + } + + /** + * NOT IN过滤 + * @access public + * @param string $field 字段名 + * @param array $value 数据 + * @return static + */ + public function whereNotIn(string $field, array $value) + { + return $this->where($field, 'not in', $value); + } + + /** + * BETWEEN 过滤 + * @access public + * @param string $field 字段名 + * @param mixed $value 数据 + * @return static + */ + public function whereBetween(string $field, $value) + { + return $this->where($field, 'between', $value); + } + + /** + * NOT BETWEEN 过滤 + * @access public + * @param string $field 字段名 + * @param mixed $value 数据 + * @return static + */ + public function whereNotBetween(string $field, $value) + { + return $this->where($field, 'not between', $value); + } + /** * 返回数据中指定的一列 * @access public - * @param mixed $columnKey 键名 - * @param mixed $indexKey 作为索引值的列 + * @param string|null $columnKey 键名 + * @param string|null $indexKey 作为索引值的列 * @return array */ - public function column($columnKey, $indexKey = null) + public function column( ? string $columnKey, string $indexKey = null) { return array_column($this->items, $columnKey, $indexKey); } @@ -407,7 +490,7 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria * 对数组排序 * * @access public - * @param callable|null $callback + * @param callable|null $callback 回调 * @return static */ public function sort(callable $callback = null) @@ -416,7 +499,6 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria $callback = $callback ?: function ($a, $b) { return $a == $b ? 0 : (($a < $b) ? -1 : 1); - }; uasort($items, $callback); @@ -427,22 +509,17 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria /** * 指定字段排序 * @access public - * @param string $field 排序字段 - * @param string $order 排序 - * @param bool $intSort 是否为数字排序 + * @param string $field 排序字段 + * @param string $order 排序 * @return $this */ - public function order($field, $order = null, $intSort = true) + public function order(string $field, string $order = 'asc') { - return $this->sort(function ($a, $b) use ($field, $order, $intSort) { - $fieldA = isset($a[$field]) ? $a[$field] : null; - $fieldB = isset($b[$field]) ? $b[$field] : null; + return $this->sort(function ($a, $b) use ($field, $order) { + $fieldA = $a[$field] ?? null; + $fieldB = $b[$field] ?? null; - if ($intSort) { - return 'desc' == strtolower($order) ? $fieldB >= $fieldA : $fieldA >= $fieldB; - } else { - return 'desc' == strtolower($order) ? strcmp($fieldB, $fieldA) : strcmp($fieldA, $fieldB); - } + return 'desc' == strtolower($order) ? intval($fieldB > $fieldA) : intval($fieldA > $fieldB); }); } @@ -461,16 +538,42 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria return new static($items); } + /** + * 获取第一个单元数据 + * + * @access public + * @param callable|null $callback + * @param null $default + * @return mixed + */ + public function first(callable $callback = null, $default = null) + { + return Arr::first($this->items, $callback, $default); + } + + /** + * 获取最后一个单元数据 + * + * @access public + * @param callable|null $callback + * @param null $default + * @return mixed + */ + public function last(callable $callback = null, $default = null) + { + return Arr::last($this->items, $callback, $default); + } + /** * 截取数组 * * @access public - * @param int $offset - * @param int $length - * @param bool $preserveKeys + * @param int $offset 起始位置 + * @param int $length 截取长度 + * @param bool $preserveKeys preserveKeys * @return static */ - public function slice($offset, $length = null, $preserveKeys = false) + public function slice(int $offset, int $length = null, bool $preserveKeys = false) { return new static(array_slice($this->items, $offset, $length, $preserveKeys)); } @@ -521,10 +624,10 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria /** * 转换当前数据集为JSON字符串 * @access public - * @param integer $options json参数 + * @param integer $options json参数 * @return string */ - public function toJson($options = JSON_UNESCAPED_UNICODE) + public function toJson(int $options = JSON_UNESCAPED_UNICODE) : string { return json_encode($this->toArray(), $options); } @@ -538,10 +641,10 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria * 转换成数组 * * @access public - * @param mixed $items + * @param mixed $items 数据 * @return array */ - protected function convertToArray($items) + protected function convertToArray($items): array { if ($items instanceof self) { return $items->all(); diff --git a/vendor/topthink/think-helper/src/contract/Arrayable.php b/vendor/topthink/think-helper/src/contract/Arrayable.php new file mode 100644 index 000000000..7c6b992b0 --- /dev/null +++ b/vendor/topthink/think-helper/src/contract/Arrayable.php @@ -0,0 +1,8 @@ + +// +---------------------------------------------------------------------- + +use think\Collection; +use think\helper\Arr; + +if (!function_exists('throw_if')) { + /** + * 按条件抛异常 + * + * @param mixed $condition + * @param Throwable|string $exception + * @param array ...$parameters + * @return mixed + * + * @throws Throwable + */ + function throw_if($condition, $exception, ...$parameters) + { + if ($condition) { + throw (is_string($exception) ? new $exception(...$parameters) : $exception); + } + + return $condition; + } +} + +if (!function_exists('throw_unless')) { + /** + * 按条件抛异常 + * + * @param mixed $condition + * @param Throwable|string $exception + * @param array ...$parameters + * @return mixed + * @throws Throwable + */ + function throw_unless($condition, $exception, ...$parameters) + { + if (!$condition) { + throw (is_string($exception) ? new $exception(...$parameters) : $exception); + } + + return $condition; + } +} + +if (!function_exists('tap')) { + /** + * 对一个值调用给定的闭包,然后返回该值 + * + * @param mixed $value + * @param callable|null $callback + * @return mixed + */ + function tap($value, $callback = null) + { + if (is_null($callback)) { + return $value; + } + + $callback($value); + + return $value; + } +} + +if (!function_exists('value')) { + /** + * Return the default value of the given value. + * + * @param mixed $value + * @return mixed + */ + function value($value) + { + return $value instanceof Closure ? $value() : $value; + } +} + +if (!function_exists('collect')) { + /** + * Create a collection from the given value. + * + * @param mixed $value + * @return Collection + */ + function collect($value = null) + { + return new Collection($value); + } +} + +if (!function_exists('data_fill')) { + /** + * Fill in data where it's missing. + * + * @param mixed $target + * @param string|array $key + * @param mixed $value + * @return mixed + */ + function data_fill(&$target, $key, $value) + { + return data_set($target, $key, $value, false); + } +} + +if (!function_exists('data_get')) { + /** + * Get an item from an array or object using "dot" notation. + * + * @param mixed $target + * @param string|array|int $key + * @param mixed $default + * @return mixed + */ + function data_get($target, $key, $default = null) + { + if (is_null($key)) { + return $target; + } + + $key = is_array($key) ? $key : explode('.', $key); + + while (!is_null($segment = array_shift($key))) { + if ('*' === $segment) { + if ($target instanceof Collection) { + $target = $target->all(); + } elseif (!is_array($target)) { + return value($default); + } + + $result = []; + + foreach ($target as $item) { + $result[] = data_get($item, $key); + } + + return in_array('*', $key) ? Arr::collapse($result) : $result; + } + + if (Arr::accessible($target) && Arr::exists($target, $segment)) { + $target = $target[$segment]; + } elseif (is_object($target) && isset($target->{$segment})) { + $target = $target->{$segment}; + } else { + return value($default); + } + } + + return $target; + } +} + +if (!function_exists('data_set')) { + /** + * Set an item on an array or object using dot notation. + * + * @param mixed $target + * @param string|array $key + * @param mixed $value + * @param bool $overwrite + * @return mixed + */ + function data_set(&$target, $key, $value, $overwrite = true) + { + $segments = is_array($key) ? $key : explode('.', $key); + + if (($segment = array_shift($segments)) === '*') { + if (!Arr::accessible($target)) { + $target = []; + } + + if ($segments) { + foreach ($target as &$inner) { + data_set($inner, $segments, $value, $overwrite); + } + } elseif ($overwrite) { + foreach ($target as &$inner) { + $inner = $value; + } + } + } elseif (Arr::accessible($target)) { + if ($segments) { + if (!Arr::exists($target, $segment)) { + $target[$segment] = []; + } + + data_set($target[$segment], $segments, $value, $overwrite); + } elseif ($overwrite || !Arr::exists($target, $segment)) { + $target[$segment] = $value; + } + } elseif (is_object($target)) { + if ($segments) { + if (!isset($target->{$segment})) { + $target->{$segment} = []; + } + + data_set($target->{$segment}, $segments, $value, $overwrite); + } elseif ($overwrite || !isset($target->{$segment})) { + $target->{$segment} = $value; + } + } else { + $target = []; + + if ($segments) { + data_set($target[$segment], $segments, $value, $overwrite); + } elseif ($overwrite) { + $target[$segment] = $value; + } + } + + return $target; + } +} + +if (!function_exists('trait_uses_recursive')) { + /** + * 获取一个trait里所有引用到的trait + * + * @param string $trait Trait + * @return array + */ + function trait_uses_recursive(string $trait): array + { + $traits = class_uses($trait); + foreach ($traits as $trait) { + $traits += trait_uses_recursive($trait); + } + + return $traits; + } +} + +if (!function_exists('class_basename')) { + /** + * 获取类名(不包含命名空间) + * + * @param mixed $class 类名 + * @return string + */ + function class_basename($class): string + { + $class = is_object($class) ? get_class($class) : $class; + return basename(str_replace('\\', '/', $class)); + } +} + +if (!function_exists('class_uses_recursive')) { + /** + *获取一个类里所有用到的trait,包括父类的 + * + * @param mixed $class 类名 + * @return array + */ + function class_uses_recursive($class): array + { + if (is_object($class)) { + $class = get_class($class); + } + + $results = []; + $classes = array_merge([$class => $class], class_parents($class)); + foreach ($classes as $class) { + $results += trait_uses_recursive($class); + } + + return array_unique($results); + } +} diff --git a/vendor/topthink/think-helper/src/helper/Arr.php b/vendor/topthink/think-helper/src/helper/Arr.php new file mode 100644 index 000000000..ed4d6a9ef --- /dev/null +++ b/vendor/topthink/think-helper/src/helper/Arr.php @@ -0,0 +1,634 @@ + +// +---------------------------------------------------------------------- + +namespace think\helper; + +use ArrayAccess; +use InvalidArgumentException; +use think\Collection; + +class Arr +{ + + /** + * Determine whether the given value is array accessible. + * + * @param mixed $value + * @return bool + */ + public static function accessible($value) + { + return is_array($value) || $value instanceof ArrayAccess; + } + + /** + * Add an element to an array using "dot" notation if it doesn't exist. + * + * @param array $array + * @param string $key + * @param mixed $value + * @return array + */ + public static function add($array, $key, $value) + { + if (is_null(static::get($array, $key))) { + static::set($array, $key, $value); + } + + return $array; + } + + /** + * Collapse an array of arrays into a single array. + * + * @param array $array + * @return array + */ + public static function collapse($array) + { + $results = []; + + foreach ($array as $values) { + if ($values instanceof Collection) { + $values = $values->all(); + } elseif (!is_array($values)) { + continue; + } + + $results = array_merge($results, $values); + } + + return $results; + } + + /** + * Cross join the given arrays, returning all possible permutations. + * + * @param array ...$arrays + * @return array + */ + public static function crossJoin(...$arrays) + { + $results = [[]]; + + foreach ($arrays as $index => $array) { + $append = []; + + foreach ($results as $product) { + foreach ($array as $item) { + $product[$index] = $item; + + $append[] = $product; + } + } + + $results = $append; + } + + return $results; + } + + /** + * Divide an array into two arrays. One with keys and the other with values. + * + * @param array $array + * @return array + */ + public static function divide($array) + { + return [array_keys($array), array_values($array)]; + } + + /** + * Flatten a multi-dimensional associative array with dots. + * + * @param array $array + * @param string $prepend + * @return array + */ + public static function dot($array, $prepend = '') + { + $results = []; + + foreach ($array as $key => $value) { + if (is_array($value) && !empty($value)) { + $results = array_merge($results, static::dot($value, $prepend . $key . '.')); + } else { + $results[$prepend . $key] = $value; + } + } + + return $results; + } + + /** + * Get all of the given array except for a specified array of keys. + * + * @param array $array + * @param array|string $keys + * @return array + */ + public static function except($array, $keys) + { + static::forget($array, $keys); + + return $array; + } + + /** + * Determine if the given key exists in the provided array. + * + * @param \ArrayAccess|array $array + * @param string|int $key + * @return bool + */ + public static function exists($array, $key) + { + if ($array instanceof ArrayAccess) { + return $array->offsetExists($key); + } + + return array_key_exists($key, $array); + } + + /** + * Return the first element in an array passing a given truth test. + * + * @param array $array + * @param callable|null $callback + * @param mixed $default + * @return mixed + */ + public static function first($array, callable $callback = null, $default = null) + { + if (is_null($callback)) { + if (empty($array)) { + return value($default); + } + + foreach ($array as $item) { + return $item; + } + } + + foreach ($array as $key => $value) { + if (call_user_func($callback, $value, $key)) { + return $value; + } + } + + return value($default); + } + + /** + * Return the last element in an array passing a given truth test. + * + * @param array $array + * @param callable|null $callback + * @param mixed $default + * @return mixed + */ + public static function last($array, callable $callback = null, $default = null) + { + if (is_null($callback)) { + return empty($array) ? value($default) : end($array); + } + + return static::first(array_reverse($array, true), $callback, $default); + } + + /** + * Flatten a multi-dimensional array into a single level. + * + * @param array $array + * @param int $depth + * @return array + */ + public static function flatten($array, $depth = INF) + { + $result = []; + + foreach ($array as $item) { + $item = $item instanceof Collection ? $item->all() : $item; + + if (!is_array($item)) { + $result[] = $item; + } elseif ($depth === 1) { + $result = array_merge($result, array_values($item)); + } else { + $result = array_merge($result, static::flatten($item, $depth - 1)); + } + } + + return $result; + } + + /** + * Remove one or many array items from a given array using "dot" notation. + * + * @param array $array + * @param array|string $keys + * @return void + */ + public static function forget(&$array, $keys) + { + $original = &$array; + + $keys = (array) $keys; + + if (count($keys) === 0) { + return; + } + + foreach ($keys as $key) { + // if the exact key exists in the top-level, remove it + if (static::exists($array, $key)) { + unset($array[$key]); + + continue; + } + + $parts = explode('.', $key); + + // clean up before each pass + $array = &$original; + + while (count($parts) > 1) { + $part = array_shift($parts); + + if (isset($array[$part]) && is_array($array[$part])) { + $array = &$array[$part]; + } else { + continue 2; + } + } + + unset($array[array_shift($parts)]); + } + } + + /** + * Get an item from an array using "dot" notation. + * + * @param \ArrayAccess|array $array + * @param string $key + * @param mixed $default + * @return mixed + */ + public static function get($array, $key, $default = null) + { + if (!static::accessible($array)) { + return value($default); + } + + if (is_null($key)) { + return $array; + } + + if (static::exists($array, $key)) { + return $array[$key]; + } + + if (strpos($key, '.') === false) { + return $array[$key] ?? value($default); + } + + foreach (explode('.', $key) as $segment) { + if (static::accessible($array) && static::exists($array, $segment)) { + $array = $array[$segment]; + } else { + return value($default); + } + } + + return $array; + } + + /** + * Check if an item or items exist in an array using "dot" notation. + * + * @param \ArrayAccess|array $array + * @param string|array $keys + * @return bool + */ + public static function has($array, $keys) + { + $keys = (array) $keys; + + if (!$array || $keys === []) { + return false; + } + + foreach ($keys as $key) { + $subKeyArray = $array; + + if (static::exists($array, $key)) { + continue; + } + + foreach (explode('.', $key) as $segment) { + if (static::accessible($subKeyArray) && static::exists($subKeyArray, $segment)) { + $subKeyArray = $subKeyArray[$segment]; + } else { + return false; + } + } + } + + return true; + } + + /** + * Determines if an array is associative. + * + * An array is "associative" if it doesn't have sequential numerical keys beginning with zero. + * + * @param array $array + * @return bool + */ + public static function isAssoc(array $array) + { + $keys = array_keys($array); + + return array_keys($keys) !== $keys; + } + + /** + * Get a subset of the items from the given array. + * + * @param array $array + * @param array|string $keys + * @return array + */ + public static function only($array, $keys) + { + return array_intersect_key($array, array_flip((array) $keys)); + } + + /** + * Pluck an array of values from an array. + * + * @param array $array + * @param string|array $value + * @param string|array|null $key + * @return array + */ + public static function pluck($array, $value, $key = null) + { + $results = []; + + [$value, $key] = static::explodePluckParameters($value, $key); + + foreach ($array as $item) { + $itemValue = data_get($item, $value); + + // If the key is "null", we will just append the value to the array and keep + // looping. Otherwise we will key the array using the value of the key we + // received from the developer. Then we'll return the final array form. + if (is_null($key)) { + $results[] = $itemValue; + } else { + $itemKey = data_get($item, $key); + + if (is_object($itemKey) && method_exists($itemKey, '__toString')) { + $itemKey = (string) $itemKey; + } + + $results[$itemKey] = $itemValue; + } + } + + return $results; + } + + /** + * Explode the "value" and "key" arguments passed to "pluck". + * + * @param string|array $value + * @param string|array|null $key + * @return array + */ + protected static function explodePluckParameters($value, $key) + { + $value = is_string($value) ? explode('.', $value) : $value; + + $key = is_null($key) || is_array($key) ? $key : explode('.', $key); + + return [$value, $key]; + } + + /** + * Push an item onto the beginning of an array. + * + * @param array $array + * @param mixed $value + * @param mixed $key + * @return array + */ + public static function prepend($array, $value, $key = null) + { + if (is_null($key)) { + array_unshift($array, $value); + } else { + $array = [$key => $value] + $array; + } + + return $array; + } + + /** + * Get a value from the array, and remove it. + * + * @param array $array + * @param string $key + * @param mixed $default + * @return mixed + */ + public static function pull(&$array, $key, $default = null) + { + $value = static::get($array, $key, $default); + + static::forget($array, $key); + + return $value; + } + + /** + * Get one or a specified number of random values from an array. + * + * @param array $array + * @param int|null $number + * @return mixed + * + * @throws \InvalidArgumentException + */ + public static function random($array, $number = null) + { + $requested = is_null($number) ? 1 : $number; + + $count = count($array); + + if ($requested > $count) { + throw new InvalidArgumentException( + "You requested {$requested} items, but there are only {$count} items available." + ); + } + + if (is_null($number)) { + return $array[array_rand($array)]; + } + + if ((int) $number === 0) { + return []; + } + + $keys = array_rand($array, $number); + + $results = []; + + foreach ((array) $keys as $key) { + $results[] = $array[$key]; + } + + return $results; + } + + /** + * Set an array item to a given value using "dot" notation. + * + * If no key is given to the method, the entire array will be replaced. + * + * @param array $array + * @param string $key + * @param mixed $value + * @return array + */ + public static function set(&$array, $key, $value) + { + if (is_null($key)) { + return $array = $value; + } + + $keys = explode('.', $key); + + while (count($keys) > 1) { + $key = array_shift($keys); + + // If the key doesn't exist at this depth, we will just create an empty array + // to hold the next value, allowing us to create the arrays to hold final + // values at the correct depth. Then we'll keep digging into the array. + if (!isset($array[$key]) || !is_array($array[$key])) { + $array[$key] = []; + } + + $array = &$array[$key]; + } + + $array[array_shift($keys)] = $value; + + return $array; + } + + /** + * Shuffle the given array and return the result. + * + * @param array $array + * @param int|null $seed + * @return array + */ + public static function shuffle($array, $seed = null) + { + if (is_null($seed)) { + shuffle($array); + } else { + srand($seed); + + usort($array, function () { + return rand(-1, 1); + }); + } + + return $array; + } + + /** + * Sort the array using the given callback or "dot" notation. + * + * @param array $array + * @param callable|string|null $callback + * @return array + */ + public static function sort($array, $callback = null) + { + return Collection::make($array)->sort($callback)->all(); + } + + /** + * Recursively sort an array by keys and values. + * + * @param array $array + * @return array + */ + public static function sortRecursive($array) + { + foreach ($array as &$value) { + if (is_array($value)) { + $value = static::sortRecursive($value); + } + } + + if (static::isAssoc($array)) { + ksort($array); + } else { + sort($array); + } + + return $array; + } + + /** + * Convert the array into a query string. + * + * @param array $array + * @return string + */ + public static function query($array) + { + return http_build_query($array, null, '&', PHP_QUERY_RFC3986); + } + + /** + * Filter the array using the given callback. + * + * @param array $array + * @param callable $callback + * @return array + */ + public static function where($array, callable $callback) + { + return array_filter($array, $callback, ARRAY_FILTER_USE_BOTH); + } + + /** + * If the given value is not an array and not null, wrap it in one. + * + * @param mixed $value + * @return array + */ + public static function wrap($value) + { + if (is_null($value)) { + return []; + } + + return is_array($value) ? $value : [$value]; + } +} \ No newline at end of file diff --git a/vendor/topthink/think-helper/src/helper/Str.php b/vendor/topthink/think-helper/src/helper/Str.php new file mode 100644 index 000000000..7391fbd39 --- /dev/null +++ b/vendor/topthink/think-helper/src/helper/Str.php @@ -0,0 +1,234 @@ + +// +---------------------------------------------------------------------- +namespace think\helper; + +class Str +{ + + protected static $snakeCache = []; + + protected static $camelCache = []; + + protected static $studlyCache = []; + + /** + * 检查字符串中是否包含某些字符串 + * @param string $haystack + * @param string|array $needles + * @return bool + */ + public static function contains(string $haystack, $needles): bool + { + foreach ((array) $needles as $needle) { + if ('' != $needle && mb_strpos($haystack, $needle) !== false) { + return true; + } + } + + return false; + } + + /** + * 检查字符串是否以某些字符串结尾 + * + * @param string $haystack + * @param string|array $needles + * @return bool + */ + public static function endsWith(string $haystack, $needles): bool + { + foreach ((array) $needles as $needle) { + if ((string) $needle === static::substr($haystack, -static::length($needle))) { + return true; + } + } + + return false; + } + + /** + * 检查字符串是否以某些字符串开头 + * + * @param string $haystack + * @param string|array $needles + * @return bool + */ + public static function startsWith(string $haystack, $needles): bool + { + foreach ((array) $needles as $needle) { + if ('' != $needle && mb_strpos($haystack, $needle) === 0) { + return true; + } + } + + return false; + } + + /** + * 获取指定长度的随机字母数字组合的字符串 + * + * @param int $length + * @param int $type + * @param string $addChars + * @return string + */ + public static function random(int $length = 6, int $type = null, string $addChars = ''): string + { + $str = ''; + switch ($type) { + case 0: + $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' . $addChars; + break; + case 1: + $chars = str_repeat('0123456789', 3); + break; + case 2: + $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' . $addChars; + break; + case 3: + $chars = 'abcdefghijklmnopqrstuvwxyz' . $addChars; + break; + case 4: + $chars = "们以我到他会作时要动国产的一是工就年阶义发成部民可出能方进在了不和有大这主中人上为来分生对于学下级地个用同行面说种过命度革而多子后自社加小机也经力线本电高量长党得实家定深法表着水理化争现所二起政三好十战无农使性前等反体合斗路图把结第里正新开论之物从当两些还天资事队批点育重其思与间内去因件日利相由压员气业代全组数果期导平各基或月毛然如应形想制心样干都向变关问比展那它最及外没看治提五解系林者米群头意只明四道马认次文通但条较克又公孔领军流入接席位情运器并飞原油放立题质指建区验活众很教决特此常石强极土少已根共直团统式转别造切九你取西持总料连任志观调七么山程百报更见必真保热委手改管处己将修支识病象几先老光专什六型具示复安带每东增则完风回南广劳轮科北打积车计给节做务被整联步类集号列温装即毫知轴研单色坚据速防史拉世设达尔场织历花受求传口断况采精金界品判参层止边清至万确究书" . $addChars; + break; + default: + $chars = 'ABCDEFGHIJKMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789' . $addChars; + break; + } + if ($length > 10) { + $chars = $type == 1 ? str_repeat($chars, $length) : str_repeat($chars, 5); + } + if ($type != 4) { + $chars = str_shuffle($chars); + $str = substr($chars, 0, $length); + } else { + for ($i = 0; $i < $length; $i++) { + $str .= mb_substr($chars, floor(mt_rand(0, mb_strlen($chars, 'utf-8') - 1)), 1); + } + } + return $str; + } + + /** + * 字符串转小写 + * + * @param string $value + * @return string + */ + public static function lower(string $value): string + { + return mb_strtolower($value, 'UTF-8'); + } + + /** + * 字符串转大写 + * + * @param string $value + * @return string + */ + public static function upper(string $value): string + { + return mb_strtoupper($value, 'UTF-8'); + } + + /** + * 获取字符串的长度 + * + * @param string $value + * @return int + */ + public static function length(string $value): int + { + return mb_strlen($value); + } + + /** + * 截取字符串 + * + * @param string $string + * @param int $start + * @param int|null $length + * @return string + */ + public static function substr(string $string, int $start, int $length = null): string + { + return mb_substr($string, $start, $length, 'UTF-8'); + } + + /** + * 驼峰转下划线 + * + * @param string $value + * @param string $delimiter + * @return string + */ + public static function snake(string $value, string $delimiter = '_'): string + { + $key = $value; + + if (isset(static::$snakeCache[$key][$delimiter])) { + return static::$snakeCache[$key][$delimiter]; + } + + if (!ctype_lower($value)) { + $value = preg_replace('/\s+/u', '', $value); + + $value = static::lower(preg_replace('/(.)(?=[A-Z])/u', '$1' . $delimiter, $value)); + } + + return static::$snakeCache[$key][$delimiter] = $value; + } + + /** + * 下划线转驼峰(首字母小写) + * + * @param string $value + * @return string + */ + public static function camel(string $value): string + { + if (isset(static::$camelCache[$value])) { + return static::$camelCache[$value]; + } + + return static::$camelCache[$value] = lcfirst(static::studly($value)); + } + + /** + * 下划线转驼峰(首字母大写) + * + * @param string $value + * @return string + */ + public static function studly(string $value): string + { + $key = $value; + + if (isset(static::$studlyCache[$key])) { + return static::$studlyCache[$key]; + } + + $value = ucwords(str_replace(['-', '_'], ' ', $value)); + + return static::$studlyCache[$key] = str_replace(' ', '', $value); + } + + /** + * 转为首字母大写的标题格式 + * + * @param string $value + * @return string + */ + public static function title(string $value): string + { + return mb_convert_case($value, MB_CASE_TITLE, 'UTF-8'); + } +} diff --git a/vendor/topthink/think-multi-app/LICENSE b/vendor/topthink/think-multi-app/LICENSE new file mode 100644 index 000000000..261eeb9e9 --- /dev/null +++ b/vendor/topthink/think-multi-app/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/topthink/think-multi-app/README.md b/vendor/topthink/think-multi-app/README.md new file mode 100644 index 000000000..a746fa7a7 --- /dev/null +++ b/vendor/topthink/think-multi-app/README.md @@ -0,0 +1,14 @@ +# think-multi-app + +用于ThinkPHP6+的多应用支持 + +## 安装 + +~~~ +composer require topthink/think-multi-app +~~~ + +## 使用 + +用法参考ThinkPHP6完全开发手册[多应用模式](https://www.kancloud.cn/manual/thinkphp6_0/1297876)章节。 + diff --git a/vendor/topthink/think-multi-app/composer.json b/vendor/topthink/think-multi-app/composer.json new file mode 100644 index 000000000..92d620eb1 --- /dev/null +++ b/vendor/topthink/think-multi-app/composer.json @@ -0,0 +1,28 @@ +{ + "name": "topthink/think-multi-app", + "description": "thinkphp6 multi app support", + "license": "Apache-2.0", + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "require": { + "php": ">=7.1.0", + "topthink/framework": "^6.0.0" + }, + "autoload": { + "psr-4": { + "think\\app\\": "src" + } + }, + "extra": { + "think":{ + "services":[ + "think\\app\\Service" + ] + } + }, + "minimum-stability": "dev" +} diff --git a/vendor/topthink/think-multi-app/src/MultiApp.php b/vendor/topthink/think-multi-app/src/MultiApp.php new file mode 100644 index 000000000..b0ac260d9 --- /dev/null +++ b/vendor/topthink/think-multi-app/src/MultiApp.php @@ -0,0 +1,245 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\app; + +use Closure; +use think\App; +use think\exception\HttpException; +use think\Request; +use think\Response; + +/** + * 多应用模式支持 + */ +class MultiApp +{ + + /** @var App */ + protected $app; + + /** + * 应用名称 + * @var string + */ + protected $name; + + /** + * 应用名称 + * @var string + */ + protected $appName; + + /** + * 应用路径 + * @var string + */ + protected $path; + + public function __construct(App $app) + { + $this->app = $app; + $this->name = $this->app->http->getName(); + $this->path = $this->app->http->getPath(); + } + + /** + * 多应用解析 + * @access public + * @param Request $request + * @param Closure $next + * @return Response + */ + public function handle($request, Closure $next) + { + if (!$this->parseMultiApp()) { + return $next($request); + } + + return $this->app->middleware->pipeline('app') + ->send($request) + ->then(function ($request) use ($next) { + return $next($request); + }); + } + + /** + * 获取路由目录 + * @access protected + * @return string + */ + protected function getRoutePath(): string + { + return $this->app->getAppPath() . 'route' . DIRECTORY_SEPARATOR; + } + + /** + * 解析多应用 + * @return bool + */ + protected function parseMultiApp(): bool + { + $scriptName = $this->getScriptName(); + $defaultApp = $this->app->config->get('app.default_app') ?: 'index'; + + if ($this->name || ($scriptName && !in_array($scriptName, ['index', 'router', 'think']))) { + $appName = $this->name ?: $scriptName; + $this->app->http->setBind(); + } else { + // 自动多应用识别 + $this->app->http->setBind(false); + $appName = null; + $this->appName = ''; + + $bind = $this->app->config->get('app.domain_bind', []); + + if (!empty($bind)) { + // 获取当前子域名 + $subDomain = $this->app->request->subDomain(); + $domain = $this->app->request->host(true); + + if (isset($bind[$domain])) { + $appName = $bind[$domain]; + $this->app->http->setBind(); + } elseif (isset($bind[$subDomain])) { + $appName = $bind[$subDomain]; + $this->app->http->setBind(); + } elseif (isset($bind['*'])) { + $appName = $bind['*']; + $this->app->http->setBind(); + } + } + + if (!$this->app->http->isBind()) { + $path = $this->app->request->pathinfo(); + $map = $this->app->config->get('app.app_map', []); + $deny = $this->app->config->get('app.deny_app_list', []); + $name = current(explode('/', $path)); + + if (strpos($name, '.')) { + $name = strstr($name, '.', true); + } + + if (isset($map[$name])) { + if ($map[$name] instanceof Closure) { + $result = call_user_func_array($map[$name], [$this->app]); + $appName = $result ?: $name; + } else { + $appName = $map[$name]; + } + } elseif ($name && (false !== array_search($name, $map) || in_array($name, $deny))) { + throw new HttpException(404, 'app not exists:' . $name); + } elseif ($name && isset($map['*'])) { + $appName = $map['*']; + } else { + $appName = $name ?: $defaultApp; + $appPath = $this->path ?: $this->app->getBasePath() . $appName . DIRECTORY_SEPARATOR; + + if (!is_dir($appPath)) { + $express = $this->app->config->get('app.app_express', false); + if ($express) { + $this->setApp($defaultApp); + return true; + } else { + return false; + } + } + } + + if ($name) { + $this->app->request->setRoot('/' . $name); + $this->app->request->setPathinfo(strpos($path, '/') ? ltrim(strstr($path, '/'), '/') : ''); + } + } + } + + $this->setApp($appName ?: $defaultApp); + return true; + } + + /** + * 获取当前运行入口名称 + * @access protected + * @codeCoverageIgnore + * @return string + */ + protected function getScriptName(): string + { + if (isset($_SERVER['SCRIPT_FILENAME'])) { + $file = $_SERVER['SCRIPT_FILENAME']; + } elseif (isset($_SERVER['argv'][0])) { + $file = realpath($_SERVER['argv'][0]); + } + + return isset($file) ? pathinfo($file, PATHINFO_FILENAME) : ''; + } + + /** + * 设置应用 + * @param string $appName + */ + protected function setApp(string $appName): void + { + $this->appName = $appName; + $this->app->http->name($appName); + + $appPath = $this->path ?: $this->app->getBasePath() . $appName . DIRECTORY_SEPARATOR; + + $this->app->setAppPath($appPath); + // 设置应用命名空间 + $this->app->setNamespace($this->app->config->get('app.app_namespace') ?: 'app\\' . $appName); + + if (is_dir($appPath)) { + $this->app->setRuntimePath($this->app->getRuntimePath() . $appName . DIRECTORY_SEPARATOR); + $this->app->http->setRoutePath($this->getRoutePath()); + + //加载应用 + $this->loadApp($appName, $appPath); + } + } + + /** + * 加载应用文件 + * @param string $appName 应用名 + * @return void + */ + protected function loadApp(string $appName, string $appPath): void + { + if (is_file($appPath . 'common.php')) { + include_once $appPath . 'common.php'; + } + + $files = []; + + $files = array_merge($files, glob($appPath . 'config' . DIRECTORY_SEPARATOR . '*' . $this->app->getConfigExt())); + + foreach ($files as $file) { + $this->app->config->load($file, pathinfo($file, PATHINFO_FILENAME)); + } + + if (is_file($appPath . 'event.php')) { + $this->app->loadEvent(include $appPath . 'event.php'); + } + + if (is_file($appPath . 'middleware.php')) { + $this->app->middleware->import(include $appPath . 'middleware.php', 'app'); + } + + if (is_file($appPath . 'provider.php')) { + $this->app->bind(include $appPath . 'provider.php'); + } + + // 加载应用默认语言包 + $this->app->loadLangPack($this->app->lang->defaultLangSet()); + } + +} diff --git a/vendor/topthink/think-multi-app/src/Service.php b/vendor/topthink/think-multi-app/src/Service.php new file mode 100644 index 000000000..22b85320d --- /dev/null +++ b/vendor/topthink/think-multi-app/src/Service.php @@ -0,0 +1,32 @@ + +// +---------------------------------------------------------------------- +namespace think\app; + +use think\Service as BaseService; + +class Service extends BaseService +{ + public function boot() + { + $this->app->event->listen('HttpRun', function () { + $this->app->middleware->add(MultiApp::class); + }); + + $this->commands([ + 'build' => command\Build::class, + 'clear' => command\Clear::class, + ]); + + $this->app->bind([ + 'think\route\Url' => Url::class, + ]); + } +} diff --git a/vendor/topthink/think-multi-app/src/Url.php b/vendor/topthink/think-multi-app/src/Url.php new file mode 100644 index 000000000..7bd6057f9 --- /dev/null +++ b/vendor/topthink/think-multi-app/src/Url.php @@ -0,0 +1,232 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\app; + +use think\App; +use think\Route; +use think\route\Url as UrlBuild; + +/** + * 路由地址生成 + */ +class Url extends UrlBuild +{ + /** + * 直接解析URL地址 + * @access protected + * @param string $url URL + * @param string|bool $domain Domain + * @return string + */ + protected function parseUrl(string $url, &$domain): string + { + $request = $this->app->request; + + if (0 === strpos($url, '/')) { + // 直接作为路由地址解析 + $url = substr($url, 1); + } elseif (false !== strpos($url, '\\')) { + // 解析到类 + $url = ltrim(str_replace('\\', '/', $url), '/'); + } elseif (0 === strpos($url, '@')) { + // 解析到控制器 + $url = substr($url, 1); + } elseif ('' === $url) { + $url = $this->getAppName() . '/' . $request->controller() . '/' . $request->action(); + } else { + // 解析到 应用/控制器/操作 + $controller = $request->controller(); + $app = $this->getAppName(); + $path = explode('/', $url); + $action = array_pop($path); + $controller = empty($path) ? $controller : array_pop($path); + $app = empty($path) ? $app : array_pop($path); + $url = $controller . '/' . $action; + $bind = $this->app->config->get('app.domain_bind', []); + + if ($key = array_search($this->app->http->getName(), $bind)) { + isset($bind[$_SERVER['SERVER_NAME']]) && $domain = $_SERVER['SERVER_NAME']; + + $domain = is_bool($domain) ? $key : $domain; + } else { + $url = $app . '/' . $url; + } + } + + return $url; + } + + public function build() + { + // 解析URL + $url = $this->url; + $suffix = $this->suffix; + $domain = $this->domain; + $request = $this->app->request; + $vars = $this->vars; + + if (0 === strpos($url, '[') && $pos = strpos($url, ']')) { + // [name] 表示使用路由命名标识生成URL + $name = substr($url, 1, $pos - 1); + $url = 'name' . substr($url, $pos + 1); + } + + if (false === strpos($url, '://') && 0 !== strpos($url, '/')) { + $info = parse_url($url); + $url = !empty($info['path']) ? $info['path'] : ''; + + if (isset($info['fragment'])) { + // 解析锚点 + $anchor = $info['fragment']; + + if (false !== strpos($anchor, '?')) { + // 解析参数 + list($anchor, $info['query']) = explode('?', $anchor, 2); + } + + if (false !== strpos($anchor, '@')) { + // 解析域名 + list($anchor, $domain) = explode('@', $anchor, 2); + } + } elseif (strpos($url, '@') && false === strpos($url, '\\')) { + // 解析域名 + list($url, $domain) = explode('@', $url, 2); + } + } + + if ($url) { + $checkName = isset($name) ? $name : $url . (isset($info['query']) ? '?' . $info['query'] : ''); + $checkDomain = $domain && is_string($domain) ? $domain : null; + + $rule = $this->route->getName($checkName, $checkDomain); + + if (empty($rule) && isset($info['query'])) { + $rule = $this->route->getName($url, $checkDomain); + // 解析地址里面参数 合并到vars + parse_str($info['query'], $params); + $vars = array_merge($params, $vars); + unset($info['query']); + } + } + + if (!empty($rule) && $match = $this->getRuleUrl($rule, $vars, $domain)) { + // 匹配路由命名标识 + $url = $match[0]; + + if ($domain && !empty($match[1])) { + $domain = $match[1]; + } + + if (!is_null($match[2])) { + $suffix = $match[2]; + } + + if (!$this->app->http->isBind()) { + $app = $this->getAppName(); + $url = $app . '/' . $url; + } + } elseif (!empty($rule) && isset($name)) { + throw new \InvalidArgumentException('route name not exists:' . $name); + } else { + // 检测URL绑定 + $bind = $this->route->getDomainBind($domain && is_string($domain) ? $domain : null); + + if ($bind && 0 === strpos($url, $bind)) { + $url = substr($url, strlen($bind) + 1); + } else { + $binds = $this->route->getBind(); + + foreach ($binds as $key => $val) { + if (is_string($val) && 0 === strpos($url, $val) && substr_count($val, '/') > 1) { + $url = substr($url, strlen($val) + 1); + $domain = $key; + break; + } + } + } + + // 路由标识不存在 直接解析 + $url = $this->parseUrl($url, $domain); + + if (isset($info['query'])) { + // 解析地址里面参数 合并到vars + parse_str($info['query'], $params); + $vars = array_merge($params, $vars); + } + } + + // 还原URL分隔符 + $depr = $this->route->config('pathinfo_depr'); + $url = str_replace('/', $depr, $url); + + $file = $request->baseFile(); + if ($file && 0 !== strpos($request->url(), $file)) { + $file = str_replace('\\', '/', dirname($file)); + } + + $url = rtrim($file, '/') . '/' . ltrim($url, '/'); + + // URL后缀 + if ('/' == substr($url, -1) || '' == $url) { + $suffix = ''; + } else { + $suffix = $this->parseSuffix($suffix); + } + + // 锚点 + $anchor = !empty($anchor) ? '#' . $anchor : ''; + + // 参数组装 + if (!empty($vars)) { + // 添加参数 + if ($this->route->config('url_common_param')) { + $vars = http_build_query($vars); + $url .= $suffix . '?' . $vars . $anchor; + } else { + foreach ($vars as $var => $val) { + $val = (string) $val; + if ('' !== $val) { + $url .= $depr . $var . $depr . urlencode($val); + } + } + + $url .= $suffix . $anchor; + } + } else { + $url .= $suffix . $anchor; + } + + // 检测域名 + $domain = $this->parseDomain($url, $domain); + + // URL组装 + return $domain . rtrim($this->root, '/') . '/' . ltrim($url, '/'); + } + + /** + * 获取URL的应用名 + * @access protected + * @return string + */ + protected function getAppName() + { + $app = $this->app->http->getName(); + $map = $this->app->config->get('app.app_map', []); + + if ($key = array_search($app, $map)) { + $app = $key; + } + + return $app; + } +} diff --git a/vendor/topthink/think-multi-app/src/command/Build.php b/vendor/topthink/think-multi-app/src/command/Build.php new file mode 100644 index 000000000..65b2f8747 --- /dev/null +++ b/vendor/topthink/think-multi-app/src/command/Build.php @@ -0,0 +1,180 @@ + +// +---------------------------------------------------------------------- + +namespace think\app\command; + +use think\console\Command; +use think\console\Input; +use think\console\input\Argument; +use think\console\Output; + +class Build extends Command +{ + /** + * 应用基础目录 + * @var string + */ + protected $basePath; + + /** + * {@inheritdoc} + */ + protected function configure() + { + $this->setName('build') + ->addArgument('app', Argument::OPTIONAL, 'app name .') + ->setDescription('Build App Dirs'); + } + + protected function execute(Input $input, Output $output) + { + $this->basePath = $this->app->getBasePath(); + $app = $input->getArgument('app') ?: ''; + + if (is_file($this->basePath . 'build.php')) { + $list = include $this->basePath . 'build.php'; + } else { + $list = [ + '__dir__' => ['controller', 'model', 'view'], + ]; + } + + $this->buildApp($app, $list); + $output->writeln("Successed"); + + } + + /** + * 创建应用 + * @access protected + * @param string $app 应用名 + * @param array $list 目录结构 + * @return void + */ + protected function buildApp(string $app, array $list = []): void + { + if (!is_dir($this->basePath . $app)) { + // 创建应用目录 + mkdir($this->basePath . $app); + } + + $appPath = $this->basePath . ($app ? $app . DIRECTORY_SEPARATOR : ''); + $namespace = 'app' . ($app ? '\\' . $app : ''); + + // 创建配置文件和公共文件 + $this->buildCommon($app); + // 创建模块的默认页面 + $this->buildHello($app, $namespace); + + foreach ($list as $path => $file) { + if ('__dir__' == $path) { + // 生成子目录 + foreach ($file as $dir) { + $this->checkDirBuild($appPath . $dir); + } + } elseif ('__file__' == $path) { + // 生成(空白)文件 + foreach ($file as $name) { + if (!is_file($appPath . $name)) { + file_put_contents($appPath . $name, 'php' == pathinfo($name, PATHINFO_EXTENSION) ? 'app->config->get('route.controller_suffix')) { + $filename = $appPath . $path . DIRECTORY_SEPARATOR . $val . 'Controller.php'; + $class = $val . 'Controller'; + } + $content = "checkDirBuild(dirname($filename)); + $content = ''; + break; + default: + // 其他文件 + $content = "app->config->get('route.controller_suffix') ? 'Controller' : ''; + $filename = $this->basePath . ($app ? $app . DIRECTORY_SEPARATOR : '') . 'controller' . DIRECTORY_SEPARATOR . 'Index' . $suffix . '.php'; + + if (!is_file($filename)) { + $content = file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'controller.stub'); + $content = str_replace(['{%name%}', '{%app%}', '{%layer%}', '{%suffix%}'], [$app, $namespace, 'controller', $suffix], $content); + $this->checkDirBuild(dirname($filename)); + + file_put_contents($filename, $content); + } + } + + /** + * 创建应用的公共文件 + * @access protected + * @param string $app 目录 + * @return void + */ + protected function buildCommon(string $app): void + { + $appPath = $this->basePath . ($app ? $app . DIRECTORY_SEPARATOR : ''); + + if (!is_file($appPath . 'common.php')) { + file_put_contents($appPath . 'common.php', " // +---------------------------------------------------------------------- -namespace think\console\command; +namespace think\app\command; use think\console\Command; use think\console\Input; +use think\console\input\Argument; use think\console\input\Option; use think\console\Output; -use think\facade\App; -use think\facade\Cache; class Clear extends Command { protected function configure() { // 指令配置 - $this - ->setName('clear') - ->addOption('path', 'd', Option::VALUE_OPTIONAL, 'path to clear', null) + $this->setName('clear') + ->addArgument('app', Argument::OPTIONAL, 'app name .') ->addOption('cache', 'c', Option::VALUE_NONE, 'clear cache file') - ->addOption('route', 'u', Option::VALUE_NONE, 'clear route cache') ->addOption('log', 'l', Option::VALUE_NONE, 'clear log file') ->addOption('dir', 'r', Option::VALUE_NONE, 'clear empty dir') ->setDescription('Clear runtime file'); @@ -34,25 +31,24 @@ class Clear extends Command protected function execute(Input $input, Output $output) { - if ($input->getOption('route')) { - Cache::clear('route_cache'); - } else { - if ($input->getOption('cache')) { - $path = App::getRuntimePath() . 'cache'; - } elseif ($input->getOption('log')) { - $path = App::getRuntimePath() . 'log'; - } else { - $path = $input->getOption('path') ?: App::getRuntimePath(); - } + $app = $input->getArgument('app') ?: ''; + $runtimePath = $this->app->getRootPath() . 'runtime' . DIRECTORY_SEPARATOR . ($app ? $app . DIRECTORY_SEPARATOR : ''); - $rmdir = $input->getOption('dir') ? true : false; - $this->clear(rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR, $rmdir); + if ($input->getOption('cache')) { + $path = $runtimePath . 'cache'; + } elseif ($input->getOption('log')) { + $path = $runtimePath . 'log'; + } else { + $path = $runtimePath; } + $rmdir = $input->getOption('dir') ? true : false; + $this->clear(rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR, $rmdir); + $output->writeln("Clear Successed"); } - protected function clear($path, $rmdir) + protected function clear(string $path, bool $rmdir): void { $files = is_dir($path) ? scandir($path) : []; diff --git a/vendor/topthink/think-multi-app/src/command/stubs/controller.stub b/vendor/topthink/think-multi-app/src/command/stubs/controller.stub new file mode 100644 index 000000000..263c4c642 --- /dev/null +++ b/vendor/topthink/think-multi-app/src/command/stubs/controller.stub @@ -0,0 +1,12 @@ +=7.1.0", + "ext-json": "*", + "ext-pdo": "*", + "psr/simple-cache": "^1.0", + "psr/log": "~1.0", + "topthink/think-helper":"^3.1" + }, + "require-dev": { + "phpunit/phpunit": "^7|^8|^9.5" + }, + "autoload": { + "psr-4": { + "think\\": "src" + }, + "files": [ + "stubs/load_stubs.php" + ] + }, + "autoload-dev": { + "psr-4": { + "tests\\": "tests" + } + }, + "config": { + "sort-packages": true + } +} diff --git a/vendor/topthink/think-orm/src/DbManager.php b/vendor/topthink/think-orm/src/DbManager.php new file mode 100644 index 000000000..147d9f63e --- /dev/null +++ b/vendor/topthink/think-orm/src/DbManager.php @@ -0,0 +1,376 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think; + +use InvalidArgumentException; +use Psr\Log\LoggerInterface; +use Psr\SimpleCache\CacheInterface; +use think\db\BaseQuery; +use think\db\ConnectionInterface; +use think\db\Query; +use think\db\Raw; + +/** + * Class DbManager + * @package think + * @mixin BaseQuery + * @mixin Query + */ +class DbManager +{ + /** + * 数据库连接实例 + * @var array + */ + protected $instance = []; + + /** + * 数据库配置 + * @var array + */ + protected $config = []; + + /** + * Event对象或者数组 + * @var array|object + */ + protected $event; + + /** + * SQL监听 + * @var array + */ + protected $listen = []; + + /** + * SQL日志 + * @var array + */ + protected $dbLog = []; + + /** + * 查询次数 + * @var int + */ + protected $queryTimes = 0; + + /** + * 查询缓存对象 + * @var CacheInterface + */ + protected $cache; + + /** + * 查询日志对象 + * @var LoggerInterface + */ + protected $log; + + /** + * 架构函数 + * @access public + */ + public function __construct() + { + $this->modelMaker(); + } + + /** + * 注入模型对象 + * @access public + * @return void + */ + protected function modelMaker() + { + Model::setDb($this); + + if (is_object($this->event)) { + Model::setEvent($this->event); + } + + Model::maker(function (Model $model) { + $isAutoWriteTimestamp = $model->getAutoWriteTimestamp(); + + if (is_null($isAutoWriteTimestamp)) { + // 自动写入时间戳 + $model->isAutoWriteTimestamp($this->getConfig('auto_timestamp', true)); + } + + $dateFormat = $model->getDateFormat(); + + if (is_null($dateFormat)) { + // 设置时间戳格式 + $model->setDateFormat($this->getConfig('datetime_format', 'Y-m-d H:i:s')); + } + }); + } + + /** + * 监听SQL + * @access protected + * @return void + */ + public function triggerSql(): void + {} + + /** + * 初始化配置参数 + * @access public + * @param array $config 连接配置 + * @return void + */ + public function setConfig($config): void + { + $this->config = $config; + } + + /** + * 设置缓存对象 + * @access public + * @param CacheInterface $cache 缓存对象 + * @return void + */ + public function setCache(CacheInterface $cache): void + { + $this->cache = $cache; + } + + /** + * 设置日志对象 + * @access public + * @param LoggerInterface $log 日志对象 + * @return void + */ + public function setLog(LoggerInterface $log): void + { + $this->log = $log; + } + + /** + * 记录SQL日志 + * @access protected + * @param string $log SQL日志信息 + * @param string $type 日志类型 + * @return void + */ + public function log(string $log, string $type = 'sql') + { + if ($this->log) { + $this->log->log($type, $log); + } else { + $this->dbLog[$type][] = $log; + } + } + + /** + * 获得查询日志(没有设置日志对象使用) + * @access public + * @param bool $clear 是否清空 + * @return array + */ + public function getDbLog(bool $clear = false): array + { + $logs = $this->dbLog; + if ($clear) { + $this->dbLog = []; + } + + return $logs; + } + + /** + * 获取配置参数 + * @access public + * @param string $name 配置参数 + * @param mixed $default 默认值 + * @return mixed + */ + public function getConfig(string $name = '', $default = null) + { + if ('' === $name) { + return $this->config; + } + + return $this->config[$name] ?? $default; + } + + /** + * 创建/切换数据库连接查询 + * @access public + * @param string|null $name 连接配置标识 + * @param bool $force 强制重新连接 + * @return ConnectionInterface + */ + public function connect(string $name = null, bool $force = false) + { + return $this->instance($name, $force); + } + + /** + * 创建数据库连接实例 + * @access protected + * @param string|null $name 连接标识 + * @param bool $force 强制重新连接 + * @return ConnectionInterface + */ + protected function instance(string $name = null, bool $force = false): ConnectionInterface + { + if (empty($name)) { + $name = $this->getConfig('default', 'mysql'); + } + + if ($force || !isset($this->instance[$name])) { + $this->instance[$name] = $this->createConnection($name); + } + + return $this->instance[$name]; + } + + /** + * 获取连接配置 + * @param string $name + * @return array + */ + protected function getConnectionConfig(string $name): array + { + $connections = $this->getConfig('connections'); + if (!isset($connections[$name])) { + throw new InvalidArgumentException('Undefined db config:' . $name); + } + + return $connections[$name]; + } + + /** + * 创建连接 + * @param $name + * @return ConnectionInterface + */ + protected function createConnection(string $name): ConnectionInterface + { + $config = $this->getConnectionConfig($name); + + $type = !empty($config['type']) ? $config['type'] : 'mysql'; + + if (false !== strpos($type, '\\')) { + $class = $type; + } else { + $class = '\\think\\db\\connector\\' . ucfirst($type); + } + + /** @var ConnectionInterface $connection */ + $connection = new $class($config); + $connection->setDb($this); + + if ($this->cache) { + $connection->setCache($this->cache); + } + + return $connection; + } + + /** + * 使用表达式设置数据 + * @access public + * @param string $value 表达式 + * @return Raw + */ + public function raw(string $value): Raw + { + return new Raw($value); + } + + /** + * 更新查询次数 + * @access public + * @return void + */ + public function updateQueryTimes(): void + { + $this->queryTimes++; + } + + /** + * 重置查询次数 + * @access public + * @return void + */ + public function clearQueryTimes(): void + { + $this->queryTimes = 0; + } + + /** + * 获得查询次数 + * @access public + * @return integer + */ + public function getQueryTimes(): int + { + return $this->queryTimes; + } + + /** + * 监听SQL执行 + * @access public + * @param callable $callback 回调方法 + * @return void + */ + public function listen(callable $callback): void + { + $this->listen[] = $callback; + } + + /** + * 获取监听SQL执行 + * @access public + * @return array + */ + public function getListen(): array + { + return $this->listen; + } + + /** + * 注册回调方法 + * @access public + * @param string $event 事件名 + * @param callable $callback 回调方法 + * @return void + */ + public function event(string $event, callable $callback): void + { + $this->event[$event][] = $callback; + } + + /** + * 触发事件 + * @access public + * @param string $event 事件名 + * @param mixed $params 传入参数 + * @return mixed + */ + public function trigger(string $event, $params = null) + { + if (isset($this->event[$event])) { + foreach ($this->event[$event] as $callback) { + call_user_func_array($callback, [$this]); + } + } + } + + public function __call($method, $args) + { + return call_user_func_array([$this->connect(), $method], $args); + } +} diff --git a/vendor/topthink/think-orm/src/Model.php b/vendor/topthink/think-orm/src/Model.php new file mode 100644 index 000000000..35c9b256d --- /dev/null +++ b/vendor/topthink/think-orm/src/Model.php @@ -0,0 +1,1068 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think; + +use ArrayAccess; +use Closure; +use JsonSerializable; +use think\contract\Arrayable; +use think\contract\Jsonable; +use think\db\BaseQuery as Query; + +/** + * Class Model + * @package think + * @mixin Query + * @method void onAfterRead(Model $model) static after_read事件定义 + * @method mixed onBeforeInsert(Model $model) static before_insert事件定义 + * @method void onAfterInsert(Model $model) static after_insert事件定义 + * @method mixed onBeforeUpdate(Model $model) static before_update事件定义 + * @method void onAfterUpdate(Model $model) static after_update事件定义 + * @method mixed onBeforeWrite(Model $model) static before_write事件定义 + * @method void onAfterWrite(Model $model) static after_write事件定义 + * @method mixed onBeforeDelete(Model $model) static before_write事件定义 + * @method void onAfterDelete(Model $model) static after_delete事件定义 + * @method void onBeforeRestore(Model $model) static before_restore事件定义 + * @method void onAfterRestore(Model $model) static after_restore事件定义 + */ +abstract class Model implements JsonSerializable, ArrayAccess, Arrayable, Jsonable +{ + use model\concern\Attribute; + use model\concern\RelationShip; + use model\concern\ModelEvent; + use model\concern\TimeStamp; + use model\concern\Conversion; + + /** + * 数据是否存在 + * @var bool + */ + private $exists = false; + + /** + * 是否强制更新所有数据 + * @var bool + */ + private $force = false; + + /** + * 是否Replace + * @var bool + */ + private $replace = false; + + /** + * 数据表后缀 + * @var string + */ + protected $suffix; + + /** + * 更新条件 + * @var array + */ + private $updateWhere; + + /** + * 数据库配置 + * @var string + */ + protected $connection; + + /** + * 模型名称 + * @var string + */ + protected $name; + + /** + * 主键值 + * @var string + */ + protected $key; + + /** + * 数据表名称 + * @var string + */ + protected $table; + + /** + * 初始化过的模型. + * @var array + */ + protected static $initialized = []; + + /** + * 软删除字段默认值 + * @var mixed + */ + protected $defaultSoftDelete; + + /** + * 全局查询范围 + * @var array + */ + protected $globalScope = []; + + /** + * 延迟保存信息 + * @var bool + */ + private $lazySave = false; + + /** + * Db对象 + * @var DbManager + */ + protected static $db; + + /** + * 容器对象的依赖注入方法 + * @var callable + */ + protected static $invoker; + + /** + * 服务注入 + * @var Closure[] + */ + protected static $maker = []; + + /** + * 方法注入 + * @var Closure[][] + */ + protected static $macro = []; + + /** + * 设置服务注入 + * @access public + * @param Closure $maker + * @return void + */ + public static function maker(Closure $maker) + { + static::$maker[] = $maker; + } + + /** + * 设置方法注入 + * @access public + * @param string $method + * @param Closure $closure + * @return void + */ + public static function macro(string $method, Closure $closure) + { + if (!isset(static::$macro[static::class])) { + static::$macro[static::class] = []; + } + static::$macro[static::class][$method] = $closure; + } + + /** + * 设置Db对象 + * @access public + * @param DbManager $db Db对象 + * @return void + */ + public static function setDb(DbManager $db) + { + self::$db = $db; + } + + /** + * 设置容器对象的依赖注入方法 + * @access public + * @param callable $callable 依赖注入方法 + * @return void + */ + public static function setInvoker(callable $callable): void + { + self::$invoker = $callable; + } + + /** + * 调用反射执行模型方法 支持参数绑定 + * @access public + * @param mixed $method + * @param array $vars 参数 + * @return mixed + */ + public function invoke($method, array $vars = []) + { + if (self::$invoker) { + $call = self::$invoker; + return $call($method instanceof Closure ? $method : Closure::fromCallable([$this, $method]), $vars); + } + + return call_user_func_array($method instanceof Closure ? $method : [$this, $method], $vars); + } + + /** + * 架构函数 + * @access public + * @param array $data 数据 + */ + public function __construct(array $data = []) + { + $this->data = $data; + + if (!empty($this->data)) { + // 废弃字段 + foreach ((array) $this->disuse as $key) { + if (array_key_exists($key, $this->data)) { + unset($this->data[$key]); + } + } + } + + // 记录原始数据 + $this->origin = $this->data; + + if (empty($this->name)) { + // 当前模型名 + $name = str_replace('\\', '/', static::class); + $this->name = basename($name); + } + + if (!empty(static::$maker)) { + foreach (static::$maker as $maker) { + call_user_func($maker, $this); + } + } + + // 执行初始化操作 + $this->initialize(); + } + + /** + * 获取当前模型名称 + * @access public + * @return string + */ + public function getName(): string + { + return $this->name; + } + + /** + * 创建新的模型实例 + * @access public + * @param array $data 数据 + * @param mixed $where 更新条件 + * @return Model + */ + public function newInstance(array $data = [], $where = null): Model + { + $model = new static($data); + + if ($this->connection) { + $model->setConnection($this->connection); + } + + if ($this->suffix) { + $model->setSuffix($this->suffix); + } + + if (empty($data)) { + return $model; + } + + $model->exists(true); + + $model->setUpdateWhere($where); + + $model->trigger('AfterRead'); + + return $model; + } + + /** + * 设置模型的更新条件 + * @access protected + * @param mixed $where 更新条件 + * @return void + */ + protected function setUpdateWhere($where): void + { + $this->updateWhere = $where; + } + + /** + * 设置当前模型的数据库连接 + * @access public + * @param string $connection 数据表连接标识 + * @return $this + */ + public function setConnection(string $connection) + { + $this->connection = $connection; + return $this; + } + + /** + * 获取当前模型的数据库连接标识 + * @access public + * @return string + */ + public function getConnection(): string + { + return $this->connection ?: ''; + } + + /** + * 设置当前模型数据表的后缀 + * @access public + * @param string $suffix 数据表后缀 + * @return $this + */ + public function setSuffix(string $suffix) + { + $this->suffix = $suffix; + return $this; + } + + /** + * 获取当前模型的数据表后缀 + * @access public + * @return string + */ + public function getSuffix(): string + { + return $this->suffix ?: ''; + } + + /** + * 获取当前模型的数据库查询对象 + * @access public + * @param array $scope 设置不使用的全局查询范围 + * @return Query + */ + public function db($scope = []): Query + { + /** @var Query $query */ + $query = self::$db->connect($this->connection) + ->name($this->name . $this->suffix) + ->pk($this->pk); + + if (!empty($this->table)) { + $query->table($this->table . $this->suffix); + } + + $query->model($this) + ->json($this->json, $this->jsonAssoc) + ->setFieldType(array_merge($this->schema, $this->jsonType)); + + // 软删除 + if (property_exists($this, 'withTrashed') && !$this->withTrashed) { + $this->withNoTrashed($query); + } + + // 全局作用域 + if (is_array($scope)) { + $globalScope = array_diff($this->globalScope, $scope); + $query->scope($globalScope); + } + + // 返回当前模型的数据库查询对象 + return $query; + } + + /** + * 初始化模型 + * @access private + * @return void + */ + private function initialize(): void + { + if (!isset(static::$initialized[static::class])) { + static::$initialized[static::class] = true; + static::init(); + } + } + + /** + * 初始化处理 + * @access protected + * @return void + */ + protected static function init() + { + } + + protected function checkData(): void + { + } + + protected function checkResult($result): void + { + } + + /** + * 更新是否强制写入数据 而不做比较(亦可用于软删除的强制删除) + * @access public + * @param bool $force + * @return $this + */ + public function force(bool $force = true) + { + $this->force = $force; + return $this; + } + + /** + * 判断force + * @access public + * @return bool + */ + public function isForce(): bool + { + return $this->force; + } + + /** + * 新增数据是否使用Replace + * @access public + * @param bool $replace + * @return $this + */ + public function replace(bool $replace = true) + { + $this->replace = $replace; + return $this; + } + + /** + * 刷新模型数据 + * @access public + * @param bool $relation 是否刷新关联数据 + * @return $this + */ + public function refresh(bool $relation = false) + { + if ($this->exists) { + $this->data = $this->db()->find($this->getKey())->getData(); + $this->origin = $this->data; + $this->get = []; + + if ($relation) { + $this->relation = []; + } + } + + return $this; + } + + /** + * 设置数据是否存在 + * @access public + * @param bool $exists + * @return $this + */ + public function exists(bool $exists = true) + { + $this->exists = $exists; + return $this; + } + + /** + * 判断数据是否存在数据库 + * @access public + * @return bool + */ + public function isExists(): bool + { + return $this->exists; + } + + /** + * 判断模型是否为空 + * @access public + * @return bool + */ + public function isEmpty(): bool + { + return empty($this->data); + } + + /** + * 延迟保存当前数据对象 + * @access public + * @param array|bool $data 数据 + * @return void + */ + public function lazySave($data = []): void + { + if (false === $data) { + $this->lazySave = false; + } else { + if (is_array($data)) { + $this->setAttrs($data); + } + + $this->lazySave = true; + } + } + + /** + * 保存当前数据对象 + * @access public + * @param array $data 数据 + * @param string $sequence 自增序列名 + * @return bool + */ + public function save(array $data = [], string $sequence = null): bool + { + // 数据对象赋值 + $this->setAttrs($data); + + if ($this->isEmpty() || false === $this->trigger('BeforeWrite')) { + return false; + } + + $result = $this->exists ? $this->updateData() : $this->insertData($sequence); + + if (false === $result) { + return false; + } + + // 写入回调 + $this->trigger('AfterWrite'); + + // 重新记录原始数据 + $this->origin = $this->data; + $this->get = []; + $this->lazySave = false; + + return true; + } + + /** + * 检查数据是否允许写入 + * @access protected + * @return array + */ + protected function checkAllowFields(): array + { + // 检测字段 + if (empty($this->field)) { + if (!empty($this->schema)) { + $this->field = array_keys(array_merge($this->schema, $this->jsonType)); + } else { + $query = $this->db(); + $table = $this->table ? $this->table . $this->suffix : $query->getTable(); + + $this->field = $query->getConnection()->getTableFields($table); + } + + return $this->field; + } + + $field = $this->field; + + if ($this->autoWriteTimestamp) { + array_push($field, $this->createTime, $this->updateTime); + } + + if (!empty($this->disuse)) { + // 废弃字段 + $field = array_diff($field, $this->disuse); + } + + return $field; + } + + /** + * 保存写入数据 + * @access protected + * @return bool + */ + protected function updateData(): bool + { + // 事件回调 + if (false === $this->trigger('BeforeUpdate')) { + return false; + } + + $this->checkData(); + + // 获取有更新的数据 + $data = $this->getChangedData(); + + if (empty($data)) { + // 关联更新 + if (!empty($this->relationWrite)) { + $this->autoRelationUpdate(); + } + + return true; + } + + if ($this->autoWriteTimestamp && $this->updateTime) { + // 自动写入更新时间 + $data[$this->updateTime] = $this->autoWriteTimestamp(); + $this->data[$this->updateTime] = $this->getTimestampValue($data[$this->updateTime]); + } + + // 检查允许字段 + $allowFields = $this->checkAllowFields(); + + foreach ($this->relationWrite as $name => $val) { + if (!is_array($val)) { + continue; + } + + foreach ($val as $key) { + if (isset($data[$key])) { + unset($data[$key]); + } + } + } + + // 模型更新 + $db = $this->db(); + + $db->transaction(function () use ($data, $allowFields, $db) { + $this->key = null; + $where = $this->getWhere(); + + $result = $db->where($where) + ->strict(false) + ->cache(true) + ->setOption('key', $this->key) + ->field($allowFields) + ->update($data); + + $this->checkResult($result); + + // 关联更新 + if (!empty($this->relationWrite)) { + $this->autoRelationUpdate(); + } + }); + + // 更新回调 + $this->trigger('AfterUpdate'); + + return true; + } + + /** + * 新增写入数据 + * @access protected + * @param string $sequence 自增名 + * @return bool + */ + protected function insertData(string $sequence = null): bool + { + if (false === $this->trigger('BeforeInsert')) { + return false; + } + + $this->checkData(); + $data = $this->data; + + // 时间戳自动写入 + if ($this->autoWriteTimestamp) { + if ($this->createTime && !isset($data[$this->createTime])) { + $data[$this->createTime] = $this->autoWriteTimestamp(); + $this->data[$this->createTime] = $this->getTimestampValue($data[$this->createTime]); + } + + if ($this->updateTime && !isset($data[$this->updateTime])) { + $data[$this->updateTime] = $this->autoWriteTimestamp(); + $this->data[$this->updateTime] = $this->getTimestampValue($data[$this->updateTime]); + } + } + + // 检查允许字段 + $allowFields = $this->checkAllowFields(); + + $db = $this->db(); + + $db->transaction(function () use ($data, $sequence, $allowFields, $db) { + $result = $db->strict(false) + ->field($allowFields) + ->replace($this->replace) + ->sequence($sequence) + ->insert($data, true); + + // 获取自动增长主键 + if ($result) { + $pk = $this->getPk(); + + if (is_string($pk) && (!isset($this->data[$pk]) || '' == $this->data[$pk])) { + unset($this->get[$pk]); + $this->data[$pk] = $result; + } + } + + // 关联写入 + if (!empty($this->relationWrite)) { + $this->autoRelationInsert(); + } + }); + + // 标记数据已经存在 + $this->exists = true; + $this->origin = $this->data; + + // 新增回调 + $this->trigger('AfterInsert'); + + return true; + } + + /** + * 获取当前的更新条件 + * @access public + * @return mixed + */ + public function getWhere() + { + $pk = $this->getPk(); + + if (is_string($pk) && isset($this->origin[$pk])) { + $where = [[$pk, '=', $this->origin[$pk]]]; + $this->key = $this->origin[$pk]; + } elseif (is_array($pk)) { + foreach ($pk as $field) { + if (isset($this->origin[$field])) { + $where[] = [$field, '=', $this->origin[$field]]; + } + } + } + + if (empty($where)) { + $where = empty($this->updateWhere) ? null : $this->updateWhere; + } + + return $where; + } + + /** + * 保存多个数据到当前数据对象 + * @access public + * @param iterable $dataSet 数据 + * @param boolean $replace 是否自动识别更新和写入 + * @return Collection + * @throws \Exception + */ + public function saveAll(iterable $dataSet, bool $replace = true): Collection + { + $db = $this->db(); + + $result = $db->transaction(function () use ($replace, $dataSet) { + + $pk = $this->getPk(); + + if (is_string($pk) && $replace) { + $auto = true; + } + + $result = []; + + $suffix = $this->getSuffix(); + + foreach ($dataSet as $key => $data) { + if ($this->exists || (!empty($auto) && isset($data[$pk]))) { + $result[$key] = static::update($data, [], [], $suffix); + } else { + $result[$key] = static::create($data, $this->field, $this->replace, $suffix); + } + } + + return $result; + }); + + return $this->toCollection($result); + } + + /** + * 删除当前的记录 + * @access public + * @return bool + */ + public function delete(): bool + { + if (!$this->exists || $this->isEmpty() || false === $this->trigger('BeforeDelete')) { + return false; + } + + // 读取更新条件 + $where = $this->getWhere(); + + $db = $this->db(); + + $db->transaction(function () use ($where, $db) { + // 删除当前模型数据 + $db->where($where)->delete(); + + // 关联删除 + if (!empty($this->relationWrite)) { + $this->autoRelationDelete(); + } + }); + + $this->trigger('AfterDelete'); + + $this->exists = false; + $this->lazySave = false; + + return true; + } + + /** + * 写入数据 + * @access public + * @param array $data 数据数组 + * @param array $allowField 允许字段 + * @param bool $replace 使用Replace + * @param string $suffix 数据表后缀 + * @return static + */ + public static function create(array $data, array $allowField = [], bool $replace = false, string $suffix = ''): Model + { + $model = new static(); + + if (!empty($allowField)) { + $model->allowField($allowField); + } + + if (!empty($suffix)) { + $model->setSuffix($suffix); + } + + $model->replace($replace)->save($data); + + return $model; + } + + /** + * 更新数据 + * @access public + * @param array $data 数据数组 + * @param mixed $where 更新条件 + * @param array $allowField 允许字段 + * @param string $suffix 数据表后缀 + * @return static + */ + public static function update(array $data, $where = [], array $allowField = [], string $suffix = '') + { + $model = new static(); + + if (!empty($allowField)) { + $model->allowField($allowField); + } + + if (!empty($where)) { + $model->setUpdateWhere($where); + } + + if (!empty($suffix)) { + $model->setSuffix($suffix); + } + + $model->exists(true)->save($data); + + return $model; + } + + /** + * 删除记录 + * @access public + * @param mixed $data 主键列表 支持闭包查询条件 + * @param bool $force 是否强制删除 + * @return bool + */ + public static function destroy($data, bool $force = false): bool + { + if (empty($data) && 0 !== $data) { + return false; + } + + $model = new static(); + + $query = $model->db(); + + if (is_array($data) && key($data) !== 0) { + $query->where($data); + $data = null; + } elseif ($data instanceof \Closure) { + $data($query); + $data = null; + } + + $resultSet = $query->select($data); + + foreach ($resultSet as $result) { + $result->force($force)->delete(); + } + + return true; + } + + /** + * 解序列化后处理 + */ + public function __wakeup() + { + $this->initialize(); + } + + /** + * 修改器 设置数据对象的值 + * @access public + * @param string $name 名称 + * @param mixed $value 值 + * @return void + */ + public function __set(string $name, $value): void + { + $this->setAttr($name, $value); + } + + /** + * 获取器 获取数据对象的值 + * @access public + * @param string $name 名称 + * @return mixed + */ + public function __get(string $name) + { + return $this->getAttr($name); + } + + /** + * 检测数据对象的值 + * @access public + * @param string $name 名称 + * @return bool + */ + public function __isset(string $name): bool + { + return !is_null($this->getAttr($name)); + } + + /** + * 销毁数据对象的值 + * @access public + * @param string $name 名称 + * @return void + */ + public function __unset(string $name): void + { + unset($this->data[$name], + $this->get[$name], + $this->relation[$name]); + } + + // ArrayAccess + public function offsetSet($name, $value) + { + $this->setAttr($name, $value); + } + + public function offsetExists($name): bool + { + return $this->__isset($name); + } + + public function offsetUnset($name) + { + $this->__unset($name); + } + + public function offsetGet($name) + { + return $this->getAttr($name); + } + + /** + * 设置不使用的全局查询范围 + * @access public + * @param array $scope 不启用的全局查询范围 + * @return Query + */ + public static function withoutGlobalScope(array $scope = null) + { + $model = new static(); + + return $model->db($scope); + } + + /** + * 切换后缀进行查询 + * @access public + * @param string $suffix 切换的表后缀 + * @return Model + */ + public static function suffix(string $suffix) + { + $model = new static(); + $model->setSuffix($suffix); + + return $model; + } + + /** + * 切换数据库连接进行查询 + * @access public + * @param string $connection 数据库连接标识 + * @return Model + */ + public static function connect(string $connection) + { + $model = new static(); + $model->setConnection($connection); + + return $model; + } + + public function __call($method, $args) + { + if (isset(static::$macro[static::class][$method])) { + return call_user_func_array(static::$macro[static::class][$method]->bindTo($this, static::class), $args); + } + + if ('withattr' == strtolower($method)) { + return call_user_func_array([$this, 'withAttribute'], $args); + } + + return call_user_func_array([$this->db(), $method], $args); + } + + public static function __callStatic($method, $args) + { + if (isset(static::$macro[static::class][$method])) { + return call_user_func_array(static::$macro[static::class][$method]->bindTo(null, static::class), $args); + } + + $model = new static(); + + return call_user_func_array([$model->db(), $method], $args); + } + + /** + * 析构方法 + * @access public + */ + public function __destruct() + { + if ($this->lazySave) { + $this->save(); + } + } +} diff --git a/thinkphp/library/think/Paginator.php b/vendor/topthink/think-orm/src/Paginator.php old mode 100755 new mode 100644 similarity index 65% rename from thinkphp/library/think/Paginator.php rename to vendor/topthink/think-orm/src/Paginator.php index bbe63e2e3..f5d800682 --- a/thinkphp/library/think/Paginator.php +++ b/vendor/topthink/think-orm/src/Paginator.php @@ -2,22 +2,30 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: zhangyajun <448901948@qq.com> // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think; use ArrayAccess; use ArrayIterator; +use Closure; use Countable; +use DomainException; use IteratorAggregate; use JsonSerializable; +use think\paginator\driver\Bootstrap; use Traversable; +/** + * 分页基础类 + * @mixin Collection + */ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable { /** @@ -34,13 +42,13 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J /** * 当前页 - * @var integer + * @var int */ protected $currentPage; /** * 最后一页 - * @var integer + * @var int */ protected $lastPage; @@ -52,7 +60,7 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J /** * 每页数量 - * @var integer + * @var int */ protected $listRows; @@ -73,7 +81,24 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J 'fragment' => '', ]; - public function __construct($items, $listRows, $currentPage = null, $total = null, $simple = false, $options = []) + /** + * 获取当前页码 + * @var Closure + */ + protected static $currentPageResolver; + + /** + * 获取当前路径 + * @var Closure + */ + protected static $currentPathResolver; + + /** + * @var Closure + */ + protected static $maker; + + public function __construct($items, int $listRows, int $currentPage = 1, int $total = null, bool $simple = false, array $options = []) { $this->options = array_merge($this->options, $options); @@ -101,20 +126,29 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J /** * @access public - * @param $items - * @param $listRows - * @param null $currentPage - * @param null $total + * @param mixed $items + * @param int $listRows + * @param int $currentPage + * @param int $total * @param bool $simple * @param array $options * @return Paginator */ - public static function make($items, $listRows, $currentPage = null, $total = null, $simple = false, $options = []) + public static function make($items, int $listRows, int $currentPage = 1, int $total = null, bool $simple = false, array $options = []) { - return new static($items, $listRows, $currentPage, $total, $simple, $options); + if (isset(static::$maker)) { + return call_user_func(static::$maker, $items, $listRows, $currentPage, $total, $simple, $options); + } + + return new Bootstrap($items, $listRows, $currentPage, $total, $simple, $options); } - protected function setCurrentPage($currentPage) + public static function maker(Closure $resolver) + { + static::$maker = $resolver; + } + + protected function setCurrentPage(int $currentPage): int { if (!$this->simple && $currentPage > $this->lastPage) { return $this->lastPage > 0 ? $this->lastPage : 1; @@ -127,10 +161,10 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J * 获取页码对应的链接 * * @access protected - * @param $page + * @param int $page * @return string */ - protected function url($page) + protected function url(int $page): string { if ($page <= 0) { $page = 1; @@ -150,7 +184,7 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J $url = $path; if (!empty($parameters)) { - $url .= '?' . http_build_query($parameters, null, '&'); + $url .= '?' . http_build_query($parameters, '', '&'); } return $url . $this->buildFragment(); @@ -159,54 +193,91 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J /** * 自动获取当前页码 * @access public - * @param string $varPage - * @param int $default + * @param string $varPage + * @param int $default * @return int */ - public static function getCurrentPage($varPage = 'page', $default = 1) + public static function getCurrentPage(string $varPage = 'page', int $default = 1): int { - $page = Container::get('request')->param($varPage); - - if (filter_var($page, FILTER_VALIDATE_INT) !== false && (int) $page >= 1) { - return $page; + if (isset(static::$currentPageResolver)) { + return call_user_func(static::$currentPageResolver, $varPage); } return $default; } /** - * 自动获取当前的path - * @access public - * @return string + * 设置获取当前页码闭包 + * @param Closure $resolver */ - public static function getCurrentPath() + public static function currentPageResolver(Closure $resolver) { - return Container::get('request')->baseUrl(); + static::$currentPageResolver = $resolver; } - public function total() + /** + * 自动获取当前的path + * @access public + * @param string $default + * @return string + */ + public static function getCurrentPath($default = '/'): string + { + if (isset(static::$currentPathResolver)) { + return call_user_func(static::$currentPathResolver); + } + + return $default; + } + + /** + * 设置获取当前路径闭包 + * @param Closure $resolver + */ + public static function currentPathResolver(Closure $resolver) + { + static::$currentPathResolver = $resolver; + } + + /** + * 获取数据总条数 + * @return int + */ + public function total(): int { if ($this->simple) { - throw new \DomainException('not support total'); + throw new DomainException('not support total'); } return $this->total; } - public function listRows() + /** + * 获取每页数量 + * @return int + */ + public function listRows(): int { return $this->listRows; } - public function currentPage() + /** + * 获取当前页页码 + * @return int + */ + public function currentPage(): int { return $this->currentPage; } - public function lastPage() + /** + * 获取最后一页页码 + * @return int + */ + public function lastPage(): int { if ($this->simple) { - throw new \DomainException('not support last'); + throw new DomainException('not support last'); } return $this->lastPage; @@ -215,9 +286,9 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J /** * 数据是否足够分页 * @access public - * @return boolean + * @return bool */ - public function hasPages() + public function hasPages(): bool { return !(1 == $this->currentPage && !$this->hasMore); } @@ -226,11 +297,11 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J * 创建一组分页链接 * * @access public - * @param int $start - * @param int $end + * @param int $start + * @param int $end * @return array */ - public function getUrlRange($start, $end) + public function getUrlRange(int $start, int $end): array { $urls = []; @@ -245,10 +316,10 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J * 设置URL锚点 * * @access public - * @param string|null $fragment + * @param string|null $fragment * @return $this */ - public function fragment($fragment) + public function fragment(string $fragment = null) { $this->options['fragment'] = $fragment; @@ -259,19 +330,12 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J * 添加URL参数 * * @access public - * @param array|string $key - * @param string|null $value + * @param array $append * @return $this */ - public function appends($key, $value = null) + public function appends(array $append) { - if (!is_array($key)) { - $queries = [$key => $value]; - } else { - $queries = $key; - } - - foreach ($queries as $k => $v) { + foreach ($append as $k => $v) { if ($k !== $this->options['var_page']) { $this->options['query'][$k] = $v; } @@ -286,7 +350,7 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J * @access public * @return string */ - protected function buildFragment() + protected function buildFragment(): string { return $this->options['fragment'] ? '#' . $this->options['fragment'] : ''; } @@ -303,12 +367,17 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J return $this->items->all(); } + /** + * 获取数据集 + * + * @return Collection|\think\model\Collection + */ public function getCollection() { return $this->items; } - public function isEmpty() + public function isEmpty(): bool { return $this->items->isEmpty(); } @@ -317,7 +386,7 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J * 给每个元素执行个回调 * * @access public - * @param callable $callback + * @param callable $callback * @return $this */ public function each(callable $callback) @@ -349,7 +418,7 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J /** * Whether a offset exists * @access public - * @param mixed $offset + * @param mixed $offset * @return bool */ public function offsetExists($offset) @@ -360,7 +429,7 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J /** * Offset to retrieve * @access public - * @param mixed $offset + * @param mixed $offset * @return mixed */ public function offsetGet($offset) @@ -371,8 +440,8 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J /** * Offset to set * @access public - * @param mixed $offset - * @param mixed $value + * @param mixed $offset + * @param mixed $value */ public function offsetSet($offset, $value) { @@ -382,7 +451,7 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J /** * Offset to unset * @access public - * @param mixed $offset + * @param mixed $offset * @return void * @since 5.0.0 */ @@ -392,9 +461,10 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J } /** - * Count elements of an object + * 统计数据集条数 + * @return int */ - public function count() + public function count(): int { return $this->items->count(); } @@ -404,11 +474,15 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J return (string) $this->render(); } - public function toArray() + /** + * 转换为数组 + * @return array + */ + public function toArray(): array { try { $total = $this->total(); - } catch (\DomainException $e) { + } catch (DomainException $e) { $total = null; } @@ -431,11 +505,10 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J public function __call($name, $arguments) { - $collection = $this->getCollection(); + $result = call_user_func_array([$this->items, $name], $arguments); - $result = call_user_func_array([$collection, $name], $arguments); - - if ($result === $collection) { + if ($result instanceof Collection) { + $this->items = $result; return $this; } diff --git a/vendor/topthink/think-orm/src/db/BaseQuery.php b/vendor/topthink/think-orm/src/db/BaseQuery.php new file mode 100644 index 000000000..4e9a20daa --- /dev/null +++ b/vendor/topthink/think-orm/src/db/BaseQuery.php @@ -0,0 +1,1278 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\db; + +use think\Collection; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException as Exception; +use think\db\exception\ModelNotFoundException; +use think\helper\Str; +use think\Model; +use think\Paginator; + +/** + * 数据查询基础类 + */ +abstract class BaseQuery +{ + use concern\TimeFieldQuery; + use concern\AggregateQuery; + use concern\ModelRelationQuery; + use concern\ResultOperation; + use concern\Transaction; + use concern\WhereQuery; + + /** + * 当前数据库连接对象 + * @var Connection + */ + protected $connection; + + /** + * 当前数据表名称(不含前缀) + * @var string + */ + protected $name = ''; + + /** + * 当前数据表主键 + * @var string|array + */ + protected $pk; + + /** + * 当前数据表自增主键 + * @var string + */ + protected $autoinc; + + /** + * 当前数据表前缀 + * @var string + */ + protected $prefix = ''; + + /** + * 当前查询参数 + * @var array + */ + protected $options = []; + + /** + * 架构函数 + * @access public + * @param ConnectionInterface $connection 数据库连接对象 + */ + public function __construct(ConnectionInterface $connection) + { + $this->connection = $connection; + + $this->prefix = $this->connection->getConfig('prefix'); + } + + /** + * 利用__call方法实现一些特殊的Model方法 + * @access public + * @param string $method 方法名称 + * @param array $args 调用参数 + * @return mixed + * @throws Exception + */ + public function __call(string $method, array $args) + { + if (strtolower(substr($method, 0, 5)) == 'getby') { + // 根据某个字段获取记录 + $field = Str::snake(substr($method, 5)); + return $this->where($field, '=', $args[0])->find(); + } elseif (strtolower(substr($method, 0, 10)) == 'getfieldby') { + // 根据某个字段获取记录的某个值 + $name = Str::snake(substr($method, 10)); + return $this->where($name, '=', $args[0])->value($args[1]); + } elseif (strtolower(substr($method, 0, 7)) == 'whereor') { + $name = Str::snake(substr($method, 7)); + array_unshift($args, $name); + return call_user_func_array([$this, 'whereOr'], $args); + } elseif (strtolower(substr($method, 0, 5)) == 'where') { + $name = Str::snake(substr($method, 5)); + array_unshift($args, $name); + return call_user_func_array([$this, 'where'], $args); + } elseif ($this->model && method_exists($this->model, 'scope' . $method)) { + // 动态调用命名范围 + $method = 'scope' . $method; + array_unshift($args, $this); + + call_user_func_array([$this->model, $method], $args); + return $this; + } else { + throw new Exception('method not exist:' . static::class . '->' . $method); + } + } + + /** + * 创建一个新的查询对象 + * @access public + * @return BaseQuery + */ + public function newQuery(): BaseQuery + { + $query = new static($this->connection); + + if ($this->model) { + $query->model($this->model); + } + + if (isset($this->options['table'])) { + $query->table($this->options['table']); + } else { + $query->name($this->name); + } + + if (isset($this->options['json'])) { + $query->json($this->options['json'], $this->options['json_assoc']); + } + + if (isset($this->options['field_type'])) { + $query->setFieldType($this->options['field_type']); + } + + return $query; + } + + /** + * 获取当前的数据库Connection对象 + * @access public + * @return ConnectionInterface + */ + public function getConnection() + { + return $this->connection; + } + + /** + * 指定当前数据表名(不含前缀) + * @access public + * @param string $name 不含前缀的数据表名字 + * @return $this + */ + public function name(string $name) + { + $this->name = $name; + return $this; + } + + /** + * 获取当前的数据表名称 + * @access public + * @return string + */ + public function getName(): string + { + return $this->name ?: $this->model->getName(); + } + + /** + * 获取数据库的配置参数 + * @access public + * @param string $name 参数名称 + * @return mixed + */ + public function getConfig(string $name = '') + { + return $this->connection->getConfig($name); + } + + /** + * 得到当前或者指定名称的数据表 + * @access public + * @param string $name 不含前缀的数据表名字 + * @return mixed + */ + public function getTable(string $name = '') + { + if (empty($name) && isset($this->options['table'])) { + return $this->options['table']; + } + + $name = $name ?: $this->name; + + return $this->prefix . Str::snake($name); + } + + /** + * 设置字段类型信息 + * @access public + * @param array $type 字段类型信息 + * @return $this + */ + public function setFieldType(array $type) + { + $this->options['field_type'] = $type; + return $this; + } + + /** + * 获取最近一次查询的sql语句 + * @access public + * @return string + */ + public function getLastSql(): string + { + return $this->connection->getLastSql(); + } + + /** + * 获取返回或者影响的记录数 + * @access public + * @return integer + */ + public function getNumRows(): int + { + return $this->connection->getNumRows(); + } + + /** + * 获取最近插入的ID + * @access public + * @param string $sequence 自增序列名 + * @return mixed + */ + public function getLastInsID(string $sequence = null) + { + return $this->connection->getLastInsID($this, $sequence); + } + + /** + * 得到某个字段的值 + * @access public + * @param string $field 字段名 + * @param mixed $default 默认值 + * @return mixed + */ + public function value(string $field, $default = null) + { + return $this->connection->value($this, $field, $default); + } + + /** + * 得到某个列的数组 + * @access public + * @param string|array $field 字段名 多个字段用逗号分隔 + * @param string $key 索引 + * @return array + */ + public function column($field, string $key = ''): array + { + return $this->connection->column($this, $field, $key); + } + + /** + * 查询SQL组装 union + * @access public + * @param mixed $union UNION + * @param boolean $all 是否适用UNION ALL + * @return $this + */ + public function union($union, bool $all = false) + { + $this->options['union']['type'] = $all ? 'UNION ALL' : 'UNION'; + + if (is_array($union)) { + $this->options['union'] = array_merge($this->options['union'], $union); + } else { + $this->options['union'][] = $union; + } + + return $this; + } + + /** + * 查询SQL组装 union all + * @access public + * @param mixed $union UNION数据 + * @return $this + */ + public function unionAll($union) + { + return $this->union($union, true); + } + + /** + * 指定查询字段 + * @access public + * @param mixed $field 字段信息 + * @return $this + */ + public function field($field) + { + if (empty($field)) { + return $this; + } elseif ($field instanceof Raw) { + $this->options['field'][] = $field; + return $this; + } + + if (is_string($field)) { + if (preg_match('/[\<\'\"\(]/', $field)) { + return $this->fieldRaw($field); + } + + $field = array_map('trim', explode(',', $field)); + } + + if (true === $field) { + // 获取全部字段 + $fields = $this->getTableFields(); + $field = $fields ?: ['*']; + } + + if (isset($this->options['field'])) { + $field = array_merge((array) $this->options['field'], $field); + } + + $this->options['field'] = array_unique($field); + + return $this; + } + + /** + * 指定要排除的查询字段 + * @access public + * @param array|string $field 要排除的字段 + * @return $this + */ + public function withoutField($field) + { + if (empty($field)) { + return $this; + } + + if (is_string($field)) { + $field = array_map('trim', explode(',', $field)); + } + + // 字段排除 + $fields = $this->getTableFields(); + $field = $fields ? array_diff($fields, $field) : $field; + + if (isset($this->options['field'])) { + $field = array_merge((array) $this->options['field'], $field); + } + + $this->options['field'] = array_unique($field); + + return $this; + } + + /** + * 指定其它数据表的查询字段 + * @access public + * @param mixed $field 字段信息 + * @param string $tableName 数据表名 + * @param string $prefix 字段前缀 + * @param string $alias 别名前缀 + * @return $this + */ + public function tableField($field, string $tableName, string $prefix = '', string $alias = '') + { + if (empty($field)) { + return $this; + } + + if (is_string($field)) { + $field = array_map('trim', explode(',', $field)); + } + + if (true === $field) { + // 获取全部字段 + $fields = $this->getTableFields($tableName); + $field = $fields ?: ['*']; + } + + // 添加统一的前缀 + $prefix = $prefix ?: $tableName; + foreach ($field as $key => &$val) { + if (is_numeric($key) && $alias) { + $field[$prefix . '.' . $val] = $alias . $val; + unset($field[$key]); + } elseif (is_numeric($key)) { + $val = $prefix . '.' . $val; + } + } + + if (isset($this->options['field'])) { + $field = array_merge((array) $this->options['field'], $field); + } + + $this->options['field'] = array_unique($field); + + return $this; + } + + /** + * 设置数据 + * @access public + * @param array $data 数据 + * @return $this + */ + public function data(array $data) + { + $this->options['data'] = $data; + + return $this; + } + + /** + * 去除查询参数 + * @access public + * @param string $option 参数名 留空去除所有参数 + * @return $this + */ + public function removeOption(string $option = '') + { + if ('' === $option) { + $this->options = []; + $this->bind = []; + } elseif (isset($this->options[$option])) { + unset($this->options[$option]); + } + + return $this; + } + + /** + * 指定查询数量 + * @access public + * @param int $offset 起始位置 + * @param int $length 查询数量 + * @return $this + */ + public function limit(int $offset, int $length = null) + { + $this->options['limit'] = $offset . ($length ? ',' . $length : ''); + + return $this; + } + + /** + * 指定分页 + * @access public + * @param int $page 页数 + * @param int $listRows 每页数量 + * @return $this + */ + public function page(int $page, int $listRows = null) + { + $this->options['page'] = [$page, $listRows]; + + return $this; + } + + /** + * 指定当前操作的数据表 + * @access public + * @param mixed $table 表名 + * @return $this + */ + public function table($table) + { + if (is_string($table)) { + if (strpos($table, ')')) { + // 子查询 + } elseif (false === strpos($table, ',')) { + if (strpos($table, ' ')) { + [$item, $alias] = explode(' ', $table); + $table = []; + $this->alias([$item => $alias]); + $table[$item] = $alias; + } + } else { + $tables = explode(',', $table); + $table = []; + + foreach ($tables as $item) { + $item = trim($item); + if (strpos($item, ' ')) { + [$item, $alias] = explode(' ', $item); + $this->alias([$item => $alias]); + $table[$item] = $alias; + } else { + $table[] = $item; + } + } + } + } elseif (is_array($table)) { + $tables = $table; + $table = []; + + foreach ($tables as $key => $val) { + if (is_numeric($key)) { + $table[] = $val; + } else { + $this->alias([$key => $val]); + $table[$key] = $val; + } + } + } + + $this->options['table'] = $table; + + return $this; + } + + /** + * 指定排序 order('id','desc') 或者 order(['id'=>'desc','create_time'=>'desc']) + * @access public + * @param string|array|Raw $field 排序字段 + * @param string $order 排序 + * @return $this + */ + public function order($field, string $order = '') + { + if (empty($field)) { + return $this; + } elseif ($field instanceof Raw) { + $this->options['order'][] = $field; + return $this; + } + + if (is_string($field)) { + if (!empty($this->options['via'])) { + $field = $this->options['via'] . '.' . $field; + } + if (strpos($field, ',')) { + $field = array_map('trim', explode(',', $field)); + } else { + $field = empty($order) ? $field : [$field => $order]; + } + } elseif (!empty($this->options['via'])) { + foreach ($field as $key => $val) { + if (is_numeric($key)) { + $field[$key] = $this->options['via'] . '.' . $val; + } else { + $field[$this->options['via'] . '.' . $key] = $val; + unset($field[$key]); + } + } + } + + if (!isset($this->options['order'])) { + $this->options['order'] = []; + } + + if (is_array($field)) { + $this->options['order'] = array_merge($this->options['order'], $field); + } else { + $this->options['order'][] = $field; + } + + return $this; + } + + /** + * 分页查询 + * @access public + * @param int|array $listRows 每页数量 数组表示配置参数 + * @param int|bool $simple 是否简洁模式或者总记录数 + * @return Paginator + * @throws Exception + */ + public function paginate($listRows = null, $simple = false): Paginator + { + if (is_int($simple)) { + $total = $simple; + $simple = false; + } + + $defaultConfig = [ + 'query' => [], //url额外参数 + 'fragment' => '', //url锚点 + 'var_page' => 'page', //分页变量 + 'list_rows' => 15, //每页数量 + ]; + + if (is_array($listRows)) { + $config = array_merge($defaultConfig, $listRows); + $listRows = intval($config['list_rows']); + } else { + $config = $defaultConfig; + $listRows = intval($listRows ?: $config['list_rows']); + } + + $page = isset($config['page']) ? (int) $config['page'] : Paginator::getCurrentPage($config['var_page']); + + $page = $page < 1 ? 1 : $page; + + $config['path'] = $config['path'] ?? Paginator::getCurrentPath(); + + if (!isset($total) && !$simple) { + $options = $this->getOptions(); + + unset($this->options['order'], $this->options['limit'], $this->options['page'], $this->options['field']); + + $bind = $this->bind; + $total = $this->count(); + $results = $this->options($options)->bind($bind)->page($page, $listRows)->select(); + } elseif ($simple) { + $results = $this->limit(($page - 1) * $listRows, $listRows + 1)->select(); + $total = null; + } else { + $results = $this->page($page, $listRows)->select(); + } + + $this->removeOption('limit'); + $this->removeOption('page'); + + return Paginator::make($results, $listRows, $page, $total, $simple, $config); + } + + /** + * 根据数字类型字段进行分页查询(大数据) + * @access public + * @param int|array $listRows 每页数量或者分页配置 + * @param string $key 分页索引键 + * @param string $sort 索引键排序 asc|desc + * @return Paginator + * @throws Exception + */ + public function paginateX($listRows = null, string $key = null, string $sort = null): Paginator + { + $defaultConfig = [ + 'query' => [], //url额外参数 + 'fragment' => '', //url锚点 + 'var_page' => 'page', //分页变量 + 'list_rows' => 15, //每页数量 + ]; + + $config = is_array($listRows) ? array_merge($defaultConfig, $listRows) : $defaultConfig; + $listRows = is_int($listRows) ? $listRows : (int) $config['list_rows']; + $page = isset($config['page']) ? (int) $config['page'] : Paginator::getCurrentPage($config['var_page']); + $page = $page < 1 ? 1 : $page; + + $config['path'] = $config['path'] ?? Paginator::getCurrentPath(); + + $key = $key ?: $this->getPk(); + $options = $this->getOptions(); + + if (is_null($sort)) { + $order = $options['order'] ?? ''; + if (!empty($order)) { + $sort = $order[$key] ?? 'desc'; + } else { + $this->order($key, 'desc'); + $sort = 'desc'; + } + } else { + $this->order($key, $sort); + } + + $newOption = $options; + unset($newOption['field'], $newOption['page']); + + $data = $this->newQuery() + ->options($newOption) + ->field($key) + ->where(true) + ->order($key, $sort) + ->limit(1) + ->find(); + + $result = $data[$key]; + + if (is_numeric($result)) { + $lastId = 'asc' == $sort ? ($result - 1) + ($page - 1) * $listRows : ($result + 1) - ($page - 1) * $listRows; + } else { + throw new Exception('not support type'); + } + + $results = $this->when($lastId, function ($query) use ($key, $sort, $lastId) { + $query->where($key, 'asc' == $sort ? '>' : '<', $lastId); + }) + ->limit($listRows) + ->select(); + + $this->options($options); + + return Paginator::make($results, $listRows, $page, null, true, $config); + } + + /** + * 根据最后ID查询更多N个数据 + * @access public + * @param int $limit LIMIT + * @param int|string $lastId LastId + * @param string $key 分页索引键 默认为主键 + * @param string $sort 索引键排序 asc|desc + * @return array + * @throws Exception + */ + public function more(int $limit, $lastId = null, string $key = null, string $sort = null): array + { + $key = $key ?: $this->getPk(); + + if (is_null($sort)) { + $order = $this->getOptions('order'); + if (!empty($order)) { + $sort = $order[$key] ?? 'desc'; + } else { + $this->order($key, 'desc'); + $sort = 'desc'; + } + } else { + $this->order($key, $sort); + } + + $result = $this->when($lastId, function ($query) use ($key, $sort, $lastId) { + $query->where($key, 'asc' == $sort ? '>' : '<', $lastId); + })->limit($limit)->select(); + + $last = $result->last(); + + $result->first(); + + return [ + 'data' => $result, + 'lastId' => $last[$key], + ]; + } + + /** + * 查询缓存 + * @access public + * @param mixed $key 缓存key + * @param integer|\DateTime $expire 缓存有效期 + * @param string|array $tag 缓存标签 + * @return $this + */ + public function cache($key = true, $expire = null, $tag = null) + { + if (false === $key || !$this->getConnection()->getCache()) { + return $this; + } + + if ($key instanceof \DateTimeInterface || $key instanceof \DateInterval || (is_int($key) && is_null($expire))) { + $expire = $key; + $key = true; + } + + $this->options['cache'] = [$key, $expire, $tag]; + + return $this; + } + + /** + * 指定查询lock + * @access public + * @param bool|string $lock 是否lock + * @return $this + */ + public function lock($lock = false) + { + $this->options['lock'] = $lock; + + if ($lock) { + $this->options['master'] = true; + } + + return $this; + } + + /** + * 指定数据表别名 + * @access public + * @param array|string $alias 数据表别名 + * @return $this + */ + public function alias($alias) + { + if (is_array($alias)) { + $this->options['alias'] = $alias; + } else { + $table = $this->getTable(); + + $this->options['alias'][$table] = $alias; + } + + return $this; + } + + /** + * 设置从主服务器读取数据 + * @access public + * @param bool $readMaster 是否从主服务器读取 + * @return $this + */ + public function master(bool $readMaster = true) + { + $this->options['master'] = $readMaster; + return $this; + } + + /** + * 设置是否严格检查字段名 + * @access public + * @param bool $strict 是否严格检查字段 + * @return $this + */ + public function strict(bool $strict = true) + { + $this->options['strict'] = $strict; + return $this; + } + + /** + * 设置自增序列名 + * @access public + * @param string $sequence 自增序列名 + * @return $this + */ + public function sequence(string $sequence = null) + { + $this->options['sequence'] = $sequence; + return $this; + } + + /** + * 设置JSON字段信息 + * @access public + * @param array $json JSON字段 + * @param bool $assoc 是否取出数组 + * @return $this + */ + public function json(array $json = [], bool $assoc = false) + { + $this->options['json'] = $json; + $this->options['json_assoc'] = $assoc; + return $this; + } + + /** + * 指定数据表主键 + * @access public + * @param string|array $pk 主键 + * @return $this + */ + public function pk($pk) + { + $this->pk = $pk; + return $this; + } + + /** + * 查询参数批量赋值 + * @access protected + * @param array $options 表达式参数 + * @return $this + */ + protected function options(array $options) + { + $this->options = $options; + return $this; + } + + /** + * 获取当前的查询参数 + * @access public + * @param string $name 参数名 + * @return mixed + */ + public function getOptions(string $name = '') + { + if ('' === $name) { + return $this->options; + } + + return $this->options[$name] ?? null; + } + + /** + * 设置当前的查询参数 + * @access public + * @param string $option 参数名 + * @param mixed $value 参数值 + * @return $this + */ + public function setOption(string $option, $value) + { + $this->options[$option] = $value; + return $this; + } + + /** + * 设置当前字段添加的表别名 + * @access public + * @param string $via 临时表别名 + * @return $this + */ + public function via(string $via = '') + { + $this->options['via'] = $via; + + return $this; + } + + /** + * 保存记录 自动判断insert或者update + * @access public + * @param array $data 数据 + * @param bool $forceInsert 是否强制insert + * @return integer + */ + public function save(array $data = [], bool $forceInsert = false) + { + if ($forceInsert) { + return $this->insert($data); + } + + $this->options['data'] = array_merge($this->options['data'] ?? [], $data); + + if (!empty($this->options['where'])) { + $isUpdate = true; + } else { + $isUpdate = $this->parseUpdateData($this->options['data']); + } + + return $isUpdate ? $this->update() : $this->insert(); + } + + /** + * 插入记录 + * @access public + * @param array $data 数据 + * @param boolean $getLastInsID 返回自增主键 + * @return integer|string + */ + public function insert(array $data = [], bool $getLastInsID = false) + { + if (!empty($data)) { + $this->options['data'] = $data; + } + + return $this->connection->insert($this, $getLastInsID); + } + + /** + * 插入记录并获取自增ID + * @access public + * @param array $data 数据 + * @return integer|string + */ + public function insertGetId(array $data) + { + return $this->insert($data, true); + } + + /** + * 批量插入记录 + * @access public + * @param array $dataSet 数据集 + * @param integer $limit 每次写入数据限制 + * @return integer + */ + public function insertAll(array $dataSet = [], int $limit = 0): int + { + if (empty($dataSet)) { + $dataSet = $this->options['data'] ?? []; + } + + if (empty($limit) && !empty($this->options['limit']) && is_numeric($this->options['limit'])) { + $limit = (int) $this->options['limit']; + } + + return $this->connection->insertAll($this, $dataSet, $limit); + } + + /** + * 通过Select方式插入记录 + * @access public + * @param array $fields 要插入的数据表字段名 + * @param string $table 要插入的数据表名 + * @return integer + */ + public function selectInsert(array $fields, string $table): int + { + return $this->connection->selectInsert($this, $fields, $table); + } + + /** + * 更新记录 + * @access public + * @param mixed $data 数据 + * @return integer + * @throws Exception + */ + public function update(array $data = []): int + { + if (!empty($data)) { + $this->options['data'] = array_merge($this->options['data'] ?? [], $data); + } + + if (empty($this->options['where'])) { + $this->parseUpdateData($this->options['data']); + } + + if (empty($this->options['where']) && $this->model) { + $this->where($this->model->getWhere()); + } + + if (empty($this->options['where'])) { + // 如果没有任何更新条件则不执行 + throw new Exception('miss update condition'); + } + + return $this->connection->update($this); + } + + /** + * 删除记录 + * @access public + * @param mixed $data 表达式 true 表示强制删除 + * @return int + * @throws Exception + */ + public function delete($data = null): int + { + if (!is_null($data) && true !== $data) { + // AR模式分析主键条件 + $this->parsePkWhere($data); + } + + if (empty($this->options['where']) && $this->model) { + $this->where($this->model->getWhere()); + } + + if (true !== $data && empty($this->options['where'])) { + // 如果条件为空 不进行删除操作 除非设置 1=1 + throw new Exception('delete without condition'); + } + + if (!empty($this->options['soft_delete'])) { + // 软删除 + list($field, $condition) = $this->options['soft_delete']; + if ($condition) { + unset($this->options['soft_delete']); + $this->options['data'] = [$field => $condition]; + + return $this->connection->update($this); + } + } + + $this->options['data'] = $data; + + return $this->connection->delete($this); + } + + /** + * 查找记录 + * @access public + * @param mixed $data 数据 + * @return Collection + * @throws Exception + * @throws ModelNotFoundException + * @throws DataNotFoundException + */ + public function select($data = null): Collection + { + if (!is_null($data)) { + // 主键条件分析 + $this->parsePkWhere($data); + } + + $resultSet = $this->connection->select($this); + + // 返回结果处理 + if (!empty($this->options['fail']) && count($resultSet) == 0) { + $this->throwNotFound(); + } + + // 数据列表读取后的处理 + if (!empty($this->model)) { + // 生成模型对象 + $resultSet = $this->resultSetToModelCollection($resultSet); + } else { + $this->resultSet($resultSet); + } + + return $resultSet; + } + + /** + * 查找单条记录 + * @access public + * @param mixed $data 查询数据 + * @return array|Model|null + * @throws Exception + * @throws ModelNotFoundException + * @throws DataNotFoundException + */ + public function find($data = null) + { + if (!is_null($data)) { + // AR模式分析主键条件 + $this->parsePkWhere($data); + } + + if (empty($this->options['where']) && empty($this->options['order'])) { + $result = []; + } else { + $result = $this->connection->find($this); + } + + // 数据处理 + if (empty($result)) { + return $this->resultToEmpty(); + } + + if (!empty($this->model)) { + // 返回模型对象 + $this->resultToModel($result, $this->options); + } else { + $this->result($result); + } + + return $result; + } + + /** + * 分析表达式(可用于查询或者写入操作) + * @access public + * @return array + */ + public function parseOptions(): array + { + $options = $this->getOptions(); + + // 获取数据表 + if (empty($options['table'])) { + $options['table'] = $this->getTable(); + } + + if (!isset($options['where'])) { + $options['where'] = []; + } elseif (isset($options['view'])) { + // 视图查询条件处理 + $this->parseView($options); + } + + foreach (['data', 'order', 'join', 'union'] as $name) { + if (!isset($options[$name])) { + $options[$name] = []; + } + } + + if (!isset($options['strict'])) { + $options['strict'] = $this->connection->getConfig('fields_strict'); + } + + foreach (['master', 'lock', 'fetch_sql', 'array', 'distinct', 'procedure'] as $name) { + if (!isset($options[$name])) { + $options[$name] = false; + } + } + + foreach (['group', 'having', 'limit', 'force', 'comment', 'partition', 'duplicate', 'extra'] as $name) { + if (!isset($options[$name])) { + $options[$name] = ''; + } + } + + if (isset($options['page'])) { + // 根据页数计算limit + [$page, $listRows] = $options['page']; + $page = $page > 0 ? $page : 1; + $listRows = $listRows ?: (is_numeric($options['limit']) ? $options['limit'] : 20); + $offset = $listRows * ($page - 1); + $options['limit'] = $offset . ',' . $listRows; + } + + $this->options = $options; + + return $options; + } + + /** + * 分析数据是否存在更新条件 + * @access public + * @param array $data 数据 + * @return bool + * @throws Exception + */ + public function parseUpdateData(&$data): bool + { + $pk = $this->getPk(); + $isUpdate = false; + // 如果存在主键数据 则自动作为更新条件 + if (is_string($pk) && isset($data[$pk])) { + $this->where($pk, '=', $data[$pk]); + $this->options['key'] = $data[$pk]; + unset($data[$pk]); + $isUpdate = true; + } elseif (is_array($pk)) { + foreach ($pk as $field) { + if (isset($data[$field])) { + $this->where($field, '=', $data[$field]); + $isUpdate = true; + } else { + // 如果缺少复合主键数据则不执行 + throw new Exception('miss complex primary data'); + } + unset($data[$field]); + } + } + + return $isUpdate; + } + + /** + * 把主键值转换为查询条件 支持复合主键 + * @access public + * @param array|string $data 主键数据 + * @return void + * @throws Exception + */ + public function parsePkWhere($data): void + { + $pk = $this->getPk(); + + if (is_string($pk)) { + // 获取数据表 + if (empty($this->options['table'])) { + $this->options['table'] = $this->getTable(); + } + + $table = is_array($this->options['table']) ? key($this->options['table']) : $this->options['table']; + + if (!empty($this->options['alias'][$table])) { + $alias = $this->options['alias'][$table]; + } + + $key = isset($alias) ? $alias . '.' . $pk : $pk; + // 根据主键查询 + if (is_array($data)) { + $this->where($key, 'in', $data); + } else { + $this->where($key, '=', $data); + $this->options['key'] = $data; + } + } + } + + /** + * 获取模型的更新条件 + * @access protected + * @param array $options 查询参数 + */ + protected function getModelUpdateCondition(array $options) + { + return $options['where']['AND'] ?? null; + } +} diff --git a/vendor/topthink/think-orm/src/db/Builder.php b/vendor/topthink/think-orm/src/db/Builder.php new file mode 100644 index 000000000..73244f4d7 --- /dev/null +++ b/vendor/topthink/think-orm/src/db/Builder.php @@ -0,0 +1,1305 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\db; + +use Closure; +use PDO; +use think\db\exception\DbException as Exception; + +/** + * Db Builder + */ +abstract class Builder +{ + /** + * Connection对象 + * @var ConnectionInterface + */ + protected $connection; + + /** + * 查询表达式映射 + * @var array + */ + protected $exp = ['NOTLIKE' => 'NOT LIKE', 'NOTIN' => 'NOT IN', 'NOTBETWEEN' => 'NOT BETWEEN', 'NOTEXISTS' => 'NOT EXISTS', 'NOTNULL' => 'NOT NULL', 'NOTBETWEEN TIME' => 'NOT BETWEEN TIME']; + + /** + * 查询表达式解析 + * @var array + */ + protected $parser = [ + 'parseCompare' => ['=', '<>', '>', '>=', '<', '<='], + 'parseLike' => ['LIKE', 'NOT LIKE'], + 'parseBetween' => ['NOT BETWEEN', 'BETWEEN'], + 'parseIn' => ['NOT IN', 'IN'], + 'parseExp' => ['EXP'], + 'parseNull' => ['NOT NULL', 'NULL'], + 'parseBetweenTime' => ['BETWEEN TIME', 'NOT BETWEEN TIME'], + 'parseTime' => ['< TIME', '> TIME', '<= TIME', '>= TIME'], + 'parseExists' => ['NOT EXISTS', 'EXISTS'], + 'parseColumn' => ['COLUMN'], + ]; + + /** + * SELECT SQL表达式 + * @var string + */ + protected $selectSql = 'SELECT%DISTINCT%%EXTRA% %FIELD% FROM %TABLE%%FORCE%%JOIN%%WHERE%%GROUP%%HAVING%%UNION%%ORDER%%LIMIT% %LOCK%%COMMENT%'; + + /** + * INSERT SQL表达式 + * @var string + */ + protected $insertSql = '%INSERT%%EXTRA% INTO %TABLE% (%FIELD%) VALUES (%DATA%) %COMMENT%'; + + /** + * INSERT ALL SQL表达式 + * @var string + */ + protected $insertAllSql = '%INSERT%%EXTRA% INTO %TABLE% (%FIELD%) %DATA% %COMMENT%'; + + /** + * UPDATE SQL表达式 + * @var string + */ + protected $updateSql = 'UPDATE%EXTRA% %TABLE% SET %SET%%JOIN%%WHERE%%ORDER%%LIMIT% %LOCK%%COMMENT%'; + + /** + * DELETE SQL表达式 + * @var string + */ + protected $deleteSql = 'DELETE%EXTRA% FROM %TABLE%%USING%%JOIN%%WHERE%%ORDER%%LIMIT% %LOCK%%COMMENT%'; + + /** + * 架构函数 + * @access public + * @param ConnectionInterface $connection 数据库连接对象实例 + */ + public function __construct(ConnectionInterface $connection) + { + $this->connection = $connection; + } + + /** + * 获取当前的连接对象实例 + * @access public + * @return ConnectionInterface + */ + public function getConnection(): ConnectionInterface + { + return $this->connection; + } + + /** + * 注册查询表达式解析 + * @access public + * @param string $name 解析方法 + * @param array $parser 匹配表达式数据 + * @return $this + */ + public function bindParser(string $name, array $parser) + { + $this->parser[$name] = $parser; + return $this; + } + + /** + * 数据分析 + * @access protected + * @param Query $query 查询对象 + * @param array $data 数据 + * @param array $fields 字段信息 + * @param array $bind 参数绑定 + * @return array + */ + protected function parseData(Query $query, array $data = [], array $fields = [], array $bind = []): array + { + if (empty($data)) { + return []; + } + + $options = $query->getOptions(); + + // 获取绑定信息 + if (empty($bind)) { + $bind = $query->getFieldsBindType(); + } + + if (empty($fields)) { + if (empty($options['field']) || '*' == $options['field']) { + $fields = array_keys($bind); + } else { + $fields = $options['field']; + } + } + + $result = []; + + foreach ($data as $key => $val) { + $item = $this->parseKey($query, $key, true); + + if ($val instanceof Raw) { + $result[$item] = $this->parseRaw($query, $val); + continue; + } elseif (!is_scalar($val) && (in_array($key, (array) $query->getOptions('json')) || 'json' == $query->getFieldType($key))) { + $val = json_encode($val); + } + + if (false !== strpos($key, '->')) { + [$key, $name] = explode('->', $key, 2); + $item = $this->parseKey($query, $key); + $result[$item] = 'json_set(' . $item . ', \'$.' . $name . '\', ' . $this->parseDataBind($query, $key . '->' . $name, $val, $bind) . ')'; + } elseif (false === strpos($key, '.') && !in_array($key, $fields, true)) { + if ($options['strict']) { + throw new Exception('fields not exists:[' . $key . ']'); + } + } elseif (is_null($val)) { + $result[$item] = 'NULL'; + } elseif (is_array($val) && !empty($val) && is_string($val[0])) { + switch (strtoupper($val[0])) { + case 'INC': + $result[$item] = $item . ' + ' . floatval($val[1]); + break; + case 'DEC': + $result[$item] = $item . ' - ' . floatval($val[1]); + break; + } + } elseif (is_scalar($val)) { + // 过滤非标量数据 + $result[$item] = $this->parseDataBind($query, $key, $val, $bind); + } + } + + return $result; + } + + /** + * 数据绑定处理 + * @access protected + * @param Query $query 查询对象 + * @param string $key 字段名 + * @param mixed $data 数据 + * @param array $bind 绑定数据 + * @return string + */ + protected function parseDataBind(Query $query, string $key, $data, array $bind = []): string + { + if ($data instanceof Raw) { + return $this->parseRaw($query, $data); + } + + $name = $query->bindValue($data, $bind[$key] ?? PDO::PARAM_STR); + + return ':' . $name; + } + + /** + * 字段名分析 + * @access public + * @param Query $query 查询对象 + * @param mixed $key 字段名 + * @param bool $strict 严格检测 + * @return string + */ + public function parseKey(Query $query, $key, bool $strict = false): string + { + return $key; + } + + /** + * 查询额外参数分析 + * @access protected + * @param Query $query 查询对象 + * @param string $extra 额外参数 + * @return string + */ + protected function parseExtra(Query $query, string $extra): string + { + return preg_match('/^[\w]+$/i', $extra) ? ' ' . strtoupper($extra) : ''; + } + + /** + * field分析 + * @access protected + * @param Query $query 查询对象 + * @param mixed $fields 字段名 + * @return string + */ + protected function parseField(Query $query, $fields): string + { + if (is_array($fields)) { + // 支持 'field1'=>'field2' 这样的字段别名定义 + $array = []; + + foreach ($fields as $key => $field) { + if ($field instanceof Raw) { + $array[] = $this->parseRaw($query, $field); + } elseif (!is_numeric($key)) { + $array[] = $this->parseKey($query, $key) . ' AS ' . $this->parseKey($query, $field, true); + } else { + $array[] = $this->parseKey($query, $field); + } + } + + $fieldsStr = implode(',', $array); + } else { + $fieldsStr = '*'; + } + + return $fieldsStr; + } + + /** + * table分析 + * @access protected + * @param Query $query 查询对象 + * @param mixed $tables 表名 + * @return string + */ + protected function parseTable(Query $query, $tables): string + { + $item = []; + $options = $query->getOptions(); + + foreach ((array) $tables as $key => $table) { + if ($table instanceof Raw) { + $item[] = $this->parseRaw($query, $table); + } elseif (!is_numeric($key)) { + $item[] = $this->parseKey($query, $key) . ' ' . $this->parseKey($query, $table); + } elseif (isset($options['alias'][$table])) { + $item[] = $this->parseKey($query, $table) . ' ' . $this->parseKey($query, $options['alias'][$table]); + } else { + $item[] = $this->parseKey($query, $table); + } + } + + return implode(',', $item); + } + + /** + * where分析 + * @access protected + * @param Query $query 查询对象 + * @param mixed $where 查询条件 + * @return string + */ + protected function parseWhere(Query $query, array $where): string + { + $options = $query->getOptions(); + $whereStr = $this->buildWhere($query, $where); + + if (!empty($options['soft_delete'])) { + // 附加软删除条件 + [$field, $condition] = $options['soft_delete']; + + $binds = $query->getFieldsBindType(); + $whereStr = $whereStr ? '( ' . $whereStr . ' ) AND ' : ''; + $whereStr = $whereStr . $this->parseWhereItem($query, $field, $condition, $binds); + } + + return empty($whereStr) ? '' : ' WHERE ' . $whereStr; + } + + /** + * 生成查询条件SQL + * @access public + * @param Query $query 查询对象 + * @param mixed $where 查询条件 + * @return string + */ + public function buildWhere(Query $query, array $where): string + { + if (empty($where)) { + $where = []; + } + + $whereStr = ''; + + $binds = $query->getFieldsBindType(); + + foreach ($where as $logic => $val) { + $str = $this->parseWhereLogic($query, $logic, $val, $binds); + + $whereStr .= empty($whereStr) ? substr(implode(' ', $str), strlen($logic) + 1) : implode(' ', $str); + } + + return $whereStr; + } + + /** + * 不同字段使用相同查询条件(AND) + * @access protected + * @param Query $query 查询对象 + * @param string $logic Logic + * @param array $val 查询条件 + * @param array $binds 参数绑定 + * @return array + */ + protected function parseWhereLogic(Query $query, string $logic, array $val, array $binds = []): array + { + $where = []; + foreach ($val as $value) { + if ($value instanceof Raw) { + $where[] = ' ' . $logic . ' ( ' . $this->parseRaw($query, $value) . ' )'; + continue; + } + + if (is_array($value)) { + if (key($value) !== 0) { + throw new Exception('where express error:' . var_export($value, true)); + } + $field = array_shift($value); + } elseif (true === $value) { + $where[] = ' ' . $logic . ' 1 '; + continue; + } elseif (!($value instanceof Closure)) { + throw new Exception('where express error:' . var_export($value, true)); + } + + if ($value instanceof Closure) { + // 使用闭包查询 + $whereClosureStr = $this->parseClosureWhere($query, $value, $logic); + if ($whereClosureStr) { + $where[] = $whereClosureStr; + } + } elseif (is_array($field)) { + $where[] = $this->parseMultiWhereField($query, $value, $field, $logic, $binds); + } elseif ($field instanceof Raw) { + $where[] = ' ' . $logic . ' ' . $this->parseWhereItem($query, $field, $value, $binds); + } elseif (strpos($field, '|')) { + $where[] = $this->parseFieldsOr($query, $value, $field, $logic, $binds); + } elseif (strpos($field, '&')) { + $where[] = $this->parseFieldsAnd($query, $value, $field, $logic, $binds); + } else { + // 对字段使用表达式查询 + $field = is_string($field) ? $field : ''; + $where[] = ' ' . $logic . ' ' . $this->parseWhereItem($query, $field, $value, $binds); + } + } + + return $where; + } + + /** + * 不同字段使用相同查询条件(AND) + * @access protected + * @param Query $query 查询对象 + * @param mixed $value 查询条件 + * @param string $field 查询字段 + * @param string $logic Logic + * @param array $binds 参数绑定 + * @return string + */ + protected function parseFieldsAnd(Query $query, $value, string $field, string $logic, array $binds): string + { + $item = []; + + foreach (explode('&', $field) as $k) { + $item[] = $this->parseWhereItem($query, $k, $value, $binds); + } + + return ' ' . $logic . ' ( ' . implode(' AND ', $item) . ' )'; + } + + /** + * 不同字段使用相同查询条件(OR) + * @access protected + * @param Query $query 查询对象 + * @param mixed $value 查询条件 + * @param string $field 查询字段 + * @param string $logic Logic + * @param array $binds 参数绑定 + * @return string + */ + protected function parseFieldsOr(Query $query, $value, string $field, string $logic, array $binds): string + { + $item = []; + + foreach (explode('|', $field) as $k) { + $item[] = $this->parseWhereItem($query, $k, $value, $binds); + } + + return ' ' . $logic . ' ( ' . implode(' OR ', $item) . ' )'; + } + + /** + * 闭包查询 + * @access protected + * @param Query $query 查询对象 + * @param Closure $value 查询条件 + * @param string $logic Logic + * @return string + */ + protected function parseClosureWhere(Query $query, Closure $value, string $logic): string + { + $newQuery = $query->newQuery(); + $value($newQuery); + $whereClosure = $this->buildWhere($newQuery, $newQuery->getOptions('where') ?: []); + + if (!empty($whereClosure)) { + $query->bind($newQuery->getBind(false)); + $where = ' ' . $logic . ' ( ' . $whereClosure . ' )'; + } + + return $where ?? ''; + } + + /** + * 复合条件查询 + * @access protected + * @param Query $query 查询对象 + * @param mixed $value 查询条件 + * @param mixed $field 查询字段 + * @param string $logic Logic + * @param array $binds 参数绑定 + * @return string + */ + protected function parseMultiWhereField(Query $query, $value, $field, string $logic, array $binds): string + { + array_unshift($value, $field); + + $where = []; + foreach ($value as $item) { + $where[] = $this->parseWhereItem($query, array_shift($item), $item, $binds); + } + + return ' ' . $logic . ' ( ' . implode(' AND ', $where) . ' )'; + } + + /** + * where子单元分析 + * @access protected + * @param Query $query 查询对象 + * @param mixed $field 查询字段 + * @param array $val 查询条件 + * @param array $binds 参数绑定 + * @return string + */ + protected function parseWhereItem(Query $query, $field, array $val, array $binds = []): string + { + // 字段分析 + $key = $field ? $this->parseKey($query, $field, true) : ''; + + [$exp, $value] = $val; + + // 检测操作符 + if (!is_string($exp)) { + throw new Exception('where express error:' . var_export($exp, true)); + } + + $exp = strtoupper($exp); + if (isset($this->exp[$exp])) { + $exp = $this->exp[$exp]; + } + + if (is_string($field) && 'LIKE' != $exp) { + $bindType = $binds[$field] ?? PDO::PARAM_STR; + } else { + $bindType = PDO::PARAM_STR; + } + + if ($value instanceof Raw) { + + } elseif (is_object($value) && method_exists($value, '__toString')) { + // 对象数据写入 + $value = $value->__toString(); + } + + if (is_scalar($value) && !in_array($exp, ['EXP', 'NOT NULL', 'NULL', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN']) && strpos($exp, 'TIME') === false) { + if (is_string($value) && 0 === strpos($value, ':') && $query->isBind(substr($value, 1))) { + } else { + $name = $query->bindValue($value, $bindType); + $value = ':' . $name; + } + } + + // 解析查询表达式 + foreach ($this->parser as $fun => $parse) { + if (in_array($exp, $parse)) { + return $this->$fun($query, $key, $exp, $value, $field, $bindType, $val[2] ?? 'AND'); + } + } + + throw new Exception('where express error:' . $exp); + } + + /** + * 模糊查询 + * @access protected + * @param Query $query 查询对象 + * @param string $key + * @param string $exp + * @param array $value + * @param string $field + * @param integer $bindType + * @param string $logic + * @return string + */ + protected function parseLike(Query $query, string $key, string $exp, $value, $field, int $bindType, string $logic): string + { + // 模糊匹配 + if (is_array($value)) { + $array = []; + foreach ($value as $item) { + $name = $query->bindValue($item, PDO::PARAM_STR); + $array[] = $key . ' ' . $exp . ' :' . $name; + } + + $whereStr = '(' . implode(' ' . strtoupper($logic) . ' ', $array) . ')'; + } else { + $whereStr = $key . ' ' . $exp . ' ' . $value; + } + + return $whereStr; + } + + /** + * 表达式查询 + * @access protected + * @param Query $query 查询对象 + * @param string $key + * @param string $exp + * @param array $value + * @param string $field + * @param integer $bindType + * @return string + */ + protected function parseExp(Query $query, string $key, string $exp, Raw $value, string $field, int $bindType): string + { + // 表达式查询 + return '( ' . $key . ' ' . $this->parseRaw($query, $value) . ' )'; + } + + /** + * 表达式查询 + * @access protected + * @param Query $query 查询对象 + * @param string $key + * @param string $exp + * @param array $value + * @param string $field + * @param integer $bindType + * @return string + */ + protected function parseColumn(Query $query, string $key, $exp, array $value, string $field, int $bindType): string + { + // 字段比较查询 + [$op, $field] = $value; + + if (!in_array(trim($op), ['=', '<>', '>', '>=', '<', '<='])) { + throw new Exception('where express error:' . var_export($value, true)); + } + + return '( ' . $key . ' ' . $op . ' ' . $this->parseKey($query, $field, true) . ' )'; + } + + /** + * Null查询 + * @access protected + * @param Query $query 查询对象 + * @param string $key + * @param string $exp + * @param mixed $value + * @param string $field + * @param integer $bindType + * @return string + */ + protected function parseNull(Query $query, string $key, string $exp, $value, $field, int $bindType): string + { + // NULL 查询 + return $key . ' IS ' . $exp; + } + + /** + * 范围查询 + * @access protected + * @param Query $query 查询对象 + * @param string $key + * @param string $exp + * @param mixed $value + * @param string $field + * @param integer $bindType + * @return string + */ + protected function parseBetween(Query $query, string $key, string $exp, $value, $field, int $bindType): string + { + // BETWEEN 查询 + $data = is_array($value) ? $value : explode(',', $value); + + $min = $query->bindValue($data[0], $bindType); + $max = $query->bindValue($data[1], $bindType); + + return $key . ' ' . $exp . ' :' . $min . ' AND :' . $max . ' '; + } + + /** + * Exists查询 + * @access protected + * @param Query $query 查询对象 + * @param string $key + * @param string $exp + * @param mixed $value + * @param string $field + * @param integer $bindType + * @return string + */ + protected function parseExists(Query $query, string $key, string $exp, $value, string $field, int $bindType): string + { + // EXISTS 查询 + if ($value instanceof Closure) { + $value = $this->parseClosure($query, $value, false); + } elseif ($value instanceof Raw) { + $value = $this->parseRaw($query, $value); + } else { + throw new Exception('where express error:' . $value); + } + + return $exp . ' ( ' . $value . ' )'; + } + + /** + * 时间比较查询 + * @access protected + * @param Query $query 查询对象 + * @param string $key + * @param string $exp + * @param mixed $value + * @param string $field + * @param integer $bindType + * @return string + */ + protected function parseTime(Query $query, string $key, string $exp, $value, $field, int $bindType): string + { + return $key . ' ' . substr($exp, 0, 2) . ' ' . $this->parseDateTime($query, $value, $field, $bindType); + } + + /** + * 大小比较查询 + * @access protected + * @param Query $query 查询对象 + * @param string $key + * @param string $exp + * @param mixed $value + * @param string $field + * @param integer $bindType + * @return string + */ + protected function parseCompare(Query $query, string $key, string $exp, $value, $field, int $bindType): string + { + if (is_array($value)) { + throw new Exception('where express error:' . $exp . var_export($value, true)); + } + + // 比较运算 + if ($value instanceof Closure) { + $value = $this->parseClosure($query, $value); + } + + if ('=' == $exp && is_null($value)) { + return $key . ' IS NULL'; + } + + return $key . ' ' . $exp . ' ' . $value; + } + + /** + * 时间范围查询 + * @access protected + * @param Query $query 查询对象 + * @param string $key + * @param string $exp + * @param mixed $value + * @param string $field + * @param integer $bindType + * @return string + */ + protected function parseBetweenTime(Query $query, string $key, string $exp, $value, $field, int $bindType): string + { + if (is_string($value)) { + $value = explode(',', $value); + } + + return $key . ' ' . substr($exp, 0, -4) + . $this->parseDateTime($query, $value[0], $field, $bindType) + . ' AND ' + . $this->parseDateTime($query, $value[1], $field, $bindType); + + } + + /** + * IN查询 + * @access protected + * @param Query $query 查询对象 + * @param string $key + * @param string $exp + * @param mixed $value + * @param string $field + * @param integer $bindType + * @return string + */ + protected function parseIn(Query $query, string $key, string $exp, $value, $field, int $bindType): string + { + // IN 查询 + if ($value instanceof Closure) { + $value = $this->parseClosure($query, $value, false); + } elseif ($value instanceof Raw) { + $value = $this->parseRaw($query, $value); + } else { + $value = array_unique(is_array($value) ? $value : explode(',', $value)); + if (count($value) === 0) { + return 'IN' == $exp ? '0 = 1' : '1 = 1'; + } + $array = []; + + foreach ($value as $v) { + $name = $query->bindValue($v, $bindType); + $array[] = ':' . $name; + } + + if (count($array) == 1) { + return $key . ('IN' == $exp ? ' = ' : ' <> ') . $array[0]; + } else { + $value = implode(',', $array); + } + } + + return $key . ' ' . $exp . ' (' . $value . ')'; + } + + /** + * 闭包子查询 + * @access protected + * @param Query $query 查询对象 + * @param \Closure $call + * @param bool $show + * @return string + */ + protected function parseClosure(Query $query, Closure $call, bool $show = true): string + { + $newQuery = $query->newQuery()->removeOption(); + $call($newQuery); + + return $newQuery->buildSql($show); + } + + /** + * 日期时间条件解析 + * @access protected + * @param Query $query 查询对象 + * @param mixed $value + * @param string $key + * @param integer $bindType + * @return string + */ + protected function parseDateTime(Query $query, $value, string $key, int $bindType): string + { + $options = $query->getOptions(); + + // 获取时间字段类型 + if (strpos($key, '.')) { + [$table, $key] = explode('.', $key); + + if (isset($options['alias']) && $pos = array_search($table, $options['alias'])) { + $table = $pos; + } + } else { + $table = $options['table']; + } + + $type = $query->getFieldType($key); + + if ($type) { + if (is_string($value)) { + $value = strtotime($value) ?: $value; + } + + if (is_int($value)) { + if (preg_match('/(datetime|timestamp)/is', $type)) { + // 日期及时间戳类型 + $value = date('Y-m-d H:i:s', $value); + } elseif (preg_match('/(date)/is', $type)) { + // 日期及时间戳类型 + $value = date('Y-m-d', $value); + } + } + } + + $name = $query->bindValue($value, $bindType); + + return ':' . $name; + } + + /** + * limit分析 + * @access protected + * @param Query $query 查询对象 + * @param mixed $limit + * @return string + */ + protected function parseLimit(Query $query, string $limit): string + { + return (!empty($limit) && false === strpos($limit, '(')) ? ' LIMIT ' . $limit . ' ' : ''; + } + + /** + * join分析 + * @access protected + * @param Query $query 查询对象 + * @param array $join + * @return string + */ + protected function parseJoin(Query $query, array $join): string + { + $joinStr = ''; + + foreach ($join as $item) { + [$table, $type, $on] = $item; + + if (strpos($on, '=')) { + [$val1, $val2] = explode('=', $on, 2); + + $condition = $this->parseKey($query, $val1) . '=' . $this->parseKey($query, $val2); + } else { + $condition = $on; + } + + $table = $this->parseTable($query, $table); + + $joinStr .= ' ' . $type . ' JOIN ' . $table . ' ON ' . $condition; + } + + return $joinStr; + } + + /** + * order分析 + * @access protected + * @param Query $query 查询对象 + * @param array $order + * @return string + */ + protected function parseOrder(Query $query, array $order): string + { + $array = []; + foreach ($order as $key => $val) { + if ($val instanceof Raw) { + $array[] = $this->parseRaw($query, $val); + } elseif (is_array($val) && preg_match('/^[\w\.]+$/', $key)) { + $array[] = $this->parseOrderField($query, $key, $val); + } elseif ('[rand]' == $val) { + $array[] = $this->parseRand($query); + } elseif (is_string($val)) { + if (is_numeric($key)) { + [$key, $sort] = explode(' ', strpos($val, ' ') ? $val : $val . ' '); + } else { + $sort = $val; + } + + if (preg_match('/^[\w\.]+$/', $key)) { + $sort = strtoupper($sort); + $sort = in_array($sort, ['ASC', 'DESC'], true) ? ' ' . $sort : ''; + $array[] = $this->parseKey($query, $key, true) . $sort; + } else { + throw new Exception('order express error:' . $key); + } + } + } + + return empty($array) ? '' : ' ORDER BY ' . implode(',', $array); + } + + /** + * 分析Raw对象 + * @access protected + * @param Query $query 查询对象 + * @param Raw $raw Raw对象 + * @return string + */ + protected function parseRaw(Query $query, Raw $raw): string + { + $sql = $raw->getValue(); + $bind = $raw->getBind(); + + if ($bind) { + $query->bindParams($sql, $bind); + } + + return $sql; + } + + /** + * 随机排序 + * @access protected + * @param Query $query 查询对象 + * @return string + */ + protected function parseRand(Query $query): string + { + return ''; + } + + /** + * orderField分析 + * @access protected + * @param Query $query 查询对象 + * @param string $key + * @param array $val + * @return string + */ + protected function parseOrderField(Query $query, string $key, array $val): string + { + if (isset($val['sort'])) { + $sort = $val['sort']; + unset($val['sort']); + } else { + $sort = ''; + } + + $sort = strtoupper($sort); + $sort = in_array($sort, ['ASC', 'DESC'], true) ? ' ' . $sort : ''; + $bind = $query->getFieldsBindType(); + + foreach ($val as $item) { + $val[] = $this->parseDataBind($query, $key, $item, $bind); + } + + return 'field(' . $this->parseKey($query, $key, true) . ',' . implode(',', $val) . ')' . $sort; + } + + /** + * group分析 + * @access protected + * @param Query $query 查询对象 + * @param mixed $group + * @return string + */ + protected function parseGroup(Query $query, $group): string + { + if (empty($group)) { + return ''; + } + + if (is_string($group)) { + $group = explode(',', $group); + } + + $val = []; + foreach ($group as $key) { + $val[] = $this->parseKey($query, $key); + } + + return ' GROUP BY ' . implode(',', $val); + } + + /** + * having分析 + * @access protected + * @param Query $query 查询对象 + * @param string $having + * @return string + */ + protected function parseHaving(Query $query, string $having): string + { + return !empty($having) ? ' HAVING ' . $having : ''; + } + + /** + * comment分析 + * @access protected + * @param Query $query 查询对象 + * @param string $comment + * @return string + */ + protected function parseComment(Query $query, string $comment): string + { + if (false !== strpos($comment, '*/')) { + $comment = strstr($comment, '*/', true); + } + + return !empty($comment) ? ' /* ' . $comment . ' */' : ''; + } + + /** + * distinct分析 + * @access protected + * @param Query $query 查询对象 + * @param mixed $distinct + * @return string + */ + protected function parseDistinct(Query $query, bool $distinct): string + { + return !empty($distinct) ? ' DISTINCT ' : ''; + } + + /** + * union分析 + * @access protected + * @param Query $query 查询对象 + * @param array $union + * @return string + */ + protected function parseUnion(Query $query, array $union): string + { + if (empty($union)) { + return ''; + } + + $type = $union['type']; + unset($union['type']); + + foreach ($union as $u) { + if ($u instanceof Closure) { + $sql[] = $type . ' ' . $this->parseClosure($query, $u); + } elseif (is_string($u)) { + $sql[] = $type . ' ( ' . $u . ' )'; + } + } + + return ' ' . implode(' ', $sql); + } + + /** + * index分析,可在操作链中指定需要强制使用的索引 + * @access protected + * @param Query $query 查询对象 + * @param mixed $index + * @return string + */ + protected function parseForce(Query $query, $index): string + { + if (empty($index)) { + return ''; + } + + if (is_array($index)) { + $index = join(',', $index); + } + + return sprintf(" FORCE INDEX ( %s ) ", $index); + } + + /** + * 设置锁机制 + * @access protected + * @param Query $query 查询对象 + * @param bool|string $lock + * @return string + */ + protected function parseLock(Query $query, $lock = false): string + { + if (is_bool($lock)) { + return $lock ? ' FOR UPDATE ' : ''; + } + + if (is_string($lock) && !empty($lock)) { + return ' ' . trim($lock) . ' '; + } else { + return ''; + } + } + + /** + * 生成查询SQL + * @access public + * @param Query $query 查询对象 + * @param bool $one 是否仅获取一个记录 + * @return string + */ + public function select(Query $query, bool $one = false): string + { + $options = $query->getOptions(); + + return str_replace( + ['%TABLE%', '%DISTINCT%', '%EXTRA%', '%FIELD%', '%JOIN%', '%WHERE%', '%GROUP%', '%HAVING%', '%ORDER%', '%LIMIT%', '%UNION%', '%LOCK%', '%COMMENT%', '%FORCE%'], + [ + $this->parseTable($query, $options['table']), + $this->parseDistinct($query, $options['distinct']), + $this->parseExtra($query, $options['extra']), + $this->parseField($query, $options['field'] ?? '*'), + $this->parseJoin($query, $options['join']), + $this->parseWhere($query, $options['where']), + $this->parseGroup($query, $options['group']), + $this->parseHaving($query, $options['having']), + $this->parseOrder($query, $options['order']), + $this->parseLimit($query, $one ? '1' : $options['limit']), + $this->parseUnion($query, $options['union']), + $this->parseLock($query, $options['lock']), + $this->parseComment($query, $options['comment']), + $this->parseForce($query, $options['force']), + ], + $this->selectSql); + } + + /** + * 生成Insert SQL + * @access public + * @param Query $query 查询对象 + * @return string + */ + public function insert(Query $query): string + { + $options = $query->getOptions(); + + // 分析并处理数据 + $data = $this->parseData($query, $options['data']); + if (empty($data)) { + return ''; + } + + $fields = array_keys($data); + $values = array_values($data); + + return str_replace( + ['%INSERT%', '%TABLE%', '%EXTRA%', '%FIELD%', '%DATA%', '%COMMENT%'], + [ + !empty($options['replace']) ? 'REPLACE' : 'INSERT', + $this->parseTable($query, $options['table']), + $this->parseExtra($query, $options['extra']), + implode(' , ', $fields), + implode(' , ', $values), + $this->parseComment($query, $options['comment']), + ], + $this->insertSql); + } + + /** + * 生成insertall SQL + * @access public + * @param Query $query 查询对象 + * @param array $dataSet 数据集 + * @return string + */ + public function insertAll(Query $query, array $dataSet): string + { + $options = $query->getOptions(); + + // 获取绑定信息 + $bind = $query->getFieldsBindType(); + + // 获取合法的字段 + if (empty($options['field']) || '*' == $options['field']) { + $allowFields = array_keys($bind); + } else { + $allowFields = $options['field']; + } + + $fields = []; + $values = []; + + foreach ($dataSet as $k => $data) { + $data = $this->parseData($query, $data, $allowFields, $bind); + + $values[] = 'SELECT ' . implode(',', array_values($data)); + + if (!isset($insertFields)) { + $insertFields = array_keys($data); + } + } + + foreach ($insertFields as $field) { + $fields[] = $this->parseKey($query, $field); + } + + return str_replace( + ['%INSERT%', '%TABLE%', '%EXTRA%', '%FIELD%', '%DATA%', '%COMMENT%'], + [ + !empty($options['replace']) ? 'REPLACE' : 'INSERT', + $this->parseTable($query, $options['table']), + $this->parseExtra($query, $options['extra']), + implode(' , ', $fields), + implode(' UNION ALL ', $values), + $this->parseComment($query, $options['comment']), + ], + $this->insertAllSql); + } + + /** + * 生成slect insert SQL + * @access public + * @param Query $query 查询对象 + * @param array $fields 数据 + * @param string $table 数据表 + * @return string + */ + public function selectInsert(Query $query, array $fields, string $table): string + { + foreach ($fields as &$field) { + $field = $this->parseKey($query, $field, true); + } + + return 'INSERT INTO ' . $this->parseTable($query, $table) . ' (' . implode(',', $fields) . ') ' . $this->select($query); + } + + /** + * 生成update SQL + * @access public + * @param Query $query 查询对象 + * @return string + */ + public function update(Query $query): string + { + $options = $query->getOptions(); + + $data = $this->parseData($query, $options['data']); + + if (empty($data)) { + return ''; + } + + $set = []; + foreach ($data as $key => $val) { + $set[] = $key . ' = ' . $val; + } + + return str_replace( + ['%TABLE%', '%EXTRA%', '%SET%', '%JOIN%', '%WHERE%', '%ORDER%', '%LIMIT%', '%LOCK%', '%COMMENT%'], + [ + $this->parseTable($query, $options['table']), + $this->parseExtra($query, $options['extra']), + implode(' , ', $set), + $this->parseJoin($query, $options['join']), + $this->parseWhere($query, $options['where']), + $this->parseOrder($query, $options['order']), + $this->parseLimit($query, $options['limit']), + $this->parseLock($query, $options['lock']), + $this->parseComment($query, $options['comment']), + ], + $this->updateSql); + } + + /** + * 生成delete SQL + * @access public + * @param Query $query 查询对象 + * @return string + */ + public function delete(Query $query): string + { + $options = $query->getOptions(); + + return str_replace( + ['%TABLE%', '%EXTRA%', '%USING%', '%JOIN%', '%WHERE%', '%ORDER%', '%LIMIT%', '%LOCK%', '%COMMENT%'], + [ + $this->parseTable($query, $options['table']), + $this->parseExtra($query, $options['extra']), + !empty($options['using']) ? ' USING ' . $this->parseTable($query, $options['using']) . ' ' : '', + $this->parseJoin($query, $options['join']), + $this->parseWhere($query, $options['where']), + $this->parseOrder($query, $options['order']), + $this->parseLimit($query, $options['limit']), + $this->parseLock($query, $options['lock']), + $this->parseComment($query, $options['comment']), + ], + $this->deleteSql); + } +} diff --git a/vendor/topthink/think-orm/src/db/CacheItem.php b/vendor/topthink/think-orm/src/db/CacheItem.php new file mode 100644 index 000000000..839f38409 --- /dev/null +++ b/vendor/topthink/think-orm/src/db/CacheItem.php @@ -0,0 +1,209 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\db; + +use DateInterval; +use DateTime; +use DateTimeInterface; +use think\db\exception\InvalidArgumentException; + +/** + * CacheItem实现类 + */ +class CacheItem +{ + /** + * 缓存Key + * @var string + */ + protected $key; + + /** + * 缓存内容 + * @var mixed + */ + protected $value; + + /** + * 过期时间 + * @var int|DateTimeInterface + */ + protected $expire; + + /** + * 缓存tag + * @var string + */ + protected $tag; + + /** + * 缓存是否命中 + * @var bool + */ + protected $isHit = false; + + public function __construct(string $key = null) + { + $this->key = $key; + } + + /** + * 为此缓存项设置「键」 + * @access public + * @param string $key + * @return $this + */ + public function setKey(string $key) + { + $this->key = $key; + return $this; + } + + /** + * 返回当前缓存项的「键」 + * @access public + * @return string + */ + public function getKey() + { + return $this->key; + } + + /** + * 返回当前缓存项的有效期 + * @access public + * @return DateTimeInterface|int|null + */ + public function getExpire() + { + if ($this->expire instanceof DateTimeInterface) { + return $this->expire; + } + + return $this->expire ? $this->expire - time() : null; + } + + /** + * 获取缓存Tag + * @access public + * @return string|array + */ + public function getTag() + { + return $this->tag; + } + + /** + * 凭借此缓存项的「键」从缓存系统里面取出缓存项 + * @access public + * @return mixed + */ + public function get() + { + return $this->value; + } + + /** + * 确认缓存项的检查是否命中 + * @access public + * @return bool + */ + public function isHit(): bool + { + return $this->isHit; + } + + /** + * 为此缓存项设置「值」 + * @access public + * @param mixed $value + * @return $this + */ + public function set($value) + { + $this->value = $value; + $this->isHit = true; + return $this; + } + + /** + * 为此缓存项设置所属标签 + * @access public + * @param string|array $tag + * @return $this + */ + public function tag($tag = null) + { + $this->tag = $tag; + return $this; + } + + /** + * 设置缓存项的有效期 + * @access public + * @param mixed $expire + * @return $this + */ + public function expire($expire) + { + if (is_null($expire)) { + $this->expire = null; + } elseif (is_numeric($expire) || $expire instanceof DateInterval) { + $this->expiresAfter($expire); + } elseif ($expire instanceof DateTimeInterface) { + $this->expire = $expire; + } else { + throw new InvalidArgumentException('not support datetime'); + } + + return $this; + } + + /** + * 设置缓存项的准确过期时间点 + * @access public + * @param DateTimeInterface $expiration + * @return $this + */ + public function expiresAt($expiration) + { + if ($expiration instanceof DateTimeInterface) { + $this->expire = $expiration; + } else { + throw new InvalidArgumentException('not support datetime'); + } + + return $this; + } + + /** + * 设置缓存项的过期时间 + * @access public + * @param int|DateInterval $timeInterval + * @return $this + * @throws InvalidArgumentException + */ + public function expiresAfter($timeInterval) + { + if ($timeInterval instanceof DateInterval) { + $this->expire = (int) DateTime::createFromFormat('U', (string) time())->add($timeInterval)->format('U'); + } elseif (is_numeric($timeInterval)) { + $this->expire = $timeInterval + time(); + } else { + throw new InvalidArgumentException('not support datetime'); + } + + return $this; + } + +} diff --git a/vendor/topthink/think-orm/src/db/Connection.php b/vendor/topthink/think-orm/src/db/Connection.php new file mode 100644 index 000000000..aa86ba8e5 --- /dev/null +++ b/vendor/topthink/think-orm/src/db/Connection.php @@ -0,0 +1,347 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\db; + +use Psr\SimpleCache\CacheInterface; +use think\DbManager; + +/** + * 数据库连接基础类 + */ +abstract class Connection implements ConnectionInterface +{ + + /** + * 当前SQL指令 + * @var string + */ + protected $queryStr = ''; + + /** + * 返回或者影响记录数 + * @var int + */ + protected $numRows = 0; + + /** + * 事务指令数 + * @var int + */ + protected $transTimes = 0; + + /** + * 错误信息 + * @var string + */ + protected $error = ''; + + /** + * 数据库连接ID 支持多个连接 + * @var array + */ + protected $links = []; + + /** + * 当前连接ID + * @var object + */ + protected $linkID; + + /** + * 当前读连接ID + * @var object + */ + protected $linkRead; + + /** + * 当前写连接ID + * @var object + */ + protected $linkWrite; + + /** + * 数据表信息 + * @var array + */ + protected $info = []; + + /** + * 查询开始时间 + * @var float + */ + protected $queryStartTime; + + /** + * Builder对象 + * @var Builder + */ + protected $builder; + + /** + * Db对象 + * @var DbManager + */ + protected $db; + + /** + * 是否读取主库 + * @var bool + */ + protected $readMaster = false; + + /** + * 数据库连接参数配置 + * @var array + */ + protected $config = []; + + /** + * 缓存对象 + * @var CacheInterface + */ + protected $cache; + + /** + * 架构函数 读取数据库配置信息 + * @access public + * @param array $config 数据库配置数组 + */ + public function __construct(array $config = []) + { + if (!empty($config)) { + $this->config = array_merge($this->config, $config); + } + + // 创建Builder对象 + $class = $this->getBuilderClass(); + + $this->builder = new $class($this); + } + + /** + * 获取当前的builder实例对象 + * @access public + * @return Builder + */ + public function getBuilder() + { + return $this->builder; + } + + /** + * 创建查询对象 + */ + public function newQuery() + { + $class = $this->getQueryClass(); + + /** @var BaseQuery $query */ + $query = new $class($this); + + $timeRule = $this->db->getConfig('time_query_rule'); + if (!empty($timeRule)) { + $query->timeRule($timeRule); + } + + return $query; + } + + /** + * 指定表名开始查询 + * @param $table + * @return BaseQuery + */ + public function table($table) + { + return $this->newQuery()->table($table); + } + + /** + * 指定表名开始查询(不带前缀) + * @param $name + * @return BaseQuery + */ + public function name($name) + { + return $this->newQuery()->name($name); + } + + /** + * 设置当前的数据库Db对象 + * @access public + * @param DbManager $db + * @return void + */ + public function setDb(DbManager $db) + { + $this->db = $db; + } + + /** + * 设置当前的缓存对象 + * @access public + * @param CacheInterface $cache + * @return void + */ + public function setCache(CacheInterface $cache) + { + $this->cache = $cache; + } + + /** + * 获取当前的缓存对象 + * @access public + * @return CacheInterface|null + */ + public function getCache() + { + return $this->cache; + } + + /** + * 获取数据库的配置参数 + * @access public + * @param string $config 配置名称 + * @return mixed + */ + public function getConfig(string $config = '') + { + if ('' === $config) { + return $this->config; + } + + return $this->config[$config] ?? null; + } + + /** + * 数据库SQL监控 + * @access protected + * @param string $sql 执行的SQL语句 留空自动获取 + * @param bool $master 主从标记 + * @return void + */ + protected function trigger(string $sql = '', bool $master = false): void + { + $listen = $this->db->getListen(); + if (empty($listen)) { + $listen[] = function ($sql, $time, $master) { + if (0 === strpos($sql, 'CONNECT:')) { + $this->db->log($sql); + return; + } + + // 记录SQL + if (is_bool($master)) { + // 分布式记录当前操作的主从 + $master = $master ? 'master|' : 'slave|'; + } else { + $master = ''; + } + + $this->db->log($sql . ' [ ' . $master . 'RunTime:' . $time . 's ]'); + }; + } + + $runtime = number_format((microtime(true) - $this->queryStartTime), 6); + $sql = $sql ?: $this->getLastsql(); + + if (empty($this->config['deploy'])) { + $master = null; + } + + foreach ($listen as $callback) { + if (is_callable($callback)) { + $callback($sql, $runtime, $master); + } + } + } + + /** + * 缓存数据 + * @access protected + * @param CacheItem $cacheItem 缓存Item + */ + protected function cacheData(CacheItem $cacheItem) + { + if ($cacheItem->getTag() && method_exists($this->cache, 'tag')) { + $this->cache->tag($cacheItem->getTag())->set($cacheItem->getKey(), $cacheItem->get(), $cacheItem->getExpire()); + } else { + $this->cache->set($cacheItem->getKey(), $cacheItem->get(), $cacheItem->getExpire()); + } + } + + /** + * 分析缓存Key + * @access protected + * @param BaseQuery $query 查询对象 + * @param string $method 查询方法 + * @return string + */ + protected function getCacheKey(BaseQuery $query, string $method = ''): string + { + if (!empty($query->getOptions('key')) && empty($method)) { + $key = 'think_' . $this->getConfig('database') . '.' . $query->getTable() . '|' . $query->getOptions('key'); + } else { + $key = $query->getQueryGuid(); + } + + return $key; + } + + /** + * 分析缓存 + * @access protected + * @param BaseQuery $query 查询对象 + * @param array $cache 缓存信息 + * @param string $method 查询方法 + * @return CacheItem + */ + protected function parseCache(BaseQuery $query, array $cache, string $method = ''): CacheItem + { + [$key, $expire, $tag] = $cache; + + if ($key instanceof CacheItem) { + $cacheItem = $key; + } else { + if (true === $key) { + $key = $this->getCacheKey($query, $method); + } + + $cacheItem = new CacheItem($key); + $cacheItem->expire($expire); + $cacheItem->tag($tag); + } + + return $cacheItem; + } + + /** + * 获取返回或者影响的记录数 + * @access public + * @return integer + */ + public function getNumRows(): int + { + return $this->numRows; + } + + /** + * 析构方法 + * @access public + */ + public function __destruct() + { + // 关闭连接 + $this->close(); + } +} diff --git a/vendor/topthink/think-orm/src/db/ConnectionInterface.php b/vendor/topthink/think-orm/src/db/ConnectionInterface.php new file mode 100644 index 000000000..18fe1316c --- /dev/null +++ b/vendor/topthink/think-orm/src/db/ConnectionInterface.php @@ -0,0 +1,190 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\db; + +use Psr\SimpleCache\CacheInterface; +use think\DbManager; + +/** + * Connection interface + */ +interface ConnectionInterface +{ + /** + * 获取当前连接器类对应的Query类 + * @access public + * @return string + */ + public function getQueryClass(): string; + + /** + * 指定表名开始查询 + * @param $table + * @return BaseQuery + */ + public function table($table); + + /** + * 指定表名开始查询(不带前缀) + * @param $name + * @return BaseQuery + */ + public function name($name); + + /** + * 连接数据库方法 + * @access public + * @param array $config 接参数 + * @param integer $linkNum 连接序号 + * @return mixed + */ + public function connect(array $config = [], $linkNum = 0); + + /** + * 设置当前的数据库Db对象 + * @access public + * @param DbManager $db + * @return void + */ + public function setDb(DbManager $db); + + /** + * 设置当前的缓存对象 + * @access public + * @param CacheInterface $cache + * @return void + */ + public function setCache(CacheInterface $cache); + + /** + * 获取数据库的配置参数 + * @access public + * @param string $config 配置名称 + * @return mixed + */ + public function getConfig(string $config = ''); + + /** + * 关闭数据库(或者重新连接) + * @access public + * @return $this + */ + public function close(); + + /** + * 查找单条记录 + * @access public + * @param BaseQuery $query 查询对象 + * @return array + */ + public function find(BaseQuery $query): array; + + /** + * 查找记录 + * @access public + * @param BaseQuery $query 查询对象 + * @return array + */ + public function select(BaseQuery $query): array; + + /** + * 插入记录 + * @access public + * @param BaseQuery $query 查询对象 + * @param boolean $getLastInsID 返回自增主键 + * @return mixed + */ + public function insert(BaseQuery $query, bool $getLastInsID = false); + + /** + * 批量插入记录 + * @access public + * @param BaseQuery $query 查询对象 + * @param mixed $dataSet 数据集 + * @return integer + */ + public function insertAll(BaseQuery $query, array $dataSet = []): int; + + /** + * 更新记录 + * @access public + * @param BaseQuery $query 查询对象 + * @return integer + */ + public function update(BaseQuery $query): int; + + /** + * 删除记录 + * @access public + * @param BaseQuery $query 查询对象 + * @return int + */ + public function delete(BaseQuery $query): int; + + /** + * 得到某个字段的值 + * @access public + * @param BaseQuery $query 查询对象 + * @param string $field 字段名 + * @param mixed $default 默认值 + * @return mixed + */ + public function value(BaseQuery $query, string $field, $default = null); + + /** + * 得到某个列的数组 + * @access public + * @param BaseQuery $query 查询对象 + * @param string|array $column 字段名 多个字段用逗号分隔 + * @param string $key 索引 + * @return array + */ + public function column(BaseQuery $query, $column, string $key = ''): array; + + /** + * 执行数据库事务 + * @access public + * @param callable $callback 数据操作方法回调 + * @return mixed + */ + public function transaction(callable $callback); + + /** + * 启动事务 + * @access public + * @return void + */ + public function startTrans(); + + /** + * 用于非自动提交状态下面的查询提交 + * @access public + * @return void + */ + public function commit(); + + /** + * 事务回滚 + * @access public + * @return void + */ + public function rollback(); + + /** + * 获取最近一次查询的sql语句 + * @access public + * @return string + */ + public function getLastSql(): string; + +} diff --git a/vendor/topthink/think-orm/src/db/Fetch.php b/vendor/topthink/think-orm/src/db/Fetch.php new file mode 100644 index 000000000..16caed2b0 --- /dev/null +++ b/vendor/topthink/think-orm/src/db/Fetch.php @@ -0,0 +1,494 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\db; + +use think\db\exception\DbException as Exception; +use think\helper\Str; + +/** + * SQL获取类 + */ +class Fetch +{ + /** + * 查询对象 + * @var Query + */ + protected $query; + + /** + * Connection对象 + * @var Connection + */ + protected $connection; + + /** + * Builder对象 + * @var Builder + */ + protected $builder; + + /** + * 创建一个查询SQL获取对象 + * + * @param Query $query 查询对象 + */ + public function __construct(Query $query) + { + $this->query = $query; + $this->connection = $query->getConnection(); + $this->builder = $this->connection->getBuilder(); + } + + /** + * 聚合查询 + * @access protected + * @param string $aggregate 聚合方法 + * @param string $field 字段名 + * @return string + */ + protected function aggregate(string $aggregate, string $field): string + { + $this->query->parseOptions(); + + $field = $aggregate . '(' . $this->builder->parseKey($this->query, $field) . ') AS think_' . strtolower($aggregate); + + return $this->value($field, 0, false); + } + + /** + * 得到某个字段的值 + * @access public + * @param string $field 字段名 + * @param mixed $default 默认值 + * @param bool $one + * @return string + */ + public function value(string $field, $default = null, bool $one = true): string + { + $options = $this->query->parseOptions(); + + if (isset($options['field'])) { + $this->query->removeOption('field'); + } + + $this->query->setOption('field', (array) $field); + + // 生成查询SQL + $sql = $this->builder->select($this->query, $one); + + if (isset($options['field'])) { + $this->query->setOption('field', $options['field']); + } else { + $this->query->removeOption('field'); + } + + return $this->fetch($sql); + } + + /** + * 得到某个列的数组 + * @access public + * @param string $field 字段名 多个字段用逗号分隔 + * @param string $key 索引 + * @return string + */ + public function column(string $field, string $key = ''): string + { + $options = $this->query->parseOptions(); + + if (isset($options['field'])) { + $this->query->removeOption('field'); + } + + if ($key && '*' != $field) { + $field = $key . ',' . $field; + } + + $field = array_map('trim', explode(',', $field)); + + $this->query->setOption('field', $field); + + // 生成查询SQL + $sql = $this->builder->select($this->query); + + if (isset($options['field'])) { + $this->query->setOption('field', $options['field']); + } else { + $this->query->removeOption('field'); + } + + return $this->fetch($sql); + } + + /** + * 插入记录 + * @access public + * @param array $data 数据 + * @return string + */ + public function insert(array $data = []): string + { + $options = $this->query->parseOptions(); + + if (!empty($data)) { + $this->query->setOption('data', $data); + } + + $sql = $this->builder->insert($this->query); + + return $this->fetch($sql); + } + + /** + * 插入记录并获取自增ID + * @access public + * @param array $data 数据 + * @return string + */ + public function insertGetId(array $data = []): string + { + return $this->insert($data); + } + + /** + * 保存数据 自动判断insert或者update + * @access public + * @param array $data 数据 + * @param bool $forceInsert 是否强制insert + * @return string + */ + public function save(array $data = [], bool $forceInsert = false): string + { + if ($forceInsert) { + return $this->insert($data); + } + + $data = array_merge($this->query->getOptions('data') ?: [], $data); + + $this->query->setOption('data', $data); + + if ($this->query->getOptions('where')) { + $isUpdate = true; + } else { + $isUpdate = $this->query->parseUpdateData($data); + } + + return $isUpdate ? $this->update() : $this->insert(); + } + + /** + * 批量插入记录 + * @access public + * @param array $dataSet 数据集 + * @param integer $limit 每次写入数据限制 + * @return string + */ + public function insertAll(array $dataSet = [], int $limit = null): string + { + $options = $this->query->parseOptions(); + + if (empty($dataSet)) { + $dataSet = $options['data']; + } + + if (empty($limit) && !empty($options['limit'])) { + $limit = $options['limit']; + } + + if ($limit) { + $array = array_chunk($dataSet, $limit, true); + $fetchSql = []; + foreach ($array as $item) { + $sql = $this->builder->insertAll($this->query, $item); + $bind = $this->query->getBind(); + + $fetchSql[] = $this->connection->getRealSql($sql, $bind); + } + + return implode(';', $fetchSql); + } + + $sql = $this->builder->insertAll($this->query, $dataSet); + + return $this->fetch($sql); + } + + /** + * 通过Select方式插入记录 + * @access public + * @param array $fields 要插入的数据表字段名 + * @param string $table 要插入的数据表名 + * @return string + */ + public function selectInsert(array $fields, string $table): string + { + $this->query->parseOptions(); + + $sql = $this->builder->selectInsert($this->query, $fields, $table); + + return $this->fetch($sql); + } + + /** + * 更新记录 + * @access public + * @param mixed $data 数据 + * @return string + */ + public function update(array $data = []): string + { + $options = $this->query->parseOptions(); + + $data = !empty($data) ? $data : $options['data']; + + $pk = $this->query->getPk(); + + if (empty($options['where'])) { + // 如果存在主键数据 则自动作为更新条件 + if (is_string($pk) && isset($data[$pk])) { + $this->query->where($pk, '=', $data[$pk]); + unset($data[$pk]); + } elseif (is_array($pk)) { + // 增加复合主键支持 + foreach ($pk as $field) { + if (isset($data[$field])) { + $this->query->where($field, '=', $data[$field]); + } else { + // 如果缺少复合主键数据则不执行 + throw new Exception('miss complex primary data'); + } + unset($data[$field]); + } + } + + if (empty($this->query->getOptions('where'))) { + // 如果没有任何更新条件则不执行 + throw new Exception('miss update condition'); + } + } + + // 更新数据 + $this->query->setOption('data', $data); + + // 生成UPDATE SQL语句 + $sql = $this->builder->update($this->query); + + return $this->fetch($sql); + } + + /** + * 删除记录 + * @access public + * @param mixed $data 表达式 true 表示强制删除 + * @return string + */ + public function delete($data = null): string + { + $options = $this->query->parseOptions(); + + if (!is_null($data) && true !== $data) { + // AR模式分析主键条件 + $this->query->parsePkWhere($data); + } + + if (!empty($options['soft_delete'])) { + // 软删除 + [$field, $condition] = $options['soft_delete']; + if ($condition) { + $this->query->setOption('soft_delete', null); + $this->query->setOption('data', [$field => $condition]); + // 生成删除SQL语句 + $sql = $this->builder->delete($this->query); + return $this->fetch($sql); + } + } + + // 生成删除SQL语句 + $sql = $this->builder->delete($this->query); + + return $this->fetch($sql); + } + + /** + * 查找记录 返回SQL + * @access public + * @param mixed $data + * @return string + */ + public function select($data = null): string + { + $this->query->parseOptions(); + + if (!is_null($data)) { + // 主键条件分析 + $this->query->parsePkWhere($data); + } + + // 生成查询SQL + $sql = $this->builder->select($this->query); + + return $this->fetch($sql); + } + + /** + * 查找单条记录 返回SQL语句 + * @access public + * @param mixed $data + * @return string + */ + public function find($data = null): string + { + $this->query->parseOptions(); + + if (!is_null($data)) { + // AR模式分析主键条件 + $this->query->parsePkWhere($data); + } + + // 生成查询SQL + $sql = $this->builder->select($this->query, true); + + // 获取实际执行的SQL语句 + return $this->fetch($sql); + } + + /** + * 查找多条记录 如果不存在则抛出异常 + * @access public + * @param mixed $data + * @return string + */ + public function selectOrFail($data = null): string + { + return $this->select($data); + } + + /** + * 查找单条记录 如果不存在则抛出异常 + * @access public + * @param mixed $data + * @return string + */ + public function findOrFail($data = null): string + { + return $this->find($data); + } + + /** + * 查找单条记录 不存在返回空数据(或者空模型) + * @access public + * @param mixed $data 数据 + * @return string + */ + public function findOrEmpty($data = null) + { + return $this->find($data); + } + + /** + * 获取实际的SQL语句 + * @access public + * @param string $sql + * @return string + */ + public function fetch(string $sql): string + { + $bind = $this->query->getBind(); + + return $this->connection->getRealSql($sql, $bind); + } + + /** + * COUNT查询 + * @access public + * @param string $field 字段名 + * @return string + */ + public function count(string $field = '*'): string + { + $options = $this->query->parseOptions(); + + if (!empty($options['group'])) { + // 支持GROUP + $bind = $this->query->getBind(); + $subSql = $this->query->options($options)->field('count(' . $field . ') AS think_count')->bind($bind)->buildSql(); + + $query = $this->query->newQuery()->table([$subSql => '_group_count_']); + + return $query->fetchsql()->aggregate('COUNT', '*'); + } else { + return $this->aggregate('COUNT', $field); + } + } + + /** + * SUM查询 + * @access public + * @param string $field 字段名 + * @return string + */ + public function sum(string $field): string + { + return $this->aggregate('SUM', $field); + } + + /** + * MIN查询 + * @access public + * @param string $field 字段名 + * @return string + */ + public function min(string $field): string + { + return $this->aggregate('MIN', $field); + } + + /** + * MAX查询 + * @access public + * @param string $field 字段名 + * @return string + */ + public function max(string $field): string + { + return $this->aggregate('MAX', $field); + } + + /** + * AVG查询 + * @access public + * @param string $field 字段名 + * @return string + */ + public function avg(string $field): string + { + return $this->aggregate('AVG', $field); + } + + public function __call($method, $args) + { + if (strtolower(substr($method, 0, 5)) == 'getby') { + // 根据某个字段获取记录 + $field = Str::snake(substr($method, 5)); + return $this->where($field, '=', $args[0])->find(); + } elseif (strtolower(substr($method, 0, 10)) == 'getfieldby') { + // 根据某个字段获取记录的某个值 + $name = Str::snake(substr($method, 10)); + return $this->where($name, '=', $args[0])->value($args[1]); + } + + $result = call_user_func_array([$this->query, $method], $args); + return $result === $this->query ? $this : $result; + } +} diff --git a/vendor/topthink/think-orm/src/db/Mongo.php b/vendor/topthink/think-orm/src/db/Mongo.php new file mode 100644 index 000000000..5e8a09a51 --- /dev/null +++ b/vendor/topthink/think-orm/src/db/Mongo.php @@ -0,0 +1,712 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); +namespace think\db; + +use MongoDB\Driver\Command; +use MongoDB\Driver\Cursor; +use MongoDB\Driver\Exception\AuthenticationException; +use MongoDB\Driver\Exception\ConnectionException; +use MongoDB\Driver\Exception\InvalidArgumentException; +use MongoDB\Driver\Exception\RuntimeException; +use MongoDB\Driver\ReadPreference; +use MongoDB\Driver\WriteConcern; +use think\db\exception\DbException as Exception; +use think\Paginator; + +class Mongo extends BaseQuery +{ + /** + * 当前数据库连接对象 + * @var \think\db\connector\Mongo + */ + protected $connection; + + /** + * 执行指令 返回数据集 + * @access public + * @param Command $command 指令 + * @param string $dbName + * @param ReadPreference $readPreference readPreference + * @param string|array $typeMap 指定返回的typeMap + * @return mixed + * @throws AuthenticationException + * @throws InvalidArgumentException + * @throws ConnectionException + * @throws RuntimeException + */ + public function command(Command $command, string $dbName = '', ReadPreference $readPreference = null, $typeMap = null) + { + return $this->connection->command($command, $dbName, $readPreference, $typeMap); + } + + /** + * 执行command + * @access public + * @param string|array|object $command 指令 + * @param mixed $extra 额外参数 + * @param string $db 数据库名 + * @return array + */ + public function cmd($command, $extra = null, string $db = ''): array + { + $this->parseOptions(); + return $this->connection->cmd($this, $command, $extra, $db); + } + + /** + * 指定distinct查询 + * @access public + * @param string $field 字段名 + * @return array + */ + public function getDistinct(string $field) + { + $result = $this->cmd('distinct', $field); + return $result[0]['values']; + } + + /** + * 获取数据库的所有collection + * @access public + * @param string $db 数据库名称 留空为当前数据库 + * @throws Exception + */ + public function listCollections(string $db = '') + { + $cursor = $this->cmd('listCollections', null, $db); + $result = []; + foreach ($cursor as $collection) { + $result[] = $collection['name']; + } + + return $result; + } + + /** + * COUNT查询 + * @access public + * @param string $field 字段名 + * @return integer + */ + public function count(string $field = null): int + { + $result = $this->cmd('count'); + + return $result[0]['n']; + } + + /** + * 聚合查询 + * @access public + * @param string $aggregate 聚合指令 + * @param string $field 字段名 + * @param bool $force 强制转为数字类型 + * @return mixed + */ + public function aggregate(string $aggregate, $field, bool $force = false) + { + $result = $this->cmd('aggregate', [strtolower($aggregate), $field]); + $value = $result[0]['aggregate'] ?? 0; + + if ($force) { + $value += 0; + } + + return $value; + } + + /** + * 多聚合操作 + * + * @param array $aggregate 聚合指令, 可以聚合多个参数, 如 ['sum' => 'field1', 'avg' => 'field2'] + * @param array $groupBy 类似mysql里面的group字段, 可以传入多个字段, 如 ['field_a', 'field_b', 'field_c'] + * @return array 查询结果 + */ + public function multiAggregate(array $aggregate, array $groupBy): array + { + $result = $this->cmd('multiAggregate', [$aggregate, $groupBy]); + + foreach ($result as &$row) { + if (isset($row['_id']) && !empty($row['_id'])) { + foreach ($row['_id'] as $k => $v) { + $row[$k] = $v; + } + unset($row['_id']); + } + } + + return $result; + } + + /** + * 字段值增长 + * @access public + * @param string $field 字段名 + * @param float $step 增长值 + * @return $this + */ + public function inc(string $field, float $step = 1) + { + $this->options['data'][$field] = ['$inc', $step]; + + return $this; + } + + /** + * 字段值减少 + * @access public + * @param string $field 字段名 + * @param float $step 减少值 + * @return $this + */ + public function dec(string $field, float $step = 1) + { + return $this->inc($field, -1 * $step); + } + + /** + * 指定当前操作的Collection + * @access public + * @param string $table 表名 + * @return $this + */ + public function table($table) + { + $this->options['table'] = $table; + + return $this; + } + + /** + * table方法的别名 + * @access public + * @param string $collection + * @return $this + */ + public function collection(string $collection) + { + return $this->table($collection); + } + + /** + * 设置typeMap + * @access public + * @param string|array $typeMap + * @return $this + */ + public function typeMap($typeMap) + { + $this->options['typeMap'] = $typeMap; + return $this; + } + + /** + * awaitData + * @access public + * @param bool $awaitData + * @return $this + */ + public function awaitData(bool $awaitData) + { + $this->options['awaitData'] = $awaitData; + return $this; + } + + /** + * batchSize + * @access public + * @param integer $batchSize + * @return $this + */ + public function batchSize(int $batchSize) + { + $this->options['batchSize'] = $batchSize; + return $this; + } + + /** + * exhaust + * @access public + * @param bool $exhaust + * @return $this + */ + public function exhaust(bool $exhaust) + { + $this->options['exhaust'] = $exhaust; + return $this; + } + + /** + * 设置modifiers + * @access public + * @param array $modifiers + * @return $this + */ + public function modifiers(array $modifiers) + { + $this->options['modifiers'] = $modifiers; + return $this; + } + + /** + * 设置noCursorTimeout + * @access public + * @param bool $noCursorTimeout + * @return $this + */ + public function noCursorTimeout(bool $noCursorTimeout) + { + $this->options['noCursorTimeout'] = $noCursorTimeout; + return $this; + } + + /** + * 设置oplogReplay + * @access public + * @param bool $oplogReplay + * @return $this + */ + public function oplogReplay(bool $oplogReplay) + { + $this->options['oplogReplay'] = $oplogReplay; + return $this; + } + + /** + * 设置partial + * @access public + * @param bool $partial + * @return $this + */ + public function partial(bool $partial) + { + $this->options['partial'] = $partial; + return $this; + } + + /** + * maxTimeMS + * @access public + * @param string $maxTimeMS + * @return $this + */ + public function maxTimeMS(string $maxTimeMS) + { + $this->options['maxTimeMS'] = $maxTimeMS; + return $this; + } + + /** + * collation + * @access public + * @param array $collation + * @return $this + */ + public function collation(array $collation) + { + $this->options['collation'] = $collation; + return $this; + } + + /** + * 设置是否REPLACE + * @access public + * @param bool $replace 是否使用REPLACE写入数据 + * @return $this + */ + public function replace(bool $replace = true) + { + return $this; + } + + /** + * 设置返回字段 + * @access public + * @param mixed $field 字段信息 + * @return $this + */ + public function field($field) + { + if (empty($field) || '*' == $field) { + return $this; + } + + if (is_string($field)) { + $field = array_map('trim', explode(',', $field)); + } + + $projection = []; + foreach ($field as $key => $val) { + if (is_numeric($key)) { + $projection[$val] = 1; + } else { + $projection[$key] = $val; + } + } + + $this->options['projection'] = $projection; + + return $this; + } + + /** + * 指定要排除的查询字段 + * @access public + * @param array|string $field 要排除的字段 + * @return $this + */ + public function withoutField($field) + { + if (empty($field) || '*' == $field) { + return $this; + } + + if (is_string($field)) { + $field = array_map('trim', explode(',', $field)); + } + + $projection = []; + foreach ($field as $key => $val) { + if (is_numeric($key)) { + $projection[$val] = 0; + } else { + $projection[$key] = $val; + } + } + + $this->options['projection'] = $projection; + return $this; + } + + /** + * 设置skip + * @access public + * @param integer $skip + * @return $this + */ + public function skip(int $skip) + { + $this->options['skip'] = $skip; + return $this; + } + + /** + * 设置slaveOk + * @access public + * @param bool $slaveOk + * @return $this + */ + public function slaveOk(bool $slaveOk) + { + $this->options['slaveOk'] = $slaveOk; + return $this; + } + + /** + * 指定查询数量 + * @access public + * @param int $offset 起始位置 + * @param int $length 查询数量 + * @return $this + */ + public function limit(int $offset, int $length = null) + { + if (is_null($length)) { + $length = $offset; + $offset = 0; + } + + $this->options['skip'] = $offset; + $this->options['limit'] = $length; + + return $this; + } + + /** + * 设置sort + * @access public + * @param array|string $field + * @param string $order + * @return $this + */ + public function order($field, string $order = '') + { + if (is_array($field)) { + $this->options['sort'] = $field; + } else { + $this->options['sort'][$field] = 'asc' == strtolower($order) ? 1 : -1; + } + return $this; + } + + /** + * 设置tailable + * @access public + * @param bool $tailable + * @return $this + */ + public function tailable(bool $tailable) + { + $this->options['tailable'] = $tailable; + return $this; + } + + /** + * 设置writeConcern对象 + * @access public + * @param WriteConcern $writeConcern + * @return $this + */ + public function writeConcern(WriteConcern $writeConcern) + { + $this->options['writeConcern'] = $writeConcern; + return $this; + } + + /** + * 获取当前数据表的主键 + * @access public + * @return string|array + */ + public function getPk() + { + return $this->pk ?: $this->connection->getConfig('pk'); + } + + /** + * 执行查询但只返回Cursor对象 + * @access public + * @return Cursor + */ + public function getCursor(): Cursor + { + $this->parseOptions(); + + return $this->connection->getCursor($this); + } + + /** + * 获取当前的查询标识 + * @access public + * @param mixed $data 要序列化的数据 + * @return string + */ + public function getQueryGuid($data = null): string + { + return md5($this->getConfig('database') . serialize(var_export($data ?: $this->options, true))); + } + + /** + * 分页查询 + * @access public + * @param int|array $listRows 每页数量 数组表示配置参数 + * @param int|bool $simple 是否简洁模式或者总记录数 + * @return Paginator + * @throws Exception + */ + public function paginate($listRows = null, $simple = false): Paginator + { + if (is_int($simple)) { + $total = $simple; + $simple = false; + } + + $defaultConfig = [ + 'query' => [], //url额外参数 + 'fragment' => '', //url锚点 + 'var_page' => 'page', //分页变量 + 'list_rows' => 15, //每页数量 + ]; + + if (is_array($listRows)) { + $config = array_merge($defaultConfig, $listRows); + $listRows = intval($config['list_rows']); + } else { + $config = $defaultConfig; + $listRows = intval($listRows ?: $config['list_rows']); + } + + $page = isset($config['page']) ? (int) $config['page'] : Paginator::getCurrentPage($config['var_page']); + + $page = $page < 1 ? 1 : $page; + + $config['path'] = $config['path'] ?? Paginator::getCurrentPath(); + + if (!isset($total) && !$simple) { + $options = $this->getOptions(); + + unset($this->options['order'], $this->options['limit'], $this->options['page'], $this->options['field']); + + $total = $this->count(); + $results = $this->options($options)->page($page, $listRows)->select(); + } elseif ($simple) { + $results = $this->limit(($page - 1) * $listRows, $listRows + 1)->select(); + $total = null; + } else { + $results = $this->page($page, $listRows)->select(); + } + + $this->removeOption('limit'); + $this->removeOption('page'); + + return Paginator::make($results, $listRows, $page, $total, $simple, $config); + } + + /** + * 分批数据返回处理 + * @access public + * @param integer $count 每次处理的数据数量 + * @param callable $callback 处理回调方法 + * @param string|array $column 分批处理的字段名 + * @param string $order 字段排序 + * @return bool + * @throws Exception + */ + public function chunk(int $count, callable $callback, $column = null, string $order = 'asc'): bool + { + $options = $this->getOptions(); + $column = $column ?: $this->getPk(); + + if (isset($options['order'])) { + unset($options['order']); + } + + if (is_array($column)) { + $times = 1; + $query = $this->options($options)->page($times, $count); + } else { + $query = $this->options($options)->limit($count); + + if (strpos($column, '.')) { + [$alias, $key] = explode('.', $column); + } else { + $key = $column; + } + } + + $resultSet = $query->order($column, $order)->select(); + + while (count($resultSet) > 0) { + if (false === call_user_func($callback, $resultSet)) { + return false; + } + + if (isset($times)) { + $times++; + $query = $this->options($options)->page($times, $count); + } else { + $end = $resultSet->pop(); + $lastId = is_array($end) ? $end[$key] : $end->getData($key); + + $query = $this->options($options) + ->limit($count) + ->where($column, 'asc' == strtolower($order) ? '>' : '<', $lastId); + } + + $resultSet = $query->order($column, $order)->select(); + } + + return true; + } + + /** + * 分析表达式(可用于查询或者写入操作) + * @access public + * @return array + */ + public function parseOptions(): array + { + $options = $this->options; + + // 获取数据表 + if (empty($options['table'])) { + $options['table'] = $this->getTable(); + } + + foreach (['where', 'data'] as $name) { + if (!isset($options[$name])) { + $options[$name] = []; + } + } + + $modifiers = empty($options['modifiers']) ? [] : $options['modifiers']; + if (isset($options['comment'])) { + $modifiers['$comment'] = $options['comment']; + } + + if (isset($options['maxTimeMS'])) { + $modifiers['$maxTimeMS'] = $options['maxTimeMS']; + } + + if (!empty($modifiers)) { + $options['modifiers'] = $modifiers; + } + + if (!isset($options['projection'])) { + $options['projection'] = []; + } + + if (!isset($options['typeMap'])) { + $options['typeMap'] = $this->getConfig('type_map'); + } + + if (!isset($options['limit'])) { + $options['limit'] = 0; + } + + foreach (['master', 'fetch_sql', 'fetch_cursor'] as $name) { + if (!isset($options[$name])) { + $options[$name] = false; + } + } + + if (isset($options['page'])) { + // 根据页数计算limit + [$page, $listRows] = $options['page']; + + $page = $page > 0 ? $page : 1; + $listRows = $listRows > 0 ? $listRows : (is_numeric($options['limit']) ? $options['limit'] : 20); + $offset = $listRows * ($page - 1); + $options['skip'] = intval($offset); + $options['limit'] = intval($listRows); + } + + $this->options = $options; + + return $options; + } + + /** + * 获取字段类型信息 + * @access public + * @return array + */ + public function getFieldsType(): array + { + if (!empty($this->options['field_type'])) { + return $this->options['field_type']; + } + + return []; + } + + /** + * 获取字段类型信息 + * @access public + * @param string $field 字段名 + * @return string|null + */ + public function getFieldType(string $field) + { + $fieldType = $this->getFieldsType(); + + return $fieldType[$field] ?? null; + } +} diff --git a/vendor/topthink/think-orm/src/db/PDOConnection.php b/vendor/topthink/think-orm/src/db/PDOConnection.php new file mode 100644 index 000000000..0a51c0c4f --- /dev/null +++ b/vendor/topthink/think-orm/src/db/PDOConnection.php @@ -0,0 +1,1792 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\db; + +use Closure; +use PDO; +use PDOStatement; +use think\db\exception\BindParamException; +use think\db\exception\DbException; +use think\db\exception\PDOException; +use think\Model; + +/** + * 数据库连接基础类 + * @property PDO[] $links + * @property PDO $linkID + * @property PDO $linkRead + * @property PDO $linkWrite + */ +abstract class PDOConnection extends Connection +{ + const PARAM_FLOAT = 21; + + /** + * 数据库连接参数配置 + * @var array + */ + protected $config = [ + // 数据库类型 + 'type' => '', + // 服务器地址 + 'hostname' => '', + // 数据库名 + 'database' => '', + // 用户名 + 'username' => '', + // 密码 + 'password' => '', + // 端口 + 'hostport' => '', + // 连接dsn + 'dsn' => '', + // 数据库连接参数 + 'params' => [], + // 数据库编码默认采用utf8 + 'charset' => 'utf8', + // 数据库表前缀 + 'prefix' => '', + // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) + 'deploy' => 0, + // 数据库读写是否分离 主从式有效 + 'rw_separate' => false, + // 读写分离后 主服务器数量 + 'master_num' => 1, + // 指定从服务器序号 + 'slave_no' => '', + // 模型写入后自动读取主服务器 + 'read_master' => false, + // 是否严格检查字段是否存在 + 'fields_strict' => true, + // 开启字段缓存 + 'fields_cache' => false, + // 监听SQL + 'trigger_sql' => true, + // Builder类 + 'builder' => '', + // Query类 + 'query' => '', + // 是否需要断线重连 + 'break_reconnect' => false, + // 断线标识字符串 + 'break_match_str' => [], + ]; + + /** + * PDO操作实例 + * @var PDOStatement + */ + protected $PDOStatement; + + /** + * 当前SQL指令 + * @var string + */ + protected $queryStr = ''; + + /** + * 事务指令数 + * @var int + */ + protected $transTimes = 0; + + /** + * 重连次数 + * @var int + */ + protected $reConnectTimes = 0; + + /** + * 查询结果类型 + * @var int + */ + protected $fetchType = PDO::FETCH_ASSOC; + + /** + * 字段属性大小写 + * @var int + */ + protected $attrCase = PDO::CASE_LOWER; + + /** + * 数据表信息 + * @var array + */ + protected $info = []; + + /** + * 查询开始时间 + * @var float + */ + protected $queryStartTime; + + /** + * PDO连接参数 + * @var array + */ + protected $params = [ + PDO::ATTR_CASE => PDO::CASE_NATURAL, + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL, + PDO::ATTR_STRINGIFY_FETCHES => false, + PDO::ATTR_EMULATE_PREPARES => false, + ]; + + /** + * 参数绑定类型映射 + * @var array + */ + protected $bindType = [ + 'string' => PDO::PARAM_STR, + 'str' => PDO::PARAM_STR, + 'integer' => PDO::PARAM_INT, + 'int' => PDO::PARAM_INT, + 'boolean' => PDO::PARAM_BOOL, + 'bool' => PDO::PARAM_BOOL, + 'float' => self::PARAM_FLOAT, + 'datetime' => PDO::PARAM_STR, + 'timestamp' => PDO::PARAM_STR, + ]; + + /** + * 服务器断线标识字符 + * @var array + */ + protected $breakMatchStr = [ + 'server has gone away', + 'no connection to the server', + 'Lost connection', + 'is dead or not enabled', + 'Error while sending', + 'decryption failed or bad record mac', + 'server closed the connection unexpectedly', + 'SSL connection has been closed unexpectedly', + 'Error writing data to the connection', + 'Resource deadlock avoided', + 'failed with errno', + 'child connection forced to terminate due to client_idle_limit', + 'query_wait_timeout', + 'reset by peer', + 'Physical connection is not usable', + 'TCP Provider: Error code 0x68', + 'ORA-03114', + 'Packets out of order. Expected', + 'Adaptive Server connection failed', + 'Communication link failure', + 'connection is no longer usable', + 'Login timeout expired', + 'SQLSTATE[HY000] [2002] Connection refused', + 'running with the --read-only option so it cannot execute this statement', + 'The connection is broken and recovery is not possible. The connection is marked by the client driver as unrecoverable. No attempt was made to restore the connection.', + 'SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Try again', + 'SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Name or service not known', + 'SQLSTATE[HY000]: General error: 7 SSL SYSCALL error: EOF detected', + 'SQLSTATE[HY000] [2002] Connection timed out', + 'SSL: Connection timed out', + 'SQLSTATE[HY000]: General error: 1105 The last transaction was aborted due to Seamless Scaling. Please retry.', + ]; + + /** + * 绑定参数 + * @var array + */ + protected $bind = []; + + /** + * 获取当前连接器类对应的Query类 + * @access public + * @return string + */ + public function getQueryClass(): string + { + return $this->getConfig('query') ?: Query::class; + } + + /** + * 获取当前连接器类对应的Builder类 + * @access public + * @return string + */ + public function getBuilderClass(): string + { + return $this->getConfig('builder') ?: '\\think\\db\\builder\\' . ucfirst($this->getConfig('type')); + } + + /** + * 解析pdo连接的dsn信息 + * @access protected + * @param array $config 连接信息 + * @return string + */ + abstract protected function parseDsn(array $config): string; + + /** + * 取得数据表的字段信息 + * @access public + * @param string $tableName 数据表名称 + * @return array + */ + abstract public function getFields(string $tableName): array; + + /** + * 取得数据库的表信息 + * @access public + * @param string $dbName 数据库名称 + * @return array + */ + abstract public function getTables(string $dbName = ''): array; + + /** + * 对返数据表字段信息进行大小写转换出来 + * @access public + * @param array $info 字段信息 + * @return array + */ + public function fieldCase(array $info): array + { + // 字段大小写转换 + switch ($this->attrCase) { + case PDO::CASE_LOWER: + $info = array_change_key_case($info); + break; + case PDO::CASE_UPPER: + $info = array_change_key_case($info, CASE_UPPER); + break; + case PDO::CASE_NATURAL: + default: + // 不做转换 + } + + return $info; + } + + /** + * 获取字段类型 + * @access protected + * @param string $type 字段类型 + * @return string + */ + protected function getFieldType(string $type): string + { + if (0 === strpos($type, 'set') || 0 === strpos($type, 'enum')) { + $result = 'string'; + } elseif (preg_match('/(double|float|decimal|real|numeric)/is', $type)) { + $result = 'float'; + } elseif (preg_match('/(int|serial|bit)/is', $type)) { + $result = 'int'; + } elseif (preg_match('/bool/is', $type)) { + $result = 'bool'; + } elseif (0 === strpos($type, 'timestamp')) { + $result = 'timestamp'; + } elseif (0 === strpos($type, 'datetime')) { + $result = 'datetime'; + } elseif (0 === strpos($type, 'date')) { + $result = 'date'; + } else { + $result = 'string'; + } + + return $result; + } + + /** + * 获取字段绑定类型 + * @access public + * @param string $type 字段类型 + * @return integer + */ + public function getFieldBindType(string $type): int + { + if (in_array($type, ['integer', 'string', 'float', 'boolean', 'bool', 'int', 'str'])) { + $bind = $this->bindType[$type]; + } elseif (0 === strpos($type, 'set') || 0 === strpos($type, 'enum')) { + $bind = PDO::PARAM_STR; + } elseif (preg_match('/(double|float|decimal|real|numeric)/is', $type)) { + $bind = self::PARAM_FLOAT; + } elseif (preg_match('/(int|serial|bit)/is', $type)) { + $bind = PDO::PARAM_INT; + } elseif (preg_match('/bool/is', $type)) { + $bind = PDO::PARAM_BOOL; + } else { + $bind = PDO::PARAM_STR; + } + + return $bind; + } + + /** + * 获取数据表信息缓存key + * @access protected + * @param string $schema 数据表名称 + * @return string + */ + protected function getSchemaCacheKey(string $schema): string + { + return $this->getConfig('hostname') . ':' . $this->getConfig('hostport') . '@' . $schema; + } + + /** + * @param string $tableName 数据表名称 + * @param bool $force 强制从数据库获取 + * @return array + */ + public function getSchemaInfo(string $tableName, $force = false) + { + if (!strpos($tableName, '.')) { + $schema = $this->getConfig('database') . '.' . $tableName; + } else { + $schema = $tableName; + } + + if (!isset($this->info[$schema]) || $force) { + // 读取字段缓存 + $cacheKey = $this->getSchemaCacheKey($schema); + $cacheField = $this->config['fields_cache'] && !empty($this->cache); + + if ($cacheField && !$force) { + $info = $this->cache->get($cacheKey); + } + + if (empty($info)) { + $info = $this->getTableFieldsInfo($tableName); + if ($cacheField) { + $this->cache->set($cacheKey, $info); + } + } + + $pk = $info['_pk'] ?? null; + $autoinc = $info['_autoinc'] ?? null; + unset($info['_pk'], $info['_autoinc']); + + $bind = []; + foreach ($info as $name => $val) { + $bind[$name] = $this->getFieldBindType($val); + } + + $this->info[$schema] = [ + 'fields' => array_keys($info), + 'type' => $info, + 'bind' => $bind, + 'pk' => $pk, + 'autoinc' => $autoinc, + ]; + } + + return $this->info[$schema]; + } + + /** + * 获取数据表信息 + * @access public + * @param mixed $tableName 数据表名 留空自动获取 + * @param string $fetch 获取信息类型 包括 fields type bind pk + * @return mixed + */ + public function getTableInfo($tableName, string $fetch = '') + { + if (is_array($tableName)) { + $tableName = key($tableName) ?: current($tableName); + } + + if (strpos($tableName, ',') || strpos($tableName, ')')) { + // 多表不获取字段信息 + return []; + } + + [$tableName] = explode(' ', $tableName); + + $info = $this->getSchemaInfo($tableName); + + return $fetch ? $info[$fetch] : $info; + } + + /** + * 获取数据表的字段信息 + * @access public + * @param string $tableName 数据表名 + * @return array + */ + public function getTableFieldsInfo(string $tableName): array + { + $fields = $this->getFields($tableName); + $info = []; + + foreach ($fields as $key => $val) { + // 记录字段类型 + $info[$key] = $this->getFieldType($val['type']); + + if (!empty($val['primary'])) { + $pk[] = $key; + } + + if (!empty($val['autoinc'])) { + $autoinc = $key; + } + } + + if (isset($pk)) { + // 设置主键 + $pk = count($pk) > 1 ? $pk : $pk[0]; + $info['_pk'] = $pk; + } + + if (isset($autoinc)) { + $info['_autoinc'] = $autoinc; + } + + return $info; + } + + /** + * 获取数据表的主键 + * @access public + * @param mixed $tableName 数据表名 + * @return string|array + */ + public function getPk($tableName) + { + return $this->getTableInfo($tableName, 'pk'); + } + + /** + * 获取数据表的自增主键 + * @access public + * @param mixed $tableName 数据表名 + * @return string + */ + public function getAutoInc($tableName) + { + return $this->getTableInfo($tableName, 'autoinc'); + } + + /** + * 获取数据表字段信息 + * @access public + * @param mixed $tableName 数据表名 + * @return array + */ + public function getTableFields($tableName): array + { + return $this->getTableInfo($tableName, 'fields'); + } + + /** + * 获取数据表字段类型 + * @access public + * @param mixed $tableName 数据表名 + * @param string $field 字段名 + * @return array|string + */ + public function getFieldsType($tableName, string $field = null) + { + $result = $this->getTableInfo($tableName, 'type'); + + if ($field && isset($result[$field])) { + return $result[$field]; + } + + return $result; + } + + /** + * 获取数据表绑定信息 + * @access public + * @param mixed $tableName 数据表名 + * @return array + */ + public function getFieldsBind($tableName): array + { + return $this->getTableInfo($tableName, 'bind'); + } + + /** + * 连接数据库方法 + * @access public + * @param array $config 连接参数 + * @param integer $linkNum 连接序号 + * @param array|bool $autoConnection 是否自动连接主数据库(用于分布式) + * @return PDO + * @throws PDOException + */ + public function connect(array $config = [], $linkNum = 0, $autoConnection = false): PDO + { + if (isset($this->links[$linkNum])) { + return $this->links[$linkNum]; + } + + if (empty($config)) { + $config = $this->config; + } else { + $config = array_merge($this->config, $config); + } + + // 连接参数 + if (isset($config['params']) && is_array($config['params'])) { + $params = $config['params'] + $this->params; + } else { + $params = $this->params; + } + + // 记录当前字段属性大小写设置 + $this->attrCase = $params[PDO::ATTR_CASE]; + + if (!empty($config['break_match_str'])) { + $this->breakMatchStr = array_merge($this->breakMatchStr, (array) $config['break_match_str']); + } + + try { + if (empty($config['dsn'])) { + $config['dsn'] = $this->parseDsn($config); + } + + $startTime = microtime(true); + + $this->links[$linkNum] = $this->createPdo($config['dsn'], $config['username'], $config['password'], $params); + + // SQL监控 + if (!empty($config['trigger_sql'])) { + $this->trigger('CONNECT:[ UseTime:' . number_format(microtime(true) - $startTime, 6) . 's ] ' . $config['dsn']); + } + + return $this->links[$linkNum]; + } catch (\PDOException $e) { + if ($autoConnection) { + $this->db->log($e->getMessage(), 'error'); + return $this->connect($autoConnection, $linkNum); + } else { + throw $e; + } + } + } + + /** + * 视图查询 + * @access public + * @param array $args + * @return BaseQuery + */ + public function view(...$args) + { + return $this->newQuery()->view(...$args); + } + + /** + * 创建PDO实例 + * @param $dsn + * @param $username + * @param $password + * @param $params + * @return PDO + */ + protected function createPdo($dsn, $username, $password, $params) + { + return new PDO($dsn, $username, $password, $params); + } + + /** + * 释放查询结果 + * @access public + */ + public function free(): void + { + $this->PDOStatement = null; + } + + /** + * 获取PDO对象 + * @access public + * @return PDO|false + */ + public function getPdo() + { + if (!$this->linkID) { + return false; + } + + return $this->linkID; + } + + /** + * 执行查询 使用生成器返回数据 + * @access public + * @param BaseQuery $query 查询对象 + * @param string $sql sql指令 + * @param array $bind 参数绑定 + * @param Model|null $model 模型对象实例 + * @param null $condition 查询条件 + * @return \Generator + * @throws DbException + */ + public function getCursor(BaseQuery $query, string $sql, array $bind = [], $model = null, $condition = null) + { + $this->queryPDOStatement($query, $sql, $bind); + + // 返回结果集 + while ($result = $this->PDOStatement->fetch($this->fetchType)) { + if ($model) { + yield $model->newInstance($result, $condition); + } else { + yield $result; + } + } + } + + /** + * 执行查询 返回数据集 + * @access public + * @param string $sql sql指令 + * @param array $bind 参数绑定 + * @param bool $master 主库读取 + * @return array + * @throws DbException + */ + public function query(string $sql, array $bind = [], bool $master = false): array + { + return $this->pdoQuery($this->newQuery(), $sql, $bind, $master); + } + + /** + * 执行语句 + * @access public + * @param string $sql sql指令 + * @param array $bind 参数绑定 + * @return int + * @throws DbException + */ + public function execute(string $sql, array $bind = []): int + { + return $this->pdoExecute($this->newQuery(), $sql, $bind, true); + } + + /** + * 执行查询 返回数据集 + * @access protected + * @param BaseQuery $query 查询对象 + * @param mixed $sql sql指令 + * @param array $bind 参数绑定 + * @param bool $master 主库读取 + * @return array + * @throws DbException + */ + protected function pdoQuery(BaseQuery $query, $sql, array $bind = [], bool $master = null): array + { + // 分析查询表达式 + $query->parseOptions(); + + if ($query->getOptions('cache')) { + // 检查查询缓存 + $cacheItem = $this->parseCache($query, $query->getOptions('cache')); + $key = $cacheItem->getKey(); + + $data = $this->cache->get($key); + + if (null !== $data) { + return $data; + } + } + + if ($sql instanceof Closure) { + $sql = $sql($query); + $bind = $query->getBind(); + } + + if (!isset($master)) { + $master = $query->getOptions('master') ? true : false; + } + + $procedure = $query->getOptions('procedure') ? true : in_array(strtolower(substr(trim($sql), 0, 4)), ['call', 'exec']); + + $this->getPDOStatement($sql, $bind, $master, $procedure); + + $resultSet = $this->getResult($procedure); + + if (isset($cacheItem) && $resultSet) { + // 缓存数据集 + $cacheItem->set($resultSet); + $this->cacheData($cacheItem); + } + + return $resultSet; + } + + /** + * 执行查询但只返回PDOStatement对象 + * @access public + * @param BaseQuery $query 查询对象 + * @return \PDOStatement + * @throws DbException + */ + public function pdo(BaseQuery $query): PDOStatement + { + $bind = $query->getBind(); + // 生成查询SQL + $sql = $this->builder->select($query); + + return $this->queryPDOStatement($query, $sql, $bind); + } + + /** + * 执行查询但只返回PDOStatement对象 + * @access public + * @param string $sql sql指令 + * @param array $bind 参数绑定 + * @param bool $master 是否在主服务器读操作 + * @param bool $procedure 是否为存储过程调用 + * @return PDOStatement + * @throws DbException + */ + public function getPDOStatement(string $sql, array $bind = [], bool $master = false, bool $procedure = false): PDOStatement + { + try { + $this->initConnect($this->readMaster ?: $master); + // 记录SQL语句 + $this->queryStr = $sql; + $this->bind = $bind; + + $this->db->updateQueryTimes(); + $this->queryStartTime = microtime(true); + + // 预处理 + $this->PDOStatement = $this->linkID->prepare($sql); + + // 参数绑定 + if ($procedure) { + $this->bindParam($bind); + } else { + $this->bindValue($bind); + } + + // 执行查询 + $this->PDOStatement->execute(); + + // SQL监控 + if (!empty($this->config['trigger_sql'])) { + $this->trigger('', $master); + } + + $this->reConnectTimes = 0; + + return $this->PDOStatement; + } catch (\Throwable | \Exception $e) { + if ($this->transTimes > 0) { + // 事务活动中时不应该进行重试,应直接中断执行,防止造成污染。 + if ($this->isBreak($e)) { + // 尝试对事务计数进行重置 + $this->transTimes = 0; + } + } else { + if ($this->reConnectTimes < 4 && $this->isBreak($e)) { + ++$this->reConnectTimes; + return $this->close()->getPDOStatement($sql, $bind, $master, $procedure); + } + } + + if ($e instanceof \PDOException) { + throw new PDOException($e, $this->config, $this->getLastsql()); + } else { + throw $e; + } + } + } + + /** + * 执行语句 + * @access protected + * @param BaseQuery $query 查询对象 + * @param string $sql sql指令 + * @param array $bind 参数绑定 + * @param bool $origin 是否原生查询 + * @return int + * @throws DbException + */ + protected function pdoExecute(BaseQuery $query, string $sql, array $bind = [], bool $origin = false): int + { + if ($origin) { + $query->parseOptions(); + } + + $this->queryPDOStatement($query->master(true), $sql, $bind); + + if (!$origin && !empty($this->config['deploy']) && !empty($this->config['read_master'])) { + $this->readMaster = true; + } + + $this->numRows = $this->PDOStatement->rowCount(); + + if ($query->getOptions('cache')) { + // 清理缓存数据 + $cacheItem = $this->parseCache($query, $query->getOptions('cache')); + $key = $cacheItem->getKey(); + $tag = $cacheItem->getTag(); + + if (isset($key) && $this->cache->has($key)) { + $this->cache->delete($key); + } elseif (!empty($tag) && method_exists($this->cache, 'tag')) { + $this->cache->tag($tag)->clear(); + } + } + + return $this->numRows; + } + + /** + * @param BaseQuery $query + * @param string $sql + * @param array $bind + * @return PDOStatement + * @throws DbException + */ + protected function queryPDOStatement(BaseQuery $query, string $sql, array $bind = []): PDOStatement + { + $options = $query->getOptions(); + $master = !empty($options['master']) ? true : false; + $procedure = !empty($options['procedure']) ? true : in_array(strtolower(substr(trim($sql), 0, 4)), ['call', 'exec']); + + return $this->getPDOStatement($sql, $bind, $master, $procedure); + } + + /** + * 查找单条记录 + * @access public + * @param BaseQuery $query 查询对象 + * @return array + * @throws DbException + */ + public function find(BaseQuery $query): array + { + // 事件回调 + $result = $this->db->trigger('before_find', $query); + + if (!$result) { + // 执行查询 + $resultSet = $this->pdoQuery($query, function ($query) { + return $this->builder->select($query, true); + }); + + $result = $resultSet[0] ?? []; + } + + return $result; + } + + /** + * 使用游标查询记录 + * @access public + * @param BaseQuery $query 查询对象 + * @return \Generator + */ + public function cursor(BaseQuery $query) + { + // 分析查询表达式 + $options = $query->parseOptions(); + + // 生成查询SQL + $sql = $this->builder->select($query); + + $condition = $options['where']['AND'] ?? null; + + // 执行查询操作 + return $this->getCursor($query, $sql, $query->getBind(), $query->getModel(), $condition); + } + + /** + * 查找记录 + * @access public + * @param BaseQuery $query 查询对象 + * @return array + * @throws DbException + */ + public function select(BaseQuery $query): array + { + $resultSet = $this->db->trigger('before_select', $query); + + if (!$resultSet) { + // 执行查询操作 + $resultSet = $this->pdoQuery($query, function ($query) { + return $this->builder->select($query); + }); + } + + return $resultSet; + } + + /** + * 插入记录 + * @access public + * @param BaseQuery $query 查询对象 + * @param boolean $getLastInsID 返回自增主键 + * @return mixed + */ + public function insert(BaseQuery $query, bool $getLastInsID = false) + { + // 分析查询表达式 + $options = $query->parseOptions(); + + // 生成SQL语句 + $sql = $this->builder->insert($query); + + // 执行操作 + $result = '' == $sql ? 0 : $this->pdoExecute($query, $sql, $query->getBind()); + + if ($result) { + $sequence = $options['sequence'] ?? null; + $lastInsId = $this->getLastInsID($query, $sequence); + + $data = $options['data']; + + if ($lastInsId) { + $pk = $query->getAutoInc(); + if ($pk) { + $data[$pk] = $lastInsId; + } + } + + $query->setOption('data', $data); + + $this->db->trigger('after_insert', $query); + + if ($getLastInsID && $lastInsId) { + return $lastInsId; + } + } + + return $result; + } + + /** + * 批量插入记录 + * @access public + * @param BaseQuery $query 查询对象 + * @param mixed $dataSet 数据集 + * @param integer $limit 每次写入数据限制 + * @return integer + * @throws \Exception + * @throws \Throwable + */ + public function insertAll(BaseQuery $query, array $dataSet = [], int $limit = 0): int + { + if (!is_array(reset($dataSet))) { + return 0; + } + + $options = $query->parseOptions(); + $replace = !empty($options['replace']); + + if (0 === $limit && count($dataSet) >= 5000) { + $limit = 1000; + } + + if ($limit) { + // 分批写入 自动启动事务支持 + $this->startTrans(); + + try { + $array = array_chunk($dataSet, $limit, true); + $count = 0; + + foreach ($array as $item) { + $sql = $this->builder->insertAll($query, $item, $replace); + $count += $this->pdoExecute($query, $sql, $query->getBind()); + } + + // 提交事务 + $this->commit(); + } catch (\Exception | \Throwable $e) { + $this->rollback(); + throw $e; + } + + return $count; + } + + $sql = $this->builder->insertAll($query, $dataSet, $replace); + + return $this->pdoExecute($query, $sql, $query->getBind()); + } + + /** + * 通过Select方式插入记录 + * @access public + * @param BaseQuery $query 查询对象 + * @param array $fields 要插入的数据表字段名 + * @param string $table 要插入的数据表名 + * @return integer + * @throws PDOException + */ + public function selectInsert(BaseQuery $query, array $fields, string $table): int + { + // 分析查询表达式 + $query->parseOptions(); + + $sql = $this->builder->selectInsert($query, $fields, $table); + + return $this->pdoExecute($query, $sql, $query->getBind()); + } + + /** + * 更新记录 + * @access public + * @param BaseQuery $query 查询对象 + * @return integer + * @throws PDOException + */ + public function update(BaseQuery $query): int + { + $query->parseOptions(); + + // 生成UPDATE SQL语句 + $sql = $this->builder->update($query); + + // 执行操作 + $result = '' == $sql ? 0 : $this->pdoExecute($query, $sql, $query->getBind()); + + if ($result) { + $this->db->trigger('after_update', $query); + } + + return $result; + } + + /** + * 删除记录 + * @access public + * @param BaseQuery $query 查询对象 + * @return int + * @throws PDOException + */ + public function delete(BaseQuery $query): int + { + // 分析查询表达式 + $query->parseOptions(); + + // 生成删除SQL语句 + $sql = $this->builder->delete($query); + + // 执行操作 + $result = $this->pdoExecute($query, $sql, $query->getBind()); + + if ($result) { + $this->db->trigger('after_delete', $query); + } + + return $result; + } + + /** + * 得到某个字段的值 + * @access public + * @param BaseQuery $query 查询对象 + * @param string $field 字段名 + * @param mixed $default 默认值 + * @param bool $one 返回一个值 + * @return mixed + */ + public function value(BaseQuery $query, string $field, $default = null, bool $one = true) + { + $options = $query->parseOptions(); + + if (isset($options['field'])) { + $query->removeOption('field'); + } + + if (isset($options['group'])) { + $query->group(''); + } + + $query->setOption('field', (array) $field); + + if (!empty($options['cache'])) { + $cacheItem = $this->parseCache($query, $options['cache'], 'value'); + $key = $cacheItem->getKey(); + + if ($this->cache->has($key)) { + return $this->cache->get($key); + } + } + + // 生成查询SQL + $sql = $this->builder->select($query, $one); + + if (isset($options['field'])) { + $query->setOption('field', $options['field']); + } else { + $query->removeOption('field'); + } + + if (isset($options['group'])) { + $query->setOption('group', $options['group']); + } + + // 执行查询操作 + $pdo = $this->getPDOStatement($sql, $query->getBind(), $options['master']); + + $result = $pdo->fetchColumn(); + + if (isset($cacheItem)) { + // 缓存数据 + $cacheItem->set($result); + $this->cacheData($cacheItem); + } + + return false !== $result ? $result : $default; + } + + /** + * 得到某个字段的值 + * @access public + * @param BaseQuery $query 查询对象 + * @param string $aggregate 聚合方法 + * @param mixed $field 字段名 + * @param bool $force 强制转为数字类型 + * @return mixed + */ + public function aggregate(BaseQuery $query, string $aggregate, $field, bool $force = false) + { + if (is_string($field) && 0 === stripos($field, 'DISTINCT ')) { + [$distinct, $field] = explode(' ', $field); + } + + $field = $aggregate . '(' . (!empty($distinct) ? 'DISTINCT ' : '') . $this->builder->parseKey($query, $field, true) . ') AS think_' . strtolower($aggregate); + + $result = $this->value($query, $field, 0, false); + + return $force ? (float) $result : $result; + } + + /** + * 得到某个列的数组 + * @access public + * @param BaseQuery $query 查询对象 + * @param string|array $column 字段名 多个字段用逗号分隔 + * @param string $key 索引 + * @return array + */ + public function column(BaseQuery $query, $column, string $key = ''): array + { + $options = $query->parseOptions(); + + if (isset($options['field'])) { + $query->removeOption('field'); + } + + if (empty($key) || trim($key) === '') { + $key = null; + } + + if (\is_string($column)) { + $column = \trim($column); + if ('*' !== $column) { + $column = \array_map('\trim', \explode(',', $column)); + } + } elseif (\is_array($column)) { + if (\in_array('*', $column)) { + $column = '*'; + } + } else { + throw new DbException('not support type'); + } + + $field = $column; + if ('*' !== $column && $key && !\in_array($key, $column)) { + $field[] = $key; + } + + $query->setOption('field', $field); + + if (!empty($options['cache'])) { + // 判断查询缓存 + $cacheItem = $this->parseCache($query, $options['cache'], 'column'); + $name = $cacheItem->getKey(); + + if ($this->cache->has($name)) { + return $this->cache->get($name); + } + } + + // 生成查询SQL + $sql = $this->builder->select($query); + + if (isset($options['field'])) { + $query->setOption('field', $options['field']); + } else { + $query->removeOption('field'); + } + + // 执行查询操作 + $pdo = $this->getPDOStatement($sql, $query->getBind(), $options['master']); + $resultSet = $pdo->fetchAll(PDO::FETCH_ASSOC); + + if (is_string($key) && strpos($key, '.')) { + [$alias, $key] = explode('.', $key); + } + + if (empty($resultSet)) { + $result = []; + } elseif ('*' !== $column && \count($column) === 1) { + $column = \array_shift($column); + if (\strpos($column, ' ')) { + $column = \substr(\strrchr(\trim($column), ' '), 1); + } + + if (\strpos($column, '.')) { + [$alias, $column] = \explode('.', $column); + } + + $result = \array_column($resultSet, $column, $key); + } elseif ($key) { + $result = \array_column($resultSet, null, $key); + } else { + $result = $resultSet; + } + + if (isset($cacheItem)) { + // 缓存数据 + $cacheItem->set($result); + $this->cacheData($cacheItem); + } + + return $result; + } + + /** + * 根据参数绑定组装最终的SQL语句 便于调试 + * @access public + * @param string $sql 带参数绑定的sql语句 + * @param array $bind 参数绑定列表 + * @return string + */ + public function getRealSql(string $sql, array $bind = []): string + { + foreach ($bind as $key => $val) { + $value = strval(is_array($val) ? $val[0] : $val); + $type = is_array($val) ? $val[1] : PDO::PARAM_STR; + + if (self::PARAM_FLOAT == $type || PDO::PARAM_STR == $type) { + $value = '\'' . addslashes($value) . '\''; + } elseif (PDO::PARAM_INT == $type && '' === $value) { + $value = '0'; + } + + // 判断占位符 + $sql = is_numeric($key) ? + substr_replace($sql, $value, strpos($sql, '?'), 1) : + substr_replace($sql, $value, strpos($sql, ':' . $key), strlen(':' . $key)); + } + + return rtrim($sql); + } + + /** + * 参数绑定 + * 支持 ['name'=>'value','id'=>123] 对应命名占位符 + * 或者 ['value',123] 对应问号占位符 + * @access public + * @param array $bind 要绑定的参数列表 + * @return void + * @throws BindParamException + */ + protected function bindValue(array $bind = []): void + { + foreach ($bind as $key => $val) { + // 占位符 + $param = is_numeric($key) ? $key + 1 : ':' . $key; + + if (is_array($val)) { + if (PDO::PARAM_INT == $val[1] && '' === $val[0]) { + $val[0] = 0; + } elseif (self::PARAM_FLOAT == $val[1]) { + $val[0] = is_string($val[0]) ? (float) $val[0] : $val[0]; + $val[1] = PDO::PARAM_STR; + } + + $result = $this->PDOStatement->bindValue($param, $val[0], $val[1]); + } else { + $result = $this->PDOStatement->bindValue($param, $val); + } + + if (!$result) { + throw new BindParamException( + "Error occurred when binding parameters '{$param}'", + $this->config, + $this->getLastsql(), + $bind + ); + } + } + } + + /** + * 存储过程的输入输出参数绑定 + * @access public + * @param array $bind 要绑定的参数列表 + * @return void + * @throws BindParamException + */ + protected function bindParam(array $bind): void + { + foreach ($bind as $key => $val) { + $param = is_numeric($key) ? $key + 1 : ':' . $key; + + if (is_array($val)) { + array_unshift($val, $param); + $result = call_user_func_array([$this->PDOStatement, 'bindParam'], $val); + } else { + $result = $this->PDOStatement->bindValue($param, $val); + } + + if (!$result) { + $param = array_shift($val); + + throw new BindParamException( + "Error occurred when binding parameters '{$param}'", + $this->config, + $this->getLastsql(), + $bind + ); + } + } + } + + /** + * 获得数据集数组 + * @access protected + * @param bool $procedure 是否存储过程 + * @return array + */ + protected function getResult(bool $procedure = false): array + { + if ($procedure) { + // 存储过程返回结果 + return $this->procedure(); + } + + $result = $this->PDOStatement->fetchAll($this->fetchType); + + $this->numRows = count($result); + + return $result; + } + + /** + * 获得存储过程数据集 + * @access protected + * @return array + */ + protected function procedure(): array + { + $item = []; + + do { + $result = $this->getResult(); + if (!empty($result)) { + $item[] = $result; + } + } while ($this->PDOStatement->nextRowset()); + + $this->numRows = count($item); + + return $item; + } + + /** + * 执行数据库事务 + * @access public + * @param callable $callback 数据操作方法回调 + * @return mixed + * @throws PDOException + * @throws \Exception + * @throws \Throwable + */ + public function transaction(callable $callback) + { + $this->startTrans(); + + try { + $result = null; + if (is_callable($callback)) { + $result = $callback($this); + } + + $this->commit(); + return $result; + } catch (\Exception | \Throwable $e) { + $this->rollback(); + throw $e; + } + } + + /** + * 启动事务 + * @access public + * @return void + * @throws \PDOException + * @throws \Exception + */ + public function startTrans(): void + { + try { + $this->initConnect(true); + + ++$this->transTimes; + + if (1 == $this->transTimes) { + $this->linkID->beginTransaction(); + } elseif ($this->transTimes > 1 && $this->supportSavepoint()) { + $this->linkID->exec( + $this->parseSavepoint('trans' . $this->transTimes) + ); + } + $this->reConnectTimes = 0; + } catch (\Throwable | \Exception $e) { + if ($this->transTimes === 1 && $this->reConnectTimes < 4 && $this->isBreak($e)) { + --$this->transTimes; + ++$this->reConnectTimes; + $this->close()->startTrans(); + } else { + if ($this->isBreak($e)) { + // 尝试对事务计数进行重置 + $this->transTimes = 0; + } + throw $e; + } + } + } + + /** + * 用于非自动提交状态下面的查询提交 + * @access public + * @return void + * @throws \PDOException + */ + public function commit(): void + { + $this->initConnect(true); + + if (1 == $this->transTimes) { + $this->linkID->commit(); + } + + --$this->transTimes; + } + + /** + * 事务回滚 + * @access public + * @return void + * @throws \PDOException + */ + public function rollback(): void + { + $this->initConnect(true); + + if (1 == $this->transTimes) { + $this->linkID->rollBack(); + } elseif ($this->transTimes > 1 && $this->supportSavepoint()) { + $this->linkID->exec( + $this->parseSavepointRollBack('trans' . $this->transTimes) + ); + } + + $this->transTimes = max(0, $this->transTimes - 1); + } + + /** + * 是否支持事务嵌套 + * @return bool + */ + protected function supportSavepoint(): bool + { + return false; + } + + /** + * 生成定义保存点的SQL + * @access protected + * @param string $name 标识 + * @return string + */ + protected function parseSavepoint(string $name): string + { + return 'SAVEPOINT ' . $name; + } + + /** + * 生成回滚到保存点的SQL + * @access protected + * @param string $name 标识 + * @return string + */ + protected function parseSavepointRollBack(string $name): string + { + return 'ROLLBACK TO SAVEPOINT ' . $name; + } + + /** + * 批处理执行SQL语句 + * 批处理的指令都认为是execute操作 + * @access public + * @param BaseQuery $query 查询对象 + * @param array $sqlArray SQL批处理指令 + * @param array $bind 参数绑定 + * @return bool + */ + public function batchQuery(BaseQuery $query, array $sqlArray = [], array $bind = []): bool + { + // 自动启动事务支持 + $this->startTrans(); + + try { + foreach ($sqlArray as $sql) { + $this->pdoExecute($query, $sql, $bind); + } + // 提交事务 + $this->commit(); + } catch (\Exception $e) { + $this->rollback(); + throw $e; + } + + return true; + } + + /** + * 关闭数据库(或者重新连接) + * @access public + * @return $this + */ + public function close() + { + $this->linkID = null; + $this->linkWrite = null; + $this->linkRead = null; + $this->links = []; + $this->transTimes = 0; + + $this->free(); + + return $this; + } + + /** + * 是否断线 + * @access protected + * @param \PDOException|\Exception $e 异常对象 + * @return bool + */ + protected function isBreak($e): bool + { + if (!$this->config['break_reconnect']) { + return false; + } + + $error = $e->getMessage(); + + foreach ($this->breakMatchStr as $msg) { + if (false !== stripos($error, $msg)) { + return true; + } + } + + return false; + } + + /** + * 获取最近一次查询的sql语句 + * @access public + * @return string + */ + public function getLastSql(): string + { + return $this->getRealSql($this->queryStr, $this->bind); + } + + /** + * 获取最近插入的ID + * @access public + * @param BaseQuery $query 查询对象 + * @param string $sequence 自增序列名 + * @return mixed + */ + public function getLastInsID(BaseQuery $query, string $sequence = null) + { + try { + $insertId = $this->linkID->lastInsertId($sequence); + } catch (\Exception $e) { + $insertId = ''; + } + + return $this->autoInsIDType($query, $insertId); + } + + /** + * 获取最近插入的ID + * @access public + * @param BaseQuery $query 查询对象 + * @param string $insertId 自增ID + * @return mixed + */ + protected function autoInsIDType(BaseQuery $query, string $insertId) + { + $pk = $query->getAutoInc(); + + if ($pk) { + $type = $this->getFieldBindType($pk); + + if (PDO::PARAM_INT == $type) { + $insertId = (int) $insertId; + } elseif (self::PARAM_FLOAT == $type) { + $insertId = (float) $insertId; + } + } + + return $insertId; + } + + /** + * 获取最近的错误信息 + * @access public + * @return string + */ + public function getError(): string + { + if ($this->PDOStatement) { + $error = $this->PDOStatement->errorInfo(); + $error = $error[1] . ':' . $error[2]; + } else { + $error = ''; + } + + if ('' != $this->queryStr) { + $error .= "\n [ SQL语句 ] : " . $this->getLastsql(); + } + + return $error; + } + + /** + * 初始化数据库连接 + * @access protected + * @param boolean $master 是否主服务器 + * @return void + */ + protected function initConnect(bool $master = true): void + { + if (!empty($this->config['deploy'])) { + // 采用分布式数据库 + if ($master || $this->transTimes) { + if (!$this->linkWrite) { + $this->linkWrite = $this->multiConnect(true); + } + + $this->linkID = $this->linkWrite; + } else { + if (!$this->linkRead) { + $this->linkRead = $this->multiConnect(false); + } + + $this->linkID = $this->linkRead; + } + } elseif (!$this->linkID) { + // 默认单数据库 + $this->linkID = $this->connect(); + } + } + + /** + * 连接分布式服务器 + * @access protected + * @param boolean $master 主服务器 + * @return PDO + */ + protected function multiConnect(bool $master = false): PDO + { + $config = []; + + // 分布式数据库配置解析 + foreach (['username', 'password', 'hostname', 'hostport', 'database', 'dsn', 'charset'] as $name) { + $config[$name] = is_string($this->config[$name]) ? explode(',', $this->config[$name]) : $this->config[$name]; + } + + // 主服务器序号 + $m = floor(mt_rand(0, $this->config['master_num'] - 1)); + + if ($this->config['rw_separate']) { + // 主从式采用读写分离 + if ($master) // 主服务器写入 + { + $r = $m; + } elseif (is_numeric($this->config['slave_no'])) { + // 指定服务器读 + $r = $this->config['slave_no']; + } else { + // 读操作连接从服务器 每次随机连接的数据库 + $r = floor(mt_rand($this->config['master_num'], count($config['hostname']) - 1)); + } + } else { + // 读写操作不区分服务器 每次随机连接的数据库 + $r = floor(mt_rand(0, count($config['hostname']) - 1)); + } + $dbMaster = false; + + if ($m != $r) { + $dbMaster = []; + foreach (['username', 'password', 'hostname', 'hostport', 'database', 'dsn', 'charset'] as $name) { + $dbMaster[$name] = $config[$name][$m] ?? $config[$name][0]; + } + } + + $dbConfig = []; + + foreach (['username', 'password', 'hostname', 'hostport', 'database', 'dsn', 'charset'] as $name) { + $dbConfig[$name] = $config[$name][$r] ?? $config[$name][0]; + } + + return $this->connect($dbConfig, $r, $r == $m ? false : $dbMaster); + } + + /** + * 启动XA事务 + * @access public + * @param string $xid XA事务id + * @return void + */ + public function startTransXa(string $xid) + {} + + /** + * 预编译XA事务 + * @access public + * @param string $xid XA事务id + * @return void + */ + public function prepareXa(string $xid) + {} + + /** + * 提交XA事务 + * @access public + * @param string $xid XA事务id + * @return void + */ + public function commitXa(string $xid) + {} + + /** + * 回滚XA事务 + * @access public + * @param string $xid XA事务id + * @return void + */ + public function rollbackXa(string $xid) + {} +} diff --git a/vendor/topthink/think-orm/src/db/Query.php b/vendor/topthink/think-orm/src/db/Query.php new file mode 100644 index 000000000..80e01cd9b --- /dev/null +++ b/vendor/topthink/think-orm/src/db/Query.php @@ -0,0 +1,451 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\db; + +use PDOStatement; +use think\helper\Str; + +/** + * PDO数据查询类 + */ +class Query extends BaseQuery +{ + use concern\JoinAndViewQuery; + use concern\ParamsBind; + use concern\TableFieldInfo; + + /** + * 表达式方式指定Field排序 + * @access public + * @param string $field 排序字段 + * @param array $bind 参数绑定 + * @return $this + */ + public function orderRaw(string $field, array $bind = []) + { + $this->options['order'][] = new Raw($field, $bind); + + return $this; + } + + /** + * 表达式方式指定查询字段 + * @access public + * @param string $field 字段名 + * @return $this + */ + public function fieldRaw(string $field) + { + $this->options['field'][] = new Raw($field); + + return $this; + } + + /** + * 指定Field排序 orderField('id',[1,2,3],'desc') + * @access public + * @param string $field 排序字段 + * @param array $values 排序值 + * @param string $order 排序 desc/asc + * @return $this + */ + public function orderField(string $field, array $values, string $order = '') + { + if (!empty($values)) { + $values['sort'] = $order; + + $this->options['order'][$field] = $values; + } + + return $this; + } + + /** + * 随机排序 + * @access public + * @return $this + */ + public function orderRand() + { + $this->options['order'][] = '[rand]'; + return $this; + } + + /** + * 使用表达式设置数据 + * @access public + * @param string $field 字段名 + * @param string $value 字段值 + * @return $this + */ + public function exp(string $field, string $value) + { + $this->options['data'][$field] = new Raw($value); + return $this; + } + + /** + * 表达式方式指定当前操作的数据表 + * @access public + * @param mixed $table 表名 + * @return $this + */ + public function tableRaw(string $table) + { + $this->options['table'] = new Raw($table); + + return $this; + } + + /** + * 获取执行的SQL语句而不进行实际的查询 + * @access public + * @param bool $fetch 是否返回sql + * @return $this|Fetch + */ + public function fetchSql(bool $fetch = true) + { + $this->options['fetch_sql'] = $fetch; + + if ($fetch) { + return new Fetch($this); + } + + return $this; + } + + /** + * 批处理执行SQL语句 + * 批处理的指令都认为是execute操作 + * @access public + * @param array $sql SQL批处理指令 + * @return bool + */ + public function batchQuery(array $sql = []): bool + { + return $this->connection->batchQuery($this, $sql); + } + + /** + * USING支持 用于多表删除 + * @access public + * @param mixed $using USING + * @return $this + */ + public function using($using) + { + $this->options['using'] = $using; + return $this; + } + + /** + * 存储过程调用 + * @access public + * @param bool $procedure 是否为存储过程查询 + * @return $this + */ + public function procedure(bool $procedure = true) + { + $this->options['procedure'] = $procedure; + return $this; + } + + /** + * 指定group查询 + * @access public + * @param string|array $group GROUP + * @return $this + */ + public function group($group) + { + $this->options['group'] = $group; + return $this; + } + + /** + * 指定having查询 + * @access public + * @param string $having having + * @return $this + */ + public function having(string $having) + { + $this->options['having'] = $having; + return $this; + } + + /** + * 指定distinct查询 + * @access public + * @param bool $distinct 是否唯一 + * @return $this + */ + public function distinct(bool $distinct = true) + { + $this->options['distinct'] = $distinct; + return $this; + } + + /** + * 指定强制索引 + * @access public + * @param string $force 索引名称 + * @return $this + */ + public function force(string $force) + { + $this->options['force'] = $force; + return $this; + } + + /** + * 查询注释 + * @access public + * @param string $comment 注释 + * @return $this + */ + public function comment(string $comment) + { + $this->options['comment'] = $comment; + return $this; + } + + /** + * 设置是否REPLACE + * @access public + * @param bool $replace 是否使用REPLACE写入数据 + * @return $this + */ + public function replace(bool $replace = true) + { + $this->options['replace'] = $replace; + return $this; + } + + /** + * 设置当前查询所在的分区 + * @access public + * @param string|array $partition 分区名称 + * @return $this + */ + public function partition($partition) + { + $this->options['partition'] = $partition; + return $this; + } + + /** + * 设置DUPLICATE + * @access public + * @param array|string|Raw $duplicate DUPLICATE信息 + * @return $this + */ + public function duplicate($duplicate) + { + $this->options['duplicate'] = $duplicate; + return $this; + } + + /** + * 设置查询的额外参数 + * @access public + * @param string $extra 额外信息 + * @return $this + */ + public function extra(string $extra) + { + $this->options['extra'] = $extra; + return $this; + } + + /** + * 创建子查询SQL + * @access public + * @param bool $sub 是否添加括号 + * @return string + * @throws Exception + */ + public function buildSql(bool $sub = true): string + { + return $sub ? '( ' . $this->fetchSql()->select() . ' )' : $this->fetchSql()->select(); + } + + /** + * 获取当前数据表的主键 + * @access public + * @return string|array + */ + public function getPk() + { + if (empty($this->pk)) { + $this->pk = $this->connection->getPk($this->getTable()); + } + + return $this->pk; + } + + /** + * 指定数据表自增主键 + * @access public + * @param string $autoinc 自增键 + * @return $this + */ + public function autoinc(string $autoinc) + { + $this->autoinc = $autoinc; + return $this; + } + + /** + * 获取当前数据表的自增主键 + * @access public + * @return string|null + */ + public function getAutoInc() + { + $tableName = $this->getTable(); + + if (empty($this->autoinc) && $tableName) { + $this->autoinc = $this->connection->getAutoInc($tableName); + } + + return $this->autoinc; + } + + /** + * 字段值增长 + * @access public + * @param string $field 字段名 + * @param float $step 增长值 + * @return $this + */ + public function inc(string $field, float $step = 1) + { + $this->options['data'][$field] = ['INC', $step]; + + return $this; + } + + /** + * 字段值减少 + * @access public + * @param string $field 字段名 + * @param float $step 增长值 + * @return $this + */ + public function dec(string $field, float $step = 1) + { + $this->options['data'][$field] = ['DEC', $step]; + return $this; + } + + /** + * 获取当前的查询标识 + * @access public + * @param mixed $data 要序列化的数据 + * @return string + */ + public function getQueryGuid($data = null): string + { + return md5($this->getConfig('database') . serialize(var_export($data ?: $this->options, true)) . serialize($this->getBind(false))); + } + + /** + * 执行查询但只返回PDOStatement对象 + * @access public + * @return PDOStatement + */ + public function getPdo(): PDOStatement + { + return $this->connection->pdo($this); + } + + /** + * 使用游标查找记录 + * @access public + * @param mixed $data 数据 + * @return \Generator + */ + public function cursor($data = null) + { + if (!is_null($data)) { + // 主键条件分析 + $this->parsePkWhere($data); + } + + $this->options['data'] = $data; + + $connection = clone $this->connection; + + return $connection->cursor($this); + } + + /** + * 分批数据返回处理 + * @access public + * @param integer $count 每次处理的数据数量 + * @param callable $callback 处理回调方法 + * @param string|array $column 分批处理的字段名 + * @param string $order 字段排序 + * @return bool + * @throws Exception + */ + public function chunk(int $count, callable $callback, $column = null, string $order = 'asc'): bool + { + $options = $this->getOptions(); + $column = $column ?: $this->getPk(); + + if (isset($options['order'])) { + unset($options['order']); + } + + $bind = $this->bind; + + if (is_array($column)) { + $times = 1; + $query = $this->options($options)->page($times, $count); + } else { + $query = $this->options($options)->limit($count); + + if (strpos($column, '.')) { + [$alias, $key] = explode('.', $column); + } else { + $key = $column; + } + } + + $resultSet = $query->order($column, $order)->select(); + + while (count($resultSet) > 0) { + if (false === call_user_func($callback, $resultSet)) { + return false; + } + + if (isset($times)) { + $times++; + $query = $this->options($options)->page($times, $count); + } else { + $end = $resultSet->pop(); + $lastId = is_array($end) ? $end[$key] : $end->getData($key); + + $query = $this->options($options) + ->limit($count) + ->where($column, 'asc' == strtolower($order) ? '>' : '<', $lastId); + } + + $resultSet = $query->bind($bind)->order($column, $order)->select(); + } + + return true; + } +} diff --git a/thinkphp/library/think/db/Expression.php b/vendor/topthink/think-orm/src/db/Raw.php old mode 100755 new mode 100644 similarity index 65% rename from thinkphp/library/think/db/Expression.php rename to vendor/topthink/think-orm/src/db/Raw.php index f1b92abd7..833fbf08c --- a/thinkphp/library/think/db/Expression.php +++ b/vendor/topthink/think-orm/src/db/Raw.php @@ -2,16 +2,20 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\db; -class Expression +/** + * SQL Raw + */ +class Raw { /** * 查询表达式 @@ -20,15 +24,24 @@ class Expression */ protected $value; + /** + * 参数绑定 + * + * @var array + */ + protected $bind = []; + /** * 创建一个查询表达式 * * @param string $value + * @param array $bind * @return void */ - public function __construct($value) + public function __construct(string $value, array $bind = []) { $this->value = $value; + $this->bind = $bind; } /** @@ -36,11 +49,21 @@ class Expression * * @return string */ - public function getValue() + public function getValue(): string { return $this->value; } + /** + * 获取参数绑定 + * + * @return string + */ + public function getBind(): array + { + return $this->bind; + } + public function __toString() { return (string) $this->value; diff --git a/thinkphp/library/think/db/Where.php b/vendor/topthink/think-orm/src/db/Where.php old mode 100755 new mode 100644 similarity index 83% rename from thinkphp/library/think/db/Where.php rename to vendor/topthink/think-orm/src/db/Where.php index 9132e5461..088046089 --- a/thinkphp/library/think/db/Where.php +++ b/vendor/topthink/think-orm/src/db/Where.php @@ -2,17 +2,21 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\db; use ArrayAccess; +/** + * 数组查询对象 + */ class Where implements ArrayAccess { /** @@ -22,7 +26,7 @@ class Where implements ArrayAccess protected $where = []; /** - * 是否需要增加括号 + * 是否需要把查询条件两边增加括号 * @var bool */ protected $enclose = false; @@ -33,7 +37,7 @@ class Where implements ArrayAccess * @param array $where 查询条件数组 * @param bool $enclose 是否增加括号 */ - public function __construct(array $where = [], $enclose = false) + public function __construct(array $where = [], bool $enclose = false) { $this->where = $where; $this->enclose = $enclose; @@ -45,7 +49,7 @@ class Where implements ArrayAccess * @param bool $enclose * @return $this */ - public function enclose($enclose = true) + public function enclose(bool $enclose = true) { $this->enclose = $enclose; return $this; @@ -56,12 +60,12 @@ class Where implements ArrayAccess * @access public * @return array */ - public function parse() + public function parse(): array { $where = []; foreach ($this->where as $key => $val) { - if ($val instanceof Expression) { + if ($val instanceof Raw) { $where[] = [$key, 'exp', $val]; } elseif (is_null($val)) { $where[] = [$key, 'NULL', '']; @@ -82,21 +86,21 @@ class Where implements ArrayAccess * @param array $where 查询条件 * @return array */ - protected function parseItem($field, $where = []) + protected function parseItem(string $field, array $where = []): array { $op = $where[0]; - $condition = isset($where[1]) ? $where[1] : null; + $condition = $where[1] ?? null; if (is_array($op)) { // 同一字段多条件查询 array_unshift($where, $field); } elseif (is_null($condition)) { - if (in_array(strtoupper($op), ['NULL', 'NOTNULL', 'NOT NULL'], true)) { + if (is_string($op) && in_array(strtoupper($op), ['NULL', 'NOTNULL', 'NOT NULL'], true)) { // null查询 $where = [$field, $op, '']; - } elseif (in_array($op, ['=', 'eq', 'EQ', null], true)) { + } elseif (is_null($op) || '=' == $op) { $where = [$field, 'NULL', '']; - } elseif (in_array($op, ['<>', 'neq', 'NEQ'], true)) { + } elseif ('<>' == $op) { $where = [$field, 'NOTNULL', '']; } else { // 字段相等查询 @@ -129,14 +133,14 @@ class Where implements ArrayAccess */ public function __get($name) { - return isset($this->where[$name]) ? $this->where[$name] : null; + return $this->where[$name] ?? null; } /** * 检测数据对象的值 * @access public * @param string $name 名称 - * @return boolean + * @return bool */ public function __isset($name) { diff --git a/vendor/topthink/think-orm/src/db/builder/Mongo.php b/vendor/topthink/think-orm/src/db/builder/Mongo.php new file mode 100644 index 000000000..823156bc3 --- /dev/null +++ b/vendor/topthink/think-orm/src/db/builder/Mongo.php @@ -0,0 +1,675 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); +namespace think\db\builder; + +use MongoDB\BSON\Javascript; +use MongoDB\BSON\ObjectID; +use MongoDB\BSON\Regex; +use MongoDB\Driver\BulkWrite; +use MongoDB\Driver\Command; +use MongoDB\Driver\Exception\InvalidArgumentException; +use MongoDB\Driver\Query as MongoQuery; +use think\db\connector\Mongo as Connection; +use think\db\exception\DbException as Exception; +use think\db\Mongo as Query; + +class Mongo +{ + // connection对象实例 + protected $connection; + // 最后插入ID + protected $insertId = []; + // 查询表达式 + protected $exp = ['<>' => 'ne', '=' => 'eq', '>' => 'gt', '>=' => 'gte', '<' => 'lt', '<=' => 'lte', 'in' => 'in', 'not in' => 'nin', 'nin' => 'nin', 'mod' => 'mod', 'exists' => 'exists', 'null' => 'null', 'notnull' => 'not null', 'not null' => 'not null', 'regex' => 'regex', 'type' => 'type', 'all' => 'all', '> time' => '> time', '< time' => '< time', 'between' => 'between', 'not between' => 'not between', 'between time' => 'between time', 'not between time' => 'not between time', 'notbetween time' => 'not between time', 'like' => 'like', 'near' => 'near', 'size' => 'size']; + + /** + * 架构函数 + * @access public + * @param Connection $connection 数据库连接对象实例 + */ + public function __construct(Connection $connection) + { + $this->connection = $connection; + } + + /** + * 获取当前的连接对象实例 + * @access public + * @return Connection + */ + public function getConnection(): Connection + { + return $this->connection; + } + + /** + * key分析 + * @access protected + * @param string $key + * @return string + */ + protected function parseKey(Query $query, string $key): string + { + if (0 === strpos($key, '__TABLE__.')) { + [$collection, $key] = explode('.', $key, 2); + } + + if ('id' == $key && $this->connection->getConfig('pk_convert_id')) { + $key = '_id'; + } + + return trim($key); + } + + /** + * value分析 + * @access protected + * @param Query $query 查询对象 + * @param mixed $value + * @param string $field + * @return string + */ + protected function parseValue(Query $query, $value, $field = '') + { + if ('_id' == $field && 'ObjectID' == $this->connection->getConfig('pk_type') && is_string($value)) { + try { + return new ObjectID($value); + } catch (InvalidArgumentException $e) { + return new ObjectID(); + } + } + + return $value; + } + + /** + * insert数据分析 + * @access protected + * @param Query $query 查询对象 + * @param array $data 数据 + * @return array + */ + protected function parseData(Query $query, array $data): array + { + if (empty($data)) { + return []; + } + + $result = []; + + foreach ($data as $key => $val) { + $item = $this->parseKey($query, $key); + + if (is_object($val)) { + $result[$item] = $val; + } elseif (isset($val[0]) && 'exp' == $val[0]) { + $result[$item] = $val[1]; + } elseif (is_null($val)) { + $result[$item] = 'NULL'; + } else { + $result[$item] = $this->parseValue($query, $val, $key); + } + } + + return $result; + } + + /** + * Set数据分析 + * @access protected + * @param Query $query 查询对象 + * @param array $data 数据 + * @return array + */ + protected function parseSet(Query $query, array $data): array + { + if (empty($data)) { + return []; + } + + $result = []; + + foreach ($data as $key => $val) { + $item = $this->parseKey($query, $key); + + if (is_array($val) && isset($val[0]) && is_string($val[0]) && 0 === strpos($val[0], '$')) { + $result[$val[0]][$item] = $this->parseValue($query, $val[1], $key); + } else { + $result['$set'][$item] = $this->parseValue($query, $val, $key); + } + } + + return $result; + } + + /** + * 生成查询过滤条件 + * @access public + * @param Query $query 查询对象 + * @param mixed $where + * @return array + */ + public function parseWhere(Query $query, array $where): array + { + if (empty($where)) { + $where = []; + } + + $filter = []; + foreach ($where as $logic => $val) { + $logic = '$' . strtolower($logic); + foreach ($val as $field => $value) { + if (is_array($value)) { + if (key($value) !== 0) { + throw new Exception('where express error:' . var_export($value, true)); + } + $field = array_shift($value); + } elseif (!($value instanceof \Closure)) { + throw new Exception('where express error:' . var_export($value, true)); + } + + if ($value instanceof \Closure) { + // 使用闭包查询 + $query = new Query($this->connection); + call_user_func_array($value, [ & $query]); + $filter[$logic][] = $this->parseWhere($query, $query->getOptions('where')); + } else { + if (strpos($field, '|')) { + // 不同字段使用相同查询条件(OR) + $array = explode('|', $field); + foreach ($array as $k) { + $filter['$or'][] = $this->parseWhereItem($query, $k, $value); + } + } elseif (strpos($field, '&')) { + // 不同字段使用相同查询条件(AND) + $array = explode('&', $field); + foreach ($array as $k) { + $filter['$and'][] = $this->parseWhereItem($query, $k, $value); + } + } else { + // 对字段使用表达式查询 + $field = is_string($field) ? $field : ''; + $filter[$logic][] = $this->parseWhereItem($query, $field, $value); + } + } + } + } + + $options = $query->getOptions(); + if (!empty($options['soft_delete'])) { + // 附加软删除条件 + [$field, $condition] = $options['soft_delete']; + $filter['$and'][] = $this->parseWhereItem($query, $field, $condition); + } + + return $filter; + } + + // where子单元分析 + protected function parseWhereItem(Query $query, $field, $val): array + { + $key = $field ? $this->parseKey($query, $field) : ''; + // 查询规则和条件 + if (!is_array($val)) { + $val = ['=', $val]; + } + [$exp, $value] = $val; + + // 对一个字段使用多个查询条件 + if (is_array($exp)) { + $data = []; + foreach ($val as $value) { + $exp = $value[0]; + $value = $value[1]; + if (!in_array($exp, $this->exp)) { + $exp = strtolower($exp); + if (isset($this->exp[$exp])) { + $exp = $this->exp[$exp]; + } + } + $k = '$' . $exp; + $data[$k] = $value; + } + $result[$key] = $data; + return $result; + } elseif (!in_array($exp, $this->exp)) { + $exp = strtolower($exp); + if (isset($this->exp[$exp])) { + $exp = $this->exp[$exp]; + } else { + throw new Exception('where express error:' . $exp); + } + } + + $result = []; + if ('=' == $exp) { + // 普通查询 + $result[$key] = $this->parseValue($query, $value, $key); + } elseif (in_array($exp, ['neq', 'ne', 'gt', 'egt', 'gte', 'lt', 'lte', 'elt', 'mod'])) { + // 比较运算 + $k = '$' . $exp; + $result[$key] = [$k => $this->parseValue($query, $value, $key)]; + } elseif ('null' == $exp) { + // NULL 查询 + $result[$key] = null; + } elseif ('not null' == $exp) { + $result[$key] = ['$ne' => null]; + } elseif ('all' == $exp) { + // 满足所有指定条件 + $result[$key] = ['$all', $this->parseValue($query, $value, $key)]; + } elseif ('between' == $exp) { + // 区间查询 + $value = is_array($value) ? $value : explode(',', $value); + $result[$key] = ['$gte' => $this->parseValue($query, $value[0], $key), '$lte' => $this->parseValue($query, $value[1], $key)]; + } elseif ('not between' == $exp) { + // 范围查询 + $value = is_array($value) ? $value : explode(',', $value); + $result[$key] = ['$lt' => $this->parseValue($query, $value[0], $key), '$gt' => $this->parseValue($query, $value[1], $key)]; + } elseif ('exists' == $exp) { + // 字段是否存在 + $result[$key] = ['$exists' => (bool) $value]; + } elseif ('type' == $exp) { + // 类型查询 + $result[$key] = ['$type' => intval($value)]; + } elseif ('exp' == $exp) { + // 表达式查询 + $result['$where'] = $value instanceof Javascript ? $value : new Javascript($value); + } elseif ('like' == $exp) { + // 模糊查询 采用正则方式 + $result[$key] = $value instanceof Regex ? $value : new Regex($value, 'i'); + } elseif (in_array($exp, ['nin', 'in'])) { + // IN 查询 + $value = is_array($value) ? $value : explode(',', $value); + foreach ($value as $k => $val) { + $value[$k] = $this->parseValue($query, $val, $key); + } + $result[$key] = ['$' . $exp => $value]; + } elseif ('regex' == $exp) { + $result[$key] = $value instanceof Regex ? $value : new Regex($value, 'i'); + } elseif ('< time' == $exp) { + $result[$key] = ['$lt' => $this->parseDateTime($query, $value, $field)]; + } elseif ('> time' == $exp) { + $result[$key] = ['$gt' => $this->parseDateTime($query, $value, $field)]; + } elseif ('between time' == $exp) { + // 区间查询 + $value = is_array($value) ? $value : explode(',', $value); + $result[$key] = ['$gte' => $this->parseDateTime($query, $value[0], $field), '$lte' => $this->parseDateTime($query, $value[1], $field)]; + } elseif ('not between time' == $exp) { + // 范围查询 + $value = is_array($value) ? $value : explode(',', $value); + $result[$key] = ['$lt' => $this->parseDateTime($query, $value[0], $field), '$gt' => $this->parseDateTime($query, $value[1], $field)]; + } elseif ('near' == $exp) { + // 经纬度查询 + $result[$key] = ['$near' => $this->parseValue($query, $value, $key)]; + } elseif ('size' == $exp) { + // 元素长度查询 + $result[$key] = ['$size' => intval($value)]; + } else { + // 普通查询 + $result[$key] = $this->parseValue($query, $value, $key); + } + + return $result; + } + + /** + * 日期时间条件解析 + * @access protected + * @param Query $query 查询对象 + * @param string $value + * @param string $key + * @return string + */ + protected function parseDateTime(Query $query, $value, $key) + { + // 获取时间字段类型 + $type = $query->getFieldType($key); + + if ($type) { + if (is_string($value)) { + $value = strtotime($value) ?: $value; + } + + if (is_int($value)) { + if (preg_match('/(datetime|timestamp)/is', $type)) { + // 日期及时间戳类型 + $value = date('Y-m-d H:i:s', $value); + } elseif (preg_match('/(date)/is', $type)) { + // 日期及时间戳类型 + $value = date('Y-m-d', $value); + } + } + } + + return $value; + } + + /** + * 获取最后写入的ID 如果是insertAll方法的话 返回所有写入的ID + * @access public + * @return mixed + */ + public function getLastInsID() + { + return $this->insertId; + } + + /** + * 生成insert BulkWrite对象 + * @access public + * @param Query $query 查询对象 + * @return BulkWrite + */ + public function insert(Query $query): BulkWrite + { + // 分析并处理数据 + $options = $query->getOptions(); + + $data = $this->parseData($query, $options['data']); + + $bulk = new BulkWrite; + + if ($insertId = $bulk->insert($data)) { + $this->insertId = $insertId; + } + + $this->log('insert', $data, $options); + + return $bulk; + } + + /** + * 生成insertall BulkWrite对象 + * @access public + * @param Query $query 查询对象 + * @param array $dataSet 数据集 + * @return BulkWrite + */ + public function insertAll(Query $query, array $dataSet): BulkWrite + { + $bulk = new BulkWrite; + $options = $query->getOptions(); + + $this->insertId = []; + foreach ($dataSet as $data) { + // 分析并处理数据 + $data = $this->parseData($query, $data); + if ($insertId = $bulk->insert($data)) { + $this->insertId[] = $insertId; + } + } + + $this->log('insert', $dataSet, $options); + + return $bulk; + } + + /** + * 生成update BulkWrite对象 + * @access public + * @param Query $query 查询对象 + * @return BulkWrite + */ + public function update(Query $query): BulkWrite + { + $options = $query->getOptions(); + + $data = $this->parseSet($query, $options['data']); + $where = $this->parseWhere($query, $options['where']); + + if (1 == $options['limit']) { + $updateOptions = ['multi' => false]; + } else { + $updateOptions = ['multi' => true]; + } + + $bulk = new BulkWrite; + + $bulk->update($where, $data, $updateOptions); + + $this->log('update', $data, $where); + + return $bulk; + } + + /** + * 生成delete BulkWrite对象 + * @access public + * @param Query $query 查询对象 + * @return BulkWrite + */ + public function delete(Query $query): BulkWrite + { + $options = $query->getOptions(); + $where = $this->parseWhere($query, $options['where']); + + $bulk = new BulkWrite; + + if (1 == $options['limit']) { + $deleteOptions = ['limit' => 1]; + } else { + $deleteOptions = ['limit' => 0]; + } + + $bulk->delete($where, $deleteOptions); + + $this->log('remove', $where, $deleteOptions); + + return $bulk; + } + + /** + * 生成Mongo查询对象 + * @access public + * @param Query $query 查询对象 + * @param bool $one 是否仅获取一个记录 + * @return MongoQuery + */ + public function select(Query $query, bool $one = false): MongoQuery + { + $options = $query->getOptions(); + + $where = $this->parseWhere($query, $options['where']); + + if ($one) { + $options['limit'] = 1; + } + + $query = new MongoQuery($where, $options); + + $this->log('find', $where, $options); + + return $query; + } + + /** + * 生成Count命令 + * @access public + * @param Query $query 查询对象 + * @return Command + */ + public function count(Query $query): Command + { + $options = $query->getOptions(); + + $cmd['count'] = $options['table']; + $cmd['query'] = (object) $this->parseWhere($query, $options['where']); + + foreach (['hint', 'limit', 'maxTimeMS', 'skip'] as $option) { + if (isset($options[$option])) { + $cmd[$option] = $options[$option]; + } + } + + $command = new Command($cmd); + $this->log('cmd', 'count', $cmd); + + return $command; + } + + /** + * 聚合查询命令 + * @access public + * @param Query $query 查询对象 + * @param array $extra 指令和字段 + * @return Command + */ + public function aggregate(Query $query, array $extra): Command + { + $options = $query->getOptions(); + [$fun, $field] = $extra; + + if ('id' == $field && $this->connection->getConfig('pk_convert_id')) { + $field = '_id'; + } + + $group = isset($options['group']) ? '$' . $options['group'] : null; + + $pipeline = [ + ['$match' => (object) $this->parseWhere($query, $options['where'])], + ['$group' => ['_id' => $group, 'aggregate' => ['$' . $fun => '$' . $field]]], + ]; + + $cmd = [ + 'aggregate' => $options['table'], + 'allowDiskUse' => true, + 'pipeline' => $pipeline, + 'cursor' => new \stdClass, + ]; + + foreach (['explain', 'collation', 'bypassDocumentValidation', 'readConcern'] as $option) { + if (isset($options[$option])) { + $cmd[$option] = $options[$option]; + } + } + + $command = new Command($cmd); + + $this->log('aggregate', $cmd); + + return $command; + } + + /** + * 多聚合查询命令, 可以对多个字段进行 group by 操作 + * + * @param Query $query 查询对象 + * @param array $extra 指令和字段 + * @return Command + */ + public function multiAggregate(Query $query, $extra): Command + { + $options = $query->getOptions(); + + [$aggregate, $groupBy] = $extra; + + $groups = ['_id' => []]; + + foreach ($groupBy as $field) { + $groups['_id'][$field] = '$' . $field; + } + + foreach ($aggregate as $fun => $field) { + $groups[$field . '_' . $fun] = ['$' . $fun => '$' . $field]; + } + + $pipeline = [ + ['$match' => (object) $this->parseWhere($query, $options['where'])], + ['$group' => $groups], + ]; + + $cmd = [ + 'aggregate' => $options['table'], + 'allowDiskUse' => true, + 'pipeline' => $pipeline, + 'cursor' => new \stdClass, + ]; + + foreach (['explain', 'collation', 'bypassDocumentValidation', 'readConcern'] as $option) { + if (isset($options[$option])) { + $cmd[$option] = $options[$option]; + } + } + + $command = new Command($cmd); + $this->log('group', $cmd); + + return $command; + } + + /** + * 生成distinct命令 + * @access public + * @param Query $query 查询对象 + * @param string $field 字段名 + * @return Command + */ + public function distinct(Query $query, $field): Command + { + $options = $query->getOptions(); + + $cmd = [ + 'distinct' => $options['table'], + 'key' => $field, + ]; + + if (!empty($options['where'])) { + $cmd['query'] = (object) $this->parseWhere($query, $options['where']); + } + + if (isset($options['maxTimeMS'])) { + $cmd['maxTimeMS'] = $options['maxTimeMS']; + } + + $command = new Command($cmd); + + $this->log('cmd', 'distinct', $cmd); + + return $command; + } + + /** + * 查询所有的collection + * @access public + * @return Command + */ + public function listcollections(): Command + { + $cmd = ['listCollections' => 1]; + $command = new Command($cmd); + + $this->log('cmd', 'listCollections', $cmd); + + return $command; + } + + /** + * 查询数据表的状态信息 + * @access public + * @param Query $query 查询对象 + * @return Command + */ + public function collStats(Query $query): Command + { + $options = $query->getOptions(); + + $cmd = ['collStats' => $options['table']]; + $command = new Command($cmd); + + $this->log('cmd', 'collStats', $cmd); + + return $command; + } + + protected function log($type, $data, $options = []) + { + $this->connection->mongoLog($type, $data, $options); + } +} diff --git a/vendor/topthink/think-orm/src/db/builder/Mysql.php b/vendor/topthink/think-orm/src/db/builder/Mysql.php new file mode 100644 index 000000000..136b0dee0 --- /dev/null +++ b/vendor/topthink/think-orm/src/db/builder/Mysql.php @@ -0,0 +1,426 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\db\builder; + +use think\db\Builder; +use think\db\exception\DbException as Exception; +use think\db\Query; +use think\db\Raw; + +/** + * mysql数据库驱动 + */ +class Mysql extends Builder +{ + /** + * 查询表达式解析 + * @var array + */ + protected $parser = [ + 'parseCompare' => ['=', '<>', '>', '>=', '<', '<='], + 'parseLike' => ['LIKE', 'NOT LIKE'], + 'parseBetween' => ['NOT BETWEEN', 'BETWEEN'], + 'parseIn' => ['NOT IN', 'IN'], + 'parseExp' => ['EXP'], + 'parseRegexp' => ['REGEXP', 'NOT REGEXP'], + 'parseNull' => ['NOT NULL', 'NULL'], + 'parseBetweenTime' => ['BETWEEN TIME', 'NOT BETWEEN TIME'], + 'parseTime' => ['< TIME', '> TIME', '<= TIME', '>= TIME'], + 'parseExists' => ['NOT EXISTS', 'EXISTS'], + 'parseColumn' => ['COLUMN'], + 'parseFindInSet' => ['FIND IN SET'], + ]; + + /** + * SELECT SQL表达式 + * @var string + */ + protected $selectSql = 'SELECT%DISTINCT%%EXTRA% %FIELD% FROM %TABLE%%PARTITION%%FORCE%%JOIN%%WHERE%%GROUP%%HAVING%%UNION%%ORDER%%LIMIT% %LOCK%%COMMENT%'; + + /** + * INSERT SQL表达式 + * @var string + */ + protected $insertSql = '%INSERT%%EXTRA% INTO %TABLE%%PARTITION% SET %SET% %DUPLICATE%%COMMENT%'; + + /** + * INSERT ALL SQL表达式 + * @var string + */ + protected $insertAllSql = '%INSERT%%EXTRA% INTO %TABLE%%PARTITION% (%FIELD%) VALUES %DATA% %DUPLICATE%%COMMENT%'; + + /** + * UPDATE SQL表达式 + * @var string + */ + protected $updateSql = 'UPDATE%EXTRA% %TABLE%%PARTITION% %JOIN% SET %SET% %WHERE% %ORDER%%LIMIT% %LOCK%%COMMENT%'; + + /** + * DELETE SQL表达式 + * @var string + */ + protected $deleteSql = 'DELETE%EXTRA% FROM %TABLE%%PARTITION%%USING%%JOIN%%WHERE%%ORDER%%LIMIT% %LOCK%%COMMENT%'; + + /** + * 生成查询SQL + * @access public + * @param Query $query 查询对象 + * @param bool $one 是否仅获取一个记录 + * @return string + */ + public function select(Query $query, bool $one = false): string + { + $options = $query->getOptions(); + + return str_replace( + ['%TABLE%', '%PARTITION%', '%DISTINCT%', '%EXTRA%', '%FIELD%', '%JOIN%', '%WHERE%', '%GROUP%', '%HAVING%', '%ORDER%', '%LIMIT%', '%UNION%', '%LOCK%', '%COMMENT%', '%FORCE%'], + [ + $this->parseTable($query, $options['table']), + $this->parsePartition($query, $options['partition']), + $this->parseDistinct($query, $options['distinct']), + $this->parseExtra($query, $options['extra']), + $this->parseField($query, $options['field'] ?? '*'), + $this->parseJoin($query, $options['join']), + $this->parseWhere($query, $options['where']), + $this->parseGroup($query, $options['group']), + $this->parseHaving($query, $options['having']), + $this->parseOrder($query, $options['order']), + $this->parseLimit($query, $one ? '1' : $options['limit']), + $this->parseUnion($query, $options['union']), + $this->parseLock($query, $options['lock']), + $this->parseComment($query, $options['comment']), + $this->parseForce($query, $options['force']), + ], + $this->selectSql); + } + + /** + * 生成Insert SQL + * @access public + * @param Query $query 查询对象 + * @return string + */ + public function insert(Query $query): string + { + $options = $query->getOptions(); + + // 分析并处理数据 + $data = $this->parseData($query, $options['data']); + if (empty($data)) { + return ''; + } + + $set = []; + foreach ($data as $key => $val) { + $set[] = $key . ' = ' . $val; + } + + return str_replace( + ['%INSERT%', '%EXTRA%', '%TABLE%', '%PARTITION%', '%SET%', '%DUPLICATE%', '%COMMENT%'], + [ + !empty($options['replace']) ? 'REPLACE' : 'INSERT', + $this->parseExtra($query, $options['extra']), + $this->parseTable($query, $options['table']), + $this->parsePartition($query, $options['partition']), + implode(' , ', $set), + $this->parseDuplicate($query, $options['duplicate']), + $this->parseComment($query, $options['comment']), + ], + $this->insertSql); + } + + /** + * 生成insertall SQL + * @access public + * @param Query $query 查询对象 + * @param array $dataSet 数据集 + * @param bool $replace 是否replace + * @return string + */ + public function insertAll(Query $query, array $dataSet, bool $replace = false): string + { + $options = $query->getOptions(); + + // 获取绑定信息 + $bind = $query->getFieldsBindType(); + + // 获取合法的字段 + if (empty($options['field']) || '*' == $options['field']) { + $allowFields = array_keys($bind); + } else { + $allowFields = $options['field']; + } + + $fields = []; + $values = []; + + foreach ($dataSet as $data) { + $data = $this->parseData($query, $data, $allowFields, $bind); + + $values[] = '( ' . implode(',', array_values($data)) . ' )'; + + if (!isset($insertFields)) { + $insertFields = array_keys($data); + } + } + + foreach ($insertFields as $field) { + $fields[] = $this->parseKey($query, $field); + } + + return str_replace( + ['%INSERT%', '%EXTRA%', '%TABLE%', '%PARTITION%', '%FIELD%', '%DATA%', '%DUPLICATE%', '%COMMENT%'], + [ + $replace ? 'REPLACE' : 'INSERT', + $this->parseExtra($query, $options['extra']), + $this->parseTable($query, $options['table']), + $this->parsePartition($query, $options['partition']), + implode(' , ', $fields), + implode(' , ', $values), + $this->parseDuplicate($query, $options['duplicate']), + $this->parseComment($query, $options['comment']), + ], + $this->insertAllSql); + } + + /** + * 生成update SQL + * @access public + * @param Query $query 查询对象 + * @return string + */ + public function update(Query $query): string + { + $options = $query->getOptions(); + + $data = $this->parseData($query, $options['data']); + + if (empty($data)) { + return ''; + } + $set = []; + foreach ($data as $key => $val) { + $set[] = $key . ' = ' . $val; + } + + return str_replace( + ['%TABLE%', '%PARTITION%', '%EXTRA%', '%SET%', '%JOIN%', '%WHERE%', '%ORDER%', '%LIMIT%', '%LOCK%', '%COMMENT%'], + [ + $this->parseTable($query, $options['table']), + $this->parsePartition($query, $options['partition']), + $this->parseExtra($query, $options['extra']), + implode(' , ', $set), + $this->parseJoin($query, $options['join']), + $this->parseWhere($query, $options['where']), + $this->parseOrder($query, $options['order']), + $this->parseLimit($query, $options['limit']), + $this->parseLock($query, $options['lock']), + $this->parseComment($query, $options['comment']), + ], + $this->updateSql); + } + + /** + * 生成delete SQL + * @access public + * @param Query $query 查询对象 + * @return string + */ + public function delete(Query $query): string + { + $options = $query->getOptions(); + + return str_replace( + ['%TABLE%', '%PARTITION%', '%EXTRA%', '%USING%', '%JOIN%', '%WHERE%', '%ORDER%', '%LIMIT%', '%LOCK%', '%COMMENT%'], + [ + $this->parseTable($query, $options['table']), + $this->parsePartition($query, $options['partition']), + $this->parseExtra($query, $options['extra']), + !empty($options['using']) ? ' USING ' . $this->parseTable($query, $options['using']) . ' ' : '', + $this->parseJoin($query, $options['join']), + $this->parseWhere($query, $options['where']), + $this->parseOrder($query, $options['order']), + $this->parseLimit($query, $options['limit']), + $this->parseLock($query, $options['lock']), + $this->parseComment($query, $options['comment']), + ], + $this->deleteSql); + } + + /** + * 正则查询 + * @access protected + * @param Query $query 查询对象 + * @param string $key + * @param string $exp + * @param mixed $value + * @param string $field + * @return string + */ + protected function parseRegexp(Query $query, string $key, string $exp, $value, string $field): string + { + if ($value instanceof Raw) { + $value = $this->parseRaw($query, $value); + } + + return $key . ' ' . $exp . ' ' . $value; + } + + /** + * FIND_IN_SET 查询 + * @access protected + * @param Query $query 查询对象 + * @param string $key + * @param string $exp + * @param mixed $value + * @param string $field + * @return string + */ + protected function parseFindInSet(Query $query, string $key, string $exp, $value, string $field): string + { + if ($value instanceof Raw) { + $value = $this->parseRaw($query, $value); + } + + return 'FIND_IN_SET(' . $value . ', ' . $key . ')'; + } + + /** + * 字段和表名处理 + * @access public + * @param Query $query 查询对象 + * @param mixed $key 字段名 + * @param bool $strict 严格检测 + * @return string + */ + public function parseKey(Query $query, $key, bool $strict = false): string + { + if (is_int($key)) { + return (string) $key; + } elseif ($key instanceof Raw) { + return $this->parseRaw($query, $key); + } + + $key = trim($key); + + if (strpos($key, '->>') && false === strpos($key, '(')) { + // JSON字段支持 + [$field, $name] = explode('->>', $key, 2); + + return $this->parseKey($query, $field, true) . '->>\'$' . (strpos($name, '[') === 0 ? '' : '.') . str_replace('->>', '.', $name) . '\''; + } elseif (strpos($key, '->') && false === strpos($key, '(')) { + // JSON字段支持 + [$field, $name] = explode('->', $key, 2); + return 'json_extract(' . $this->parseKey($query, $field, true) . ', \'$' . (strpos($name, '[') === 0 ? '' : '.') . str_replace('->', '.', $name) . '\')'; + } elseif (strpos($key, '.') && !preg_match('/[,\'\"\(\)`\s]/', $key)) { + [$table, $key] = explode('.', $key, 2); + + $alias = $query->getOptions('alias'); + + if ('__TABLE__' == $table) { + $table = $query->getOptions('table'); + $table = is_array($table) ? array_shift($table) : $table; + } + + if (isset($alias[$table])) { + $table = $alias[$table]; + } + } + + if ($strict && !preg_match('/^[\w\.\*]+$/', $key)) { + throw new Exception('not support data:' . $key); + } + + if ('*' != $key && !preg_match('/[,\'\"\*\(\)`.\s]/', $key)) { + $key = '`' . $key . '`'; + } + + if (isset($table)) { + if (strpos($table, '.')) { + $table = str_replace('.', '`.`', $table); + } + + $key = '`' . $table . '`.' . $key; + } + + return $key; + } + + /** + * 随机排序 + * @access protected + * @param Query $query 查询对象 + * @return string + */ + protected function parseRand(Query $query): string + { + return 'rand()'; + } + + /** + * Partition 分析 + * @access protected + * @param Query $query 查询对象 + * @param string|array $partition 分区 + * @return string + */ + protected function parsePartition(Query $query, $partition): string + { + if ('' == $partition) { + return ''; + } + + if (is_string($partition)) { + $partition = explode(',', $partition); + } + + return ' PARTITION (' . implode(' , ', $partition) . ') '; + } + + /** + * ON DUPLICATE KEY UPDATE 分析 + * @access protected + * @param Query $query 查询对象 + * @param mixed $duplicate + * @return string + */ + protected function parseDuplicate(Query $query, $duplicate): string + { + if ('' == $duplicate) { + return ''; + } + + if ($duplicate instanceof Raw) { + return ' ON DUPLICATE KEY UPDATE ' . $this->parseRaw($query, $duplicate) . ' '; + } + + if (is_string($duplicate)) { + $duplicate = explode(',', $duplicate); + } + + $updates = []; + foreach ($duplicate as $key => $val) { + if (is_numeric($key)) { + $val = $this->parseKey($query, $val); + $updates[] = $val . ' = VALUES(' . $val . ')'; + } elseif ($val instanceof Raw) { + $updates[] = $this->parseKey($query, $key) . " = " . $this->parseRaw($query, $val); + } else { + $name = $query->bindValue($val, $query->getConnection()->getFieldBindType($key)); + $updates[] = $this->parseKey($query, $key) . " = :" . $name; + } + } + + return ' ON DUPLICATE KEY UPDATE ' . implode(' , ', $updates) . ' '; + } +} diff --git a/vendor/topthink/think-orm/src/db/builder/Oracle.php b/vendor/topthink/think-orm/src/db/builder/Oracle.php new file mode 100644 index 000000000..77ad3c81e --- /dev/null +++ b/vendor/topthink/think-orm/src/db/builder/Oracle.php @@ -0,0 +1,95 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\db\builder; + +use think\db\Builder; +use think\db\Query; + +/** + * Oracle数据库驱动 + */ +class Oracle extends Builder +{ + protected $selectSql = 'SELECT * FROM (SELECT thinkphp.*, rownum AS numrow FROM (SELECT %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%) thinkphp ) %LIMIT%%COMMENT%'; + + /** + * limit分析 + * @access protected + * @param Query $query 查询对象 + * @param mixed $limit + * @return string + */ + protected function parseLimit(Query $query, string $limit): string + { + $limitStr = ''; + + if (!empty($limit)) { + $limit = explode(',', $limit); + + if (count($limit) > 1) { + $limitStr = "(numrow>" . $limit[0] . ") AND (numrow<=" . ($limit[0] + $limit[1]) . ")"; + } else { + $limitStr = "(numrow>0 AND numrow<=" . $limit[0] . ")"; + } + + } + + return $limitStr ? ' WHERE ' . $limitStr : ''; + } + + /** + * 设置锁机制 + * @access protected + * @param Query $query 查询对象 + * @param bool|false $lock + * @return string + */ + protected function parseLock(Query $query, $lock = false): string + { + if (!$lock) { + return ''; + } + + return ' FOR UPDATE NOWAIT '; + } + + /** + * 字段和表名处理 + * @access public + * @param Query $query 查询对象 + * @param string $key + * @param string $strict + * @return string + */ + public function parseKey(Query $query, $key, bool $strict = false): string + { + $key = trim($key); + + if (strpos($key, '->') && false === strpos($key, '(')) { + // JSON字段支持 + [$field, $name] = explode($key, '->'); + $key = $field . '."' . $name . '"'; + } + + return $key; + } + + /** + * 随机排序 + * @access protected + * @param Query $query 查询对象 + * @return string + */ + protected function parseRand(Query $query): string + { + return 'DBMS_RANDOM.value'; + } +} diff --git a/thinkphp/library/think/db/builder/Pgsql.php b/vendor/topthink/think-orm/src/db/builder/Pgsql.php old mode 100755 new mode 100644 similarity index 70% rename from thinkphp/library/think/db/builder/Pgsql.php rename to vendor/topthink/think-orm/src/db/builder/Pgsql.php index 742c7db37..4eace0ac9 --- a/thinkphp/library/think/db/builder/Pgsql.php +++ b/vendor/topthink/think-orm/src/db/builder/Pgsql.php @@ -2,25 +2,35 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\db\builder; use think\db\Builder; use think\db\Query; +use think\db\Raw; /** * Pgsql数据库驱动 */ class Pgsql extends Builder { + /** + * INSERT SQL表达式 + * @var string + */ + protected $insertSql = 'INSERT INTO %TABLE% (%FIELD%) VALUES (%DATA%) %COMMENT%'; - protected $insertSql = 'INSERT INTO %TABLE% (%FIELD%) VALUES (%DATA%) %COMMENT%'; + /** + * INSERT ALL SQL表达式 + * @var string + */ protected $insertAllSql = 'INSERT INTO %TABLE% (%FIELD%) %DATA% %COMMENT%'; /** @@ -30,7 +40,7 @@ class Pgsql extends Builder * @param mixed $limit * @return string */ - public function parseLimit(Query $query, $limit) + public function parseLimit(Query $query, string $limit): string { $limitStr = ''; @@ -54,22 +64,22 @@ class Pgsql extends Builder * @param bool $strict 严格检测 * @return string */ - public function parseKey(Query $query, $key, $strict = false) + public function parseKey(Query $query, $key, bool $strict = false): string { - if (is_numeric($key)) { - return $key; - } elseif ($key instanceof Expression) { - return $key->getValue(); + if (is_int($key)) { + return (string) $key; + } elseif ($key instanceof Raw) { + return $this->parseRaw($query, $key); } $key = trim($key); if (strpos($key, '->') && false === strpos($key, '(')) { // JSON字段支持 - list($field, $name) = explode('->', $key); - $key = $field . '->>\'' . $name . '\''; + [$field, $name] = explode('->', $key); + $key = '"' . $field . '"' . '->>\'' . $name . '\''; } elseif (strpos($key, '.')) { - list($table, $key) = explode('.', $key, 2); + [$table, $key] = explode('.', $key, 2); $alias = $query->getOptions('alias'); @@ -81,6 +91,10 @@ class Pgsql extends Builder if (isset($alias[$table])) { $table = $alias[$table]; } + + if ('*' != $key && !preg_match('/[,\"\*\(\).\s]/', $key)) { + $key = '"' . $key . '"'; + } } if (isset($table)) { @@ -96,7 +110,7 @@ class Pgsql extends Builder * @param Query $query 查询对象 * @return string */ - protected function parseRand(Query $query) + protected function parseRand(Query $query): string { return 'RANDOM()'; } diff --git a/thinkphp/library/think/db/builder/Sqlite.php b/vendor/topthink/think-orm/src/db/builder/Sqlite.php old mode 100755 new mode 100644 similarity index 80% rename from thinkphp/library/think/db/builder/Sqlite.php rename to vendor/topthink/think-orm/src/db/builder/Sqlite.php index 2b887ca8e..40cab7f85 --- a/thinkphp/library/think/db/builder/Sqlite.php +++ b/vendor/topthink/think-orm/src/db/builder/Sqlite.php @@ -2,24 +2,25 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\db\builder; use think\db\Builder; use think\db\Query; +use think\db\Raw; /** * Sqlite数据库驱动 */ class Sqlite extends Builder { - /** * limit * @access public @@ -27,7 +28,7 @@ class Sqlite extends Builder * @param mixed $limit * @return string */ - public function parseLimit(Query $query, $limit) + public function parseLimit(Query $query, string $limit): string { $limitStr = ''; @@ -49,7 +50,7 @@ class Sqlite extends Builder * @param Query $query 查询对象 * @return string */ - protected function parseRand(Query $query) + protected function parseRand(Query $query): string { return 'RANDOM()'; } @@ -62,18 +63,18 @@ class Sqlite extends Builder * @param bool $strict 严格检测 * @return string */ - public function parseKey(Query $query, $key, $strict = false) + public function parseKey(Query $query, $key, bool $strict = false): string { - if (is_numeric($key)) { - return $key; - } elseif ($key instanceof Expression) { - return $key->getValue(); + if (is_int($key)) { + return (string) $key; + } elseif ($key instanceof Raw) { + return $this->parseRaw($query, $key); } $key = trim($key); if (strpos($key, '.')) { - list($table, $key) = explode('.', $key, 2); + [$table, $key] = explode('.', $key, 2); $alias = $query->getOptions('alias'); diff --git a/thinkphp/library/think/db/builder/Sqlsrv.php b/vendor/topthink/think-orm/src/db/builder/Sqlsrv.php old mode 100755 new mode 100644 similarity index 60% rename from thinkphp/library/think/db/builder/Sqlsrv.php rename to vendor/topthink/think-orm/src/db/builder/Sqlsrv.php index e24f7d25a..779b5e351 --- a/thinkphp/library/think/db/builder/Sqlsrv.php +++ b/vendor/topthink/think-orm/src/db/builder/Sqlsrv.php @@ -12,21 +12,49 @@ namespace think\db\builder; use think\db\Builder; -use think\db\Expression; +use think\db\exception\DbException as Exception; use think\db\Query; -use think\Exception; +use think\db\Raw; /** * Sqlsrv数据库驱动 */ class Sqlsrv extends Builder { - protected $selectSql = 'SELECT T1.* FROM (SELECT thinkphp.*, ROW_NUMBER() OVER (%ORDER%) AS ROW_NUMBER FROM (SELECT %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%) AS thinkphp) AS T1 %LIMIT%%COMMENT%'; + /** + * SELECT SQL表达式 + * @var string + */ + protected $selectSql = 'SELECT T1.* FROM (SELECT thinkphp.*, ROW_NUMBER() OVER (%ORDER%) AS ROW_NUMBER FROM (SELECT %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%) AS thinkphp) AS T1 %LIMIT%%COMMENT%'; + /** + * SELECT INSERT SQL表达式 + * @var string + */ protected $selectInsertSql = 'SELECT %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%'; - protected $updateSql = 'UPDATE %TABLE% SET %SET% FROM %TABLE% %JOIN% %WHERE% %LIMIT% %LOCK%%COMMENT%'; - protected $deleteSql = 'DELETE FROM %TABLE% %USING% FROM %TABLE% %JOIN% %WHERE% %LIMIT% %LOCK%%COMMENT%'; - protected $insertSql = 'INSERT INTO %TABLE% (%FIELD%) VALUES (%DATA%) %COMMENT%'; - protected $insertAllSql = 'INSERT INTO %TABLE% (%FIELD%) %DATA% %COMMENT%'; + + /** + * UPDATE SQL表达式 + * @var string + */ + protected $updateSql = 'UPDATE %TABLE% SET %SET% FROM %TABLE% %JOIN% %WHERE% %LIMIT% %LOCK%%COMMENT%'; + + /** + * DELETE SQL表达式 + * @var string + */ + protected $deleteSql = 'DELETE FROM %TABLE% %USING% FROM %TABLE% %JOIN% %WHERE% %LIMIT% %LOCK%%COMMENT%'; + + /** + * INSERT SQL表达式 + * @var string + */ + protected $insertSql = 'INSERT INTO %TABLE% (%FIELD%) VALUES (%DATA%) %COMMENT%'; + + /** + * INSERT ALL SQL表达式 + * @var string + */ + protected $insertAllSql = 'INSERT INTO %TABLE% (%FIELD%) %DATA% %COMMENT%'; /** * order分析 @@ -35,35 +63,32 @@ class Sqlsrv extends Builder * @param mixed $order * @return string */ - protected function parseOrder(Query $query, $order) + protected function parseOrder(Query $query, array $order): string { if (empty($order)) { return ' ORDER BY rand()'; } + $array = []; + foreach ($order as $key => $val) { - if ($val instanceof Expression) { - $array[] = $val->getValue(); + if ($val instanceof Raw) { + $array[] = $this->parseRaw($query, $val); } elseif ('[rand]' == $val) { $array[] = $this->parseRand($query); } else { if (is_numeric($key)) { - list($key, $sort) = explode(' ', strpos($val, ' ') ? $val : $val . ' '); + [$key, $sort] = explode(' ', strpos($val, ' ') ? $val : $val . ' '); } else { $sort = $val; } - if (preg_match('/^[\w\.]+$/', $key)) { - $sort = strtoupper($sort); - $sort = in_array($sort, ['ASC', 'DESC'], true) ? ' ' . $sort : ''; - $array[] = $this->parseKey($query, $key, true) . $sort; - } else { - throw new Exception('order express error:' . $key); - } + $sort = in_array(strtolower($sort), ['asc', 'desc'], true) ? ' ' . $sort : ''; + $array[] = $this->parseKey($query, $key, true) . $sort; } } - return empty($array) ? '' : ' ORDER BY ' . implode(',', $array); + return ' ORDER BY ' . implode(',', $array); } /** @@ -72,7 +97,7 @@ class Sqlsrv extends Builder * @param Query $query 查询对象 * @return string */ - protected function parseRand(Query $query) + protected function parseRand(Query $query): string { return 'rand()'; } @@ -85,18 +110,18 @@ class Sqlsrv extends Builder * @param bool $strict 严格检测 * @return string */ - public function parseKey(Query $query, $key, $strict = false) + public function parseKey(Query $query, $key, bool $strict = false): string { - if (is_numeric($key)) { - return $key; - } elseif ($key instanceof Expression) { - return $key->getValue(); + if (is_int($key)) { + return (string) $key; + } elseif ($key instanceof Raw) { + return $this->parseRaw($query, $key); } $key = trim($key); if (strpos($key, '.') && !preg_match('/[,\'\"\(\)\[\s]/', $key)) { - list($table, $key) = explode('.', $key, 2); + [$table, $key] = explode('.', $key, 2); $alias = $query->getOptions('alias'); @@ -114,7 +139,7 @@ class Sqlsrv extends Builder throw new Exception('not support data:' . $key); } - if ('*' != $key && ($strict || !preg_match('/[,\'\"\*\(\)\[.\s]/', $key))) { + if ('*' != $key && !preg_match('/[,\'\"\*\(\)\[.\s]/', $key)) { $key = '[' . $key . ']'; } @@ -132,7 +157,7 @@ class Sqlsrv extends Builder * @param mixed $limit * @return string */ - protected function parseLimit(Query $query, $limit) + protected function parseLimit(Query $query, string $limit): string { if (empty($limit)) { return ''; @@ -149,7 +174,7 @@ class Sqlsrv extends Builder return 'WHERE ' . $limitStr; } - public function selectInsert(Query $query, $fields, $table) + public function selectInsert(Query $query, array $fields, string $table): string { $this->selectSql = $this->selectInsertSql; diff --git a/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php b/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php new file mode 100644 index 000000000..dabfb921a --- /dev/null +++ b/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php @@ -0,0 +1,107 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\db\concern; + +use think\db\Raw; + +/** + * 聚合查询 + */ +trait AggregateQuery +{ + /** + * 聚合查询 + * @access protected + * @param string $aggregate 聚合方法 + * @param string|Raw $field 字段名 + * @param bool $force 强制转为数字类型 + * @return mixed + */ + protected function aggregate(string $aggregate, $field, bool $force = false) + { + return $this->connection->aggregate($this, $aggregate, $field, $force); + } + + /** + * COUNT查询 + * @access public + * @param string|Raw $field 字段名 + * @return int + */ + public function count(string $field = '*'): int + { + if (!empty($this->options['group'])) { + // 支持GROUP + $options = $this->getOptions(); + $subSql = $this->options($options) + ->field('count(' . $field . ') AS think_count') + ->bind($this->bind) + ->buildSql(); + + $query = $this->newQuery()->table([$subSql => '_group_count_']); + + $count = $query->aggregate('COUNT', '*'); + } else { + $count = $this->aggregate('COUNT', $field); + } + + return (int) $count; + } + + /** + * SUM查询 + * @access public + * @param string|Raw $field 字段名 + * @return float + */ + public function sum($field): float + { + return $this->aggregate('SUM', $field, true); + } + + /** + * MIN查询 + * @access public + * @param string|Raw $field 字段名 + * @param bool $force 强制转为数字类型 + * @return mixed + */ + public function min($field, bool $force = true) + { + return $this->aggregate('MIN', $field, $force); + } + + /** + * MAX查询 + * @access public + * @param string|Raw $field 字段名 + * @param bool $force 强制转为数字类型 + * @return mixed + */ + public function max($field, bool $force = true) + { + return $this->aggregate('MAX', $field, $force); + } + + /** + * AVG查询 + * @access public + * @param string|Raw $field 字段名 + * @return float + */ + public function avg($field): float + { + return $this->aggregate('AVG', $field, true); + } + +} diff --git a/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php b/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php new file mode 100644 index 000000000..c33d1ed2f --- /dev/null +++ b/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php @@ -0,0 +1,229 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\db\concern; + +use think\db\Raw; +use think\helper\Str; + +/** + * JOIN和VIEW查询 + */ +trait JoinAndViewQuery +{ + + /** + * 查询SQL组装 join + * @access public + * @param mixed $join 关联的表名 + * @param mixed $condition 条件 + * @param string $type JOIN类型 + * @param array $bind 参数绑定 + * @return $this + */ + public function join($join, string $condition = null, string $type = 'INNER', array $bind = []) + { + $table = $this->getJoinTable($join); + + if (!empty($bind) && $condition) { + $this->bindParams($condition, $bind); + } + + $this->options['join'][] = [$table, strtoupper($type), $condition]; + + return $this; + } + + /** + * LEFT JOIN + * @access public + * @param mixed $join 关联的表名 + * @param mixed $condition 条件 + * @param array $bind 参数绑定 + * @return $this + */ + public function leftJoin($join, string $condition = null, array $bind = []) + { + return $this->join($join, $condition, 'LEFT', $bind); + } + + /** + * RIGHT JOIN + * @access public + * @param mixed $join 关联的表名 + * @param mixed $condition 条件 + * @param array $bind 参数绑定 + * @return $this + */ + public function rightJoin($join, string $condition = null, array $bind = []) + { + return $this->join($join, $condition, 'RIGHT', $bind); + } + + /** + * FULL JOIN + * @access public + * @param mixed $join 关联的表名 + * @param mixed $condition 条件 + * @param array $bind 参数绑定 + * @return $this + */ + public function fullJoin($join, string $condition = null, array $bind = []) + { + return $this->join($join, $condition, 'FULL'); + } + + /** + * 获取Join表名及别名 支持 + * ['prefix_table或者子查询'=>'alias'] 'table alias' + * @access protected + * @param array|string|Raw $join JION表名 + * @param string $alias 别名 + * @return string|array + */ + protected function getJoinTable($join, &$alias = null) + { + if (is_array($join)) { + $table = $join; + $alias = array_shift($join); + return $table; + } elseif ($join instanceof Raw) { + return $join; + } + + $join = trim($join); + + if (false !== strpos($join, '(')) { + // 使用子查询 + $table = $join; + } else { + // 使用别名 + if (strpos($join, ' ')) { + // 使用别名 + [$table, $alias] = explode(' ', $join); + } else { + $table = $join; + if (false === strpos($join, '.')) { + $alias = $join; + } + } + + if ($this->prefix && false === strpos($table, '.') && 0 !== strpos($table, $this->prefix)) { + $table = $this->getTable($table); + } + } + + if (!empty($alias) && $table != $alias) { + $table = [$table => $alias]; + } + + return $table; + } + + /** + * 指定JOIN查询字段 + * @access public + * @param string|array $join 数据表 + * @param string|array $field 查询字段 + * @param string $on JOIN条件 + * @param string $type JOIN类型 + * @param array $bind 参数绑定 + * @return $this + */ + public function view($join, $field = true, $on = null, string $type = 'INNER', array $bind = []) + { + $this->options['view'] = true; + + $fields = []; + $table = $this->getJoinTable($join, $alias); + + if (true === $field) { + $fields = $alias . '.*'; + } else { + if (is_string($field)) { + $field = explode(',', $field); + } + + foreach ($field as $key => $val) { + if (is_numeric($key)) { + $fields[] = $alias . '.' . $val; + + $this->options['map'][$val] = $alias . '.' . $val; + } else { + if (preg_match('/[,=\.\'\"\(\s]/', $key)) { + $name = $key; + } else { + $name = $alias . '.' . $key; + } + + $fields[] = $name . ' AS ' . $val; + + $this->options['map'][$val] = $name; + } + } + } + + $this->field($fields); + + if ($on) { + $this->join($table, $on, $type, $bind); + } else { + $this->table($table); + } + + return $this; + } + + /** + * 视图查询处理 + * @access protected + * @param array $options 查询参数 + * @return void + */ + protected function parseView(array &$options): void + { + foreach (['AND', 'OR'] as $logic) { + if (isset($options['where'][$logic])) { + foreach ($options['where'][$logic] as $key => $val) { + if (array_key_exists($key, $options['map'])) { + array_shift($val); + array_unshift($val, $options['map'][$key]); + $options['where'][$logic][$options['map'][$key]] = $val; + unset($options['where'][$logic][$key]); + } + } + } + } + + if (isset($options['order'])) { + // 视图查询排序处理 + foreach ($options['order'] as $key => $val) { + if (is_numeric($key) && is_string($val)) { + if (strpos($val, ' ')) { + [$field, $sort] = explode(' ', $val); + if (array_key_exists($field, $options['map'])) { + $options['order'][$options['map'][$field]] = $sort; + unset($options['order'][$key]); + } + } elseif (array_key_exists($val, $options['map'])) { + $options['order'][$options['map'][$val]] = 'asc'; + unset($options['order'][$key]); + } + } elseif (array_key_exists($key, $options['map'])) { + $options['order'][$options['map'][$key]] = $val; + unset($options['order'][$key]); + } + } + } + } + +} diff --git a/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php b/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php new file mode 100644 index 000000000..ffb72de48 --- /dev/null +++ b/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php @@ -0,0 +1,524 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\db\concern; + +use Closure; +use think\helper\Str; +use think\Model; +use think\model\Collection as ModelCollection; + +/** + * 模型及关联查询 + */ +trait ModelRelationQuery +{ + + /** + * 当前模型对象 + * @var Model + */ + protected $model; + + /** + * 指定模型 + * @access public + * @param Model $model 模型对象实例 + * @return $this + */ + public function model(Model $model) + { + $this->model = $model; + return $this; + } + + /** + * 获取当前的模型对象 + * @access public + * @return Model|null + */ + public function getModel() + { + return $this->model; + } + + /** + * 设置需要隐藏的输出属性 + * @access public + * @param array $hidden 需要隐藏的字段名 + * @return $this + */ + public function hidden(array $hidden) + { + $this->options['hidden'] = $hidden; + return $this; + } + + /** + * 设置需要输出的属性 + * @access public + * @param array $visible 需要输出的属性 + * @return $this + */ + public function visible(array $visible) + { + $this->options['visible'] = $visible; + return $this; + } + + /** + * 设置需要追加输出的属性 + * @access public + * @param array $append 需要追加的属性 + * @return $this + */ + public function append(array $append) + { + $this->options['append'] = $append; + return $this; + } + + /** + * 添加查询范围 + * @access public + * @param array|string|Closure $scope 查询范围定义 + * @param array $args 参数 + * @return $this + */ + public function scope($scope, ...$args) + { + // 查询范围的第一个参数始终是当前查询对象 + array_unshift($args, $this); + + if ($scope instanceof Closure) { + call_user_func_array($scope, $args); + return $this; + } + + if (is_string($scope)) { + $scope = explode(',', $scope); + } + + if ($this->model) { + // 检查模型类的查询范围方法 + foreach ($scope as $name) { + $method = 'scope' . trim($name); + + if (method_exists($this->model, $method)) { + call_user_func_array([$this->model, $method], $args); + } + } + } + + return $this; + } + + /** + * 设置关联查询 + * @access public + * @param array $relation 关联名称 + * @return $this + */ + public function relation(array $relation) + { + if (!empty($relation)) { + $this->options['relation'] = $relation; + } + + return $this; + } + + /** + * 使用搜索器条件搜索字段 + * @access public + * @param string|array $fields 搜索字段 + * @param mixed $data 搜索数据 + * @param string $prefix 字段前缀标识 + * @return $this + */ + public function withSearch($fields, $data = [], string $prefix = '') + { + if (is_string($fields)) { + $fields = explode(',', $fields); + } + + $likeFields = $this->getConfig('match_like_fields') ?: []; + + foreach ($fields as $key => $field) { + if ($field instanceof Closure) { + $field($this, $data[$key] ?? null, $data, $prefix); + } elseif ($this->model) { + // 检测搜索器 + $fieldName = is_numeric($key) ? $field : $key; + $method = 'search' . Str::studly($fieldName) . 'Attr'; + + if (method_exists($this->model, $method)) { + $this->model->$method($this, $data[$field] ?? null, $data, $prefix); + } elseif (isset($data[$field])) { + $this->where($fieldName, in_array($fieldName, $likeFields) ? 'like' : '=', in_array($fieldName, $likeFields) ? '%' . $data[$field] . '%' : $data[$field]); + } + } + } + + return $this; + } + + /** + * 设置数据字段获取器 + * @access public + * @param string|array $name 字段名 + * @param callable $callback 闭包获取器 + * @return $this + */ + public function withAttr($name, callable $callback = null) + { + if (is_array($name)) { + $this->options['with_attr'] = $name; + } else { + $this->options['with_attr'][$name] = $callback; + } + + return $this; + } + + /** + * 关联预载入 In方式 + * @access public + * @param array|string $with 关联方法名称 + * @return $this + */ + public function with($with) + { + if (!empty($with)) { + $this->options['with'] = (array) $with; + } + + return $this; + } + + /** + * 关联预载入 JOIN方式 + * @access protected + * @param array|string $with 关联方法名 + * @param string $joinType JOIN方式 + * @return $this + */ + public function withJoin($with, string $joinType = '') + { + if (empty($with)) { + return $this; + } + + $with = (array) $with; + $first = true; + + foreach ($with as $key => $relation) { + $closure = null; + $field = true; + + if ($relation instanceof Closure) { + // 支持闭包查询过滤关联条件 + $closure = $relation; + $relation = $key; + } elseif (is_array($relation)) { + $field = $relation; + $relation = $key; + } elseif (is_string($relation) && strpos($relation, '.')) { + $relation = strstr($relation, '.', true); + } + + $result = $this->model->eagerly($this, $relation, $field, $joinType, $closure, $first); + + if (!$result) { + unset($with[$key]); + } else { + $first = false; + } + } + + $this->via(); + + $this->options['with_join'] = $with; + + return $this; + } + + /** + * 关联统计 + * @access protected + * @param array|string $relations 关联方法名 + * @param string $aggregate 聚合查询方法 + * @param string $field 字段 + * @param bool $subQuery 是否使用子查询 + * @return $this + */ + protected function withAggregate($relations, string $aggregate = 'count', $field = '*', bool $subQuery = true) + { + if (!$subQuery) { + $this->options['with_count'][] = [$relations, $aggregate, $field]; + } else { + if (!isset($this->options['field'])) { + $this->field('*'); + } + + $this->model->relationCount($this, (array) $relations, $aggregate, $field, true); + } + + return $this; + } + + /** + * 关联缓存 + * @access public + * @param string|array|bool $relation 关联方法名 + * @param mixed $key 缓存key + * @param integer|\DateTime $expire 缓存有效期 + * @param string $tag 缓存标签 + * @return $this + */ + public function withCache($relation = true, $key = true, $expire = null, string $tag = null) + { + if (false === $relation || false === $key || !$this->getConnection()->getCache()) { + return $this; + } + + if ($key instanceof \DateTimeInterface || $key instanceof \DateInterval || (is_int($key) && is_null($expire))) { + $expire = $key; + $key = true; + } + + if (true === $relation || is_numeric($relation)) { + $this->options['with_cache'] = $relation; + return $this; + } + + $relations = (array) $relation; + foreach ($relations as $name => $relation) { + if (!is_numeric($name)) { + $this->options['with_cache'][$name] = is_array($relation) ? $relation : [$key, $relation, $tag]; + } else { + $this->options['with_cache'][$relation] = [$key, $expire, $tag]; + } + } + + return $this; + } + + /** + * 关联统计 + * @access public + * @param string|array $relation 关联方法名 + * @param bool $subQuery 是否使用子查询 + * @return $this + */ + public function withCount($relation, bool $subQuery = true) + { + return $this->withAggregate($relation, 'count', '*', $subQuery); + } + + /** + * 关联统计Sum + * @access public + * @param string|array $relation 关联方法名 + * @param string $field 字段 + * @param bool $subQuery 是否使用子查询 + * @return $this + */ + public function withSum($relation, string $field, bool $subQuery = true) + { + return $this->withAggregate($relation, 'sum', $field, $subQuery); + } + + /** + * 关联统计Max + * @access public + * @param string|array $relation 关联方法名 + * @param string $field 字段 + * @param bool $subQuery 是否使用子查询 + * @return $this + */ + public function withMax($relation, string $field, bool $subQuery = true) + { + return $this->withAggregate($relation, 'max', $field, $subQuery); + } + + /** + * 关联统计Min + * @access public + * @param string|array $relation 关联方法名 + * @param string $field 字段 + * @param bool $subQuery 是否使用子查询 + * @return $this + */ + public function withMin($relation, string $field, bool $subQuery = true) + { + return $this->withAggregate($relation, 'min', $field, $subQuery); + } + + /** + * 关联统计Avg + * @access public + * @param string|array $relation 关联方法名 + * @param string $field 字段 + * @param bool $subQuery 是否使用子查询 + * @return $this + */ + public function withAvg($relation, string $field, bool $subQuery = true) + { + return $this->withAggregate($relation, 'avg', $field, $subQuery); + } + + /** + * 根据关联条件查询当前模型 + * @access public + * @param string $relation 关联方法名 + * @param mixed $operator 比较操作符 + * @param integer $count 个数 + * @param string $id 关联表的统计字段 + * @param string $joinType JOIN类型 + * @return $this + */ + public function has(string $relation, string $operator = '>=', int $count = 1, string $id = '*', string $joinType = '') + { + return $this->model->has($relation, $operator, $count, $id, $joinType, $this); + } + + /** + * 根据关联条件查询当前模型 + * @access public + * @param string $relation 关联方法名 + * @param mixed $where 查询条件(数组或者闭包) + * @param mixed $fields 字段 + * @param string $joinType JOIN类型 + * @return $this + */ + public function hasWhere(string $relation, $where = [], string $fields = '*', string $joinType = '') + { + return $this->model->hasWhere($relation, $where, $fields, $joinType, $this); + } + + /** + * 查询数据转换为模型数据集对象 + * @access protected + * @param array $resultSet 数据集 + * @return ModelCollection + */ + protected function resultSetToModelCollection(array $resultSet): ModelCollection + { + if (empty($resultSet)) { + return $this->model->toCollection(); + } + + // 检查动态获取器 + if (!empty($this->options['with_attr'])) { + foreach ($this->options['with_attr'] as $name => $val) { + if (strpos($name, '.')) { + [$relation, $field] = explode('.', $name); + + $withRelationAttr[$relation][$field] = $val; + unset($this->options['with_attr'][$name]); + } + } + } + + $withRelationAttr = $withRelationAttr ?? []; + + foreach ($resultSet as $key => &$result) { + // 数据转换为模型对象 + $this->resultToModel($result, $this->options, true, $withRelationAttr); + } + + if (!empty($this->options['with'])) { + // 预载入 + $result->eagerlyResultSet($resultSet, $this->options['with'], $withRelationAttr, false, $this->options['with_cache'] ?? false); + } + + if (!empty($this->options['with_join'])) { + // 预载入 + $result->eagerlyResultSet($resultSet, $this->options['with_join'], $withRelationAttr, true, $this->options['with_cache'] ?? false); + } + + // 模型数据集转换 + return $this->model->toCollection($resultSet); + } + + /** + * 查询数据转换为模型对象 + * @access protected + * @param array $result 查询数据 + * @param array $options 查询参数 + * @param bool $resultSet 是否为数据集查询 + * @param array $withRelationAttr 关联字段获取器 + * @return void + */ + protected function resultToModel(array &$result, array $options = [], bool $resultSet = false, array $withRelationAttr = []): void + { + // 动态获取器 + if (!empty($options['with_attr']) && empty($withRelationAttr)) { + foreach ($options['with_attr'] as $name => $val) { + if (strpos($name, '.')) { + [$relation, $field] = explode('.', $name); + + $withRelationAttr[$relation][$field] = $val; + unset($options['with_attr'][$name]); + } + } + } + + // JSON 数据处理 + if (!empty($options['json'])) { + $this->jsonResult($result, $options['json'], $options['json_assoc'], $withRelationAttr); + } + + $result = $this->model + ->newInstance($result, $resultSet ? null : $this->getModelUpdateCondition($options)); + + // 动态获取器 + if (!empty($options['with_attr'])) { + $result->withAttribute($options['with_attr']); + } + + // 输出属性控制 + if (!empty($options['visible'])) { + $result->visible($options['visible']); + } elseif (!empty($options['hidden'])) { + $result->hidden($options['hidden']); + } + + if (!empty($options['append'])) { + $result->append($options['append']); + } + + // 关联查询 + if (!empty($options['relation'])) { + $result->relationQuery($options['relation'], $withRelationAttr); + } + + // 预载入查询 + if (!$resultSet && !empty($options['with'])) { + $result->eagerlyResult($result, $options['with'], $withRelationAttr, false, $options['with_cache'] ?? false); + } + + // JOIN预载入查询 + if (!$resultSet && !empty($options['with_join'])) { + $result->eagerlyResult($result, $options['with_join'], $withRelationAttr, true, $options['with_cache'] ?? false); + } + + // 关联统计 + if (!empty($options['with_count'])) { + foreach ($options['with_count'] as $val) { + $result->relationCount($this, (array) $val[0], $val[1], $val[2], false); + } + } + } + +} diff --git a/vendor/topthink/think-orm/src/db/concern/ParamsBind.php b/vendor/topthink/think-orm/src/db/concern/ParamsBind.php new file mode 100644 index 000000000..296e2212d --- /dev/null +++ b/vendor/topthink/think-orm/src/db/concern/ParamsBind.php @@ -0,0 +1,106 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\db\concern; + +use PDO; + +/** + * 参数绑定支持 + */ +trait ParamsBind +{ + /** + * 当前参数绑定 + * @var array + */ + protected $bind = []; + + /** + * 批量参数绑定 + * @access public + * @param array $value 绑定变量值 + * @return $this + */ + public function bind(array $value) + { + $this->bind = array_merge($this->bind, $value); + return $this; + } + + /** + * 单个参数绑定 + * @access public + * @param mixed $value 绑定变量值 + * @param integer $type 绑定类型 + * @param string $name 绑定标识 + * @return string + */ + public function bindValue($value, int $type = null, string $name = null) + { + $name = $name ?: 'ThinkBind_' . (count($this->bind) + 1) . '_' . mt_rand() . '_'; + + $this->bind[$name] = [$value, $type ?: PDO::PARAM_STR]; + return $name; + } + + /** + * 检测参数是否已经绑定 + * @access public + * @param string $key 参数名 + * @return bool + */ + public function isBind($key) + { + return isset($this->bind[$key]); + } + + /** + * 参数绑定 + * @access public + * @param string $sql 绑定的sql表达式 + * @param array $bind 参数绑定 + * @return void + */ + public function bindParams(string &$sql, array $bind = []): void + { + foreach ($bind as $key => $value) { + if (is_array($value)) { + $name = $this->bindValue($value[0], $value[1], $value[2] ?? null); + } else { + $name = $this->bindValue($value); + } + + if (is_numeric($key)) { + $sql = substr_replace($sql, ':' . $name, strpos($sql, '?'), 1); + } else { + $sql = str_replace(':' . $key, ':' . $name, $sql); + } + } + } + + /** + * 获取绑定的参数 并清空 + * @access public + * @param bool $clear 是否清空绑定数据 + * @return array + */ + public function getBind(bool $clear = true): array + { + $bind = $this->bind; + if ($clear) { + $this->bind = []; + } + + return $bind; + } +} diff --git a/vendor/topthink/think-orm/src/db/concern/ResultOperation.php b/vendor/topthink/think-orm/src/db/concern/ResultOperation.php new file mode 100644 index 000000000..d93c409a9 --- /dev/null +++ b/vendor/topthink/think-orm/src/db/concern/ResultOperation.php @@ -0,0 +1,247 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\db\concern; + +use Closure; +use think\Collection; +use think\db\exception\DataNotFoundException; +use think\db\exception\DbException; +use think\db\exception\ModelNotFoundException; +use think\db\Query; +use think\helper\Str; +use think\Model; + +/** + * 查询数据处理 + */ +trait ResultOperation +{ + /** + * 是否允许返回空数据(或空模型) + * @access public + * @param bool $allowEmpty 是否允许为空 + * @return $this + */ + public function allowEmpty(bool $allowEmpty = true) + { + $this->options['allow_empty'] = $allowEmpty; + return $this; + } + + /** + * 设置查询数据不存在是否抛出异常 + * @access public + * @param bool $fail 数据不存在是否抛出异常 + * @return $this + */ + public function failException(bool $fail = true) + { + $this->options['fail'] = $fail; + return $this; + } + + /** + * 处理数据 + * @access protected + * @param array $result 查询数据 + * @return void + */ + protected function result(array &$result): void + { + if (!empty($this->options['json'])) { + $this->jsonResult($result, $this->options['json'], true); + } + + if (!empty($this->options['with_attr'])) { + $this->getResultAttr($result, $this->options['with_attr']); + } + + $this->filterResult($result); + } + + /** + * 处理数据集 + * @access public + * @param array $resultSet 数据集 + * @return void + */ + protected function resultSet(array &$resultSet): void + { + if (!empty($this->options['json'])) { + foreach ($resultSet as &$result) { + $this->jsonResult($result, $this->options['json'], true); + } + } + + if (!empty($this->options['with_attr'])) { + foreach ($resultSet as &$result) { + $this->getResultAttr($result, $this->options['with_attr']); + } + } + + if (!empty($this->options['visible']) || !empty($this->options['hidden'])) { + foreach ($resultSet as &$result) { + $this->filterResult($result); + } + } + + // 返回Collection对象 + $resultSet = new Collection($resultSet); + } + + /** + * 处理数据的可见和隐藏 + * @access protected + * @param array $result 查询数据 + * @return void + */ + protected function filterResult(&$result): void + { + $array = []; + if (!empty($this->options['visible'])) { + foreach ($this->options['visible'] as $key) { + $array[] = $key; + } + $result = array_intersect_key($result, array_flip($array)); + } elseif (!empty($this->options['hidden'])) { + foreach ($this->options['hidden'] as $key) { + $array[] = $key; + } + $result = array_diff_key($result, array_flip($array)); + } + } + + /** + * 使用获取器处理数据 + * @access protected + * @param array $result 查询数据 + * @param array $withAttr 字段获取器 + * @return void + */ + protected function getResultAttr(array &$result, array $withAttr = []): void + { + foreach ($withAttr as $name => $closure) { + $name = Str::snake($name); + + if (strpos($name, '.')) { + // 支持JSON字段 获取器定义 + [$key, $field] = explode('.', $name); + + if (isset($result[$key])) { + $result[$key][$field] = $closure($result[$key][$field] ?? null, $result[$key]); + } + } else { + $result[$name] = $closure($result[$name] ?? null, $result); + } + } + } + + /** + * 处理空数据 + * @access protected + * @return array|Model|null + * @throws DbException + * @throws ModelNotFoundException + * @throws DataNotFoundException + */ + protected function resultToEmpty() + { + if (!empty($this->options['fail'])) { + $this->throwNotFound(); + } elseif (!empty($this->options['allow_empty'])) { + return !empty($this->model) ? $this->model->newInstance() : []; + } + } + + /** + * 查找单条记录 不存在返回空数据(或者空模型) + * @access public + * @param mixed $data 数据 + * @return array|Model + */ + public function findOrEmpty($data = null) + { + return $this->allowEmpty(true)->find($data); + } + + /** + * JSON字段数据转换 + * @access protected + * @param array $result 查询数据 + * @param array $json JSON字段 + * @param bool $assoc 是否转换为数组 + * @param array $withRelationAttr 关联获取器 + * @return void + */ + protected function jsonResult(array &$result, array $json = [], bool $assoc = false, array $withRelationAttr = []): void + { + foreach ($json as $name) { + if (!isset($result[$name])) { + continue; + } + + $result[$name] = json_decode($result[$name], true); + + if (isset($withRelationAttr[$name])) { + foreach ($withRelationAttr[$name] as $key => $closure) { + $result[$name][$key] = $closure($result[$name][$key] ?? null, $result[$name]); + } + } + + if (!$assoc) { + $result[$name] = (object) $result[$name]; + } + } + } + + /** + * 查询失败 抛出异常 + * @access protected + * @return void + * @throws ModelNotFoundException + * @throws DataNotFoundException + */ + protected function throwNotFound(): void + { + if (!empty($this->model)) { + $class = get_class($this->model); + throw new ModelNotFoundException('model data Not Found:' . $class, $class, $this->options); + } + + $table = $this->getTable(); + throw new DataNotFoundException('table data not Found:' . $table, $table, $this->options); + } + + /** + * 查找多条记录 如果不存在则抛出异常 + * @access public + * @param array|string|Query|Closure $data 数据 + * @return array|Model + */ + public function selectOrFail($data = null) + { + return $this->failException(true)->select($data); + } + + /** + * 查找单条记录 如果不存在则抛出异常 + * @access public + * @param array|string|Query|Closure $data 数据 + * @return array|Model + */ + public function findOrFail($data = null) + { + return $this->failException(true)->find($data); + } + +} diff --git a/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php b/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php new file mode 100644 index 000000000..9070befea --- /dev/null +++ b/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php @@ -0,0 +1,99 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\db\concern; + +/** + * 数据字段信息 + */ +trait TableFieldInfo +{ + + /** + * 获取数据表字段信息 + * @access public + * @param string $tableName 数据表名 + * @return array + */ + public function getTableFields($tableName = ''): array + { + if ('' == $tableName) { + $tableName = $this->getTable(); + } + + return $this->connection->getTableFields($tableName); + } + + /** + * 获取详细字段类型信息 + * @access public + * @param string $tableName 数据表名称 + * @return array + */ + public function getFields(string $tableName = ''): array + { + return $this->connection->getFields($tableName ?: $this->getTable()); + } + + /** + * 获取字段类型信息 + * @access public + * @return array + */ + public function getFieldsType(): array + { + if (!empty($this->options['field_type'])) { + return $this->options['field_type']; + } + + return $this->connection->getFieldsType($this->getTable()); + } + + /** + * 获取字段类型信息 + * @access public + * @param string $field 字段名 + * @return string|null + */ + public function getFieldType(string $field) + { + $fieldType = $this->getFieldsType(); + + return $fieldType[$field] ?? null; + } + + /** + * 获取字段类型信息 + * @access public + * @return array + */ + public function getFieldsBindType(): array + { + $fieldType = $this->getFieldsType(); + + return array_map([$this->connection, 'getFieldBindType'], $fieldType); + } + + /** + * 获取字段类型信息 + * @access public + * @param string $field 字段名 + * @return int + */ + public function getFieldBindType(string $field): int + { + $fieldType = $this->getFieldType($field); + + return $this->connection->getFieldBindType($fieldType ?: ''); + } + +} diff --git a/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php b/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php new file mode 100644 index 000000000..1267e5401 --- /dev/null +++ b/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php @@ -0,0 +1,214 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\db\concern; + +/** + * 时间查询支持 + */ +trait TimeFieldQuery +{ + /** + * 日期查询表达式 + * @var array + */ + protected $timeRule = [ + 'today' => ['today', 'tomorrow -1second'], + 'yesterday' => ['yesterday', 'today -1second'], + 'week' => ['this week 00:00:00', 'next week 00:00:00 -1second'], + 'last week' => ['last week 00:00:00', 'this week 00:00:00 -1second'], + 'month' => ['first Day of this month 00:00:00', 'first Day of next month 00:00:00 -1second'], + 'last month' => ['first Day of last month 00:00:00', 'first Day of this month 00:00:00 -1second'], + 'year' => ['this year 1/1', 'next year 1/1 -1second'], + 'last year' => ['last year 1/1', 'this year 1/1 -1second'], + ]; + + /** + * 添加日期或者时间查询规则 + * @access public + * @param array $rule 时间表达式 + * @return $this + */ + public function timeRule(array $rule) + { + $this->timeRule = array_merge($this->timeRule, $rule); + return $this; + } + + /** + * 查询日期或者时间 + * @access public + * @param string $field 日期字段名 + * @param string $op 比较运算符或者表达式 + * @param string|array $range 比较范围 + * @param string $logic AND OR + * @return $this + */ + public function whereTime(string $field, string $op, $range = null, string $logic = 'AND') + { + if (is_null($range)) { + if (isset($this->timeRule[$op])) { + $range = $this->timeRule[$op]; + } else { + $range = $op; + } + $op = is_array($range) ? 'between' : '>='; + } + + return $this->parseWhereExp($logic, $field, strtolower($op) . ' time', $range, [], true); + } + + /** + * 查询某个时间间隔数据 + * @access public + * @param string $field 日期字段名 + * @param string $start 开始时间 + * @param string $interval 时间间隔单位 day/month/year/week/hour/minute/second + * @param int $step 间隔 + * @param string $logic AND OR + * @return $this + */ + public function whereTimeInterval(string $field, string $start, string $interval = 'day', int $step = 1, string $logic = 'AND') + { + $startTime = strtotime($start); + $endTime = strtotime(($step > 0 ? '+' : '-') . abs($step) . ' ' . $interval . (abs($step) > 1 ? 's' : ''), $startTime); + + return $this->whereTime($field, 'between', $step > 0 ? [$startTime, $endTime - 1] : [$endTime, $startTime - 1], $logic); + } + + /** + * 查询月数据 whereMonth('time_field', '2018-1') + * @access public + * @param string $field 日期字段名 + * @param string $month 月份信息 + * @param int $step 间隔 + * @param string $logic AND OR + * @return $this + */ + public function whereMonth(string $field, string $month = 'this month', int $step = 1, string $logic = 'AND') + { + if (in_array($month, ['this month', 'last month'])) { + $month = date('Y-m', strtotime($month)); + } + + return $this->whereTimeInterval($field, $month, 'month', $step, $logic); + } + + /** + * 查询周数据 whereWeek('time_field', '2018-1-1') 从2018-1-1开始的一周数据 + * @access public + * @param string $field 日期字段名 + * @param string $week 周信息 + * @param int $step 间隔 + * @param string $logic AND OR + * @return $this + */ + public function whereWeek(string $field, string $week = 'this week', int $step = 1, string $logic = 'AND') + { + if (in_array($week, ['this week', 'last week'])) { + $week = date('Y-m-d', strtotime($week)); + } + + return $this->whereTimeInterval($field, $week, 'week', $step, $logic); + } + + /** + * 查询年数据 whereYear('time_field', '2018') + * @access public + * @param string $field 日期字段名 + * @param string $year 年份信息 + * @param int $step 间隔 + * @param string $logic AND OR + * @return $this + */ + public function whereYear(string $field, string $year = 'this year', int $step = 1, string $logic = 'AND') + { + if (in_array($year, ['this year', 'last year'])) { + $year = date('Y', strtotime($year)); + } + + return $this->whereTimeInterval($field, $year . '-1-1', 'year', $step, $logic); + } + + /** + * 查询日数据 whereDay('time_field', '2018-1-1') + * @access public + * @param string $field 日期字段名 + * @param string $day 日期信息 + * @param int $step 间隔 + * @param string $logic AND OR + * @return $this + */ + public function whereDay(string $field, string $day = 'today', int $step = 1, string $logic = 'AND') + { + if (in_array($day, ['today', 'yesterday'])) { + $day = date('Y-m-d', strtotime($day)); + } + + return $this->whereTimeInterval($field, $day, 'day', $step, $logic); + } + + /** + * 查询日期或者时间范围 whereBetweenTime('time_field', '2018-1-1','2018-1-15') + * @access public + * @param string $field 日期字段名 + * @param string|int $startTime 开始时间 + * @param string|int $endTime 结束时间 + * @param string $logic AND OR + * @return $this + */ + public function whereBetweenTime(string $field, $startTime, $endTime, string $logic = 'AND') + { + return $this->whereTime($field, 'between', [$startTime, $endTime], $logic); + } + + /** + * 查询日期或者时间范围 whereNotBetweenTime('time_field', '2018-1-1','2018-1-15') + * @access public + * @param string $field 日期字段名 + * @param string|int $startTime 开始时间 + * @param string|int $endTime 结束时间 + * @return $this + */ + public function whereNotBetweenTime(string $field, $startTime, $endTime) + { + return $this->whereTime($field, '<', $startTime) + ->whereTime($field, '>', $endTime); + } + + /** + * 查询当前时间在两个时间字段范围 whereBetweenTimeField('start_time', 'end_time') + * @access public + * @param string $startField 开始时间字段 + * @param string $endField 结束时间字段 + * @return $this + */ + public function whereBetweenTimeField(string $startField, string $endField) + { + return $this->whereTime($startField, '<=', time()) + ->whereTime($endField, '>=', time()); + } + + /** + * 查询当前时间不在两个时间字段范围 whereNotBetweenTimeField('start_time', 'end_time') + * @access public + * @param string $startField 开始时间字段 + * @param string $endField 结束时间字段 + * @return $this + */ + public function whereNotBetweenTimeField(string $startField, string $endField) + { + return $this->whereTime($startField, '>', time()) + ->whereTime($endField, '<', time(), 'OR'); + } + +} diff --git a/vendor/topthink/think-orm/src/db/concern/Transaction.php b/vendor/topthink/think-orm/src/db/concern/Transaction.php new file mode 100644 index 000000000..f804ae2d3 --- /dev/null +++ b/vendor/topthink/think-orm/src/db/concern/Transaction.php @@ -0,0 +1,117 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\db\concern; + +use think\db\BaseQuery; + +/** + * 事务支持 + */ +trait Transaction +{ + + /** + * 执行数据库Xa事务 + * @access public + * @param callable $callback 数据操作方法回调 + * @param array $dbs 多个查询对象或者连接对象 + * @return mixed + * @throws PDOException + * @throws \Exception + * @throws \Throwable + */ + public function transactionXa($callback, array $dbs = []) + { + $xid = uniqid('xa'); + + if (empty($dbs)) { + $dbs[] = $this->getConnection(); + } + + foreach ($dbs as $key => $db) { + if ($db instanceof BaseQuery) { + $db = $db->getConnection(); + + $dbs[$key] = $db; + } + + $db->startTransXa($xid); + } + + try { + $result = null; + if (is_callable($callback)) { + $result = call_user_func_array($callback, [$this]); + } + + foreach ($dbs as $db) { + $db->prepareXa($xid); + } + + foreach ($dbs as $db) { + $db->commitXa($xid); + } + + return $result; + } catch (\Exception | \Throwable $e) { + foreach ($dbs as $db) { + $db->rollbackXa($xid); + } + throw $e; + } + } + + /** + * 执行数据库事务 + * @access public + * @param callable $callback 数据操作方法回调 + * @return mixed + */ + public function transaction(callable $callback) + { + return $this->connection->transaction($callback); + } + + /** + * 启动事务 + * @access public + * @return void + */ + public function startTrans(): void + { + $this->connection->startTrans(); + } + + /** + * 用于非自动提交状态下面的查询提交 + * @access public + * @return void + * @throws PDOException + */ + public function commit(): void + { + $this->connection->commit(); + } + + /** + * 事务回滚 + * @access public + * @return void + * @throws PDOException + */ + public function rollback(): void + { + $this->connection->rollback(); + } + +} diff --git a/vendor/topthink/think-orm/src/db/concern/WhereQuery.php b/vendor/topthink/think-orm/src/db/concern/WhereQuery.php new file mode 100644 index 000000000..131162887 --- /dev/null +++ b/vendor/topthink/think-orm/src/db/concern/WhereQuery.php @@ -0,0 +1,532 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\db\concern; + +use Closure; +use think\db\BaseQuery; +use think\db\Raw; + +trait WhereQuery +{ + /** + * 指定AND查询条件 + * @access public + * @param mixed $field 查询字段 + * @param mixed $op 查询表达式 + * @param mixed $condition 查询条件 + * @return $this + */ + public function where($field, $op = null, $condition = null) + { + if ($field instanceof $this) { + $this->parseQueryWhere($field); + return $this; + } elseif (true === $field || 1 === $field) { + $this->options['where']['AND'][] = true; + return $this; + } + + $param = func_get_args(); + array_shift($param); + return $this->parseWhereExp('AND', $field, $op, $condition, $param); + } + + /** + * 解析Query对象查询条件 + * @access public + * @param BaseQuery $query 查询对象 + * @return void + */ + protected function parseQueryWhere(BaseQuery $query): void + { + $this->options['where'] = $query->getOptions('where'); + + if ($query->getOptions('via')) { + $via = $query->getOptions('via'); + foreach ($this->options['where'] as $logic => &$where) { + foreach ($where as $key => &$val) { + if (is_array($val) && !strpos($val[0], '.')) { + $val[0] = $via . '.' . $val[0]; + } + } + } + } + + $this->bind($query->getBind(false)); + } + + /** + * 指定OR查询条件 + * @access public + * @param mixed $field 查询字段 + * @param mixed $op 查询表达式 + * @param mixed $condition 查询条件 + * @return $this + */ + public function whereOr($field, $op = null, $condition = null) + { + $param = func_get_args(); + array_shift($param); + return $this->parseWhereExp('OR', $field, $op, $condition, $param); + } + + /** + * 指定XOR查询条件 + * @access public + * @param mixed $field 查询字段 + * @param mixed $op 查询表达式 + * @param mixed $condition 查询条件 + * @return $this + */ + public function whereXor($field, $op = null, $condition = null) + { + $param = func_get_args(); + array_shift($param); + return $this->parseWhereExp('XOR', $field, $op, $condition, $param); + } + + /** + * 指定Null查询条件 + * @access public + * @param mixed $field 查询字段 + * @param string $logic 查询逻辑 and or xor + * @return $this + */ + public function whereNull(string $field, string $logic = 'AND') + { + return $this->parseWhereExp($logic, $field, 'NULL', null, [], true); + } + + /** + * 指定NotNull查询条件 + * @access public + * @param mixed $field 查询字段 + * @param string $logic 查询逻辑 and or xor + * @return $this + */ + public function whereNotNull(string $field, string $logic = 'AND') + { + return $this->parseWhereExp($logic, $field, 'NOTNULL', null, [], true); + } + + /** + * 指定Exists查询条件 + * @access public + * @param mixed $condition 查询条件 + * @param string $logic 查询逻辑 and or xor + * @return $this + */ + public function whereExists($condition, string $logic = 'AND') + { + if (is_string($condition)) { + $condition = new Raw($condition); + } + + $this->options['where'][strtoupper($logic)][] = ['', 'EXISTS', $condition]; + return $this; + } + + /** + * 指定NotExists查询条件 + * @access public + * @param mixed $condition 查询条件 + * @param string $logic 查询逻辑 and or xor + * @return $this + */ + public function whereNotExists($condition, string $logic = 'AND') + { + if (is_string($condition)) { + $condition = new Raw($condition); + } + + $this->options['where'][strtoupper($logic)][] = ['', 'NOT EXISTS', $condition]; + return $this; + } + + /** + * 指定In查询条件 + * @access public + * @param mixed $field 查询字段 + * @param mixed $condition 查询条件 + * @param string $logic 查询逻辑 and or xor + * @return $this + */ + public function whereIn(string $field, $condition, string $logic = 'AND') + { + return $this->parseWhereExp($logic, $field, 'IN', $condition, [], true); + } + + /** + * 指定NotIn查询条件 + * @access public + * @param mixed $field 查询字段 + * @param mixed $condition 查询条件 + * @param string $logic 查询逻辑 and or xor + * @return $this + */ + public function whereNotIn(string $field, $condition, string $logic = 'AND') + { + return $this->parseWhereExp($logic, $field, 'NOT IN', $condition, [], true); + } + + /** + * 指定Like查询条件 + * @access public + * @param mixed $field 查询字段 + * @param mixed $condition 查询条件 + * @param string $logic 查询逻辑 and or xor + * @return $this + */ + public function whereLike(string $field, $condition, string $logic = 'AND') + { + return $this->parseWhereExp($logic, $field, 'LIKE', $condition, [], true); + } + + /** + * 指定NotLike查询条件 + * @access public + * @param mixed $field 查询字段 + * @param mixed $condition 查询条件 + * @param string $logic 查询逻辑 and or xor + * @return $this + */ + public function whereNotLike(string $field, $condition, string $logic = 'AND') + { + return $this->parseWhereExp($logic, $field, 'NOT LIKE', $condition, [], true); + } + + /** + * 指定Between查询条件 + * @access public + * @param mixed $field 查询字段 + * @param mixed $condition 查询条件 + * @param string $logic 查询逻辑 and or xor + * @return $this + */ + public function whereBetween(string $field, $condition, string $logic = 'AND') + { + return $this->parseWhereExp($logic, $field, 'BETWEEN', $condition, [], true); + } + + /** + * 指定NotBetween查询条件 + * @access public + * @param mixed $field 查询字段 + * @param mixed $condition 查询条件 + * @param string $logic 查询逻辑 and or xor + * @return $this + */ + public function whereNotBetween(string $field, $condition, string $logic = 'AND') + { + return $this->parseWhereExp($logic, $field, 'NOT BETWEEN', $condition, [], true); + } + + /** + * 指定FIND_IN_SET查询条件 + * @access public + * @param mixed $field 查询字段 + * @param mixed $condition 查询条件 + * @param string $logic 查询逻辑 and or xor + * @return $this + */ + public function whereFindInSet(string $field, $condition, string $logic = 'AND') + { + return $this->parseWhereExp($logic, $field, 'FIND IN SET', $condition, [], true); + } + + /** + * 比较两个字段 + * @access public + * @param string $field1 查询字段 + * @param string $operator 比较操作符 + * @param string $field2 比较字段 + * @param string $logic 查询逻辑 and or xor + * @return $this + */ + public function whereColumn(string $field1, string $operator, string $field2 = null, string $logic = 'AND') + { + if (is_null($field2)) { + $field2 = $operator; + $operator = '='; + } + + return $this->parseWhereExp($logic, $field1, 'COLUMN', [$operator, $field2], [], true); + } + + /** + * 设置软删除字段及条件 + * @access public + * @param string $field 查询字段 + * @param mixed $condition 查询条件 + * @return $this + */ + public function useSoftDelete(string $field, $condition = null) + { + if ($field) { + $this->options['soft_delete'] = [$field, $condition]; + } + + return $this; + } + + /** + * 指定Exp查询条件 + * @access public + * @param mixed $field 查询字段 + * @param string $where 查询条件 + * @param array $bind 参数绑定 + * @param string $logic 查询逻辑 and or xor + * @return $this + */ + public function whereExp(string $field, string $where, array $bind = [], string $logic = 'AND') + { + $this->options['where'][$logic][] = [$field, 'EXP', new Raw($where, $bind)]; + + return $this; + } + + /** + * 指定字段Raw查询 + * @access public + * @param string $field 查询字段表达式 + * @param mixed $op 查询表达式 + * @param string $condition 查询条件 + * @param string $logic 查询逻辑 and or xor + * @return $this + */ + public function whereFieldRaw(string $field, $op, $condition = null, string $logic = 'AND') + { + if (is_null($condition)) { + $condition = $op; + $op = '='; + } + + $this->options['where'][$logic][] = [new Raw($field), $op, $condition]; + return $this; + } + + /** + * 指定表达式查询条件 + * @access public + * @param string $where 查询条件 + * @param array $bind 参数绑定 + * @param string $logic 查询逻辑 and or xor + * @return $this + */ + public function whereRaw(string $where, array $bind = [], string $logic = 'AND') + { + $this->options['where'][$logic][] = new Raw($where, $bind); + + return $this; + } + + /** + * 指定表达式查询条件 OR + * @access public + * @param string $where 查询条件 + * @param array $bind 参数绑定 + * @return $this + */ + public function whereOrRaw(string $where, array $bind = []) + { + return $this->whereRaw($where, $bind, 'OR'); + } + + /** + * 分析查询表达式 + * @access protected + * @param string $logic 查询逻辑 and or xor + * @param mixed $field 查询字段 + * @param mixed $op 查询表达式 + * @param mixed $condition 查询条件 + * @param array $param 查询参数 + * @param bool $strict 严格模式 + * @return $this + */ + protected function parseWhereExp(string $logic, $field, $op, $condition, array $param = [], bool $strict = false) + { + $logic = strtoupper($logic); + + if (is_string($field) && !empty($this->options['via']) && false === strpos($field, '.')) { + $field = $this->options['via'] . '.' . $field; + } + + if ($field instanceof Raw) { + return $this->whereRaw($field, is_array($op) ? $op : [], $logic); + } elseif ($strict) { + // 使用严格模式查询 + if ('=' == $op) { + $where = $this->whereEq($field, $condition); + } else { + $where = [$field, $op, $condition, $logic]; + } + } elseif (is_array($field)) { + // 解析数组批量查询 + return $this->parseArrayWhereItems($field, $logic); + } elseif ($field instanceof Closure) { + $where = $field; + } elseif (is_string($field)) { + if (preg_match('/[,=\<\'\"\(\s]/', $field)) { + return $this->whereRaw($field, is_array($op) ? $op : [], $logic); + } elseif (is_string($op) && strtolower($op) == 'exp' && !is_null($condition)) { + $bind = isset($param[2]) && is_array($param[2]) ? $param[2] : []; + return $this->whereExp($field, $condition, $bind, $logic); + } + + $where = $this->parseWhereItem($logic, $field, $op, $condition, $param); + } + + if (!empty($where)) { + $this->options['where'][$logic][] = $where; + } + + return $this; + } + + /** + * 分析查询表达式 + * @access protected + * @param string $logic 查询逻辑 and or xor + * @param mixed $field 查询字段 + * @param mixed $op 查询表达式 + * @param mixed $condition 查询条件 + * @param array $param 查询参数 + * @return array + */ + protected function parseWhereItem(string $logic, $field, $op, $condition, array $param = []): array + { + if (is_array($op)) { + // 同一字段多条件查询 + array_unshift($param, $field); + $where = $param; + } elseif ($field && is_null($condition)) { + if (is_string($op) && in_array(strtoupper($op), ['NULL', 'NOTNULL', 'NOT NULL'], true)) { + // null查询 + $where = [$field, $op, '']; + } elseif ('=' === $op || is_null($op)) { + $where = [$field, 'NULL', '']; + } elseif ('<>' === $op) { + $where = [$field, 'NOTNULL', '']; + } else { + // 字段相等查询 + $where = $this->whereEq($field, $op); + } + } elseif (is_string($op) && in_array(strtoupper($op), ['EXISTS', 'NOT EXISTS', 'NOTEXISTS'], true)) { + $where = [$field, $op, is_string($condition) ? new Raw($condition) : $condition]; + } else { + $where = $field ? [$field, $op, $condition, $param[2] ?? null] : []; + } + + return $where; + } + + /** + * 相等查询的主键处理 + * @access protected + * @param string $field 字段名 + * @param mixed $value 字段值 + * @return array + */ + protected function whereEq(string $field, $value): array + { + if ($this->getPk() == $field) { + $this->options['key'] = $value; + } + + return [$field, '=', $value]; + } + + /** + * 数组批量查询 + * @access protected + * @param array $field 批量查询 + * @param string $logic 查询逻辑 and or xor + * @return $this + */ + protected function parseArrayWhereItems(array $field, string $logic) + { + if (key($field) !== 0) { + $where = []; + foreach ($field as $key => $val) { + if ($val instanceof Raw) { + $where[] = [$key, 'exp', $val]; + } else { + $where[] = is_null($val) ? [$key, 'NULL', ''] : [$key, is_array($val) ? 'IN' : '=', $val]; + } + } + } else { + // 数组批量查询 + $where = $field; + } + + if (!empty($where)) { + $this->options['where'][$logic] = isset($this->options['where'][$logic]) ? + array_merge($this->options['where'][$logic], $where) : $where; + } + + return $this; + } + + /** + * 去除某个查询条件 + * @access public + * @param string $field 查询字段 + * @param string $logic 查询逻辑 and or xor + * @return $this + */ + public function removeWhereField(string $field, string $logic = 'AND') + { + $logic = strtoupper($logic); + + if (isset($this->options['where'][$logic])) { + foreach ($this->options['where'][$logic] as $key => $val) { + if (is_array($val) && $val[0] == $field) { + unset($this->options['where'][$logic][$key]); + } + } + } + + return $this; + } + + /** + * 条件查询 + * @access public + * @param mixed $condition 满足条件(支持闭包) + * @param Closure|array $query 满足条件后执行的查询表达式(闭包或数组) + * @param Closure|array $otherwise 不满足条件后执行 + * @return $this + */ + public function when($condition, $query, $otherwise = null) + { + if ($condition instanceof Closure) { + $condition = $condition($this); + } + + if ($condition) { + if ($query instanceof Closure) { + $query($this, $condition); + } elseif (is_array($query)) { + $this->where($query); + } + } elseif ($otherwise) { + if ($otherwise instanceof Closure) { + $otherwise($this, $condition); + } elseif (is_array($otherwise)) { + $this->where($otherwise); + } + } + + return $this; + } +} diff --git a/vendor/topthink/think-orm/src/db/connector/Mongo.php b/vendor/topthink/think-orm/src/db/connector/Mongo.php new file mode 100644 index 000000000..4b05b791d --- /dev/null +++ b/vendor/topthink/think-orm/src/db/connector/Mongo.php @@ -0,0 +1,1176 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\db\connector; + +use Closure; +use MongoDB\BSON\ObjectID; +use MongoDB\Driver\BulkWrite; +use MongoDB\Driver\Command; +use MongoDB\Driver\Cursor; +use MongoDB\Driver\Exception\AuthenticationException; +use MongoDB\Driver\Exception\BulkWriteException; +use MongoDB\Driver\Exception\ConnectionException; +use MongoDB\Driver\Exception\InvalidArgumentException; +use MongoDB\Driver\Exception\RuntimeException; +use MongoDB\Driver\Manager; +use MongoDB\Driver\Query as MongoQuery; +use MongoDB\Driver\ReadPreference; +use MongoDB\Driver\WriteConcern; +use think\db\BaseQuery; +use think\db\builder\Mongo as Builder; +use think\db\Connection; +use think\db\exception\DbException as Exception; +use think\db\Mongo as Query; +use function implode; +use function is_array; + +/** + * Mongo数据库驱动 + * @property Manager[] $links + * @property Manager $linkRead + * @property Manager $linkWrite + */ +class Mongo extends Connection +{ + + // 查询数据类型 + protected $dbName = ''; + protected $typeMap = 'array'; + protected $mongo; // MongoDb Object + protected $cursor; // MongoCursor Object + protected $session_uuid; // sessions会话列表当前会话数组key 随机生成 + protected $sessions = []; // 会话列表 + + /** @var Builder */ + protected $builder; + + // 数据库连接参数配置 + protected $config = [ + // 数据库类型 + 'type' => '', + // 服务器地址 + 'hostname' => '', + // 数据库名 + 'database' => '', + // 是否是复制集 + 'is_replica_set' => false, + // 用户名 + 'username' => '', + // 密码 + 'password' => '', + // 端口 + 'hostport' => '', + // 连接dsn + 'dsn' => '', + // 数据库连接参数 + 'params' => [], + // 数据库编码默认采用utf8 + 'charset' => 'utf8', + // 主键名 + 'pk' => '_id', + // 主键类型 + 'pk_type' => 'ObjectID', + // 数据库表前缀 + 'prefix' => '', + // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) + 'deploy' => 0, + // 数据库读写是否分离 主从式有效 + 'rw_separate' => false, + // 读写分离后 主服务器数量 + 'master_num' => 1, + // 指定从服务器序号 + 'slave_no' => '', + // 是否严格检查字段是否存在 + 'fields_strict' => true, + // 开启字段缓存 + 'fields_cache' => false, + // 监听SQL + 'trigger_sql' => true, + // 自动写入时间戳字段 + 'auto_timestamp' => false, + // 时间字段取出后的默认时间格式 + 'datetime_format' => 'Y-m-d H:i:s', + // 是否_id转换为id + 'pk_convert_id' => false, + // typeMap + 'type_map' => ['root' => 'array', 'document' => 'array'], + ]; + + /** + * 获取当前连接器类对应的Query类 + * @access public + * @return string + */ + public function getQueryClass(): string + { + return Query::class; + } + + /** + * 获取当前的builder实例对象 + * @access public + * @return Builder + */ + public function getBuilder() + { + return $this->builder; + } + + /** + * 获取当前连接器类对应的Builder类 + * @access public + * @return string + */ + public function getBuilderClass(): string + { + return Builder::class; + } + + /** + * 连接数据库方法 + * @access public + * @param array $config 连接参数 + * @param integer $linkNum 连接序号 + * @return Manager + * @throws InvalidArgumentException + * @throws RuntimeException + */ + public function connect(array $config = [], $linkNum = 0) + { + if (!isset($this->links[$linkNum])) { + if (empty($config)) { + $config = $this->config; + } else { + $config = array_merge($this->config, $config); + } + + $this->dbName = $config['database']; + $this->typeMap = $config['type_map']; + + if ($config['pk_convert_id'] && '_id' == $config['pk']) { + $this->config['pk'] = 'id'; + } + + if (empty($config['dsn'])) { + $config['dsn'] = 'mongodb://' . ($config['username'] ? "{$config['username']}" : '') . ($config['password'] ? ":{$config['password']}@" : '') . $config['hostname'] . ($config['hostport'] ? ":{$config['hostport']}" : ''); + } + + $startTime = microtime(true); + + $this->links[$linkNum] = new Manager($config['dsn'], $config['params']); + + if (!empty($config['trigger_sql'])) { + // 记录数据库连接信息 + $this->trigger('CONNECT:[ UseTime:' . number_format(microtime(true) - $startTime, 6) . 's ] ' . $config['dsn']); + } + + } + + return $this->links[$linkNum]; + } + + /** + * 获取Mongo Manager对象 + * @access public + * @return Manager|null + */ + public function getMongo() + { + return $this->mongo ?: null; + } + + /** + * 设置/获取当前操作的database + * @access public + * @param string $db db + * @return string + */ + public function db(string $db = null) + { + if (is_null($db)) { + return $this->dbName; + } else { + $this->dbName = $db; + } + } + + /** + * 执行查询但只返回Cursor对象 + * @access public + * @param Query $query 查询对象 + * @return Cursor + */ + public function cursor($query) + { + // 分析查询表达式 + $options = $query->parseOptions(); + + // 生成MongoQuery对象 + $mongoQuery = $this->builder->select($query); + + $master = $query->getOptions('master') ? true : false; + + // 执行查询操作 + return $this->getCursor($query, $mongoQuery, $master); + } + + /** + * 执行查询并返回Cursor对象 + * @access public + * @param BaseQuery $query 查询对象 + * @param MongoQuery|Closure $mongoQuery Mongo查询对象 + * @param bool $master 是否主库操作 + * @return Cursor + * @throws AuthenticationException + * @throws InvalidArgumentException + * @throws ConnectionException + * @throws RuntimeException + */ + public function getCursor(BaseQuery $query, $mongoQuery, bool $master = false): Cursor + { + $this->initConnect($master); + $this->db->updateQueryTimes(); + + $options = $query->getOptions(); + $namespace = $options['table']; + + if (false === strpos($namespace, '.')) { + $namespace = $this->dbName . '.' . $namespace; + } + + if (!empty($this->queryStr)) { + // 记录执行指令 + $this->queryStr = 'db' . strstr($namespace, '.') . '.' . $this->queryStr; + } + + if ($mongoQuery instanceof Closure) { + $mongoQuery = $mongoQuery($query); + } + + $readPreference = $options['readPreference'] ?? null; + $this->queryStartTime = microtime(true); + + if ($session = $this->getSession()) { + $this->cursor = $this->mongo->executeQuery($namespace, $query, [ + 'readPreference' => is_null($readPreference) ? new ReadPreference(ReadPreference::RP_PRIMARY) : $readPreference, + 'session' => $session, + ]); + } else { + $this->cursor = $this->mongo->executeQuery($namespace, $mongoQuery, $readPreference); + } + + // SQL监控 + if (!empty($this->config['trigger_sql'])) { + $this->trigger('', $master); + } + + return $this->cursor; + } + + /** + * 执行查询 返回数据集 + * @access public + * @param MongoQuery $query 查询对象 + * @return mixed + * @throws AuthenticationException + * @throws InvalidArgumentException + * @throws ConnectionException + * @throws RuntimeException + */ + public function query(MongoQuery $query) + { + return $this->mongoQuery($this->newQuery(), $query); + } + + /** + * 执行语句 + * @access public + * @param BulkWrite $bulk + * @return int + * @throws AuthenticationException + * @throws InvalidArgumentException + * @throws ConnectionException + * @throws RuntimeException + * @throws BulkWriteException + */ + public function execute(BulkWrite $bulk) + { + return $this->mongoExecute($this->newQuery(), $bulk); + } + + /** + * 执行查询 + * @access protected + * @param BaseQuery $query 查询对象 + * @param MongoQuery|Closure $mongoQuery Mongo查询对象 + * @return array + * @throws AuthenticationException + * @throws InvalidArgumentException + * @throws ConnectionException + * @throws RuntimeException + */ + protected function mongoQuery(BaseQuery $query, $mongoQuery): array + { + $options = $query->parseOptions(); + + if ($query->getOptions('cache')) { + // 检查查询缓存 + $cacheItem = $this->parseCache($query, $query->getOptions('cache')); + $key = $cacheItem->getKey(); + + if ($this->cache->has($key)) { + return $this->cache->get($key); + } + } + + if ($mongoQuery instanceof Closure) { + $mongoQuery = $mongoQuery($query); + } + + $master = $query->getOptions('master') ? true : false; + $this->getCursor($query, $mongoQuery, $master); + + $resultSet = $this->getResult($options['typeMap']); + + if (isset($cacheItem) && $resultSet) { + // 缓存数据集 + $cacheItem->set($resultSet); + $this->cacheData($cacheItem); + } + + return $resultSet; + } + + /** + * 执行写操作 + * @access protected + * @param BaseQuery $query + * @param BulkWrite $bulk + * + * @return WriteResult + * @throws AuthenticationException + * @throws InvalidArgumentException + * @throws ConnectionException + * @throws RuntimeException + * @throws BulkWriteException + */ + protected function mongoExecute(BaseQuery $query, BulkWrite $bulk) + { + $this->initConnect(true); + $this->db->updateQueryTimes(); + + $options = $query->getOptions(); + + $namespace = $options['table']; + if (false === strpos($namespace, '.')) { + $namespace = $this->dbName . '.' . $namespace; + } + + if (!empty($this->queryStr)) { + // 记录执行指令 + $this->queryStr = 'db' . strstr($namespace, '.') . '.' . $this->queryStr; + } + + $writeConcern = $options['writeConcern'] ?? null; + $this->queryStartTime = microtime(true); + + if ($session = $this->getSession()) { + $writeResult = $this->mongo->executeBulkWrite($namespace, $bulk, [ + 'session' => $session, + 'writeConcern' => is_null($writeConcern) ? new WriteConcern(1) : $writeConcern, + ]); + } else { + $writeResult = $this->mongo->executeBulkWrite($namespace, $bulk, $writeConcern); + } + + // SQL监控 + if (!empty($this->config['trigger_sql'])) { + $this->trigger(); + } + + $this->numRows = $writeResult->getMatchedCount(); + + if ($query->getOptions('cache')) { + // 清理缓存数据 + $cacheItem = $this->parseCache($query, $query->getOptions('cache')); + $key = $cacheItem->getKey(); + $tag = $cacheItem->getTag(); + + if (isset($key) && $this->cache->has($key)) { + $this->cache->delete($key); + } elseif (!empty($tag) && method_exists($this->cache, 'tag')) { + $this->cache->tag($tag)->clear(); + } + } + + return $writeResult; + } + + /** + * 执行指令 + * @access public + * @param Command $command 指令 + * @param string $dbName 当前数据库名 + * @param ReadPreference $readPreference readPreference + * @param string|array $typeMap 指定返回的typeMap + * @param bool $master 是否主库操作 + * @return array + * @throws AuthenticationException + * @throws InvalidArgumentException + * @throws ConnectionException + * @throws RuntimeException + */ + public function command(Command $command, string $dbName = '', ReadPreference $readPreference = null, $typeMap = null, bool $master = false): array + { + $this->initConnect($master); + $this->db->updateQueryTimes(); + + $this->queryStartTime = microtime(true); + + $dbName = $dbName ?: $this->dbName; + + if (!empty($this->queryStr)) { + $this->queryStr = 'db.' . $this->queryStr; + } + + if ($session = $this->getSession()) { + $this->cursor = $this->mongo->executeCommand($dbName, $command, [ + 'readPreference' => is_null($readPreference) ? new ReadPreference(ReadPreference::RP_PRIMARY) : $readPreference, + 'session' => $session, + ]); + } else { + $this->cursor = $this->mongo->executeCommand($dbName, $command, $readPreference); + } + + // SQL监控 + if (!empty($this->config['trigger_sql'])) { + $this->trigger('', $master); + } + + return $this->getResult($typeMap); + } + + /** + * 获得数据集 + * @access protected + * @param string|array $typeMap 指定返回的typeMap + * @return mixed + */ + protected function getResult($typeMap = null): array + { + // 设置结果数据类型 + if (is_null($typeMap)) { + $typeMap = $this->typeMap; + } + + $typeMap = is_string($typeMap) ? ['root' => $typeMap] : $typeMap; + + $this->cursor->setTypeMap($typeMap); + + // 获取数据集 + $result = $this->cursor->toArray(); + + if ($this->getConfig('pk_convert_id')) { + // 转换ObjectID 字段 + foreach ($result as &$data) { + $this->convertObjectID($data); + } + } + + $this->numRows = count($result); + + return $result; + } + + /** + * ObjectID处理 + * @access protected + * @param array $data 数据 + * @return void + */ + protected function convertObjectID(array &$data): void + { + if (isset($data['_id']) && is_object($data['_id'])) { + $data['id'] = $data['_id']->__toString(); + unset($data['_id']); + } + } + + /** + * 数据库日志记录(仅供参考) + * @access public + * @param string $type 类型 + * @param mixed $data 数据 + * @param array $options 参数 + * @return void + */ + public function mongoLog(string $type, $data, array $options = []) + { + if (!$this->config['trigger_sql']) { + return; + } + + if (is_array($data)) { + array_walk_recursive($data, function (&$value) { + if ($value instanceof ObjectID) { + $value = $value->__toString(); + } + }); + } + + switch (strtolower($type)) { + case 'aggregate': + $this->queryStr = 'runCommand(' . ($data ? json_encode($data) : '') . ');'; + break; + case 'find': + $this->queryStr = $type . '(' . ($data ? json_encode($data) : '') . ')'; + + if (isset($options['sort'])) { + $this->queryStr .= '.sort(' . json_encode($options['sort']) . ')'; + } + + if (isset($options['skip'])) { + $this->queryStr .= '.skip(' . $options['skip'] . ')'; + } + + if (isset($options['limit'])) { + $this->queryStr .= '.limit(' . $options['limit'] . ')'; + } + + $this->queryStr .= ';'; + break; + case 'insert': + case 'remove': + $this->queryStr = $type . '(' . ($data ? json_encode($data) : '') . ');'; + break; + case 'update': + $this->queryStr = $type . '(' . json_encode($options) . ',' . json_encode($data) . ');'; + break; + case 'cmd': + $this->queryStr = $data . '(' . json_encode($options) . ');'; + break; + } + + $this->options = $options; + } + + /** + * 获取最近执行的指令 + * @access public + * @return string + */ + public function getLastSql(): string + { + return $this->queryStr; + } + + /** + * 关闭数据库 + * @access public + */ + public function close() + { + $this->mongo = null; + $this->cursor = null; + $this->linkRead = null; + $this->linkWrite = null; + $this->links = []; + } + + /** + * 初始化数据库连接 + * @access protected + * @param boolean $master 是否主服务器 + * @return void + */ + protected function initConnect(bool $master = true): void + { + if (!empty($this->config['deploy'])) { + // 采用分布式数据库 + if ($master) { + if (!$this->linkWrite) { + $this->linkWrite = $this->multiConnect(true); + } + + $this->mongo = $this->linkWrite; + } else { + if (!$this->linkRead) { + $this->linkRead = $this->multiConnect(false); + } + + $this->mongo = $this->linkRead; + } + } elseif (!$this->mongo) { + // 默认单数据库 + $this->mongo = $this->connect(); + } + } + + /** + * 连接分布式服务器 + * @access protected + * @param boolean $master 主服务器 + * @return Manager + */ + protected function multiConnect(bool $master = false): Manager + { + $config = []; + // 分布式数据库配置解析 + foreach (['username', 'password', 'hostname', 'hostport', 'database', 'dsn'] as $name) { + $config[$name] = is_string($this->config[$name]) ? explode(',', $this->config[$name]) : $this->config[$name]; + } + + // 主服务器序号 + $m = floor(mt_rand(0, $this->config['master_num'] - 1)); + + if ($this->config['rw_separate']) { + // 主从式采用读写分离 + if ($master) // 主服务器写入 + { + if ($this->config['is_replica_set']) { + return $this->replicaSetConnect(); + } else { + $r = $m; + } + } elseif (is_numeric($this->config['slave_no'])) { + // 指定服务器读 + $r = $this->config['slave_no']; + } else { + // 读操作连接从服务器 每次随机连接的数据库 + $r = floor(mt_rand($this->config['master_num'], count($config['hostname']) - 1)); + } + } else { + // 读写操作不区分服务器 每次随机连接的数据库 + $r = floor(mt_rand(0, count($config['hostname']) - 1)); + } + + $dbConfig = []; + + foreach (['username', 'password', 'hostname', 'hostport', 'database', 'dsn'] as $name) { + $dbConfig[$name] = $config[$name][$r] ?? $config[$name][0]; + } + + return $this->connect($dbConfig, $r); + } + + /** + * 创建基于复制集的连接 + * @return Manager + */ + public function replicaSetConnect(): Manager + { + $this->dbName = $this->config['database']; + $this->typeMap = $this->config['type_map']; + + $startTime = microtime(true); + + $this->config['params']['replicaSet'] = $this->config['database']; + + $manager = new Manager($this->buildUrl(), $this->config['params']); + + // 记录数据库连接信息 + if (!empty($config['trigger_sql'])) { + $this->trigger('CONNECT:ReplicaSet[ UseTime:' . number_format(microtime(true) - $startTime, 6) . 's ] ' . $this->config['dsn']); + } + + return $manager; + } + + /** + * 根据配置信息 生成适用于连接复制集的 URL + * @return string + */ + private function buildUrl(): string + { + $url = 'mongodb://' . ($this->config['username'] ? "{$this->config['username']}" : '') . ($this->config['password'] ? ":{$this->config['password']}@" : ''); + + $hostList = is_string($this->config['hostname']) ? explode(',', $this->config['hostname']) : $this->config['hostname']; + $portList = is_string($this->config['hostport']) ? explode(',', $this->config['hostport']) : $this->config['hostport']; + + for ($i = 0; $i < count($hostList); $i++) { + $url = $url . $hostList[$i] . ':' . $portList[0] . ','; + } + + return rtrim($url, ",") . '/'; + } + + /** + * 插入记录 + * @access public + * @param BaseQuery $query 查询对象 + * @param boolean $getLastInsID 返回自增主键 + * @return mixed + * @throws AuthenticationException + * @throws InvalidArgumentException + * @throws ConnectionException + * @throws RuntimeException + * @throws BulkWriteException + */ + public function insert(BaseQuery $query, bool $getLastInsID = false) + { + // 分析查询表达式 + $options = $query->parseOptions(); + + if (empty($options['data'])) { + throw new Exception('miss data to insert'); + } + + // 生成bulk对象 + $bulk = $this->builder->insert($query); + + $writeResult = $this->mongoExecute($query, $bulk); + $result = $writeResult->getInsertedCount(); + + if ($result) { + $data = $options['data']; + $lastInsId = $this->getLastInsID($query); + + if ($lastInsId) { + $pk = $query->getPk(); + $data[$pk] = $lastInsId; + } + + $query->setOption('data', $data); + + $this->db->trigger('after_insert', $query); + + if ($getLastInsID) { + return $lastInsId; + } + } + + return $result; + } + + /** + * 获取最近插入的ID + * @access public + * @param BaseQuery $query 查询对象 + * @return mixed + */ + public function getLastInsID(BaseQuery $query) + { + $id = $this->builder->getLastInsID(); + + if (is_array($id)) { + array_walk($id, function (&$item, $key) { + if ($item instanceof ObjectID) { + $item = $item->__toString(); + } + }); + } elseif ($id instanceof ObjectID) { + $id = $id->__toString(); + } + + return $id; + } + + /** + * 批量插入记录 + * @access public + * @param BaseQuery $query 查询对象 + * @param array $dataSet 数据集 + * @return integer + * @throws AuthenticationException + * @throws InvalidArgumentException + * @throws ConnectionException + * @throws RuntimeException + * @throws BulkWriteException + */ + public function insertAll(BaseQuery $query, array $dataSet = []): int + { + // 分析查询表达式 + $query->parseOptions(); + + if (!is_array(reset($dataSet))) { + return 0; + } + + // 生成bulkWrite对象 + $bulk = $this->builder->insertAll($query, $dataSet); + + $writeResult = $this->mongoExecute($query, $bulk); + + return $writeResult->getInsertedCount(); + } + + /** + * 更新记录 + * @access public + * @param BaseQuery $query 查询对象 + * @return int + * @throws Exception + * @throws AuthenticationException + * @throws InvalidArgumentException + * @throws ConnectionException + * @throws RuntimeException + * @throws BulkWriteException + */ + public function update(BaseQuery $query): int + { + $query->parseOptions(); + + // 生成bulkWrite对象 + $bulk = $this->builder->update($query); + + $writeResult = $this->mongoExecute($query, $bulk); + + $result = $writeResult->getModifiedCount(); + + if ($result) { + $this->db->trigger('after_update', $query); + } + + return $result; + } + + /** + * 删除记录 + * @access public + * @param BaseQuery $query 查询对象 + * @return int + * @throws Exception + * @throws AuthenticationException + * @throws InvalidArgumentException + * @throws ConnectionException + * @throws RuntimeException + * @throws BulkWriteException + */ + public function delete(BaseQuery $query): int + { + // 分析查询表达式 + $query->parseOptions(); + + // 生成bulkWrite对象 + $bulk = $this->builder->delete($query); + + // 执行操作 + $writeResult = $this->mongoExecute($query, $bulk); + + $result = $writeResult->getDeletedCount(); + + if ($result) { + $this->db->trigger('after_delete', $query); + } + + return $result; + } + + /** + * 查找记录 + * @access public + * @param BaseQuery $query 查询对象 + * @return array + * @throws ModelNotFoundException + * @throws DataNotFoundException + * @throws AuthenticationException + * @throws InvalidArgumentException + * @throws ConnectionException + * @throws RuntimeException + */ + public function select(BaseQuery $query): array + { + $resultSet = $this->db->trigger('before_select', $query); + + if (!$resultSet) { + $resultSet = $this->mongoQuery($query, function ($query) { + return $this->builder->select($query); + }); + } + + return $resultSet; + } + + /** + * 查找单条记录 + * @access public + * @param BaseQuery $query 查询对象 + * @return array + * @throws ModelNotFoundException + * @throws DataNotFoundException + * @throws AuthenticationException + * @throws InvalidArgumentException + * @throws ConnectionException + * @throws RuntimeException + */ + public function find(BaseQuery $query): array + { + // 事件回调 + $result = $this->db->trigger('before_find', $query); + + if (!$result) { + // 执行查询 + $resultSet = $this->mongoQuery($query, function ($query) { + return $this->builder->select($query, true); + }); + + $result = $resultSet[0] ?? []; + } + + return $result; + } + + /** + * 得到某个字段的值 + * @access public + * @param string $field 字段名 + * @param mixed $default 默认值 + * @return mixed + */ + public function value(BaseQuery $query, string $field, $default = null) + { + $options = $query->parseOptions(); + + if (isset($options['projection'])) { + $query->removeOption('projection'); + } + + $query->setOption('projection', (array) $field); + + if (!empty($options['cache'])) { + $cacheItem = $this->parseCache($query, $options['cache']); + $key = $cacheItem->getKey(); + + if ($this->cache->has($key)) { + return $this->cache->get($key); + } + } + + $mongoQuery = $this->builder->select($query, true); + + if (isset($options['projection'])) { + $query->setOption('projection', $options['projection']); + } else { + $query->removeOption('projection'); + } + + // 执行查询操作 + $resultSet = $this->mongoQuery($query, $mongoQuery); + + if (!empty($resultSet)) { + $data = array_shift($resultSet); + $result = $data[$field]; + } else { + $result = false; + } + + if (isset($cacheItem) && false !== $result) { + // 缓存数据 + $cacheItem->set($result); + $this->cacheData($cacheItem); + } + + return false !== $result ? $result : $default; + } + + /** + * 得到某个列的数组 + * @access public + * @param BaseQuery $query + * @param string|array $field 字段名 多个字段用逗号分隔 + * @param string $key 索引 + * @return array + */ + public function column(BaseQuery $query, $field, string $key = ''): array + { + $options = $query->parseOptions(); + + if (isset($options['projection'])) { + $query->removeOption('projection'); + } + + if (is_array($field)) { + $field = implode(',', $field); + } + if ($key && '*' != $field) { + $projection = $key . ',' . $field; + } else { + $projection = $field; + } + + $query->field($projection); + + if (!empty($options['cache'])) { + // 判断查询缓存 + $cacheItem = $this->parseCache($query, $options['cache']); + $key = $cacheItem->getKey(); + + if ($this->cache->has($key)) { + return $this->cache->get($key); + } + } + + $mongoQuery = $this->builder->select($query); + + if (isset($options['projection'])) { + $query->setOption('projection', $options['projection']); + } else { + $query->removeOption('projection'); + } + + // 执行查询操作 + $resultSet = $this->mongoQuery($query, $mongoQuery); + + if (('*' == $field || strpos($field, ',')) && $key) { + $result = array_column($resultSet, null, $key); + } elseif (!empty($resultSet)) { + $result = array_column($resultSet, $field, $key); + } else { + $result = []; + } + + if (isset($cacheItem)) { + // 缓存数据 + $cacheItem->set($result); + $this->cacheData($cacheItem); + } + + return $result; + } + + /** + * 执行command + * @access public + * @param BaseQuery $query 查询对象 + * @param string|array|object $command 指令 + * @param mixed $extra 额外参数 + * @param string $db 数据库名 + * @return array + */ + public function cmd(BaseQuery $query, $command, $extra = null, string $db = ''): array + { + if (is_array($command) || is_object($command)) { + + $this->mongoLog('cmd', 'cmd', $command); + + // 直接创建Command对象 + $command = new Command($command); + } else { + // 调用Builder封装的Command对象 + $command = $this->builder->$command($query, $extra); + } + + return $this->command($command, $db); + } + + /** + * 获取数据库字段 + * @access public + * @param mixed $tableName 数据表名 + * @return array + */ + public function getTableFields($tableName): array + { + return []; + } + + /** + * 执行数据库事务 + * @access public + * @param callable $callback 数据操作方法回调 + * @return mixed + * @throws PDOException + * @throws \Exception + * @throws \Throwable + */ + public function transaction(callable $callback) + { + $this->startTrans(); + try { + $result = null; + if (is_callable($callback)) { + $result = call_user_func_array($callback, [$this]); + } + $this->commit(); + return $result; + } catch (\Exception $e) { + $this->rollback(); + throw $e; + } catch (\Throwable $e) { + $this->rollback(); + throw $e; + } + } + + /** + * 启动事务 + * @access public + * @return void + * @throws \PDOException + * @throws \Exception + */ + public function startTrans() + { + $this->initConnect(true); + $this->session_uuid = uniqid(); + $this->sessions[$this->session_uuid] = $this->getMongo()->startSession(); + + $this->sessions[$this->session_uuid]->startTransaction([]); + } + + /** + * 用于非自动提交状态下面的查询提交 + * @access public + * @return void + * @throws PDOException + */ + public function commit() + { + if ($session = $this->getSession()) { + $session->commitTransaction(); + $this->setLastSession(); + } + } + + /** + * 事务回滚 + * @access public + * @return void + * @throws PDOException + */ + public function rollback() + { + if ($session = $this->getSession()) { + $session->abortTransaction(); + $this->setLastSession(); + } + } + + /** + * 结束当前会话,设置上一个会话为当前会话 + * @author klinson + */ + protected function setLastSession() + { + if ($session = $this->getSession()) { + $session->endSession(); + unset($this->sessions[$this->session_uuid]); + if (empty($this->sessions)) { + $this->session_uuid = null; + } else { + end($this->sessions); + $this->session_uuid = key($this->sessions); + } + } + } + + /** + * 获取当前会话 + * @return \MongoDB\Driver\Session|null + * @author klinson + */ + public function getSession() + { + return ($this->session_uuid && isset($this->sessions[$this->session_uuid])) + ? $this->sessions[$this->session_uuid] + : null; + } +} diff --git a/thinkphp/library/think/db/connector/Mysql.php b/vendor/topthink/think-orm/src/db/connector/Mysql.php old mode 100755 new mode 100644 similarity index 55% rename from thinkphp/library/think/db/connector/Mysql.php rename to vendor/topthink/think-orm/src/db/connector/Mysql.php index 93b8a1825..483b447a8 --- a/thinkphp/library/think/db/connector/Mysql.php +++ b/vendor/topthink/think-orm/src/db/connector/Mysql.php @@ -2,56 +2,32 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\db\connector; use PDO; -use think\db\Connection; -use think\db\Query; +use think\db\PDOConnection; /** * mysql数据库驱动 */ -class Mysql extends Connection +class Mysql extends PDOConnection { - protected $builder = '\\think\\db\\builder\\Mysql'; - - /** - * 初始化 - * @access protected - * @return void - */ - protected function initialize() - { - // Point类型支持 - Query::extend('point', function ($query, $field, $value = null, $fun = 'GeomFromText', $type = 'POINT') { - if (!is_null($value)) { - $query->data($field, ['point', $value, $fun, $type]); - } else { - if (is_string($field)) { - $field = explode(',', $field); - } - $query->setOption('point', $field); - } - - return $query; - }); - } - /** * 解析pdo连接的dsn信息 * @access protected * @param array $config 连接信息 * @return string */ - protected function parseDsn($config) + protected function parseDsn(array $config): string { if (!empty($config['socket'])) { $dsn = 'mysql:unix_socket=' . $config['socket']; @@ -75,9 +51,9 @@ class Mysql extends Connection * @param string $tableName * @return array */ - public function getFields($tableName) + public function getFields(string $tableName): array { - list($tableName) = explode(' ', $tableName); + [$tableName] = explode(' ', $tableName); if (false === strpos($tableName, '`')) { if (strpos($tableName, '.')) { @@ -86,21 +62,23 @@ class Mysql extends Connection $tableName = '`' . $tableName . '`'; } - $sql = 'SHOW COLUMNS FROM ' . $tableName; - $pdo = $this->query($sql, [], false, true); + $sql = 'SHOW FULL COLUMNS FROM ' . $tableName; + $pdo = $this->getPDOStatement($sql); $result = $pdo->fetchAll(PDO::FETCH_ASSOC); $info = []; - if ($result) { + if (!empty($result)) { foreach ($result as $key => $val) { - $val = array_change_key_case($val); + $val = array_change_key_case($val); + $info[$val['field']] = [ 'name' => $val['field'], 'type' => $val['type'], - 'notnull' => (bool) ('' === $val['null']), // not null is empty, null is yes + 'notnull' => 'NO' == $val['null'], 'default' => $val['default'], - 'primary' => (strtolower($val['key']) == 'pri'), - 'autoinc' => (strtolower($val['extra']) == 'auto_increment'), + 'primary' => strtolower($val['key']) == 'pri', + 'autoinc' => strtolower($val['extra']) == 'auto_increment', + 'comment' => $val['comment'], ]; } } @@ -114,10 +92,10 @@ class Mysql extends Connection * @param string $dbName * @return array */ - public function getTables($dbName = '') + public function getTables(string $dbName = ''): array { $sql = !empty($dbName) ? 'SHOW TABLES FROM ' . $dbName : 'SHOW TABLES '; - $pdo = $this->query($sql, [], false, true); + $pdo = $this->getPDOStatement($sql); $result = $pdo->fetchAll(PDO::FETCH_ASSOC); $info = []; @@ -128,28 +106,7 @@ class Mysql extends Connection return $info; } - /** - * SQL性能分析 - * @access protected - * @param string $sql - * @return array - */ - protected function getExplain($sql) - { - $pdo = $this->linkID->query("EXPLAIN " . $sql); - $result = $pdo->fetch(PDO::FETCH_ASSOC); - $result = array_change_key_case($result); - - if (isset($result['extra'])) { - if (strpos($result['extra'], 'filesort') || strpos($result['extra'], 'temporary')) { - $this->log('SQL:' . $this->queryStr . '[' . $result['extra'] . ']', 'warn'); - } - } - - return $result; - } - - protected function supportSavepoint() + protected function supportSavepoint(): bool { return true; } @@ -160,14 +117,10 @@ class Mysql extends Connection * @param string $xid XA事务id * @return void */ - public function startTransXa($xid) + public function startTransXa(string $xid) { $this->initConnect(true); - if (!$this->linkID) { - return false; - } - - $this->execute("XA START '$xid'"); + $this->linkID->exec("XA START '$xid'"); } /** @@ -176,11 +129,11 @@ class Mysql extends Connection * @param string $xid XA事务id * @return void */ - public function prepareXa($xid) + public function prepareXa(string $xid) { $this->initConnect(true); - $this->execute("XA END '$xid'"); - $this->execute("XA PREPARE '$xid'"); + $this->linkID->exec("XA END '$xid'"); + $this->linkID->exec("XA PREPARE '$xid'"); } /** @@ -189,10 +142,10 @@ class Mysql extends Connection * @param string $xid XA事务id * @return void */ - public function commitXa($xid) + public function commitXa(string $xid) { $this->initConnect(true); - $this->execute("XA COMMIT '$xid'"); + $this->linkID->exec("XA COMMIT '$xid'"); } /** @@ -201,9 +154,9 @@ class Mysql extends Connection * @param string $xid XA事务id * @return void */ - public function rollbackXa($xid) + public function rollbackXa(string $xid) { $this->initConnect(true); - $this->execute("XA ROLLBACK '$xid'"); + $this->linkID->exec("XA ROLLBACK '$xid'"); } } diff --git a/vendor/topthink/think-orm/src/db/connector/Oracle.php b/vendor/topthink/think-orm/src/db/connector/Oracle.php new file mode 100644 index 000000000..236d8bfa1 --- /dev/null +++ b/vendor/topthink/think-orm/src/db/connector/Oracle.php @@ -0,0 +1,117 @@ + +// +---------------------------------------------------------------------- + +namespace think\db\connector; + +use PDO; +use think\db\BaseQuery; +use think\db\PDOConnection; + +/** + * Oracle数据库驱动 + */ +class Oracle extends PDOConnection +{ + /** + * 解析pdo连接的dsn信息 + * @access protected + * @param array $config 连接信息 + * @return string + */ + protected function parseDsn(array $config): string + { + $dsn = 'oci:dbname='; + + if (!empty($config['hostname'])) { + // Oracle Instant Client + $dsn .= '//' . $config['hostname'] . ($config['hostport'] ? ':' . $config['hostport'] : '') . '/'; + } + + $dsn .= $config['database']; + + if (!empty($config['charset'])) { + $dsn .= ';charset=' . $config['charset']; + } + + return $dsn; + } + + /** + * 取得数据表的字段信息 + * @access public + * @param string $tableName + * @return array + */ + public function getFields(string $tableName): array + { + [$tableName] = explode(' ', $tableName); + $sql = "select a.column_name,data_type,DECODE (nullable, 'Y', 0, 1) notnull,data_default, DECODE (A .column_name,b.column_name,1,0) pk from all_tab_columns a,(select column_name from all_constraints c, all_cons_columns col where c.constraint_name = col.constraint_name and c.constraint_type = 'P' and c.table_name = '" . strtoupper($tableName) . "' ) b where table_name = '" . strtoupper($tableName) . "' and a.column_name = b.column_name (+)"; + + $pdo = $this->getPDOStatement($sql); + $result = $pdo->fetchAll(PDO::FETCH_ASSOC); + $info = []; + + if ($result) { + foreach ($result as $key => $val) { + $val = array_change_key_case($val); + + $info[$val['column_name']] = [ + 'name' => $val['column_name'], + 'type' => $val['data_type'], + 'notnull' => $val['notnull'], + 'default' => $val['data_default'], + 'primary' => $val['pk'], + 'autoinc' => $val['pk'], + ]; + } + } + + return $this->fieldCase($info); + } + + /** + * 取得数据库的表信息(暂时实现取得用户表信息) + * @access public + * @param string $dbName + * @return array + */ + public function getTables(string $dbName = ''): array + { + $sql = 'select table_name from all_tables'; + $pdo = $this->getPDOStatement($sql); + $result = $pdo->fetchAll(PDO::FETCH_ASSOC); + $info = []; + + foreach ($result as $key => $val) { + $info[$key] = current($val); + } + + return $info; + } + + /** + * 获取最近插入的ID + * @access public + * @param BaseQuery $query 查询对象 + * @param string $sequence 自增序列名 + * @return mixed + */ + public function getLastInsID(BaseQuery $query, string $sequence = null) + { + $pdo = $this->linkID->query("select {$sequence}.currval as id from dual"); + $result = $pdo->fetchColumn(); + + return $result; + } + + protected function supportSavepoint(): bool + { + return true; + } +} diff --git a/thinkphp/library/think/db/connector/Pgsql.php b/vendor/topthink/think-orm/src/db/connector/Pgsql.php old mode 100755 new mode 100644 similarity index 70% rename from thinkphp/library/think/db/connector/Pgsql.php rename to vendor/topthink/think-orm/src/db/connector/Pgsql.php index ee9fca017..fec8f8401 --- a/thinkphp/library/think/db/connector/Pgsql.php +++ b/vendor/topthink/think-orm/src/db/connector/Pgsql.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -12,16 +12,18 @@ namespace think\db\connector; use PDO; -use think\db\Connection; +use think\db\PDOConnection; /** * Pgsql数据库驱动 */ -class Pgsql extends Connection +class Pgsql extends PDOConnection { - protected $builder = '\\think\\db\\builder\\Pgsql'; - // PDO连接参数 + /** + * 默认PDO连接参数 + * @var array + */ protected $params = [ PDO::ATTR_CASE => PDO::CASE_NATURAL, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, @@ -35,7 +37,7 @@ class Pgsql extends Connection * @param array $config 连接信息 * @return string */ - protected function parseDsn($config) + protected function parseDsn(array $config): string { $dsn = 'pgsql:dbname=' . $config['database'] . ';host=' . $config['hostname']; @@ -52,18 +54,19 @@ class Pgsql extends Connection * @param string $tableName * @return array */ - public function getFields($tableName) + public function getFields(string $tableName): array { - list($tableName) = explode(' ', $tableName); - $sql = 'select fields_name as "field",fields_type as "type",fields_not_null as "null",fields_key_name as "key",fields_default as "default",fields_default as "extra" from table_msg(\'' . $tableName . '\');'; + [$tableName] = explode(' ', $tableName); + $sql = 'select fields_name as "field",fields_type as "type",fields_not_null as "null",fields_key_name as "key",fields_default as "default",fields_default as "extra" from table_msg(\'' . $tableName . '\');'; - $pdo = $this->query($sql, [], false, true); + $pdo = $this->getPDOStatement($sql); $result = $pdo->fetchAll(PDO::FETCH_ASSOC); $info = []; - if ($result) { + if (!empty($result)) { foreach ($result as $key => $val) { - $val = array_change_key_case($val); + $val = array_change_key_case($val); + $info[$val['field']] = [ 'name' => $val['field'], 'type' => $val['type'], @@ -84,10 +87,10 @@ class Pgsql extends Connection * @param string $dbName * @return array */ - public function getTables($dbName = '') + public function getTables(string $dbName = ''): array { $sql = "select tablename as Tables_in_test from pg_tables where schemaname ='public'"; - $pdo = $this->query($sql, [], false, true); + $pdo = $this->getPDOStatement($sql); $result = $pdo->fetchAll(PDO::FETCH_ASSOC); $info = []; @@ -98,18 +101,7 @@ class Pgsql extends Connection return $info; } - /** - * SQL性能分析 - * @access protected - * @param string $sql - * @return array - */ - protected function getExplain($sql) - { - return []; - } - - protected function supportSavepoint() + protected function supportSavepoint(): bool { return true; } diff --git a/thinkphp/library/think/db/connector/Sqlite.php b/vendor/topthink/think-orm/src/db/connector/Sqlite.php old mode 100755 new mode 100644 similarity index 70% rename from thinkphp/library/think/db/connector/Sqlite.php rename to vendor/topthink/think-orm/src/db/connector/Sqlite.php index 5b9b3fa64..c664f202d --- a/thinkphp/library/think/db/connector/Sqlite.php +++ b/vendor/topthink/think-orm/src/db/connector/Sqlite.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -12,23 +12,21 @@ namespace think\db\connector; use PDO; -use think\db\Connection; +use think\db\PDOConnection; /** * Sqlite数据库驱动 */ -class Sqlite extends Connection +class Sqlite extends PDOConnection { - protected $builder = '\\think\\db\\builder\\Sqlite'; - /** * 解析pdo连接的dsn信息 * @access protected * @param array $config 连接信息 * @return string */ - protected function parseDsn($config) + protected function parseDsn(array $config): string { $dsn = 'sqlite:' . $config['database']; @@ -41,18 +39,19 @@ class Sqlite extends Connection * @param string $tableName * @return array */ - public function getFields($tableName) + public function getFields(string $tableName): array { - list($tableName) = explode(' ', $tableName); - $sql = 'PRAGMA table_info( ' . $tableName . ' )'; + [$tableName] = explode(' ', $tableName); + $sql = 'PRAGMA table_info( ' . $tableName . ' )'; - $pdo = $this->query($sql, [], false, true); + $pdo = $this->getPDOStatement($sql); $result = $pdo->fetchAll(PDO::FETCH_ASSOC); $info = []; - if ($result) { + if (!empty($result)) { foreach ($result as $key => $val) { - $val = array_change_key_case($val); + $val = array_change_key_case($val); + $info[$val['name']] = [ 'name' => $val['name'], 'type' => $val['type'], @@ -73,13 +72,13 @@ class Sqlite extends Connection * @param string $dbName * @return array */ - public function getTables($dbName = '') + public function getTables(string $dbName = ''): array { $sql = "SELECT name FROM sqlite_master WHERE type='table' " . "UNION ALL SELECT name FROM sqlite_temp_master " . "WHERE type='table' ORDER BY name"; - $pdo = $this->query($sql, [], false, true); + $pdo = $this->getPDOStatement($sql); $result = $pdo->fetchAll(PDO::FETCH_ASSOC); $info = []; @@ -90,18 +89,7 @@ class Sqlite extends Connection return $info; } - /** - * SQL性能分析 - * @access protected - * @param string $sql - * @return array - */ - protected function getExplain($sql) - { - return []; - } - - protected function supportSavepoint() + protected function supportSavepoint(): bool { return true; } diff --git a/vendor/topthink/think-orm/src/db/connector/Sqlsrv.php b/vendor/topthink/think-orm/src/db/connector/Sqlsrv.php new file mode 100644 index 000000000..10d944f37 --- /dev/null +++ b/vendor/topthink/think-orm/src/db/connector/Sqlsrv.php @@ -0,0 +1,122 @@ + +// +---------------------------------------------------------------------- + +namespace think\db\connector; + +use PDO; +use think\db\PDOConnection; + +/** + * Sqlsrv数据库驱动 + */ +class Sqlsrv extends PDOConnection +{ + /** + * 默认PDO连接参数 + * @var array + */ + protected $params = [ + PDO::ATTR_CASE => PDO::CASE_NATURAL, + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL, + PDO::ATTR_STRINGIFY_FETCHES => false, + ]; + + /** + * 解析pdo连接的dsn信息 + * @access protected + * @param array $config 连接信息 + * @return string + */ + protected function parseDsn(array $config): string + { + $dsn = 'sqlsrv:Database=' . $config['database'] . ';Server=' . $config['hostname']; + + if (!empty($config['hostport'])) { + $dsn .= ',' . $config['hostport']; + } + + return $dsn; + } + + /** + * 取得数据表的字段信息 + * @access public + * @param string $tableName + * @return array + */ + public function getFields(string $tableName): array + { + [$tableName] = explode(' ', $tableName); + strpos($tableName,'.') && $tableName = substr($tableName,strpos($tableName,'.') + 1); + $sql = "SELECT column_name, data_type, column_default, is_nullable + FROM information_schema.tables AS t + JOIN information_schema.columns AS c + ON t.table_catalog = c.table_catalog + AND t.table_schema = c.table_schema + AND t.table_name = c.table_name + WHERE t.table_name = '$tableName'"; + + $pdo = $this->getPDOStatement($sql); + $result = $pdo->fetchAll(PDO::FETCH_ASSOC); + $info = []; + + if (!empty($result)) { + foreach ($result as $key => $val) { + $val = array_change_key_case($val); + + $info[$val['column_name']] = [ + 'name' => $val['column_name'], + 'type' => $val['data_type'], + 'notnull' => (bool) ('' === $val['is_nullable']), // not null is empty, null is yes + 'default' => $val['column_default'], + 'primary' => false, + 'autoinc' => false, + ]; + } + } + + $sql = "SELECT column_name FROM information_schema.key_column_usage WHERE table_name='$tableName'"; + $pdo = $this->linkID->query($sql); + $result = $pdo->fetch(PDO::FETCH_ASSOC); + + if ($result) { + $info[$result['column_name']]['primary'] = true; + } + + return $this->fieldCase($info); + } + + /** + * 取得数据表的字段信息 + * @access public + * @param string $dbName + * @return array + */ + public function getTables(string $dbName = ''): array + { + $sql = "SELECT TABLE_NAME + FROM INFORMATION_SCHEMA.TABLES + WHERE TABLE_TYPE = 'BASE TABLE' + "; + + $pdo = $this->getPDOStatement($sql); + $result = $pdo->fetchAll(PDO::FETCH_ASSOC); + $info = []; + + foreach ($result as $key => $val) { + $info[$key] = current($val); + } + + return $info; + } + +} diff --git a/thinkphp/library/think/db/connector/pgsql.sql b/vendor/topthink/think-orm/src/db/connector/pgsql.sql old mode 100755 new mode 100644 similarity index 100% rename from thinkphp/library/think/db/connector/pgsql.sql rename to vendor/topthink/think-orm/src/db/connector/pgsql.sql diff --git a/thinkphp/library/think/db/exception/BindParamException.php b/vendor/topthink/think-orm/src/db/exception/BindParamException.php old mode 100755 new mode 100644 similarity index 83% rename from thinkphp/library/think/db/exception/BindParamException.php rename to vendor/topthink/think-orm/src/db/exception/BindParamException.php index dce0c7bfc..08bb38804 --- a/thinkphp/library/think/db/exception/BindParamException.php +++ b/vendor/topthink/think-orm/src/db/exception/BindParamException.php @@ -2,17 +2,16 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: 麦当苗儿 // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\db\exception; -use think\exception\DbException; - /** * PDO参数绑定异常 */ @@ -28,7 +27,7 @@ class BindParamException extends DbException * @param array $bind * @param int $code */ - public function __construct($message, $config, $sql, $bind, $code = 10502) + public function __construct(string $message, array $config, string $sql, array $bind, int $code = 10502) { $this->setData('Bind Param', $bind); parent::__construct($message, $config, $sql, $code); diff --git a/thinkphp/library/think/db/exception/DataNotFoundException.php b/vendor/topthink/think-orm/src/db/exception/DataNotFoundException.php old mode 100755 new mode 100644 similarity index 86% rename from thinkphp/library/think/db/exception/DataNotFoundException.php rename to vendor/topthink/think-orm/src/db/exception/DataNotFoundException.php index 883e333e3..d10dd4330 --- a/thinkphp/library/think/db/exception/DataNotFoundException.php +++ b/vendor/topthink/think-orm/src/db/exception/DataNotFoundException.php @@ -2,17 +2,16 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: 麦当苗儿 // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\db\exception; -use think\exception\DbException; - class DataNotFoundException extends DbException { protected $table; @@ -24,7 +23,7 @@ class DataNotFoundException extends DbException * @param string $table * @param array $config */ - public function __construct($message, $table = '', array $config = []) + public function __construct(string $message, string $table = '', array $config = []) { $this->message = $message; $this->table = $table; diff --git a/thinkphp/library/think/exception/DbException.php b/vendor/topthink/think-orm/src/db/exception/DbException.php old mode 100755 new mode 100644 similarity index 84% rename from thinkphp/library/think/exception/DbException.php rename to vendor/topthink/think-orm/src/db/exception/DbException.php index 0f504257c..f68b21c02 --- a/thinkphp/library/think/exception/DbException.php +++ b/vendor/topthink/think-orm/src/db/exception/DbException.php @@ -2,14 +2,15 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: 麦当苗儿 // +---------------------------------------------------------------------- +declare (strict_types = 1); -namespace think\exception; +namespace think\db\exception; use think\Exception; @@ -26,7 +27,7 @@ class DbException extends Exception * @param string $sql * @param int $code */ - public function __construct($message, array $config, $sql, $code = 10500) + public function __construct(string $message, array $config = [], string $sql = '', int $code = 10500) { $this->message = $message; $this->code = $code; @@ -40,5 +41,4 @@ class DbException extends Exception unset($config['username'], $config['password']); $this->setData('Database Config', $config); } - } diff --git a/vendor/topthink/think-orm/src/db/exception/InvalidArgumentException.php b/vendor/topthink/think-orm/src/db/exception/InvalidArgumentException.php new file mode 100644 index 000000000..047e45e9b --- /dev/null +++ b/vendor/topthink/think-orm/src/db/exception/InvalidArgumentException.php @@ -0,0 +1,21 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); +namespace think\db\exception; + +use Psr\SimpleCache\InvalidArgumentException as SimpleCacheInvalidArgumentInterface; + +/** + * 非法数据异常 + */ +class InvalidArgumentException extends \InvalidArgumentException implements SimpleCacheInvalidArgumentInterface +{ +} diff --git a/vendor/topthink/think-orm/src/db/exception/ModelEventException.php b/vendor/topthink/think-orm/src/db/exception/ModelEventException.php new file mode 100644 index 000000000..767bc1a9f --- /dev/null +++ b/vendor/topthink/think-orm/src/db/exception/ModelEventException.php @@ -0,0 +1,19 @@ + +// +---------------------------------------------------------------------- + +namespace think\db\exception; + +/** + * 模型事件异常 + */ +class ModelEventException extends DbException +{ +} diff --git a/thinkphp/library/think/db/exception/ModelNotFoundException.php b/vendor/topthink/think-orm/src/db/exception/ModelNotFoundException.php old mode 100755 new mode 100644 similarity index 85% rename from thinkphp/library/think/db/exception/ModelNotFoundException.php rename to vendor/topthink/think-orm/src/db/exception/ModelNotFoundException.php index ae52baf3b..84a152579 --- a/thinkphp/library/think/db/exception/ModelNotFoundException.php +++ b/vendor/topthink/think-orm/src/db/exception/ModelNotFoundException.php @@ -2,17 +2,16 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: 麦当苗儿 // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\db\exception; -use think\exception\DbException; - class ModelNotFoundException extends DbException { protected $model; @@ -24,7 +23,7 @@ class ModelNotFoundException extends DbException * @param string $model * @param array $config */ - public function __construct($message, $model = '', array $config = []) + public function __construct(string $message, string $model = '', array $config = []) { $this->message = $message; $this->model = $model; diff --git a/thinkphp/library/think/exception/PDOException.php b/vendor/topthink/think-orm/src/db/exception/PDOException.php old mode 100755 new mode 100644 similarity index 60% rename from thinkphp/library/think/exception/PDOException.php rename to vendor/topthink/think-orm/src/db/exception/PDOException.php index 25240b680..efe78b961 --- a/thinkphp/library/think/exception/PDOException.php +++ b/vendor/topthink/think-orm/src/db/exception/PDOException.php @@ -2,14 +2,15 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: 麦当苗儿 // +---------------------------------------------------------------------- +declare (strict_types = 1); -namespace think\exception; +namespace think\db\exception; /** * PDO异常处理类 @@ -25,16 +26,19 @@ class PDOException extends DbException * @param string $sql * @param int $code */ - public function __construct(\PDOException $exception, array $config, $sql, $code = 10501) + public function __construct(\PDOException $exception, array $config = [], string $sql = '', int $code = 10501) { - $error = $exception->errorInfo; + $error = $exception->errorInfo; + $message = $exception->getMessage(); - $this->setData('PDO Error Info', [ - 'SQLSTATE' => $error[0], - 'Driver Error Code' => isset($error[1]) ? $error[1] : 0, - 'Driver Error Message' => isset($error[2]) ? $error[2] : '', - ]); + if (!empty($error)) { + $this->setData('PDO Error Info', [ + 'SQLSTATE' => $error[0], + 'Driver Error Code' => isset($error[1]) ? $error[1] : 0, + 'Driver Error Message' => isset($error[2]) ? $error[2] : '', + ]); + } - parent::__construct($exception->getMessage(), $config, $sql, $code); + parent::__construct($message, $config, $sql, $code); } } diff --git a/thinkphp/library/think/facade/Url.php b/vendor/topthink/think-orm/src/facade/Db.php old mode 100755 new mode 100644 similarity index 68% rename from thinkphp/library/think/facade/Url.php rename to vendor/topthink/think-orm/src/facade/Db.php index 639591ac8..b0296c69b --- a/thinkphp/library/think/facade/Url.php +++ b/vendor/topthink/think-orm/src/facade/Db.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -14,12 +14,10 @@ namespace think\facade; use think\Facade; /** - * @see \think\Url - * @mixin \think\Url - * @method string build(string $url = '', mixed $vars = '', mixed $suffix = true, mixed $domain = false) static URL生成 支持路由反射 - * @method void root(string $root) static 指定当前生成URL地址的root + * @see \think\DbManager + * @mixin \think\DbManager */ -class Url extends Facade +class Db extends Facade { /** * 获取当前Facade对应类名(或者已经绑定的容器对象标识) @@ -28,6 +26,6 @@ class Url extends Facade */ protected static function getFacadeClass() { - return 'url'; + return 'think\DbManager'; } } diff --git a/vendor/topthink/think-orm/src/model/Collection.php b/vendor/topthink/think-orm/src/model/Collection.php new file mode 100644 index 000000000..f017e328f --- /dev/null +++ b/vendor/topthink/think-orm/src/model/Collection.php @@ -0,0 +1,265 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\model; + +use think\Collection as BaseCollection; +use think\Model; +use think\Paginator; + +/** + * 模型数据集类 + */ +class Collection extends BaseCollection +{ + /** + * 延迟预载入关联查询 + * @access public + * @param array|string $relation 关联 + * @param mixed $cache 关联缓存 + * @return $this + */ + public function load($relation, $cache = false) + { + if (!$this->isEmpty()) { + $item = current($this->items); + $item->eagerlyResultSet($this->items, (array) $relation, [], false, $cache); + } + + return $this; + } + + /** + * 删除数据集的数据 + * @access public + * @return bool + */ + public function delete(): bool + { + $this->each(function (Model $model) { + $model->delete(); + }); + + return true; + } + + /** + * 更新数据 + * @access public + * @param array $data 数据数组 + * @param array $allowField 允许字段 + * @return bool + */ + public function update(array $data, array $allowField = []): bool + { + $this->each(function (Model $model) use ($data, $allowField) { + if (!empty($allowField)) { + $model->allowField($allowField); + } + + $model->save($data); + }); + + return true; + } + + /** + * 设置需要隐藏的输出属性 + * @access public + * @param array $hidden 属性列表 + * @return $this + */ + public function hidden(array $hidden) + { + $this->each(function (Model $model) use ($hidden) { + $model->hidden($hidden); + }); + + return $this; + } + + /** + * 设置需要输出的属性 + * @access public + * @param array $visible + * @return $this + */ + public function visible(array $visible) + { + $this->each(function (Model $model) use ($visible) { + $model->visible($visible); + }); + + return $this; + } + + /** + * 设置需要追加的输出属性 + * @access public + * @param array $append 属性列表 + * @return $this + */ + public function append(array $append) + { + $this->each(function (Model $model) use ($append) { + $model->append($append); + }); + + return $this; + } + + /** + * 设置模型输出场景 + * @access public + * @param string $scene 场景名称 + * @return $this + */ + public function scene(string $scene) + { + $this->each(function (Model $model) use ($scene) { + $model->scene($scene); + }); + + return $this; + } + + /** + * 设置父模型 + * @access public + * @param Model $parent 父模型 + * @return $this + */ + public function setParent(Model $parent) + { + $this->each(function (Model $model) use ($parent) { + $model->setParent($parent); + }); + + return $this; + } + + /** + * 设置数据字段获取器 + * @access public + * @param string|array $name 字段名 + * @param callable $callback 闭包获取器 + * @return $this + */ + public function withAttr($name, $callback = null) + { + $this->each(function (Model $model) use ($name, $callback) { + $model->withAttribute($name, $callback); + }); + + return $this; + } + + /** + * 绑定(一对一)关联属性到当前模型 + * @access protected + * @param string $relation 关联名称 + * @param array $attrs 绑定属性 + * @return $this + * @throws Exception + */ + public function bindAttr(string $relation, array $attrs = []) + { + $this->each(function (Model $model) use ($relation, $attrs) { + $model->bindAttr($relation, $attrs); + }); + + return $this; + } + + /** + * 按指定键整理数据 + * + * @access public + * @param mixed $items 数据 + * @param string $indexKey 键名 + * @return array + */ + public function dictionary($items = null, string &$indexKey = null) + { + if ($items instanceof self || $items instanceof Paginator) { + $items = $items->all(); + } + + $items = is_null($items) ? $this->items : $items; + + if ($items && empty($indexKey)) { + $indexKey = $items[0]->getPk(); + } + + if (isset($indexKey) && is_string($indexKey)) { + return array_column($items, null, $indexKey); + } + + return $items; + } + + /** + * 比较数据集,返回差集 + * + * @access public + * @param mixed $items 数据 + * @param string $indexKey 指定比较的键名 + * @return static + */ + public function diff($items, string $indexKey = null) + { + if ($this->isEmpty()) { + return new static($items); + } + + $diff = []; + $dictionary = $this->dictionary($items, $indexKey); + + if (is_string($indexKey)) { + foreach ($this->items as $item) { + if (!isset($dictionary[$item[$indexKey]])) { + $diff[] = $item; + } + } + } + + return new static($diff); + } + + /** + * 比较数据集,返回交集 + * + * @access public + * @param mixed $items 数据 + * @param string $indexKey 指定比较的键名 + * @return static + */ + public function intersect($items, string $indexKey = null) + { + if ($this->isEmpty()) { + return new static([]); + } + + $intersect = []; + $dictionary = $this->dictionary($items, $indexKey); + + if (is_string($indexKey)) { + foreach ($this->items as $item) { + if (isset($dictionary[$item[$indexKey]])) { + $intersect[] = $item; + } + } + } + + return new static($intersect); + } +} diff --git a/thinkphp/library/think/model/Pivot.php b/vendor/topthink/think-orm/src/model/Pivot.php old mode 100755 new mode 100644 similarity index 65% rename from thinkphp/library/think/model/Pivot.php rename to vendor/topthink/think-orm/src/model/Pivot.php index a3a395e3f..893c01b7e --- a/thinkphp/library/think/model/Pivot.php +++ b/vendor/topthink/think-orm/src/model/Pivot.php @@ -2,33 +2,44 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\model; use think\Model; +/** + * 多对多中间表模型类 + */ class Pivot extends Model { - /** @var Model */ + /** + * 父模型 + * @var Model + */ public $parent; + /** + * 是否时间自动写入 + * @var bool + */ protected $autoWriteTimestamp = false; /** * 架构函数 * @access public - * @param array|object $data 数据 - * @param Model $parent 上级模型 - * @param string $table 中间数据表名 + * @param array $data 数据 + * @param Model $parent 上级模型 + * @param string $table 中间数据表名 */ - public function __construct($data = [], Model $parent = null, $table = '') + public function __construct(array $data = [], Model $parent = null, string $table = '') { $this->parent = $parent; diff --git a/vendor/topthink/think-orm/src/model/Relation.php b/vendor/topthink/think-orm/src/model/Relation.php new file mode 100644 index 000000000..e823bd90b --- /dev/null +++ b/vendor/topthink/think-orm/src/model/Relation.php @@ -0,0 +1,278 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\model; + +use Closure; +use ReflectionFunction; +use think\db\BaseQuery as Query; +use think\db\exception\DbException as Exception; +use think\Model; + +/** + * 模型关联基础类 + * @package think\model + * @mixin Query + */ +abstract class Relation +{ + /** + * 父模型对象 + * @var Model + */ + protected $parent; + + /** + * 当前关联的模型类名 + * @var string + */ + protected $model; + + /** + * 关联模型查询对象 + * @var Query + */ + protected $query; + + /** + * 关联表外键 + * @var string + */ + protected $foreignKey; + + /** + * 关联表主键 + * @var string + */ + protected $localKey; + + /** + * 是否执行关联基础查询 + * @var bool + */ + protected $baseQuery; + + /** + * 是否为自关联 + * @var bool + */ + protected $selfRelation = false; + + /** + * 关联数据数量限制 + * @var int + */ + protected $withLimit; + + /** + * 关联数据字段限制 + * @var array + */ + protected $withField; + + /** + * 获取关联的所属模型 + * @access public + * @return Model + */ + public function getParent(): Model + { + return $this->parent; + } + + /** + * 获取当前的关联模型类的Query实例 + * @access public + * @return Query + */ + public function getQuery() + { + return $this->query; + } + + /** + * 获取关联表外键 + * @access public + * @return string + */ + public function getForeignKey() + { + return $this->foreignKey; + } + + /** + * 获取关联表主键 + * @access public + * @return string + */ + public function getLocalKey() + { + return $this->localKey; + } + + /** + * 获取当前的关联模型类的实例 + * @access public + * @return Model + */ + public function getModel(): Model + { + return $this->query->getModel(); + } + + /** + * 当前关联是否为自关联 + * @access public + * @return bool + */ + public function isSelfRelation(): bool + { + return $this->selfRelation; + } + + /** + * 封装关联数据集 + * @access public + * @param array $resultSet 数据集 + * @param Model $parent 父模型 + * @return mixed + */ + protected function resultSetBuild(array $resultSet, Model $parent = null) + { + return (new $this->model)->toCollection($resultSet)->setParent($parent); + } + + protected function getQueryFields(string $model) + { + $fields = $this->query->getOptions('field'); + return $this->getRelationQueryFields($fields, $model); + } + + protected function getRelationQueryFields($fields, string $model) + { + if (empty($fields) || '*' == $fields) { + return $model . '.*'; + } + + if (is_string($fields)) { + $fields = explode(',', $fields); + } + + foreach ($fields as &$field) { + if (false === strpos($field, '.')) { + $field = $model . '.' . $field; + } + } + + return $fields; + } + + protected function getQueryWhere(array &$where, string $relation): void + { + foreach ($where as $key => &$val) { + if (is_string($key)) { + $where[] = [false === strpos($key, '.') ? $relation . '.' . $key : $key, '=', $val]; + unset($where[$key]); + } elseif (isset($val[0]) && false === strpos($val[0], '.')) { + $val[0] = $relation . '.' . $val[0]; + } + } + } + + /** + * 更新数据 + * @access public + * @param array $data 更新数据 + * @return integer + */ + public function update(array $data = []): int + { + return $this->query->update($data); + } + + /** + * 删除记录 + * @access public + * @param mixed $data 表达式 true 表示强制删除 + * @return int + * @throws Exception + * @throws PDOException + */ + public function delete($data = null): int + { + return $this->query->delete($data); + } + + /** + * 限制关联数据的数量 + * @access public + * @param int $limit 关联数量限制 + * @return $this + */ + public function withLimit(int $limit) + { + $this->withLimit = $limit; + return $this; + } + + /** + * 限制关联数据的字段 + * @access public + * @param array $field 关联字段限制 + * @return $this + */ + public function withField(array $field) + { + $this->withField = $field; + return $this; + } + + /** + * 判断闭包的参数类型 + * @access protected + * @return mixed + */ + protected function getClosureType(Closure $closure) + { + $reflect = new ReflectionFunction($closure); + $params = $reflect->getParameters(); + + if (!empty($params)) { + $type = $params[0]->getType(); + return is_null($type) || Relation::class == $type->getName() ? $this : $this->query; + } + + return $this; + } + + /** + * 执行基础查询(仅执行一次) + * @access protected + * @return void + */ + protected function baseQuery(): void + {} + + public function __call($method, $args) + { + if ($this->query) { + // 执行基础查询 + $this->baseQuery(); + + $result = call_user_func_array([$this->query, $method], $args); + + return $result === $this->query ? $this : $result; + } + + throw new Exception('method not exists:' . __CLASS__ . '->' . $method); + } +} diff --git a/thinkphp/library/think/model/concern/Attribute.php b/vendor/topthink/think-orm/src/model/concern/Attribute.php old mode 100755 new mode 100644 similarity index 53% rename from thinkphp/library/think/model/concern/Attribute.php rename to vendor/topthink/think-orm/src/model/concern/Attribute.php index b7a80fd3b..8f6f918de --- a/thinkphp/library/think/model/concern/Attribute.php +++ b/vendor/topthink/think-orm/src/model/concern/Attribute.php @@ -2,20 +2,24 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\model\concern; use InvalidArgumentException; -use think\Exception; -use think\Loader; +use think\db\Raw; +use think\helper\Str; use think\model\Relation; +/** + * 模型数据处理 + */ trait Attribute { /** @@ -28,25 +32,19 @@ trait Attribute * 数据表字段信息 留空则自动获取 * @var array */ + protected $schema = []; + + /** + * 当前允许写入的字段 + * @var array + */ protected $field = []; /** - * JSON数据表字段 + * 字段自动类型转换 * @var array */ - protected $json = []; - - /** - * JSON数据取出是否需要转换为数组 - * @var bool - */ - protected $jsonAssoc = false; - - /** - * JSON数据表字段类型 - * @var array - */ - protected $jsonType = []; + protected $type = []; /** * 数据表废弃字段 @@ -60,30 +58,48 @@ trait Attribute */ protected $readonly = []; - /** - * 数据表字段类型 - * @var array - */ - protected $type = []; - /** * 当前模型数据 * @var array */ private $data = []; - /** - * 修改器执行记录 - * @var array - */ - private $set = []; - /** * 原始数据 * @var array */ private $origin = []; + /** + * JSON数据表字段 + * @var array + */ + protected $json = []; + + /** + * JSON数据表字段类型 + * @var array + */ + protected $jsonType = []; + + /** + * JSON数据取出是否需要转换为数组 + * @var bool + */ + protected $jsonAssoc = false; + + /** + * 是否严格字段大小写 + * @var bool + */ + protected $strict = true; + + /** + * 获取器数据 + * @var array + */ + private $get = []; + /** * 动态获取器 * @var array @@ -106,9 +122,10 @@ trait Attribute * @param string $key 名称 * @return bool */ - protected function isPk($key) + protected function isPk(string $key): bool { $pk = $this->getPk(); + if (is_string($pk) && $pk == $key) { return true; } elseif (is_array($pk) && in_array($key, $pk)) { @@ -121,11 +138,12 @@ trait Attribute /** * 获取模型对象的主键值 * @access public - * @return integer + * @return mixed */ public function getKey() { $pk = $this->getPk(); + if (is_string($pk) && array_key_exists($pk, $this->data)) { return $this->data[$pk]; } @@ -136,15 +154,11 @@ trait Attribute /** * 设置允许写入的字段 * @access public - * @param array|string|true $field 允许写入的字段 如果为true只允许写入数据表字段 + * @param array $field 允许写入的字段 * @return $this */ - public function allowField($field) + public function allowField(array $field) { - if (is_string($field)) { - $field = explode(',', $field); - } - $this->field = $field; return $this; @@ -153,61 +167,64 @@ trait Attribute /** * 设置只读字段 * @access public - * @param array|string $field 只读字段 + * @param array $field 只读字段 * @return $this */ - public function readonly($field) + public function readOnly(array $field) { - if (is_string($field)) { - $field = explode(',', $field); - } - $this->readonly = $field; return $this; } /** - * 设置数据对象值 - * @access public - * @param mixed $data 数据或者属性名 - * @param mixed $value 值 - * @return $this + * 获取实际的字段名 + * @access protected + * @param string $name 字段名 + * @return string */ - public function data($data, $value = null) + protected function getRealFieldName(string $name): string { - if (is_string($data)) { - $this->data[$data] = $value; - return $this; + if ($this->convertNameToCamel || !$this->strict) { + return Str::snake($name); } + return $name; + } + + /** + * 设置数据对象值 + * @access public + * @param array $data 数据 + * @param bool $set 是否调用修改器 + * @param array $allow 允许的字段名 + * @return $this + */ + public function data(array $data, bool $set = false, array $allow = []) + { // 清空数据 $this->data = []; - if (is_object($data)) { - $data = get_object_vars($data); - } - - if ($this->disuse) { - // 废弃字段 - foreach ((array) $this->disuse as $key) { - if (array_key_exists($key, $data)) { - unset($data[$key]); - } + // 废弃字段 + foreach ($this->disuse as $key) { + if (array_key_exists($key, $data)) { + unset($data[$key]); } } - if (true === $value) { - // 数据对象赋值 - foreach ($data as $key => $value) { - $this->setAttr($key, $value, $data); - } - } elseif (is_array($value)) { - foreach ($value as $name) { + if (!empty($allow)) { + $result = []; + foreach ($allow as $name) { if (isset($data[$name])) { - $this->data[$name] = $data[$name]; + $result[$name] = $data[$name]; } } + $data = $result; + } + + if ($set) { + // 数据对象赋值 + $this->setAttrs($data); } else { $this->data = $data; } @@ -216,24 +233,17 @@ trait Attribute } /** - * 批量设置数据对象值 + * 批量追加数据对象值 * @access public - * @param mixed $data 数据 + * @param array $data 数据 * @param bool $set 是否需要进行数据处理 * @return $this */ - public function appendData($data, $set = false) + public function appendData(array $data, bool $set = false) { if ($set) { - // 进行数据处理 - foreach ($data as $key => $value) { - $this->setAttr($key, $value, $data); - } + $this->setAttrs($data); } else { - if (is_object($data)) { - $data = get_object_vars($data); - } - $this->data = array_merge($this->data, $data); } @@ -246,30 +256,38 @@ trait Attribute * @param string $name 字段名 留空获取全部 * @return mixed */ - public function getOrigin($name = null) + public function getOrigin(string $name = null) { if (is_null($name)) { return $this->origin; } - return array_key_exists($name, $this->origin) ? $this->origin[$name] : null; + + $fieldName = $this->getRealFieldName($name); + + return array_key_exists($fieldName, $this->origin) ? $this->origin[$fieldName] : null; } /** - * 获取对象原始数据 如果不存在指定字段返回false + * 获取当前对象数据 如果不存在指定字段返回false * @access public * @param string $name 字段名 留空获取全部 * @return mixed * @throws InvalidArgumentException */ - public function getData($name = null) + public function getData(string $name = null) { if (is_null($name)) { return $this->data; - } elseif (array_key_exists($name, $this->data)) { - return $this->data[$name]; - } elseif (array_key_exists($name, $this->relation)) { - return $this->relation[$name]; } + + $fieldName = $this->getRealFieldName($name); + + if (array_key_exists($fieldName, $this->data)) { + return $this->data[$fieldName]; + } elseif (array_key_exists($fieldName, $this->relation)) { + return $this->relation[$fieldName]; + } + throw new InvalidArgumentException('property not exists:' . static::class . '->' . $name); } @@ -278,26 +296,20 @@ trait Attribute * @access public * @return array */ - public function getChangedData() + public function getChangedData(): array { - if ($this->force) { - $data = $this->data; - } else { - $data = array_udiff_assoc($this->data, $this->origin, function ($a, $b) { - if ((empty($a) || empty($b)) && $a !== $b) { - return 1; - } + $data = $this->force ? $this->data : array_udiff_assoc($this->data, $this->origin, function ($a, $b) { + if ((empty($a) || empty($b)) && $a !== $b) { + return 1; + } - return is_object($a) || $a != $b ? 1 : 0; - }); - } + return is_object($a) || $a != $b ? 1 : 0; + }); - if (!empty($this->readonly)) { - // 只读字段不允许更新 - foreach ($this->readonly as $key => $field) { - if (isset($data[$field])) { - unset($data[$field]); - } + // 只读字段不允许更新 + foreach ($this->readonly as $key => $field) { + if (array_key_exists($field, $data)) { + unset($data[$field]); } } @@ -305,93 +317,65 @@ trait Attribute } /** - * 修改器 设置数据对象值 + * 直接设置数据对象值 + * @access public + * @param string $name 属性名 + * @param mixed $value 值 + * @return void + */ + public function set(string $name, $value): void + { + $name = $this->getRealFieldName($name); + + $this->data[$name] = $value; + unset($this->get[$name]); + } + + /** + * 通过修改器 批量设置数据对象值 + * @access public + * @param array $data 数据 + * @return void + */ + public function setAttrs(array $data): void + { + // 进行数据处理 + foreach ($data as $key => $value) { + $this->setAttr($key, $value, $data); + } + } + + /** + * 通过修改器 设置数据对象值 * @access public * @param string $name 属性名 * @param mixed $value 属性值 * @param array $data 数据 * @return void */ - public function setAttr($name, $value, $data = []) + public function setAttr(string $name, $value, array $data = []): void { - if (isset($this->set[$name])) { - return; - } + $name = $this->getRealFieldName($name); - if (is_null($value) && $this->autoWriteTimestamp && in_array($name, [$this->createTime, $this->updateTime])) { - // 自动写入的时间戳字段 - $value = $this->autoWriteTimestamp($name); - } else { - // 检测修改器 - $method = 'set' . Loader::parseName($name, 1) . 'Attr'; + // 检测修改器 + $method = 'set' . Str::studly($name) . 'Attr'; - if (method_exists($this, $method)) { - $value = $this->$method($value, array_merge($this->data, $data)); + if (method_exists($this, $method)) { + $array = $this->data; - $this->set[$name] = true; - } elseif (isset($this->type[$name])) { - // 类型转换 - $value = $this->writeTransform($value, $this->type[$name]); + $value = $this->$method($value, array_merge($this->data, $data)); + + if (is_null($value) && $array !== $this->data) { + return; } + } elseif (isset($this->type[$name])) { + // 类型转换 + $value = $this->writeTransform($value, $this->type[$name]); } // 设置数据对象属性 $this->data[$name] = $value; - } - - /** - * 是否需要自动写入时间字段 - * @access public - * @param bool $auto - * @return $this - */ - public function isAutoWriteTimestamp($auto) - { - $this->autoWriteTimestamp = $auto; - - return $this; - } - - /** - * 自动写入时间戳 - * @access protected - * @param string $name 时间戳字段 - * @return mixed - */ - protected function autoWriteTimestamp($name) - { - if (isset($this->type[$name])) { - $type = $this->type[$name]; - - if (strpos($type, ':')) { - list($type, $param) = explode(':', $type, 2); - } - - switch ($type) { - case 'datetime': - case 'date': - $format = !empty($param) ? $param : $this->dateFormat; - $format .= strpos($format, 'u') || false !== strpos($format, '\\') ? '' : '.u'; - $value = $this->formatDateTime($format); - break; - case 'timestamp': - case 'integer': - default: - $value = time(); - break; - } - } elseif (is_string($this->autoWriteTimestamp) && in_array(strtolower($this->autoWriteTimestamp), [ - 'datetime', - 'date', - 'timestamp', - ])) { - $format = strpos($this->dateFormat, 'u') || false !== strpos($this->dateFormat, '\\') ? '' : '.u'; - $value = $this->formatDateTime($this->dateFormat . $format); - } else { - $value = time(); - } - - return $value; + unset($this->get[$name]); } /** @@ -407,10 +391,14 @@ trait Attribute return; } + if ($value instanceof Raw) { + return $value; + } + if (is_array($type)) { - list($type, $param) = $type; + [$type, $param] = $type; } elseif (strpos($type, ':')) { - list($type, $param) = explode(':', $type, 2); + [$type, $param] = explode(':', $type, 2); } switch ($type) { @@ -421,7 +409,7 @@ trait Attribute if (empty($param)) { $value = (float) $value; } else { - $value = (float) number_format($value, $param, '.', ''); + $value = (float) number_format($value, (int) $param, '.', ''); } break; case 'boolean': @@ -433,9 +421,8 @@ trait Attribute } break; case 'datetime': - $format = !empty($param) ? $param : $this->dateFormat; - $value = is_numeric($value) ? $value : strtotime($value); - $value = $this->formatDateTime($format, $value); + $value = is_numeric($value) ? $value : strtotime($value); + $value = $this->formatDateTime('Y-m-d H:i:s.u', $value, true); break; case 'object': if (is_object($value)) { @@ -451,6 +438,11 @@ trait Attribute case 'serialize': $value = serialize($value); break; + default: + if (is_object($value) && false !== strpos($type, '\\') && method_exists($value, '__toString')) { + // 对象类型 + $value = $value->__toString(); + } } return $value; @@ -460,54 +452,89 @@ trait Attribute * 获取器 获取数据对象的值 * @access public * @param string $name 名称 - * @param array $item 数据 * @return mixed * @throws InvalidArgumentException */ - public function getAttr($name, &$item = null) + public function getAttr(string $name) { try { - $notFound = false; + $relation = false; $value = $this->getData($name); } catch (InvalidArgumentException $e) { - $notFound = true; + $relation = $this->isRelationAttr($name); $value = null; } - // 检测属性获取器 - $fieldName = Loader::parseName($name); - $method = 'get' . Loader::parseName($name, 1) . 'Attr'; + return $this->getValue($name, $value, $relation); + } + /** + * 获取经过获取器处理后的数据对象的值 + * @access protected + * @param string $name 字段名称 + * @param mixed $value 字段值 + * @param bool|string $relation 是否为关联属性或者关联名 + * @return mixed + * @throws InvalidArgumentException + */ + protected function getValue(string $name, $value, $relation = false) + { + // 检测属性获取器 + $fieldName = $this->getRealFieldName($name); + + if (array_key_exists($fieldName, $this->get)) { + return $this->get[$fieldName]; + } + + $method = 'get' . Str::studly($name) . 'Attr'; if (isset($this->withAttr[$fieldName])) { - if ($notFound && $relation = $this->isRelationAttr($name)) { - $modelRelation = $this->$relation(); - $value = $this->getRelationData($modelRelation); + if ($relation) { + $value = $this->getRelationValue($relation); } - $closure = $this->withAttr[$fieldName]; - $value = $closure($value, $this->data); + if (in_array($fieldName, $this->json) && is_array($this->withAttr[$fieldName])) { + $value = $this->getJsonValue($fieldName, $value); + } else { + $closure = $this->withAttr[$fieldName]; + $value = $closure($value, $this->data); + } } elseif (method_exists($this, $method)) { - if ($notFound && $relation = $this->isRelationAttr($name)) { - $modelRelation = $this->$relation(); - $value = $this->getRelationData($modelRelation); + if ($relation) { + $value = $this->getRelationValue($relation); } $value = $this->$method($value, $this->data); - } elseif (isset($this->type[$name])) { + } elseif (isset($this->type[$fieldName])) { // 类型转换 - $value = $this->readTransform($value, $this->type[$name]); - } elseif ($this->autoWriteTimestamp && in_array($name, [$this->createTime, $this->updateTime])) { - if (is_string($this->autoWriteTimestamp) && in_array(strtolower($this->autoWriteTimestamp), [ - 'datetime', - 'date', - 'timestamp', - ])) { - $value = $this->formatDateTime($this->dateFormat, $value); + $value = $this->readTransform($value, $this->type[$fieldName]); + } elseif ($this->autoWriteTimestamp && in_array($fieldName, [$this->createTime, $this->updateTime])) { + $value = $this->getTimestampValue($value); + } elseif ($relation) { + $value = $this->getRelationValue($relation); + // 保存关联对象值 + $this->relation[$name] = $value; + } + + $this->get[$fieldName] = $value; + + return $value; + } + + /** + * 获取JSON字段属性值 + * @access protected + * @param string $name 属性名 + * @param mixed $value JSON数据 + * @return mixed + */ + protected function getJsonValue($name, $value) + { + foreach ($this->withAttr[$name] as $key => $closure) { + if ($this->jsonAssoc) { + $value[$key] = $closure($value[$key], $value); } else { - $value = $this->formatDateTime($this->dateFormat, $value, true); + $value->$key = $closure($value->$key, $value); } - } elseif ($notFound) { - $value = $this->getRelationAttribute($name, $item); } return $value; @@ -516,42 +543,14 @@ trait Attribute /** * 获取关联属性值 * @access protected - * @param string $name 属性名 - * @param array $item 数据 + * @param string $relation 关联名 * @return mixed */ - protected function getRelationAttribute($name, &$item) + protected function getRelationValue(string $relation) { - $relation = $this->isRelationAttr($name); + $modelRelation = $this->$relation(); - if ($relation) { - $modelRelation = $this->$relation(); - if ($modelRelation instanceof Relation) { - $value = $this->getRelationData($modelRelation); - - if ($item && method_exists($modelRelation, 'getBindAttr') && $bindAttr = $modelRelation->getBindAttr()) { - - foreach ($bindAttr as $key => $attr) { - $key = is_numeric($key) ? $attr : $key; - - if (isset($item[$key])) { - throw new Exception('bind attr has exists:' . $key); - } else { - $item[$key] = $value ? $value->getAttr($attr) : null; - } - } - - return false; - } - - // 保存关联对象值 - $this->relation[$name] = $value; - - return $value; - } - } - - throw new InvalidArgumentException('property not exists:' . static::class . '->' . $name); + return $modelRelation instanceof Relation ? $this->getRelationData($modelRelation) : null; } /** @@ -568,9 +567,9 @@ trait Attribute } if (is_array($type)) { - list($type, $param) = $type; + [$type, $param] = $type; } elseif (strpos($type, ':')) { - list($type, $param) = explode(':', $type, 2); + [$type, $param] = explode(':', $type, 2); } switch ($type) { @@ -581,7 +580,7 @@ trait Attribute if (empty($param)) { $value = (float) $value; } else { - $value = (float) number_format($value, $param, '.', ''); + $value = (float) number_format($value, (int) $param, '.', ''); } break; case 'boolean': @@ -632,20 +631,25 @@ trait Attribute * @param callable $callback 闭包获取器 * @return $this */ - public function withAttribute($name, $callback = null) + public function withAttribute($name, callable $callback = null) { if (is_array($name)) { foreach ($name as $key => $val) { - $key = Loader::parseName($key); - - $this->withAttr[$key] = $val; + $this->withAttribute($key, $val); } } else { - $name = Loader::parseName($name); + $name = $this->getRealFieldName($name); - $this->withAttr[$name] = $callback; + if (strpos($name, '.')) { + [$name, $key] = explode('.', $name); + + $this->withAttr[$name][$key] = $callback; + } else { + $this->withAttr[$name] = $callback; + } } return $this; } + } diff --git a/vendor/topthink/think-orm/src/model/concern/Conversion.php b/vendor/topthink/think-orm/src/model/concern/Conversion.php new file mode 100644 index 000000000..35d96d050 --- /dev/null +++ b/vendor/topthink/think-orm/src/model/concern/Conversion.php @@ -0,0 +1,358 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\model\concern; + +use think\Collection; +use think\db\exception\DbException as Exception; +use think\helper\Str; +use think\Model; +use think\model\Collection as ModelCollection; +use think\model\relation\OneToOne; + +/** + * 模型数据转换处理 + */ +trait Conversion +{ + /** + * 数据输出显示的属性 + * @var array + */ + protected $visible = []; + + /** + * 数据输出隐藏的属性 + * @var array + */ + protected $hidden = []; + + /** + * 数据输出需要追加的属性 + * @var array + */ + protected $append = []; + + /** + * 场景 + * @var array + */ + protected $scene = []; + + /** + * 数据输出字段映射 + * @var array + */ + protected $mapping = []; + + /** + * 数据集对象名 + * @var string + */ + protected $resultSetType; + + /** + * 数据命名是否自动转为驼峰 + * @var bool + */ + protected $convertNameToCamel; + + /** + * 转换数据为驼峰命名(用于输出) + * @access public + * @param bool $toCamel 是否自动驼峰命名 + * @return $this + */ + public function convertNameToCamel(bool $toCamel = true) + { + $this->convertNameToCamel = $toCamel; + return $this; + } + + /** + * 设置需要附加的输出属性 + * @access public + * @param array $append 属性列表 + * @return $this + */ + public function append(array $append = []) + { + $this->append = $append; + + return $this; + } + + /** + * 设置输出层场景 + * @access public + * @param string $scene 场景名称 + * @return $this + */ + public function scene(string $scene) + { + if (isset($this->scene[$scene])) { + $data = $this->scene[$scene]; + foreach (['append', 'hidden', 'visible'] as $name) { + if (isset($data[$name])) { + $this->$name($data[$name]); + } + } + } + + return $this; + } + + /** + * 设置附加关联对象的属性 + * @access public + * @param string $attr 关联属性 + * @param string|array $append 追加属性名 + * @return $this + * @throws Exception + */ + public function appendRelationAttr(string $attr, array $append) + { + $relation = Str::camel($attr); + + if (isset($this->relation[$relation])) { + $model = $this->relation[$relation]; + } else { + $model = $this->getRelationData($this->$relation()); + } + + if ($model instanceof Model) { + foreach ($append as $key => $attr) { + $key = is_numeric($key) ? $attr : $key; + if (isset($this->data[$key])) { + throw new Exception('bind attr has exists:' . $key); + } + + $this->data[$key] = $model->$attr; + } + } + + return $this; + } + + /** + * 设置需要隐藏的输出属性 + * @access public + * @param array $hidden 属性列表 + * @return $this + */ + public function hidden(array $hidden = []) + { + $this->hidden = $hidden; + + return $this; + } + + /** + * 设置需要输出的属性 + * @access public + * @param array $visible + * @return $this + */ + public function visible(array $visible = []) + { + $this->visible = $visible; + + return $this; + } + + /** + * 设置属性的映射输出 + * @access public + * @param array $map + * @return $this + */ + public function mapping(array $map) + { + $this->mapping = $map; + + return $this; + } + + /** + * 转换当前模型对象为数组 + * @access public + * @return array + */ + public function toArray(): array + { + $item = []; + $hasVisible = false; + + foreach ($this->visible as $key => $val) { + if (is_string($val)) { + if (strpos($val, '.')) { + [$relation, $name] = explode('.', $val); + $this->visible[$relation][] = $name; + } else { + $this->visible[$val] = true; + $hasVisible = true; + } + unset($this->visible[$key]); + } + } + + foreach ($this->hidden as $key => $val) { + if (is_string($val)) { + if (strpos($val, '.')) { + [$relation, $name] = explode('.', $val); + $this->hidden[$relation][] = $name; + } else { + $this->hidden[$val] = true; + } + unset($this->hidden[$key]); + } + } + + // 合并关联数据 + $data = array_merge($this->data, $this->relation); + + foreach ($data as $key => $val) { + if ($val instanceof Model || $val instanceof ModelCollection) { + // 关联模型对象 + if (isset($this->visible[$key]) && is_array($this->visible[$key])) { + $val->visible($this->visible[$key]); + } elseif (isset($this->hidden[$key]) && is_array($this->hidden[$key])) { + $val->hidden($this->hidden[$key]); + } + // 关联模型对象 + if (!isset($this->hidden[$key]) || true !== $this->hidden[$key]) { + $item[$key] = $val->toArray(); + } + } elseif (isset($this->visible[$key])) { + $item[$key] = $this->getAttr($key); + } elseif (!isset($this->hidden[$key]) && !$hasVisible) { + $item[$key] = $this->getAttr($key); + } + + if (isset($this->mapping[$key])) { + // 检查字段映射 + $mapName = $this->mapping[$key]; + $item[$mapName] = $item[$key]; + unset($item[$key]); + } + } + + // 追加属性(必须定义获取器) + foreach ($this->append as $key => $name) { + $this->appendAttrToArray($item, $key, $name); + } + + if ($this->convertNameToCamel) { + foreach ($item as $key => $val) { + $name = Str::camel($key); + if ($name !== $key) { + $item[$name] = $val; + unset($item[$key]); + } + } + } + + return $item; + } + + protected function appendAttrToArray(array &$item, $key, $name) + { + if (is_array($name)) { + // 追加关联对象属性 + $relation = $this->getRelation($key, true); + $item[$key] = $relation ? $relation->append($name) + ->toArray() : []; + } elseif (strpos($name, '.')) { + [$key, $attr] = explode('.', $name); + // 追加关联对象属性 + $relation = $this->getRelation($key, true); + $item[$key] = $relation ? $relation->append([$attr]) + ->toArray() : []; + } else { + $value = $this->getAttr($name); + $item[$name] = $value; + + $this->getBindAttrValue($name, $value, $item); + } + } + + protected function getBindAttrValue(string $name, $value, array &$item = []) + { + $relation = $this->isRelationAttr($name); + if (!$relation) { + return false; + } + + $modelRelation = $this->$relation(); + + if ($modelRelation instanceof OneToOne) { + $bindAttr = $modelRelation->getBindAttr(); + + if (!empty($bindAttr)) { + unset($item[$name]); + } + + foreach ($bindAttr as $key => $attr) { + $key = is_numeric($key) ? $attr : $key; + + if (isset($item[$key])) { + throw new Exception('bind attr has exists:' . $key); + } + + $item[$key] = $value ? $value->getAttr($attr) : null; + } + } + } + + /** + * 转换当前模型对象为JSON字符串 + * @access public + * @param integer $options json参数 + * @return string + */ + public function toJson(int $options = JSON_UNESCAPED_UNICODE): string + { + return json_encode($this->toArray(), $options); + } + + public function __toString() + { + return $this->toJson(); + } + + // JsonSerializable + public function jsonSerialize() + { + return $this->toArray(); + } + + /** + * 转换数据集为数据集对象 + * @access public + * @param array|Collection $collection 数据集 + * @param string $resultSetType 数据集类 + * @return Collection + */ + public function toCollection(iterable $collection = [], string $resultSetType = null): Collection + { + $resultSetType = $resultSetType ?: $this->resultSetType; + + if ($resultSetType && false !== strpos($resultSetType, '\\')) { + $collection = new $resultSetType($collection); + } else { + $collection = new ModelCollection($collection); + } + + return $collection; + } + +} diff --git a/vendor/topthink/think-orm/src/model/concern/ModelEvent.php b/vendor/topthink/think-orm/src/model/concern/ModelEvent.php new file mode 100644 index 000000000..f560379eb --- /dev/null +++ b/vendor/topthink/think-orm/src/model/concern/ModelEvent.php @@ -0,0 +1,88 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\model\concern; + +use think\db\exception\ModelEventException; +use think\helper\Str; + +/** + * 模型事件处理 + */ +trait ModelEvent +{ + + /** + * Event对象 + * @var object + */ + protected static $event; + + /** + * 是否需要事件响应 + * @var bool + */ + protected $withEvent = true; + + /** + * 设置Event对象 + * @access public + * @param object $event Event对象 + * @return void + */ + public static function setEvent($event) + { + self::$event = $event; + } + + /** + * 当前操作的事件响应 + * @access protected + * @param bool $event 是否需要事件响应 + * @return $this + */ + public function withEvent(bool $event) + { + $this->withEvent = $event; + return $this; + } + + /** + * 触发事件 + * @access protected + * @param string $event 事件名 + * @return bool + */ + protected function trigger(string $event): bool + { + if (!$this->withEvent) { + return true; + } + + $call = 'on' . Str::studly($event); + + try { + if (method_exists(static::class, $call)) { + $result = call_user_func([static::class, $call], $this); + } elseif (is_object(self::$event) && method_exists(self::$event, 'trigger')) { + $result = self::$event->trigger(static::class . '.' . $event, $this); + $result = empty($result) ? true : end($result); + } else { + $result = true; + } + + return false === $result ? false : true; + } catch (ModelEventException $e) { + return false; + } + } +} diff --git a/vendor/topthink/think-orm/src/model/concern/OptimLock.php b/vendor/topthink/think-orm/src/model/concern/OptimLock.php new file mode 100644 index 000000000..5e6131833 --- /dev/null +++ b/vendor/topthink/think-orm/src/model/concern/OptimLock.php @@ -0,0 +1,85 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\model\concern; + +use think\db\exception\DbException as Exception; + +/** + * 乐观锁 + */ +trait OptimLock +{ + protected function getOptimLockField() + { + return property_exists($this, 'optimLock') && isset($this->optimLock) ? $this->optimLock : 'lock_version'; + } + + /** + * 数据检查 + * @access protected + * @return void + */ + protected function checkData(): void + { + $this->isExists() ? $this->updateLockVersion() : $this->recordLockVersion(); + } + + /** + * 记录乐观锁 + * @access protected + * @return void + */ + protected function recordLockVersion(): void + { + $optimLock = $this->getOptimLockField(); + + if ($optimLock) { + $this->set($optimLock, 0); + } + } + + /** + * 更新乐观锁 + * @access protected + * @return void + */ + protected function updateLockVersion(): void + { + $optimLock = $this->getOptimLockField(); + + if ($optimLock && $lockVer = $this->getOrigin($optimLock)) { + // 更新乐观锁 + $this->set($optimLock, $lockVer + 1); + } + } + + public function getWhere() + { + $where = parent::getWhere(); + $optimLock = $this->getOptimLockField(); + + if ($optimLock && $lockVer = $this->getOrigin($optimLock)) { + $where[] = [$optimLock, '=', $lockVer]; + } + + return $where; + } + + protected function checkResult($result): void + { + if (!$result) { + throw new Exception('record has update'); + } + } + +} diff --git a/thinkphp/library/think/model/concern/RelationShip.php b/vendor/topthink/think-orm/src/model/concern/RelationShip.php old mode 100755 new mode 100644 similarity index 50% rename from thinkphp/library/think/model/concern/RelationShip.php rename to vendor/topthink/think-orm/src/model/concern/RelationShip.php index 38ad5d20f..33c1b890e --- a/thinkphp/library/think/model/concern/RelationShip.php +++ b/vendor/topthink/think-orm/src/model/concern/RelationShip.php @@ -2,18 +2,21 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\model\concern; +use Closure; use think\Collection; -use think\db\Query; -use think\Loader; +use think\db\BaseQuery as Query; +use think\db\exception\DbException as Exception; +use think\helper\Str; use think\Model; use think\model\Relation; use think\model\relation\BelongsTo; @@ -21,9 +24,12 @@ use think\model\relation\BelongsToMany; use think\model\relation\HasMany; use think\model\relation\HasManyThrough; use think\model\relation\HasOne; +use think\model\relation\HasOneThrough; use think\model\relation\MorphMany; use think\model\relation\MorphOne; use think\model\relation\MorphTo; +use think\model\relation\MorphToMany; +use think\model\relation\OneToOne; /** * 模型关联处理 @@ -46,13 +52,13 @@ trait RelationShip * 关联写入定义信息 * @var array */ - private $together; + private $together = []; /** * 关联自动写入信息 * @var array */ - protected $relationWrite; + protected $relationWrite = []; /** * 设置父关联对象 @@ -60,7 +66,7 @@ trait RelationShip * @param Model $model 模型对象 * @return $this */ - public function setParent($model) + public function setParent(Model $model) { $this->parent = $model; @@ -72,7 +78,7 @@ trait RelationShip * @access public * @return Model */ - public function getParent() + public function getParent(): Model { return $this->parent; } @@ -81,16 +87,21 @@ trait RelationShip * 获取当前模型的关联模型数据 * @access public * @param string $name 关联方法名 + * @param bool $auto 不存在是否自动获取 * @return mixed */ - public function getRelation($name = null) + public function getRelation(string $name = null, bool $auto = false) { if (is_null($name)) { return $this->relation; - } elseif (array_key_exists($name, $this->relation)) { - return $this->relation[$name]; } - return; + + if (array_key_exists($name, $this->relation)) { + return $this->relation[$name]; + } elseif ($auto) { + $relation = Str::camel($name); + return $this->getRelationValue($relation); + } } /** @@ -101,32 +112,67 @@ trait RelationShip * @param array $data 数据 * @return $this */ - public function setRelation($name, $value, $data = []) + public function setRelation(string $name, $value, array $data = []) { // 检测修改器 - $method = 'set' . Loader::parseName($name, 1) . 'Attr'; + $method = 'set' . Str::studly($name) . 'Attr'; if (method_exists($this, $method)) { $value = $this->$method($value, array_merge($this->data, $data)); } - $this->relation[$name] = $value; + $this->relation[$this->getRealFieldName($name)] = $value; return $this; } + /** + * 查询当前模型的关联数据 + * @access public + * @param array $relations 关联名 + * @param array $withRelationAttr 关联获取器 + * @return void + */ + public function relationQuery(array $relations, array $withRelationAttr = []): void + { + foreach ($relations as $key => $relation) { + $subRelation = []; + $closure = null; + + if ($relation instanceof Closure) { + // 支持闭包查询过滤关联条件 + $closure = $relation; + $relation = $key; + } + + if (is_array($relation)) { + $subRelation = $relation; + $relation = $key; + } elseif (strpos($relation, '.')) { + [$relation, $subRelation] = explode('.', $relation, 2); + } + + $method = Str::camel($relation); + $relationName = Str::snake($relation); + + $relationResult = $this->$method(); + + if (isset($withRelationAttr[$relationName])) { + $relationResult->withAttr($withRelationAttr[$relationName]); + } + + $this->relation[$relation] = $relationResult->getRelation((array) $subRelation, $closure); + } + } + /** * 关联数据写入 * @access public - * @param array|string $relation 关联 + * @param array $relation 关联 * @return $this */ - public function together($relation) + public function together(array $relation) { - if (is_string($relation)) { - $relation = explode(',', $relation); - } - $this->together = $relation; $this->checkAutoRelationWrite(); @@ -142,17 +188,14 @@ trait RelationShip * @param integer $count 个数 * @param string $id 关联表的统计字段 * @param string $joinType JOIN类型 + * @param Query $query Query对象 * @return Query */ - public static function has($relation, $operator = '>=', $count = 1, $id = '*', $joinType = 'INNER') + public static function has(string $relation, string $operator = '>=', int $count = 1, string $id = '*', string $joinType = '', Query $query = null): Query { - $relation = (new static())->$relation(); - - if (is_array($operator) || $operator instanceof \Closure) { - return $relation->hasWhere($operator); - } - - return $relation->has($operator, $count, $id, $joinType); + return (new static()) + ->$relation() + ->has($operator, $count, $id, $joinType, $query); } /** @@ -161,76 +204,58 @@ trait RelationShip * @param string $relation 关联方法名 * @param mixed $where 查询条件(数组或者闭包) * @param mixed $fields 字段 + * @param string $joinType JOIN类型 + * @param Query $query Query对象 * @return Query */ - public static function hasWhere($relation, $where = [], $fields = '*') + public static function hasWhere(string $relation, $where = [], string $fields = '*', string $joinType = '', Query $query = null): Query { - return (new static())->$relation()->hasWhere($where, $fields); + return (new static()) + ->$relation() + ->hasWhere($where, $fields, $joinType, $query); } /** - * 查询当前模型的关联数据 + * 预载入关联查询 JOIN方式 * @access public - * @param string|array $relations 关联名 - * @param array $withRelationAttr 关联获取器 - * @return $this + * @param Query $query Query对象 + * @param string $relation 关联方法名 + * @param mixed $field 字段 + * @param string $joinType JOIN类型 + * @param Closure $closure 闭包 + * @param bool $first + * @return bool */ - public function relationQuery($relations, $withRelationAttr = []) + public function eagerly(Query $query, string $relation, $field, string $joinType = '', Closure $closure = null, bool $first = false): bool { - if (is_string($relations)) { - $relations = explode(',', $relations); + $relation = Str::camel($relation); + $class = $this->$relation(); + + if ($class instanceof OneToOne) { + $class->eagerly($query, $relation, $field, $joinType, $closure, $first); + return true; + } else { + return false; } - - foreach ($relations as $key => $relation) { - $subRelation = ''; - $closure = null; - - if ($relation instanceof \Closure) { - // 支持闭包查询过滤关联条件 - $closure = $relation; - $relation = $key; - } - - if (is_array($relation)) { - $subRelation = $relation; - $relation = $key; - } elseif (strpos($relation, '.')) { - list($relation, $subRelation) = explode('.', $relation, 2); - } - - $method = Loader::parseName($relation, 1, false); - $relationName = Loader::parseName($relation); - - $relationResult = $this->$method(); - - if (isset($withRelationAttr[$relationName])) { - $relationResult->withAttr($withRelationAttr[$relationName]); - } - - $this->relation[$relation] = $relationResult->getRelation($subRelation, $closure); - } - - return $this; } /** * 预载入关联查询 返回数据集 * @access public - * @param array $resultSet 数据集 - * @param string $relation 关联名 + * @param array $resultSet 数据集 + * @param string $relation 关联名 * @param array $withRelationAttr 关联获取器 - * @param bool $join 是否为JOIN方式 - * @return array + * @param bool $join 是否为JOIN方式 + * @param mixed $cache 关联缓存 + * @return void */ - public function eagerlyResultSet(&$resultSet, $relation, $withRelationAttr = [], $join = false) + public function eagerlyResultSet(array &$resultSet, array $relations, array $withRelationAttr = [], bool $join = false, $cache = false): void { - $relations = is_string($relation) ? explode(',', $relation) : $relation; - foreach ($relations as $key => $relation) { - $subRelation = ''; + $subRelation = []; $closure = null; - if ($relation instanceof \Closure) { + if ($relation instanceof Closure) { $closure = $relation; $relation = $key; } @@ -239,11 +264,13 @@ trait RelationShip $subRelation = $relation; $relation = $key; } elseif (strpos($relation, '.')) { - list($relation, $subRelation) = explode('.', $relation, 2); + [$relation, $subRelation] = explode('.', $relation, 2); + + $subRelation = [$subRelation]; } - $relation = Loader::parseName($relation, 1, false); - $relationName = Loader::parseName($relation); + $relationName = $relation; + $relation = Str::camel($relation); $relationResult = $this->$relation(); @@ -251,28 +278,33 @@ trait RelationShip $relationResult->withAttr($withRelationAttr[$relationName]); } - $relationResult->eagerlyResultSet($resultSet, $relation, $subRelation, $closure, $join); + if (is_scalar($cache)) { + $relationCache = [$cache]; + } else { + $relationCache = $cache[$relationName] ?? $cache; + } + + $relationResult->eagerlyResultSet($resultSet, $relationName, $subRelation, $closure, $relationCache, $join); } } /** * 预载入关联查询 返回模型对象 * @access public - * @param Model $result 数据对象 - * @param string $relation 关联名 - * @param array $withRelationAttr 关联获取器 - * @param bool $join 是否为JOIN方式 - * @return Model + * @param Model $result 数据对象 + * @param array $relations 关联 + * @param array $withRelationAttr 关联获取器 + * @param bool $join 是否为JOIN方式 + * @param mixed $cache 关联缓存 + * @return void */ - public function eagerlyResult(&$result, $relation, $withRelationAttr = [], $join = false) + public function eagerlyResult(Model $result, array $relations, array $withRelationAttr = [], bool $join = false, $cache = false): void { - $relations = is_string($relation) ? explode(',', $relation) : $relation; - foreach ($relations as $key => $relation) { - $subRelation = ''; + $subRelation = []; $closure = null; - if ($relation instanceof \Closure) { + if ($relation instanceof Closure) { $closure = $relation; $relation = $key; } @@ -281,11 +313,13 @@ trait RelationShip $subRelation = $relation; $relation = $key; } elseif (strpos($relation, '.')) { - list($relation, $subRelation) = explode('.', $relation, 2); + [$relation, $subRelation] = explode('.', $relation, 2); + + $subRelation = [$subRelation]; } - $relation = Loader::parseName($relation, 1, false); - $relationName = Loader::parseName($relation); + $relationName = $relation; + $relation = Str::camel($relation); $relationResult = $this->$relation(); @@ -293,25 +327,58 @@ trait RelationShip $relationResult->withAttr($withRelationAttr[$relationName]); } - $relationResult->eagerlyResult($result, $relation, $subRelation, $closure, $join); + if (is_scalar($cache)) { + $relationCache = [$cache]; + } else { + $relationCache = $cache[$relationName] ?? []; + } + + $relationResult->eagerlyResult($result, $relationName, $subRelation, $closure, $relationCache, $join); } } + /** + * 绑定(一对一)关联属性到当前模型 + * @access protected + * @param string $relation 关联名称 + * @param array $attrs 绑定属性 + * @return $this + * @throws Exception + */ + public function bindAttr(string $relation, array $attrs = []) + { + $relation = $this->getRelation($relation); + + foreach ($attrs as $key => $attr) { + $key = is_numeric($key) ? $attr : $key; + $value = $this->getOrigin($key); + + if (!is_null($value)) { + throw new Exception('bind attr has exists:' . $key); + } + + $this->set($key, $relation ? $relation->$attr : null); + } + + return $this; + } + /** * 关联统计 * @access public - * @param Model $result 数据对象 - * @param array $relations 关联名 - * @param string $aggregate 聚合查询方法 - * @param string $field 字段 + * @param Query $query 查询对象 + * @param array $relations 关联名 + * @param string $aggregate 聚合查询方法 + * @param string $field 字段 + * @param bool $useSubQuery 子查询 * @return void */ - public function relationCount(&$result, $relations, $aggregate = 'sum', $field = '*') + public function relationCount(Query $query, array $relations, string $aggregate = 'sum', string $field = '*', bool $useSubQuery = true): void { foreach ($relations as $key => $relation) { $closure = $name = null; - if ($relation instanceof \Closure) { + if ($relation instanceof Closure) { $closure = $relation; $relation = $key; } elseif (is_string($key)) { @@ -319,15 +386,23 @@ trait RelationShip $relation = $key; } - $relation = Loader::parseName($relation, 1, false); + $relation = Str::camel($relation); - $count = $this->$relation()->relationCount($result, $closure, $aggregate, $field, $name); - - if (empty($name)) { - $name = Loader::parseName($relation) . '_' . $aggregate; + if ($useSubQuery) { + $count = $this->$relation()->getRelationCountQuery($closure, $aggregate, $field, $name); + } else { + $count = $this->$relation()->relationCount($this, $closure, $aggregate, $field, $name); } - $result->setAttr($name, $count); + if (empty($name)) { + $name = Str::snake($relation) . '_' . $aggregate; + } + + if ($useSubQuery) { + $query->field(['(' . $count . ')' => $name]); + } else { + $this->setAttr($name, $count); + } } } @@ -339,7 +414,7 @@ trait RelationShip * @param string $localKey 当前主键 * @return HasOne */ - public function hasOne($model, $foreignKey = '', $localKey = '') + public function hasOne(string $model, string $foreignKey = '', string $localKey = ''): HasOne { // 记录当前关联信息 $model = $this->parseModel($model); @@ -357,14 +432,14 @@ trait RelationShip * @param string $localKey 关联主键 * @return BelongsTo */ - public function belongsTo($model, $foreignKey = '', $localKey = '') + public function belongsTo(string $model, string $foreignKey = '', string $localKey = ''): BelongsTo { // 记录当前关联信息 $model = $this->parseModel($model); $foreignKey = $foreignKey ?: $this->getForeignKey((new $model)->getName()); $localKey = $localKey ?: (new $model)->getPk(); - $trace = debug_backtrace(false, 2); - $relation = Loader::parseName($trace[1]['function']); + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); + $relation = Str::snake($trace[1]['function']); return new BelongsTo($this, $model, $foreignKey, $localKey, $relation); } @@ -377,7 +452,7 @@ trait RelationShip * @param string $localKey 当前主键 * @return HasMany */ - public function hasMany($model, $foreignKey = '', $localKey = '') + public function hasMany(string $model, string $foreignKey = '', string $localKey = ''): HasMany { // 记录当前关联信息 $model = $this->parseModel($model); @@ -395,9 +470,10 @@ trait RelationShip * @param string $foreignKey 关联外键 * @param string $throughKey 关联外键 * @param string $localKey 当前主键 + * @param string $throughPk 中间表主键 * @return HasManyThrough */ - public function hasManyThrough($model, $through, $foreignKey = '', $throughKey = '', $localKey = '') + public function hasManyThrough(string $model, string $through, string $foreignKey = '', string $throughKey = '', string $localKey = '', string $throughPk = ''): HasManyThrough { // 记录当前关联信息 $model = $this->parseModel($model); @@ -405,29 +481,54 @@ trait RelationShip $localKey = $localKey ?: $this->getPk(); $foreignKey = $foreignKey ?: $this->getForeignKey($this->name); $throughKey = $throughKey ?: $this->getForeignKey((new $through)->getName()); + $throughPk = $throughPk ?: (new $through)->getPk(); - return new HasManyThrough($this, $model, $through, $foreignKey, $throughKey, $localKey); + return new HasManyThrough($this, $model, $through, $foreignKey, $throughKey, $localKey, $throughPk); + } + + /** + * HAS ONE 远程关联定义 + * @access public + * @param string $model 模型名 + * @param string $through 中间模型名 + * @param string $foreignKey 关联外键 + * @param string $throughKey 关联外键 + * @param string $localKey 当前主键 + * @param string $throughPk 中间表主键 + * @return HasOneThrough + */ + public function hasOneThrough(string $model, string $through, string $foreignKey = '', string $throughKey = '', string $localKey = '', string $throughPk = ''): HasOneThrough + { + // 记录当前关联信息 + $model = $this->parseModel($model); + $through = $this->parseModel($through); + $localKey = $localKey ?: $this->getPk(); + $foreignKey = $foreignKey ?: $this->getForeignKey($this->name); + $throughKey = $throughKey ?: $this->getForeignKey((new $through)->getName()); + $throughPk = $throughPk ?: (new $through)->getPk(); + + return new HasOneThrough($this, $model, $through, $foreignKey, $throughKey, $localKey, $throughPk); } /** * BELONGS TO MANY 关联定义 * @access public * @param string $model 模型名 - * @param string $table 中间表名 + * @param string $middle 中间表/模型名 * @param string $foreignKey 关联外键 * @param string $localKey 当前模型关联键 * @return BelongsToMany */ - public function belongsToMany($model, $table = '', $foreignKey = '', $localKey = '') + public function belongsToMany(string $model, string $middle = '', string $foreignKey = '', string $localKey = ''): BelongsToMany { // 记录当前关联信息 $model = $this->parseModel($model); - $name = Loader::parseName(basename(str_replace('\\', '/', $model))); - $table = $table ?: Loader::parseName($this->name) . '_' . $name; + $name = Str::snake(class_basename($model)); + $middle = $middle ?: Str::snake($this->name) . '_' . $name; $foreignKey = $foreignKey ?: $name . '_id'; $localKey = $localKey ?: $this->getForeignKey($this->name); - return new BelongsToMany($this, $model, $table, $foreignKey, $localKey); + return new BelongsToMany($this, $model, $middle, $foreignKey, $localKey); } /** @@ -438,18 +539,18 @@ trait RelationShip * @param string $type 多态类型 * @return MorphOne */ - public function morphOne($model, $morph = null, $type = '') + public function morphOne(string $model, $morph = null, string $type = ''): MorphOne { // 记录当前关联信息 $model = $this->parseModel($model); if (is_null($morph)) { - $trace = debug_backtrace(false, 2); - $morph = Loader::parseName($trace[1]['function']); + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); + $morph = Str::snake($trace[1]['function']); } if (is_array($morph)) { - list($morphType, $foreignKey) = $morph; + [$morphType, $foreignKey] = $morph; } else { $morphType = $morph . '_type'; $foreignKey = $morph . '_id'; @@ -468,20 +569,20 @@ trait RelationShip * @param string $type 多态类型 * @return MorphMany */ - public function morphMany($model, $morph = null, $type = '') + public function morphMany(string $model, $morph = null, string $type = ''): MorphMany { // 记录当前关联信息 $model = $this->parseModel($model); if (is_null($morph)) { - $trace = debug_backtrace(false, 2); - $morph = Loader::parseName($trace[1]['function']); + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); + $morph = Str::snake($trace[1]['function']); } $type = $type ?: get_class($this); if (is_array($morph)) { - list($morphType, $foreignKey) = $morph; + [$morphType, $foreignKey] = $morph; } else { $morphType = $morph . '_type'; $foreignKey = $morph . '_id'; @@ -497,10 +598,10 @@ trait RelationShip * @param array $alias 多态别名定义 * @return MorphTo */ - public function morphTo($morph = null, $alias = []) + public function morphTo($morph = null, array $alias = []): MorphTo { - $trace = debug_backtrace(false, 2); - $relation = Loader::parseName($trace[1]['function']); + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); + $relation = Str::snake($trace[1]['function']); if (is_null($morph)) { $morph = $relation; @@ -508,7 +609,7 @@ trait RelationShip // 记录当前关联信息 if (is_array($morph)) { - list($morphType, $foreignKey) = $morph; + [$morphType, $foreignKey] = $morph; } else { $morphType = $morph . '_type'; $foreignKey = $morph . '_id'; @@ -517,18 +618,77 @@ trait RelationShip return new MorphTo($this, $morphType, $foreignKey, $alias, $relation); } + /** + * MORPH TO MANY关联定义 + * @access public + * @param string $model 模型名 + * @param string $middle 中间表名/模型名 + * @param string|array $morph 多态字段信息 + * @param string $localKey 当前模型关联键 + * @return MorphToMany + */ + public function morphToMany(string $model, string $middle, $morph = null, string $localKey = null): MorphToMany + { + if (is_null($morph)) { + $morph = $middle; + } + + // 记录当前关联信息 + if (is_array($morph)) { + [$morphType, $morphKey] = $morph; + } else { + $morphType = $morph . '_type'; + $morphKey = $morph . '_id'; + } + + $model = $this->parseModel($model); + $name = Str::snake(class_basename($model)); + $localKey = $localKey ?: $this->getForeignKey($name); + + return new MorphToMany($this, $model, $middle, $morphType, $morphKey, $localKey); + } + + /** + * MORPH BY MANY关联定义 + * @access public + * @param string $model 模型名 + * @param string $middle 中间表名/模型名 + * @param string|array $morph 多态字段信息 + * @param string $foreignKey 关联外键 + * @return MorphToMany + */ + public function morphByMany(string $model, string $middle, $morph = null, string $foreignKey = null): MorphToMany + { + if (is_null($morph)) { + $morph = $middle; + } + + // 记录当前关联信息 + if (is_array($morph)) { + [$morphType, $morphKey] = $morph; + } else { + $morphType = $morph . '_type'; + $morphKey = $morph . '_id'; + } + + $model = $this->parseModel($model); + $foreignKey = $foreignKey ?: $this->getForeignKey($this->name); + + return new MorphToMany($this, $model, $middle, $morphType, $morphKey, $foreignKey, true); + } + /** * 解析模型的完整命名空间 * @access protected * @param string $model 模型名(或者完整类名) * @return string */ - protected function parseModel($model) + protected function parseModel(string $model): string { if (false === strpos($model, '\\')) { $path = explode('\\', static::class); array_pop($path); - array_push($path, Loader::parseName($model, 1)); + array_push($path, Str::studly($model)); $model = implode('\\', $path); } @@ -541,13 +701,13 @@ trait RelationShip * @param string $name 模型名 * @return string */ - protected function getForeignKey($name) + protected function getForeignKey(string $name): string { if (strpos($name, '\\')) { - $name = basename(str_replace('\\', '/', $name)); + $name = class_basename($name); } - return Loader::parseName($name) . '_id'; + return Str::snake($name) . '_id'; } /** @@ -556,11 +716,11 @@ trait RelationShip * @param string $attr 关联属性名 * @return string|false */ - protected function isRelationAttr($attr) + protected function isRelationAttr(string $attr) { - $relation = Loader::parseName($attr, 1, false); + $relation = Str::camel($attr); - if (method_exists($this, $relation) && !method_exists('think\Model', $relation)) { + if ((method_exists($this, $relation) && !method_exists('think\Model', $relation)) || isset(static::$macro[static::class][$relation])) { return $relation; } @@ -570,19 +730,18 @@ trait RelationShip /** * 智能获取关联模型数据 * @access protected - * @param Relation $modelRelation 模型关联对象 + * @param Relation $modelRelation 模型关联对象 * @return mixed */ protected function getRelationData(Relation $modelRelation) { - if ($this->parent && !$modelRelation->isSelfRelation() && get_class($this->parent) == get_class($modelRelation->getModel())) { - $value = $this->parent; - } else { - // 获取关联数据 - $value = $modelRelation->getRelation(); + if ($this->parent && !$modelRelation->isSelfRelation() + && get_class($this->parent) == get_class($modelRelation->getModel())) { + return $this->parent; } - return $value; + // 获取关联数据 + return $modelRelation->getRelation(); } /** @@ -590,14 +749,14 @@ trait RelationShip * @access protected * @return void */ - protected function checkAutoRelationWrite() + protected function checkAutoRelationWrite(): void { foreach ($this->together as $key => $name) { if (is_array($name)) { if (key($name) === 0) { $this->relationWrite[$key] = []; // 绑定关联属性 - foreach ((array) $name as $val) { + foreach ($name as $val) { if (isset($this->data[$val])) { $this->relationWrite[$key][$val] = $this->data[$val]; } @@ -620,15 +779,16 @@ trait RelationShip * @access protected * @return void */ - protected function autoRelationUpdate() + protected function autoRelationUpdate(): void { foreach ($this->relationWrite as $name => $val) { if ($val instanceof Model) { - $val->isUpdate()->save(); + $val->exists(true)->save(); } else { - $model = $this->getRelation($name); + $model = $this->getRelation($name, true); + if ($model instanceof Model) { - $model->isUpdate()->save($val); + $model->exists(true)->save($val); } } } @@ -639,10 +799,10 @@ trait RelationShip * @access protected * @return void */ - protected function autoRelationInsert() + protected function autoRelationInsert(): void { foreach ($this->relationWrite as $name => $val) { - $method = Loader::parseName($name, 1, false); + $method = Str::camel($name); $this->$method()->save($val); } } @@ -650,21 +810,33 @@ trait RelationShip /** * 自动关联数据删除(支持一对一及一对多关联) * @access protected + * @param bool $force 强制删除 * @return void */ - protected function autoRelationDelete() + protected function autoRelationDelete($force = false): void { foreach ($this->relationWrite as $key => $name) { $name = is_numeric($key) ? $name : $key; - $result = $this->getRelation($name); + $result = $this->getRelation($name, true); if ($result instanceof Model) { - $result->delete(); + $result->force($force)->delete(); } elseif ($result instanceof Collection) { foreach ($result as $model) { - $model->delete(); + $model->force($force)->delete(); } } } } + + /** + * 移除当前模型的关联属性 + * @access public + * @return $this + */ + public function removeRelation() + { + $this->relation = []; + return $this; + } } diff --git a/thinkphp/library/think/model/concern/SoftDelete.php b/vendor/topthink/think-orm/src/model/concern/SoftDelete.php old mode 100755 new mode 100644 similarity index 58% rename from thinkphp/library/think/model/concern/SoftDelete.php rename to vendor/topthink/think-orm/src/model/concern/SoftDelete.php index 7dc96e126..5a9a56dc2 --- a/thinkphp/library/think/model/concern/SoftDelete.php +++ b/vendor/topthink/think-orm/src/model/concern/SoftDelete.php @@ -1,15 +1,26 @@ +// +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\model\concern; -use think\db\Query; +use think\db\BaseQuery as Query; +use think\Model; /** * 数据软删除 + * @mixin Model */ trait SoftDelete { - /** * 是否包含软删除数据 * @var bool @@ -19,9 +30,9 @@ trait SoftDelete /** * 判断当前实例是否被软删除 * @access public - * @return boolean + * @return bool */ - public function trashed() + public function trashed(): bool { $field = $this->getDeleteTimeField(); @@ -37,11 +48,11 @@ trait SoftDelete * @access public * @return Query */ - public static function withTrashed() + public static function withTrashed(): Query { $model = new static(); - return $model->withTrashedData(true)->db(false); + return $model->withTrashedData(true)->db(); } /** @@ -50,7 +61,7 @@ trait SoftDelete * @param bool $withTrashed 是否包含软删除数据 * @return $this */ - protected function withTrashedData($withTrashed) + protected function withTrashedData(bool $withTrashed) { $this->withTrashed = $withTrashed; return $this; @@ -61,18 +72,18 @@ trait SoftDelete * @access public * @return Query */ - public static function onlyTrashed() + public static function onlyTrashed(): Query { $model = new static(); $field = $model->getDeleteTimeField(true); if ($field) { return $model - ->db(false) + ->db() ->useSoftDelete($field, $model->getWithTrashedExp()); } - return $model->db(false); + return $model->db(); } /** @@ -80,10 +91,9 @@ trait SoftDelete * @access protected * @return array */ - protected function getWithTrashedExp() + protected function getWithTrashedExp(): array { - return is_null($this->defaultSoftDelete) ? - ['notnull', ''] : ['<>', $this->defaultSoftDelete]; + return is_null($this->defaultSoftDelete) ? ['notnull', ''] : ['<>', $this->defaultSoftDelete]; } /** @@ -91,20 +101,20 @@ trait SoftDelete * @access public * @return bool */ - public function delete($force = false) + public function delete(): bool { - if (!$this->isExists() || false === $this->trigger('before_delete', $this)) { + if (!$this->isExists() || $this->isEmpty() || false === $this->trigger('BeforeDelete')) { return false; } - $force = $force ?: $this->isForce(); $name = $this->getDeleteTimeField(); + $force = $this->isForce(); if ($name && !$force) { // 软删除 - $this->data($name, $this->autoWriteTimestamp($name)); + $this->set($name, $this->autoWriteTimestamp($name)); - $result = $this->isUpdate()->withEvent(false)->save(); + $result = $this->exists()->withEvent(false)->save(); $this->withEvent(true); } else { @@ -112,18 +122,20 @@ trait SoftDelete $where = $this->getWhere(); // 删除当前模型数据 - $result = $this->db(false) + $result = $this->db() ->where($where) ->removeOption('soft_delete') ->delete(); + + $this->lazySave(false); } // 关联删除 if (!empty($this->relationWrite)) { - $this->autoRelationDelete(); + $this->autoRelationDelete($force); } - $this->trigger('after_delete', $this); + $this->trigger('AfterDelete'); $this->exists(false); @@ -137,10 +149,10 @@ trait SoftDelete * @param bool $force 是否强制删除 * @return bool */ - public static function destroy($data, $force = false) + public static function destroy($data, bool $force = false): bool { // 包含软删除数据 - $query = (new static())->db(false); + $query = (new static())->withTrashedData(true)->db(false); if (is_array($data) && key($data) !== 0) { $query->where($data); @@ -154,10 +166,8 @@ trait SoftDelete $resultSet = $query->select($data); - if ($resultSet) { - foreach ($resultSet as $data) { - $data->force($force)->delete(); - } + foreach ($resultSet as $result) { + $result->force($force)->delete(); } return true; @@ -169,33 +179,30 @@ trait SoftDelete * @param array $where 更新条件 * @return bool */ - public function restore($where = []) + public function restore($where = []): bool { $name = $this->getDeleteTimeField(); - if ($name) { - if (false === $this->trigger('before_restore')) { - return false; - } - - if (empty($where)) { - $pk = $this->getPk(); - - $where[] = [$pk, '=', $this->getData($pk)]; - } - - // 恢复删除 - $this->db(false) - ->where($where) - ->useSoftDelete($name, $this->getWithTrashedExp()) - ->update([$name => $this->defaultSoftDelete]); - - $this->trigger('after_restore'); - - return true; + if (!$name || false === $this->trigger('BeforeRestore')) { + return false; } - return false; + if (empty($where)) { + $pk = $this->getPk(); + if (is_string($pk)) { + $where[] = [$pk, '=', $this->getData($pk)]; + } + } + + // 恢复删除 + $this->db(false) + ->where($where) + ->useSoftDelete($name, $this->getWithTrashedExp()) + ->update([$name => $this->defaultSoftDelete]); + + $this->trigger('AfterRestore'); + + return true; } /** @@ -204,7 +211,7 @@ trait SoftDelete * @param bool $read 是否查询操作 写操作的时候会自动去掉表别名 * @return string|false */ - protected function getDeleteTimeField($read = false) + protected function getDeleteTimeField(bool $read = false) { $field = property_exists($this, 'deleteTime') && isset($this->deleteTime) ? $this->deleteTime : 'delete_time'; @@ -230,12 +237,13 @@ trait SoftDelete * @param Query $query * @return void */ - protected function withNoTrashed($query) + protected function withNoTrashed(Query $query): void { $field = $this->getDeleteTimeField(true); if ($field) { - $query->useSoftDelete($field, $this->defaultSoftDelete); + $condition = is_null($this->defaultSoftDelete) ? ['null', ''] : ['=', $this->defaultSoftDelete]; + $query->useSoftDelete($field, $condition); } } } diff --git a/vendor/topthink/think-orm/src/model/concern/TimeStamp.php b/vendor/topthink/think-orm/src/model/concern/TimeStamp.php new file mode 100644 index 000000000..e207961f3 --- /dev/null +++ b/vendor/topthink/think-orm/src/model/concern/TimeStamp.php @@ -0,0 +1,208 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\model\concern; + +use DateTime; + +/** + * 自动时间戳 + */ +trait TimeStamp +{ + /** + * 是否需要自动写入时间戳 如果设置为字符串 则表示时间字段的类型 + * @var bool|string + */ + protected $autoWriteTimestamp; + + /** + * 创建时间字段 false表示关闭 + * @var false|string + */ + protected $createTime = 'create_time'; + + /** + * 更新时间字段 false表示关闭 + * @var false|string + */ + protected $updateTime = 'update_time'; + + /** + * 时间字段显示格式 + * @var string + */ + protected $dateFormat; + + /** + * 是否需要自动写入时间字段 + * @access public + * @param bool|string $auto + * @return $this + */ + public function isAutoWriteTimestamp($auto) + { + $this->autoWriteTimestamp = $this->checkTimeFieldType($auto); + + return $this; + } + + /** + * 检测时间字段的实际类型 + * @access public + * @param bool|string $type + * @return mixed + */ + protected function checkTimeFieldType($type) + { + if (true === $type) { + if (isset($this->type[$this->createTime])) { + $type = $this->type[$this->createTime]; + } elseif (isset($this->schema[$this->createTime]) && in_array($this->schema[$this->createTime], ['datetime', 'date', 'timestamp', 'int'])) { + $type = $this->schema[$this->createTime]; + } else { + $type = $this->getFieldType($this->createTime); + } + } + + return $type; + } + + /** + * 获取自动写入时间字段 + * @access public + * @return bool|string + */ + public function getAutoWriteTimestamp() + { + return $this->autoWriteTimestamp; + } + + /** + * 设置时间字段格式化 + * @access public + * @param string|false $format + * @return $this + */ + public function setDateFormat($format) + { + $this->dateFormat = $format; + + return $this; + } + + /** + * 获取自动写入时间字段 + * @access public + * @return string|false + */ + public function getDateFormat() + { + return $this->dateFormat; + } + + /** + * 自动写入时间戳 + * @access protected + * @return mixed + */ + protected function autoWriteTimestamp() + { + // 检测时间字段类型 + $type = $this->checkTimeFieldType($this->autoWriteTimestamp); + + return is_string($type) ? $this->getTimeTypeValue($type) : time(); + } + + /** + * 获取指定类型的时间字段值 + * @access protected + * @param string $type 时间字段类型 + * @return mixed + */ + protected function getTimeTypeValue(string $type) + { + $value = time(); + + switch ($type) { + case 'datetime': + case 'date': + case 'timestamp': + $value = $this->formatDateTime('Y-m-d H:i:s.u'); + break; + default: + if (false !== strpos($type, '\\')) { + // 对象数据写入 + $obj = new $type(); + if (method_exists($obj, '__toString')) { + // 对象数据写入 + $value = $obj->__toString(); + } + } + } + + return $value; + } + + /** + * 时间日期字段格式化处理 + * @access protected + * @param mixed $format 日期格式 + * @param mixed $time 时间日期表达式 + * @param bool $timestamp 时间表达式是否为时间戳 + * @return mixed + */ + protected function formatDateTime($format, $time = 'now', bool $timestamp = false) + { + if (empty($time)) { + return; + } + + if (false === $format) { + return $time; + } elseif (false !== strpos($format, '\\')) { + return new $format($time); + } + + if ($time instanceof DateTime) { + $dateTime = $time; + } elseif ($timestamp) { + $dateTime = new DateTime(); + $dateTime->setTimestamp((int) $time); + } else { + $dateTime = new DateTime($time); + } + + return $dateTime->format($format); + } + + /** + * 获取时间字段值 + * @access protected + * @param mixed $value + * @return mixed + */ + protected function getTimestampValue($value) + { + $type = $this->checkTimeFieldType($this->autoWriteTimestamp); + + if (is_string($type) && in_array(strtolower($type), [ + 'datetime', 'date', 'timestamp', + ])) { + $value = $this->formatDateTime($this->dateFormat, $value); + } else { + $value = $this->formatDateTime($this->dateFormat, $value, true); + } + + return $value; + } +} diff --git a/thinkphp/library/think/model/relation/BelongsTo.php b/vendor/topthink/think-orm/src/model/relation/BelongsTo.php old mode 100755 new mode 100644 similarity index 54% rename from thinkphp/library/think/model/relation/BelongsTo.php rename to vendor/topthink/think-orm/src/model/relation/BelongsTo.php index 98d176e8f..789c9440e --- a/thinkphp/library/think/model/relation/BelongsTo.php +++ b/vendor/topthink/think-orm/src/model/relation/BelongsTo.php @@ -2,18 +2,24 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\model\relation; -use think\Loader; +use Closure; +use think\db\BaseQuery as Query; +use think\helper\Str; use think\Model; +/** + * BelongsTo关联类 + */ class BelongsTo extends OneToOne { /** @@ -25,13 +31,12 @@ class BelongsTo extends OneToOne * @param string $localKey 关联主键 * @param string $relation 关联名 */ - public function __construct(Model $parent, $model, $foreignKey, $localKey, $relation = null) + public function __construct(Model $parent, string $model, string $foreignKey, string $localKey, string $relation = null) { $this->parent = $parent; $this->model = $model; $this->foreignKey = $foreignKey; $this->localKey = $localKey; - $this->joinType = 'INNER'; $this->query = (new $model)->db(); $this->relation = $relation; @@ -43,14 +48,14 @@ class BelongsTo extends OneToOne /** * 延迟获取关联数据 * @access public - * @param string $subRelation 子关联名 - * @param \Closure $closure 闭包查询条件 + * @param array $subRelation 子关联名 + * @param Closure $closure 闭包查询条件 * @return Model */ - public function getRelation($subRelation = '', $closure = null) + public function getRelation(array $subRelation = [], Closure $closure = null) { if ($closure) { - $closure($this->query); + $closure($this->getClosureType($closure)); } $foreignKey = $this->foreignKey; @@ -62,6 +67,11 @@ class BelongsTo extends OneToOne ->find(); if ($relationModel) { + if (!empty($this->bindAttr)) { + // 绑定关联属性 + $this->bindAttr($this->parent, $relationModel); + } + $relationModel->setParent(clone $this->parent); } @@ -71,20 +81,16 @@ class BelongsTo extends OneToOne /** * 创建关联统计子查询 * @access public - * @param \Closure $closure 闭包 - * @param string $aggregate 聚合查询方法 - * @param string $field 字段 - * @param string $aggregateAlias 聚合字段别名 + * @param Closure $closure 闭包 + * @param string $aggregate 聚合查询方法 + * @param string $field 字段 + * @param string $name 聚合字段别名 * @return string */ - public function getRelationCountQuery($closure, $aggregate = 'count', $field = '*', &$aggregateAlias = '') + public function getRelationCountQuery(Closure $closure = null, string $aggregate = 'count', string $field = '*', &$name = ''): string { if ($closure) { - $return = $closure($this->query); - - if ($return && is_string($return)) { - $aggregateAlias = $return; - } + $closure($this->getClosureType($closure), $name); } return $this->query @@ -96,14 +102,14 @@ class BelongsTo extends OneToOne /** * 关联统计 * @access public - * @param Model $result 数据对象 - * @param \Closure $closure 闭包 - * @param string $aggregate 聚合查询方法 - * @param string $field 字段 - * @param string $name 统计字段别名 + * @param Model $result 数据对象 + * @param Closure $closure 闭包 + * @param string $aggregate 聚合查询方法 + * @param string $field 字段 + * @param string $name 统计字段别名 * @return integer */ - public function relationCount($result, $closure, $aggregate = 'count', $field = '*', &$name = '') + public function relationCount(Model $result, Closure $closure = null, string $aggregate = 'count', string $field = '*', string &$name = null) { $foreignKey = $this->foreignKey; @@ -112,11 +118,7 @@ class BelongsTo extends OneToOne } if ($closure) { - $return = $closure($this->query); - - if ($return && is_string($return)) { - $name = $return; - } + $closure($this->getClosureType($closure), $name); } return $this->query @@ -131,61 +133,76 @@ class BelongsTo extends OneToOne * @param integer $count 个数 * @param string $id 关联表的统计字段 * @param string $joinType JOIN类型 + * @param Query $query Query对象 * @return Query */ - public function has($operator = '>=', $count = 1, $id = '*', $joinType = 'INNER') + public function has(string $operator = '>=', int $count = 1, string $id = '*', string $joinType = '', Query $query = null): Query { $table = $this->query->getTable(); - $model = basename(str_replace('\\', '/', get_class($this->parent))); - $relation = basename(str_replace('\\', '/', $this->model)); + $model = class_basename($this->parent); + $relation = class_basename($this->model); $localKey = $this->localKey; $foreignKey = $this->foreignKey; + $softDelete = $this->query->getOptions('soft_delete'); + $query = $query ?: $this->parent->db()->alias($model); - return $this->parent->db() - ->alias($model) - ->whereExists(function ($query) use ($table, $model, $relation, $localKey, $foreignKey) { - $query->table([$table => $relation]) - ->field($relation . '.' . $localKey) - ->whereExp($model . '.' . $foreignKey, '=' . $relation . '.' . $localKey); - }); + return $query->whereExists(function ($query) use ($table, $model, $relation, $localKey, $foreignKey, $softDelete) { + $query->table([$table => $relation]) + ->field($relation . '.' . $localKey) + ->whereExp($model . '.' . $foreignKey, '=' . $relation . '.' . $localKey) + ->when($softDelete, function ($query) use ($softDelete, $relation) { + $query->where($relation . strstr($softDelete[0], '.'), '=' == $softDelete[1][0] ? $softDelete[1][1] : null); + }); + }); } /** * 根据关联条件查询当前模型 * @access public - * @param mixed $where 查询条件(数组或者闭包) - * @param mixed $fields 字段 + * @param mixed $where 查询条件(数组或者闭包) + * @param mixed $fields 字段 + * @param string $joinType JOIN类型 + * @param Query $query Query对象 * @return Query */ - public function hasWhere($where = [], $fields = null) + public function hasWhere($where = [], $fields = null, string $joinType = '', Query $query = null): Query { $table = $this->query->getTable(); - $model = basename(str_replace('\\', '/', get_class($this->parent))); - $relation = basename(str_replace('\\', '/', $this->model)); + $model = class_basename($this->parent); + $relation = class_basename($this->model); if (is_array($where)) { $this->getQueryWhere($where, $relation); + } elseif ($where instanceof Query) { + $where->via($relation); + } elseif ($where instanceof Closure) { + $where($this->query->via($relation)); + $where = $this->query; } - $fields = $this->getRelationQueryFields($fields, $model); + $fields = $this->getRelationQueryFields($fields, $model); + $softDelete = $this->query->getOptions('soft_delete'); + $query = $query ?: $this->parent->db()->alias($model); - return $this->parent->db() - ->alias($model) - ->field($fields) - ->join([$table => $relation], $model . '.' . $this->foreignKey . '=' . $relation . '.' . $this->localKey, $this->joinType) + return $query->field($fields) + ->join([$table => $relation], $model . '.' . $this->foreignKey . '=' . $relation . '.' . $this->localKey, $joinType ?: $this->joinType) + ->when($softDelete, function ($query) use ($softDelete, $relation) { + $query->where($relation . strstr($softDelete[0], '.'), '=' == $softDelete[1][0] ? $softDelete[1][1] : null); + }) ->where($where); } /** * 预载入关联查询(数据集) * @access protected - * @param array $resultSet 数据集 - * @param string $relation 当前关联名 - * @param string $subRelation 子关联名 - * @param \Closure $closure 闭包 + * @param array $resultSet 数据集 + * @param string $relation 当前关联名 + * @param array $subRelation 子关联名 + * @param Closure $closure 闭包 + * @param array $cache 关联缓存 * @return void */ - protected function eagerlySet(&$resultSet, $relation, $subRelation, $closure) + protected function eagerlySet(array &$resultSet, string $relation, array $subRelation = [], Closure $closure = null, array $cache = []): void { $localKey = $this->localKey; $foreignKey = $this->foreignKey; @@ -203,10 +220,7 @@ class BelongsTo extends OneToOne $data = $this->eagerlyWhere([ [$localKey, 'in', $range], - ], $localKey, $relation, $subRelation, $closure); - - // 关联属性名 - $attr = Loader::parseName($relation); + ], $localKey, $subRelation, $closure, $cache); // 关联数据封装 foreach ($resultSet as $result) { @@ -216,15 +230,15 @@ class BelongsTo extends OneToOne } else { $relationModel = $data[$result->$foreignKey]; $relationModel->setParent(clone $result); - $relationModel->isUpdate(true); + $relationModel->exists(true); } if (!empty($this->bindAttr)) { // 绑定关联属性 - $this->bindAttr($relationModel, $result); + $this->bindAttr($result, $relationModel); } else { // 设置关联属性 - $result->setRelation($attr, $relationModel); + $result->setRelation($relation, $relationModel); } } } @@ -233,13 +247,14 @@ class BelongsTo extends OneToOne /** * 预载入关联查询(数据) * @access protected - * @param Model $result 数据对象 - * @param string $relation 当前关联名 - * @param string $subRelation 子关联名 - * @param \Closure $closure 闭包 + * @param Model $result 数据对象 + * @param string $relation 当前关联名 + * @param array $subRelation 子关联名 + * @param Closure $closure 闭包 + * @param array $cache 关联缓存 * @return void */ - protected function eagerlyOne(&$result, $relation, $subRelation, $closure) + protected function eagerlyOne(Model $result, string $relation, array $subRelation = [], Closure $closure = null, array $cache = []): void { $localKey = $this->localKey; $foreignKey = $this->foreignKey; @@ -248,7 +263,7 @@ class BelongsTo extends OneToOne $data = $this->eagerlyWhere([ [$localKey, '=', $result->$foreignKey], - ], $localKey, $relation, $subRelation, $closure); + ], $localKey, $subRelation, $closure, $cache); // 关联模型 if (!isset($data[$result->$foreignKey])) { @@ -256,25 +271,25 @@ class BelongsTo extends OneToOne } else { $relationModel = $data[$result->$foreignKey]; $relationModel->setParent(clone $result); - $relationModel->isUpdate(true); + $relationModel->exists(true); } if (!empty($this->bindAttr)) { // 绑定关联属性 - $this->bindAttr($relationModel, $result); + $this->bindAttr($result, $relationModel); } else { // 设置关联属性 - $result->setRelation(Loader::parseName($relation), $relationModel); + $result->setRelation($relation, $relationModel); } } /** * 添加关联数据 * @access public - * @param Model $model 关联模型对象 + * @param Model $model关联模型对象 * @return Model */ - public function associate($model) + public function associate(Model $model): Model { $this->parent->setAttr($this->foreignKey, $model->getKey()); $this->parent->save(); @@ -287,9 +302,11 @@ class BelongsTo extends OneToOne * @access public * @return Model */ - public function dissociate() + public function dissociate(): Model { - $this->parent->setAttr($this->foreignKey, null); + $foreignKey = $this->foreignKey; + + $this->parent->setAttr($foreignKey, null); $this->parent->save(); return $this->parent->setRelation($this->relation, null); @@ -300,7 +317,7 @@ class BelongsTo extends OneToOne * @access protected * @return void */ - protected function baseQuery() + protected function baseQuery(): void { if (empty($this->baseQuery)) { if (isset($this->parent->{$this->foreignKey})) { diff --git a/thinkphp/library/think/model/relation/BelongsToMany.php b/vendor/topthink/think-orm/src/model/relation/BelongsToMany.php old mode 100755 new mode 100644 similarity index 59% rename from thinkphp/library/think/model/relation/BelongsToMany.php rename to vendor/topthink/think-orm/src/model/relation/BelongsToMany.php index 747482b6e..6b64d9530 --- a/thinkphp/library/think/model/relation/BelongsToMany.php +++ b/vendor/topthink/think-orm/src/model/relation/BelongsToMany.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -11,46 +11,66 @@ namespace think\model\relation; +use Closure; use think\Collection; -use think\db\Query; -use think\Exception; -use think\Loader; +use think\db\BaseQuery as Query; +use think\db\exception\DbException as Exception; +use think\db\Raw; use think\Model; use think\model\Pivot; use think\model\Relation; +use think\Paginator; +/** + * 多对多关联类 + */ class BelongsToMany extends Relation { - // 中间表表名 + /** + * 中间表表名 + * @var string + */ protected $middle; - // 中间表模型名称 + + /** + * 中间表模型名称 + * @var string + */ protected $pivotName; - // 中间表数据名称 - protected $pivotDataName = 'pivot'; - // 中间表模型对象 + + /** + * 中间表模型对象 + * @var Pivot + */ protected $pivot; + /** + * 中间表数据名称 + * @var string + */ + protected $pivotDataName = 'pivot'; + /** * 架构函数 * @access public * @param Model $parent 上级模型对象 * @param string $model 模型名 - * @param string $table 中间表名 + * @param string $middle 中间表/模型名 * @param string $foreignKey 关联模型外键 * @param string $localKey 当前模型关联键 */ - public function __construct(Model $parent, $model, $table, $foreignKey, $localKey) + public function __construct(Model $parent, string $model, string $middle, string $foreignKey, string $localKey) { $this->parent = $parent; $this->model = $model; $this->foreignKey = $foreignKey; $this->localKey = $localKey; - if (false !== strpos($table, '\\')) { - $this->pivotName = $table; - $this->middle = basename(str_replace('\\', '/', $table)); + if (false !== strpos($middle, '\\')) { + $this->pivotName = $middle; + $this->middle = class_basename($middle); } else { - $this->middle = $table; + $this->middle = $middle; } $this->query = (new $model)->db(); @@ -63,7 +83,7 @@ class BelongsToMany extends Relation * @param $pivot * @return $this */ - public function pivot($pivot) + public function pivot(string $pivot) { $this->pivotName = $pivot; return $this; @@ -75,43 +95,29 @@ class BelongsToMany extends Relation * @param string $name * @return $this */ - public function pivotDataName($name) + public function name(string $name) { $this->pivotDataName = $name; return $this; } - /** - * 获取中间表更新条件 - * @param $data - * @return array - */ - protected function getUpdateWhere($data) - { - return [ - $this->localKey => $data[$this->localKey], - $this->foreignKey => $data[$this->foreignKey], - ]; - } - /** * 实例化中间表模型 * @access public - * @param array $data - * @param bool $isUpdate + * @param $data * @return Pivot * @throws Exception */ - protected function newPivot($data = [], $isUpdate = false) + protected function newPivot(array $data = []): Pivot { - $class = $this->pivotName ?: '\\think\\model\\Pivot'; + $class = $this->pivotName ?: Pivot::class; $pivot = new $class($data, $this->parent, $this->middle); if ($pivot instanceof Pivot) { - return $isUpdate ? $pivot->isUpdate(true, $this->getUpdateWhere($data)) : $pivot; + return $pivot; + } else { + throw new Exception('pivot model must extends: \think\model\Pivot'); } - - throw new Exception('pivot model must extends: \think\model\Pivot'); } /** @@ -119,14 +125,14 @@ class BelongsToMany extends Relation * @access protected * @param array|Collection|Paginator $models */ - protected function hydratePivot($models) + protected function hydratePivot(iterable $models) { foreach ($models as $model) { $pivot = []; foreach ($model->getData() as $key => $val) { if (strpos($key, '__')) { - list($name, $attr) = explode('__', $key, 2); + [$name, $attr] = explode('__', $key, 2); if ('pivot' == $name) { $pivot[$attr] = $val; @@ -135,42 +141,27 @@ class BelongsToMany extends Relation } } - $model->setRelation($this->pivotDataName, $this->newPivot($pivot, true)); + $model->setRelation($this->pivotDataName, $this->newPivot($pivot)); } } - /** - * 创建关联查询Query对象 - * @access protected - * @return Query - */ - protected function buildQuery() - { - $foreignKey = $this->foreignKey; - $localKey = $this->localKey; - - // 关联查询 - $pk = $this->parent->getPk(); - - $condition[] = ['pivot.' . $localKey, '=', $this->parent->$pk]; - - return $this->belongsToManyQuery($foreignKey, $localKey, $condition); - } - /** * 延迟获取关联数据 * @access public - * @param string $subRelation 子关联名 - * @param \Closure $closure 闭包查询条件 + * @param array $subRelation 子关联名 + * @param Closure $closure 闭包查询条件 * @return Collection */ - public function getRelation($subRelation = '', $closure = null) + public function getRelation(array $subRelation = [], Closure $closure = null): Collection { if ($closure) { - $closure($this->query); + $closure($this->getClosureType($closure)); } - $result = $this->buildQuery()->relation($subRelation)->select(); + $result = $this->relation($subRelation) + ->select() + ->setParent(clone $this->parent); + $this->hydratePivot($result); return $result; @@ -182,9 +173,10 @@ class BelongsToMany extends Relation * @param mixed $data * @return Collection */ - public function select($data = null) + public function select($data = null): Collection { - $result = $this->buildQuery()->select($data); + $this->baseQuery(); + $result = $this->query->select($data); $this->hydratePivot($result); return $result; @@ -193,14 +185,14 @@ class BelongsToMany extends Relation /** * 重载paginate方法 * @access public - * @param null $listRows - * @param bool $simple - * @param array $config + * @param int|array $listRows + * @param int|bool $simple * @return Paginator */ - public function paginate($listRows = null, $simple = false, $config = []) + public function paginate($listRows = null, $simple = false): Paginator { - $result = $this->buildQuery()->paginate($listRows, $simple, $config); + $this->baseQuery(); + $result = $this->query->paginate($listRows, $simple); $this->hydratePivot($result); return $result; @@ -214,36 +206,16 @@ class BelongsToMany extends Relation */ public function find($data = null) { - $result = $this->buildQuery()->find($data); - if ($result) { + $this->baseQuery(); + $result = $this->query->find($data); + + if ($result && !$result->isEmpty()) { $this->hydratePivot([$result]); } return $result; } - /** - * 查找多条记录 如果不存在则抛出异常 - * @access public - * @param array|string|Query|\Closure $data - * @return Collection - */ - public function selectOrFail($data = null) - { - return $this->failException(true)->select($data); - } - - /** - * 查找单条记录 如果不存在则抛出异常 - * @access public - * @param array|string|Query|\Closure $data - * @return Model - */ - public function findOrFail($data = null) - { - return $this->failException(true)->find($data); - } - /** * 根据关联条件查询当前模型 * @access public @@ -251,9 +223,10 @@ class BelongsToMany extends Relation * @param integer $count 个数 * @param string $id 关联表的统计字段 * @param string $joinType JOIN类型 - * @return Query + * @param Query $query Query对象 + * @return Model */ - public function has($operator = '>=', $count = 1, $id = '*', $joinType = 'INNER') + public function has(string $operator = '>=', $count = 1, $id = '*', string $joinType = 'INNER', Query $query = null) { return $this->parent; } @@ -261,12 +234,14 @@ class BelongsToMany extends Relation /** * 根据关联条件查询当前模型 * @access public - * @param mixed $where 查询条件(数组或者闭包) - * @param mixed $fields 字段 + * @param mixed $where 查询条件(数组或者闭包) + * @param mixed $fields 字段 + * @param string $joinType JOIN类型 + * @param Query $query Query对象 * @return Query * @throws Exception */ - public function hasWhere($where = [], $fields = null) + public function hasWhere($where = [], $fields = null, string $joinType = '', Query $query = null) { throw new Exception('relation not support: hasWhere'); } @@ -274,9 +249,9 @@ class BelongsToMany extends Relation /** * 设置中间表的查询条件 * @access public - * @param string $field - * @param string $op - * @param mixed $condition + * @param string $field + * @param string $op + * @param mixed $condition * @return $this */ public function wherePivot($field, $op = null, $condition = null) @@ -288,19 +263,19 @@ class BelongsToMany extends Relation /** * 预载入关联查询(数据集) * @access public - * @param array $resultSet 数据集 - * @param string $relation 当前关联名 - * @param string $subRelation 子关联名 - * @param \Closure $closure 闭包 + * @param array $resultSet 数据集 + * @param string $relation 当前关联名 + * @param array $subRelation 子关联名 + * @param Closure $closure 闭包 + * @param array $cache 关联缓存 * @return void */ - public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure) + public function eagerlyResultSet(array &$resultSet, string $relation, array $subRelation, Closure $closure = null, array $cache = []): void { - $localKey = $this->localKey; - $foreignKey = $this->foreignKey; + $localKey = $this->localKey; + $pk = $resultSet[0]->getPk(); + $range = []; - $pk = $resultSet[0]->getPk(); - $range = []; foreach ($resultSet as $result) { // 获取关联外键列表 if (isset($result->$pk)) { @@ -312,10 +287,7 @@ class BelongsToMany extends Relation // 查询关联数据 $data = $this->eagerlyManyToMany([ ['pivot.' . $localKey, 'in', $range], - ], $relation, $subRelation, $closure); - - // 关联属性名 - $attr = Loader::parseName($relation); + ], $subRelation, $closure, $cache); // 关联数据封装 foreach ($resultSet as $result) { @@ -323,7 +295,7 @@ class BelongsToMany extends Relation $data[$result->$pk] = []; } - $result->setRelation($attr, $this->resultSetBuild($data[$result->$pk])); + $result->setRelation($relation, $this->resultSetBuild($data[$result->$pk], clone $this->parent)); } } } @@ -331,13 +303,14 @@ class BelongsToMany extends Relation /** * 预载入关联查询(单个数据) * @access public - * @param Model $result 数据对象 - * @param string $relation 当前关联名 - * @param string $subRelation 子关联名 - * @param \Closure $closure 闭包 + * @param Model $result 数据对象 + * @param string $relation 当前关联名 + * @param array $subRelation 子关联名 + * @param Closure $closure 闭包 + * @param array $cache 关联缓存 * @return void */ - public function eagerlyResult(&$result, $relation, $subRelation, $closure) + public function eagerlyResult(Model $result, string $relation, array $subRelation, Closure $closure = null, array $cache = []): void { $pk = $result->getPk(); @@ -346,28 +319,28 @@ class BelongsToMany extends Relation // 查询管理数据 $data = $this->eagerlyManyToMany([ ['pivot.' . $this->localKey, '=', $pk], - ], $relation, $subRelation, $closure); + ], $subRelation, $closure, $cache); // 关联数据封装 if (!isset($data[$pk])) { $data[$pk] = []; } - $result->setRelation(Loader::parseName($relation), $this->resultSetBuild($data[$pk])); + $result->setRelation($relation, $this->resultSetBuild($data[$pk], clone $this->parent)); } } /** * 关联统计 * @access public - * @param Model $result 数据对象 - * @param \Closure $closure 闭包 - * @param string $aggregate 聚合查询方法 - * @param string $field 字段 - * @param string $name 统计字段别名 + * @param Model $result 数据对象 + * @param Closure $closure 闭包 + * @param string $aggregate 聚合查询方法 + * @param string $field 字段 + * @param string $name 统计字段别名 * @return integer */ - public function relationCount($result, $closure, $aggregate = 'count', $field = '*', &$name = '') + public function relationCount(Model $result, Closure $closure = null, string $aggregate = 'count', string $field = '*', string &$name = null): float { $pk = $result->getPk(); @@ -378,11 +351,7 @@ class BelongsToMany extends Relation $pk = $result->$pk; if ($closure) { - $return = $closure($this->query); - - if ($return && is_string($return)) { - $name = $return; - } + $closure($this->getClosureType($closure), $name); } return $this->belongsToManyQuery($this->foreignKey, $this->localKey, [ @@ -393,25 +362,21 @@ class BelongsToMany extends Relation /** * 获取关联统计子查询 * @access public - * @param \Closure $closure 闭包 - * @param string $aggregate 聚合查询方法 - * @param string $field 字段 - * @param string $aggregateAlias 聚合字段别名 - * @return array + * @param Closure $closure 闭包 + * @param string $aggregate 聚合查询方法 + * @param string $field 字段 + * @param string $name 统计字段别名 + * @return string */ - public function getRelationCountQuery($closure, $aggregate = 'count', $field = '*', &$aggregateAlias = '') + public function getRelationCountQuery(Closure $closure = null, string $aggregate = 'count', string $field = '*', string &$name = null): string { if ($closure) { - $return = $closure($this->query); - - if ($return && is_string($return)) { - $aggregateAlias = $return; - } + $closure($this->getClosureType($closure), $name); } return $this->belongsToManyQuery($this->foreignKey, $this->localKey, [ [ - 'pivot.' . $this->localKey, 'exp', $this->query->raw('=' . $this->parent->getTable() . '.' . $this->parent->getPk()), + 'pivot.' . $this->localKey, 'exp', new Raw('=' . $this->parent->db(false)->getTable() . '.' . $this->parent->getPk()), ], ])->fetchSql()->$aggregate($field); } @@ -419,21 +384,22 @@ class BelongsToMany extends Relation /** * 多对多 关联模型预查询 * @access protected - * @param array $where 关联预查询条件 - * @param string $relation 关联名 - * @param string $subRelation 子关联 - * @param \Closure $closure 闭包 + * @param array $where 关联预查询条件 + * @param array $subRelation 子关联 + * @param Closure $closure 闭包 + * @param array $cache 关联缓存 * @return array */ - protected function eagerlyManyToMany($where, $relation, $subRelation = '', $closure = null) + protected function eagerlyManyToMany(array $where, array $subRelation = [], Closure $closure = null, array $cache = []): array { - // 预载入关联查询 支持嵌套预载入 if ($closure) { - $closure($this->query); + $closure($this->getClosureType($closure)); } + // 预载入关联查询 支持嵌套预载入 $list = $this->belongsToManyQuery($this->foreignKey, $this->localKey, $where) ->with($subRelation) + ->cache($cache[0] ?? false, $cache[1] ?? null, $cache[2] ?? null) ->select(); // 组装模型数据 @@ -442,17 +408,22 @@ class BelongsToMany extends Relation $pivot = []; foreach ($set->getData() as $key => $val) { if (strpos($key, '__')) { - list($name, $attr) = explode('__', $key, 2); + [$name, $attr] = explode('__', $key, 2); if ('pivot' == $name) { $pivot[$attr] = $val; unset($set->$key); } } } + $key = $pivot[$this->localKey]; - $set->setRelation($this->pivotDataName, $this->newPivot($pivot, true)); + if ($this->withLimit && isset($data[$key]) && count($data[$key]) >= $this->withLimit) { + continue; + } - $data[$pivot[$this->localKey]][] = $set; + $set->setRelation($this->pivotDataName, $this->newPivot($pivot)); + + $data[$key][] = $set; } return $data; @@ -461,29 +432,32 @@ class BelongsToMany extends Relation /** * BELONGS TO MANY 关联查询 * @access protected - * @param string $foreignKey 关联模型关联键 - * @param string $localKey 当前模型关联键 - * @param array $condition 关联查询条件 + * @param string $foreignKey 关联模型关联键 + * @param string $localKey 当前模型关联键 + * @param array $condition 关联查询条件 * @return Query */ - protected function belongsToManyQuery($foreignKey, $localKey, $condition = []) + protected function belongsToManyQuery(string $foreignKey, string $localKey, array $condition = []): Query { // 关联查询封装 - $tableName = $this->query->getTable(); - $table = $this->pivot->getTable(); - $fields = $this->getQueryFields($tableName); - - $query = $this->query - ->field($fields) - ->field(true, false, $table, 'pivot', 'pivot__'); - if (empty($this->baseQuery)) { - $relationFk = $this->query->getPk(); - $query->join([$table => 'pivot'], 'pivot.' . $foreignKey . '=' . $tableName . '.' . $relationFk) + $tableName = $this->query->getTable(); + $table = $this->pivot->db()->getTable(); + $fields = $this->getQueryFields($tableName); + + if ($this->withLimit) { + $this->query->limit($this->withLimit); + } + + $this->query + ->field($fields) + ->tableField(true, $table, 'pivot', 'pivot__') + ->join([$table => 'pivot'], 'pivot.' . $foreignKey . '=' . $tableName . '.' . $this->query->getPk()) ->where($condition); + } - return $query; + return $this->query; } /** @@ -502,18 +476,18 @@ class BelongsToMany extends Relation /** * 批量保存当前关联数据对象 * @access public - * @param array $dataSet 数据集 - * @param array $pivot 中间表额外数据 - * @param bool $samePivot 额外数据是否相同 + * @param iterable $dataSet 数据集 + * @param array $pivot 中间表额外数据 + * @param bool $samePivot 额外数据是否相同 * @return array|false */ - public function saveAll(array $dataSet, array $pivot = [], $samePivot = false) + public function saveAll(iterable $dataSet, array $pivot = [], bool $samePivot = false) { $result = []; foreach ($dataSet as $key => $data) { if (!$samePivot) { - $pivotData = isset($pivot[$key]) ? $pivot[$key] : []; + $pivotData = $pivot[$key] ?? []; } else { $pivotData = $pivot; } @@ -532,7 +506,7 @@ class BelongsToMany extends Relation * @return array|Pivot * @throws Exception */ - public function attach($data, $pivot = []) + public function attach($data, array $pivot = []) { if (is_array($data)) { if (key($data) === 0) { @@ -547,22 +521,21 @@ class BelongsToMany extends Relation $id = $data; } elseif ($data instanceof Model) { // 根据关联表主键直接写入中间表 - $relationFk = $data->getPk(); - $id = $data->$relationFk; + $id = $data->getKey(); } - if ($id) { + if (!empty($id)) { // 保存中间表数据 - $pk = $this->parent->getPk(); - $pivot[$this->localKey] = $this->parent->$pk; - $ids = (array) $id; + $pivot[$this->localKey] = $this->parent->getKey(); + $ids = (array) $id; foreach ($ids as $id) { $pivot[$this->foreignKey] = $id; $this->pivot->replace() ->exists(false) + ->data([]) ->save($pivot); - $result[] = $this->newPivot($pivot, true); + $result[] = $this->newPivot($pivot); } if (count($result) == 1) { @@ -579,9 +552,8 @@ class BelongsToMany extends Relation /** * 判断是否存在关联数据 * @access public - * @param mixed $data 数据 可以使用关联模型对象 或者 关联对象的主键 - * @return Pivot - * @throws Exception + * @param mixed $data 数据 可以使用关联模型对象 或者 关联对象的主键 + * @return Pivot|false */ public function attached($data) { @@ -606,7 +578,7 @@ class BelongsToMany extends Relation * @param bool $relationDel 是否同时删除关联表数据 * @return integer */ - public function detach($data = null, $relationDel = false) + public function detach($data = null, bool $relationDel = false): int { if (is_array($data)) { $id = $data; @@ -615,13 +587,12 @@ class BelongsToMany extends Relation $id = $data; } elseif ($data instanceof Model) { // 根据关联表主键直接写入中间表 - $relationFk = $data->getPk(); - $id = $data->$relationFk; + $id = $data->getKey(); } // 删除中间表数据 - $pk = $this->parent->getPk(); - $pivot[] = [$this->localKey, '=', $this->parent->$pk]; + $pivot = []; + $pivot[] = [$this->localKey, '=', $this->parent->getKey()]; if (isset($id)) { $pivot[] = [$this->foreignKey, is_array($id) ? 'in' : '=', $id]; @@ -645,7 +616,7 @@ class BelongsToMany extends Relation * @param bool $detaching * @return array */ - public function sync($ids, $detaching = true) + public function sync(array $ids, bool $detaching = true): array { $changes = [ 'attached' => [], @@ -653,10 +624,8 @@ class BelongsToMany extends Relation 'updated' => [], ]; - $pk = $this->parent->getPk(); - $current = $this->pivot - ->where($this->localKey, $this->parent->$pk) + ->where($this->localKey, $this->parent->getKey()) ->column($this->foreignKey); $records = []; @@ -693,15 +662,21 @@ class BelongsToMany extends Relation * @access protected * @return void */ - protected function baseQuery() + protected function baseQuery(): void { - if (empty($this->baseQuery) && $this->parent->getData()) { - $pk = $this->parent->getPk(); - $table = $this->pivot->getTable(); + if (empty($this->baseQuery)) { + $foreignKey = $this->foreignKey; + $localKey = $this->localKey; + + // 关联查询 + if (null === $this->parent->getKey()) { + $condition = ['pivot.' . $localKey, 'exp', new Raw('=' . $this->parent->getTable() . '.' . $this->parent->getPk())]; + } else { + $condition = ['pivot.' . $localKey, '=', $this->parent->getKey()]; + } + + $this->belongsToManyQuery($foreignKey, $localKey, [$condition]); - $this->query - ->join([$table => 'pivot'], 'pivot.' . $this->foreignKey . '=' . $this->query->getTable() . '.' . $this->query->getPk()) - ->where('pivot.' . $this->localKey, $this->parent->$pk); $this->baseQuery = true; } } diff --git a/vendor/topthink/think-orm/src/model/relation/HasMany.php b/vendor/topthink/think-orm/src/model/relation/HasMany.php new file mode 100644 index 000000000..a67d41b03 --- /dev/null +++ b/vendor/topthink/think-orm/src/model/relation/HasMany.php @@ -0,0 +1,367 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\model\relation; + +use Closure; +use think\Collection; +use think\db\BaseQuery as Query; +use think\helper\Str; +use think\Model; +use think\model\Relation; + +/** + * 一对多关联类 + */ +class HasMany extends Relation +{ + /** + * 架构函数 + * @access public + * @param Model $parent 上级模型对象 + * @param string $model 模型名 + * @param string $foreignKey 关联外键 + * @param string $localKey 当前模型主键 + */ + public function __construct(Model $parent, string $model, string $foreignKey, string $localKey) + { + $this->parent = $parent; + $this->model = $model; + $this->foreignKey = $foreignKey; + $this->localKey = $localKey; + $this->query = (new $model)->db(); + + if (get_class($parent) == $model) { + $this->selfRelation = true; + } + } + + /** + * 延迟获取关联数据 + * @access public + * @param array $subRelation 子关联名 + * @param Closure $closure 闭包查询条件 + * @return Collection + */ + public function getRelation(array $subRelation = [], Closure $closure = null): Collection + { + if ($closure) { + $closure($this->getClosureType($closure)); + } + + if ($this->withLimit) { + $this->query->limit($this->withLimit); + } + + return $this->query + ->where($this->foreignKey, $this->parent->{$this->localKey}) + ->relation($subRelation) + ->select() + ->setParent(clone $this->parent); + } + + /** + * 预载入关联查询 + * @access public + * @param array $resultSet 数据集 + * @param string $relation 当前关联名 + * @param array $subRelation 子关联名 + * @param Closure $closure 闭包 + * @param array $cache 关联缓存 + * @return void + */ + public function eagerlyResultSet(array &$resultSet, string $relation, array $subRelation, Closure $closure = null, array $cache = []): void + { + $localKey = $this->localKey; + $range = []; + + foreach ($resultSet as $result) { + // 获取关联外键列表 + if (isset($result->$localKey)) { + $range[] = $result->$localKey; + } + } + + if (!empty($range)) { + $data = $this->eagerlyOneToMany([ + [$this->foreignKey, 'in', $range], + ], $subRelation, $closure, $cache); + + // 关联数据封装 + foreach ($resultSet as $result) { + $pk = $result->$localKey; + if (!isset($data[$pk])) { + $data[$pk] = []; + } + + $result->setRelation($relation, $this->resultSetBuild($data[$pk], clone $this->parent)); + } + } + } + + /** + * 预载入关联查询 + * @access public + * @param Model $result 数据对象 + * @param string $relation 当前关联名 + * @param array $subRelation 子关联名 + * @param Closure $closure 闭包 + * @param array $cache 关联缓存 + * @return void + */ + public function eagerlyResult(Model $result, string $relation, array $subRelation = [], Closure $closure = null, array $cache = []): void + { + $localKey = $this->localKey; + + if (isset($result->$localKey)) { + $pk = $result->$localKey; + $data = $this->eagerlyOneToMany([ + [$this->foreignKey, '=', $pk], + ], $subRelation, $closure, $cache); + + // 关联数据封装 + if (!isset($data[$pk])) { + $data[$pk] = []; + } + + $result->setRelation($relation, $this->resultSetBuild($data[$pk], clone $this->parent)); + } + } + + /** + * 关联统计 + * @access public + * @param Model $result 数据对象 + * @param Closure $closure 闭包 + * @param string $aggregate 聚合查询方法 + * @param string $field 字段 + * @param string $name 统计字段别名 + * @return integer + */ + public function relationCount(Model $result, Closure $closure = null, string $aggregate = 'count', string $field = '*', string &$name = null) + { + $localKey = $this->localKey; + + if (!isset($result->$localKey)) { + return 0; + } + + if ($closure) { + $closure($this->getClosureType($closure), $name); + } + + return $this->query + ->where($this->foreignKey, '=', $result->$localKey) + ->$aggregate($field); + } + + /** + * 创建关联统计子查询 + * @access public + * @param Closure $closure 闭包 + * @param string $aggregate 聚合查询方法 + * @param string $field 字段 + * @param string $name 统计字段别名 + * @return string + */ + public function getRelationCountQuery(Closure $closure = null, string $aggregate = 'count', string $field = '*', string &$name = null): string + { + if ($closure) { + $closure($this->getClosureType($closure), $name); + } + + return $this->query->alias($aggregate . '_table') + ->whereExp($aggregate . '_table.' . $this->foreignKey, '=' . $this->parent->getTable() . '.' . $this->localKey) + ->fetchSql() + ->$aggregate($field); + } + + /** + * 一对多 关联模型预查询 + * @access public + * @param array $where 关联预查询条件 + * @param array $subRelation 子关联 + * @param Closure $closure + * @param array $cache 关联缓存 + * @return array + */ + protected function eagerlyOneToMany(array $where, array $subRelation = [], Closure $closure = null, array $cache = []): array + { + $foreignKey = $this->foreignKey; + + $this->query->removeWhereField($this->foreignKey); + + // 预载入关联查询 支持嵌套预载入 + if ($closure) { + $this->baseQuery = true; + $closure($this->getClosureType($closure)); + } + + $list = $this->query + ->where($where) + ->cache($cache[0] ?? false, $cache[1] ?? null, $cache[2] ?? null) + ->with($subRelation) + ->select(); + + // 组装模型数据 + $data = []; + + foreach ($list as $set) { + $key = $set->$foreignKey; + + if ($this->withLimit && isset($data[$key]) && count($data[$key]) >= $this->withLimit) { + continue; + } + + $data[$key][] = $set; + } + + return $data; + } + + /** + * 保存(新增)当前关联数据对象 + * @access public + * @param mixed $data 数据 可以使用数组 关联模型对象 + * @param boolean $replace 是否自动识别更新和写入 + * @return Model|false + */ + public function save($data, bool $replace = true) + { + $model = $this->make(); + + return $model->replace($replace)->save($data) ? $model : false; + } + + /** + * 创建关联对象实例 + * @param array|Model $data + * @return Model + */ + public function make($data = []): Model + { + if ($data instanceof Model) { + $data = $data->getData(); + } + + // 保存关联表数据 + $data[$this->foreignKey] = $this->parent->{$this->localKey}; + + return new $this->model($data); + } + + /** + * 批量保存当前关联数据对象 + * @access public + * @param iterable $dataSet 数据集 + * @param boolean $replace 是否自动识别更新和写入 + * @return array|false + */ + public function saveAll(iterable $dataSet, bool $replace = true) + { + $result = []; + + foreach ($dataSet as $key => $data) { + $result[] = $this->save($data, $replace); + } + + return empty($result) ? false : $result; + } + + /** + * 根据关联条件查询当前模型 + * @access public + * @param string $operator 比较操作符 + * @param integer $count 个数 + * @param string $id 关联表的统计字段 + * @param string $joinType JOIN类型 + * @param Query $query Query对象 + * @return Query + */ + public function has(string $operator = '>=', int $count = 1, string $id = '*', string $joinType = 'INNER', Query $query = null): Query + { + $table = $this->query->getTable(); + + $model = class_basename($this->parent); + $relation = class_basename($this->model); + + if ('*' != $id) { + $id = $relation . '.' . (new $this->model)->getPk(); + } + + $softDelete = $this->query->getOptions('soft_delete'); + $query = $query ?: $this->parent->db()->alias($model); + + return $query->field($model . '.*') + ->join([$table => $relation], $model . '.' . $this->localKey . '=' . $relation . '.' . $this->foreignKey, $joinType) + ->when($softDelete, function ($query) use ($softDelete, $relation) { + $query->where($relation . strstr($softDelete[0], '.'), '=' == $softDelete[1][0] ? $softDelete[1][1] : null); + }) + ->group($relation . '.' . $this->foreignKey) + ->having('count(' . $id . ')' . $operator . $count); + } + + /** + * 根据关联条件查询当前模型 + * @access public + * @param mixed $where 查询条件(数组或者闭包) + * @param mixed $fields 字段 + * @param string $joinType JOIN类型 + * @param Query $query Query对象 + * @return Query + */ + public function hasWhere($where = [], $fields = null, string $joinType = '', Query $query = null): Query + { + $table = $this->query->getTable(); + $model = class_basename($this->parent); + $relation = class_basename($this->model); + + if (is_array($where)) { + $this->getQueryWhere($where, $relation); + } elseif ($where instanceof Query) { + $where->via($relation); + } elseif ($where instanceof Closure) { + $where($this->query->via($relation)); + $where = $this->query; + } + + $fields = $this->getRelationQueryFields($fields, $model); + $softDelete = $this->query->getOptions('soft_delete'); + $query = $query ?: $this->parent->db()->alias($model); + + return $query->group($model . '.' . $this->localKey) + ->field($fields) + ->join([$table => $relation], $model . '.' . $this->localKey . '=' . $relation . '.' . $this->foreignKey, $joinType) + ->when($softDelete, function ($query) use ($softDelete, $relation) { + $query->where($relation . strstr($softDelete[0], '.'), '=' == $softDelete[1][0] ? $softDelete[1][1] : null); + }) + ->where($where); + } + + /** + * 执行基础查询(仅执行一次) + * @access protected + * @return void + */ + protected function baseQuery(): void + { + if (empty($this->baseQuery)) { + if (isset($this->parent->{$this->localKey})) { + // 关联查询带入关联条件 + $this->query->where($this->foreignKey, '=', $this->parent->{$this->localKey}); + } + + $this->baseQuery = true; + } + } + +} diff --git a/vendor/topthink/think-orm/src/model/relation/HasManyThrough.php b/vendor/topthink/think-orm/src/model/relation/HasManyThrough.php new file mode 100644 index 000000000..30d5ca41c --- /dev/null +++ b/vendor/topthink/think-orm/src/model/relation/HasManyThrough.php @@ -0,0 +1,382 @@ + +// +---------------------------------------------------------------------- + +namespace think\model\relation; + +use Closure; +use think\Collection; +use think\db\BaseQuery as Query; +use think\helper\Str; +use think\Model; +use think\model\Relation; + +/** + * 远程一对多关联类 + */ +class HasManyThrough extends Relation +{ + /** + * 中间关联表外键 + * @var string + */ + protected $throughKey; + + /** + * 中间主键 + * @var string + */ + protected $throughPk; + + /** + * 中间表查询对象 + * @var Query + */ + protected $through; + + /** + * 架构函数 + * @access public + * @param Model $parent 上级模型对象 + * @param string $model 关联模型名 + * @param string $through 中间模型名 + * @param string $foreignKey 关联外键 + * @param string $throughKey 中间关联外键 + * @param string $localKey 当前模型主键 + * @param string $throughPk 中间模型主键 + */ + public function __construct(Model $parent, string $model, string $through, string $foreignKey, string $throughKey, string $localKey, string $throughPk) + { + $this->parent = $parent; + $this->model = $model; + $this->through = (new $through)->db(); + $this->foreignKey = $foreignKey; + $this->throughKey = $throughKey; + $this->localKey = $localKey; + $this->throughPk = $throughPk; + $this->query = (new $model)->db(); + } + + /** + * 延迟获取关联数据 + * @access public + * @param array $subRelation 子关联名 + * @param Closure $closure 闭包查询条件 + * @return Collection + */ + public function getRelation(array $subRelation = [], Closure $closure = null) + { + if ($closure) { + $closure($this->getClosureType($closure)); + } + + $this->baseQuery(); + + if ($this->withLimit) { + $this->query->limit($this->withLimit); + } + + return $this->query->relation($subRelation) + ->select() + ->setParent(clone $this->parent); + } + + /** + * 根据关联条件查询当前模型 + * @access public + * @param string $operator 比较操作符 + * @param integer $count 个数 + * @param string $id 关联表的统计字段 + * @param string $joinType JOIN类型 + * @param Query $query Query对象 + * @return Query + */ + public function has(string $operator = '>=', int $count = 1, string $id = '*', string $joinType = '', Query $query = null): Query + { + $model = Str::snake(class_basename($this->parent)); + $throughTable = $this->through->getTable(); + $pk = $this->throughPk; + $throughKey = $this->throughKey; + $relation = new $this->model; + $relationTable = $relation->getTable(); + $softDelete = $this->query->getOptions('soft_delete'); + + if ('*' != $id) { + $id = $relationTable . '.' . $relation->getPk(); + } + $query = $query ?: $this->parent->db()->alias($model); + + return $query->field($model . '.*') + ->join($throughTable, $throughTable . '.' . $this->foreignKey . '=' . $model . '.' . $this->localKey) + ->join($relationTable, $relationTable . '.' . $throughKey . '=' . $throughTable . '.' . $this->throughPk) + ->when($softDelete, function ($query) use ($softDelete, $relationTable) { + $query->where($relationTable . strstr($softDelete[0], '.'), '=' == $softDelete[1][0] ? $softDelete[1][1] : null); + }) + ->group($relationTable . '.' . $this->throughKey) + ->having('count(' . $id . ')' . $operator . $count); + } + + /** + * 根据关联条件查询当前模型 + * @access public + * @param mixed $where 查询条件(数组或者闭包) + * @param mixed $fields 字段 + * @param string $joinType JOIN类型 + * @param Query $query Query对象 + * @return Query + */ + public function hasWhere($where = [], $fields = null, $joinType = '', Query $query = null): Query + { + $model = Str::snake(class_basename($this->parent)); + $throughTable = $this->through->getTable(); + $pk = $this->throughPk; + $throughKey = $this->throughKey; + $modelTable = (new $this->model)->getTable(); + + if (is_array($where)) { + $this->getQueryWhere($where, $modelTable); + } elseif ($where instanceof Query) { + $where->via($modelTable); + } elseif ($where instanceof Closure) { + $where($this->query->via($modelTable)); + $where = $this->query; + } + + $fields = $this->getRelationQueryFields($fields, $model); + $softDelete = $this->query->getOptions('soft_delete'); + $query = $query ?: $this->parent->db()->alias($model); + + return $query->join($throughTable, $throughTable . '.' . $this->foreignKey . '=' . $model . '.' . $this->localKey) + ->join($modelTable, $modelTable . '.' . $throughKey . '=' . $throughTable . '.' . $this->throughPk, $joinType) + ->when($softDelete, function ($query) use ($softDelete, $modelTable) { + $query->where($modelTable . strstr($softDelete[0], '.'), '=' == $softDelete[1][0] ? $softDelete[1][1] : null); + }) + ->group($modelTable . '.' . $this->throughKey) + ->where($where) + ->field($fields); + } + + /** + * 预载入关联查询(数据集) + * @access protected + * @param array $resultSet 数据集 + * @param string $relation 当前关联名 + * @param array $subRelation 子关联名 + * @param Closure $closure 闭包 + * @param array $cache 关联缓存 + * @return void + */ + public function eagerlyResultSet(array &$resultSet, string $relation, array $subRelation = [], Closure $closure = null, array $cache = []): void + { + $localKey = $this->localKey; + $foreignKey = $this->foreignKey; + + $range = []; + foreach ($resultSet as $result) { + // 获取关联外键列表 + if (isset($result->$localKey)) { + $range[] = $result->$localKey; + } + } + + if (!empty($range)) { + $this->query->removeWhereField($foreignKey); + + $data = $this->eagerlyWhere([ + [$this->foreignKey, 'in', $range], + ], $foreignKey, $subRelation, $closure, $cache); + + // 关联数据封装 + foreach ($resultSet as $result) { + $pk = $result->$localKey; + if (!isset($data[$pk])) { + $data[$pk] = []; + } + + // 设置关联属性 + $result->setRelation($relation, $this->resultSetBuild($data[$pk], clone $this->parent)); + } + } + } + + /** + * 预载入关联查询(数据) + * @access protected + * @param Model $result 数据对象 + * @param string $relation 当前关联名 + * @param array $subRelation 子关联名 + * @param Closure $closure 闭包 + * @param array $cache 关联缓存 + * @return void + */ + public function eagerlyResult(Model $result, string $relation, array $subRelation = [], Closure $closure = null, array $cache = []): void + { + $localKey = $this->localKey; + $foreignKey = $this->foreignKey; + $pk = $result->$localKey; + + $this->query->removeWhereField($foreignKey); + + $data = $this->eagerlyWhere([ + [$foreignKey, '=', $pk], + ], $foreignKey, $subRelation, $closure, $cache); + + // 关联数据封装 + if (!isset($data[$pk])) { + $data[$pk] = []; + } + + $result->setRelation($relation, $this->resultSetBuild($data[$pk], clone $this->parent)); + } + + /** + * 关联模型预查询 + * @access public + * @param array $where 关联预查询条件 + * @param string $key 关联键名 + * @param array $subRelation 子关联 + * @param Closure $closure + * @param array $cache 关联缓存 + * @return array + */ + protected function eagerlyWhere(array $where, string $key, array $subRelation = [], Closure $closure = null, array $cache = []): array + { + // 预载入关联查询 支持嵌套预载入 + $throughList = $this->through->where($where)->select(); + $keys = $throughList->column($this->throughPk, $this->throughPk); + + if ($closure) { + $this->baseQuery = true; + $closure($this->getClosureType($closure)); + } + + $list = $this->query + ->where($this->throughKey, 'in', $keys) + ->cache($cache[0] ?? false, $cache[1] ?? null, $cache[2] ?? null) + ->select(); + + // 组装模型数据 + $data = []; + $keys = $throughList->column($this->foreignKey, $this->throughPk); + + foreach ($list as $set) { + $key = $keys[$set->{$this->throughKey}]; + + if ($this->withLimit && isset($data[$key]) && count($data[$key]) >= $this->withLimit) { + continue; + } + + $data[$key][] = $set; + } + + return $data; + } + + /** + * 关联统计 + * @access public + * @param Model $result 数据对象 + * @param Closure $closure 闭包 + * @param string $aggregate 聚合查询方法 + * @param string $field 字段 + * @param string $name 统计字段别名 + * @return mixed + */ + public function relationCount(Model $result, Closure $closure = null, string $aggregate = 'count', string $field = '*', string &$name = null) + { + $localKey = $this->localKey; + + if (!isset($result->$localKey)) { + return 0; + } + + if ($closure) { + $closure($this->getClosureType($closure), $name); + } + + $alias = Str::snake(class_basename($this->model)); + $throughTable = $this->through->getTable(); + $pk = $this->throughPk; + $throughKey = $this->throughKey; + $modelTable = $this->parent->getTable(); + + if (false === strpos($field, '.')) { + $field = $alias . '.' . $field; + } + + return $this->query + ->alias($alias) + ->join($throughTable, $throughTable . '.' . $pk . '=' . $alias . '.' . $throughKey) + ->join($modelTable, $modelTable . '.' . $this->localKey . '=' . $throughTable . '.' . $this->foreignKey) + ->where($throughTable . '.' . $this->foreignKey, $result->$localKey) + ->$aggregate($field); + } + + /** + * 创建关联统计子查询 + * @access public + * @param Closure $closure 闭包 + * @param string $aggregate 聚合查询方法 + * @param string $field 字段 + * @param string $name 统计字段别名 + * @return string + */ + public function getRelationCountQuery(Closure $closure = null, string $aggregate = 'count', string $field = '*', string &$name = null): string + { + if ($closure) { + $closure($this->getClosureType($closure), $name); + } + + $alias = Str::snake(class_basename($this->model)); + $throughTable = $this->through->getTable(); + $pk = $this->throughPk; + $throughKey = $this->throughKey; + $modelTable = $this->parent->getTable(); + + if (false === strpos($field, '.')) { + $field = $alias . '.' . $field; + } + + return $this->query + ->alias($alias) + ->join($throughTable, $throughTable . '.' . $pk . '=' . $alias . '.' . $throughKey) + ->join($modelTable, $modelTable . '.' . $this->localKey . '=' . $throughTable . '.' . $this->foreignKey) + ->whereExp($throughTable . '.' . $this->foreignKey, '=' . $this->parent->getTable() . '.' . $this->localKey) + ->fetchSql() + ->$aggregate($field); + } + + /** + * 执行基础查询(仅执行一次) + * @access protected + * @return void + */ + protected function baseQuery(): void + { + if (empty($this->baseQuery) && $this->parent->getData()) { + $alias = Str::snake(class_basename($this->model)); + $throughTable = $this->through->getTable(); + $pk = $this->throughPk; + $throughKey = $this->throughKey; + $modelTable = $this->parent->getTable(); + $fields = $this->getQueryFields($alias); + + $this->query + ->field($fields) + ->alias($alias) + ->join($throughTable, $throughTable . '.' . $pk . '=' . $alias . '.' . $throughKey) + ->join($modelTable, $modelTable . '.' . $this->localKey . '=' . $throughTable . '.' . $this->foreignKey) + ->where($throughTable . '.' . $this->foreignKey, $this->parent->{$this->localKey}); + + $this->baseQuery = true; + } + } + +} diff --git a/thinkphp/library/think/model/relation/HasOne.php b/vendor/topthink/think-orm/src/model/relation/HasOne.php old mode 100755 new mode 100644 similarity index 52% rename from thinkphp/library/think/model/relation/HasOne.php rename to vendor/topthink/think-orm/src/model/relation/HasOne.php index d8e3ec798..7fcd20a03 --- a/thinkphp/library/think/model/relation/HasOne.php +++ b/vendor/topthink/think-orm/src/model/relation/HasOne.php @@ -2,19 +2,24 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think\model\relation; -use think\db\Query; -use think\Loader; +use Closure; +use think\db\BaseQuery as Query; +use think\helper\Str; use think\Model; +/** + * HasOne 关联类 + */ class HasOne extends OneToOne { /** @@ -25,13 +30,12 @@ class HasOne extends OneToOne * @param string $foreignKey 关联外键 * @param string $localKey 当前模型主键 */ - public function __construct(Model $parent, $model, $foreignKey, $localKey) + public function __construct(Model $parent, string $model, string $foreignKey, string $localKey) { $this->parent = $parent; $this->model = $model; $this->foreignKey = $foreignKey; $this->localKey = $localKey; - $this->joinType = 'INNER'; $this->query = (new $model)->db(); if (get_class($parent) == $model) { @@ -42,16 +46,16 @@ class HasOne extends OneToOne /** * 延迟获取关联数据 * @access public - * @param string $subRelation 子关联名 - * @param \Closure $closure 闭包查询条件 + * @param array $subRelation 子关联名 + * @param Closure $closure 闭包查询条件 * @return Model */ - public function getRelation($subRelation = '', $closure = null) + public function getRelation(array $subRelation = [], Closure $closure = null) { $localKey = $this->localKey; if ($closure) { - $closure($this->query); + $closure($this->getClosureType($closure)); } // 判断关联类型执行查询 @@ -62,6 +66,11 @@ class HasOne extends OneToOne ->find(); if ($relationModel) { + if (!empty($this->bindAttr)) { + // 绑定关联属性 + $this->bindAttr($this->parent, $relationModel); + } + $relationModel->setParent(clone $this->parent); } @@ -71,20 +80,16 @@ class HasOne extends OneToOne /** * 创建关联统计子查询 * @access public - * @param \Closure $closure 闭包 - * @param string $aggregate 聚合查询方法 - * @param string $field 字段 - * @param string $aggregateAlias 聚合字段别名 + * @param Closure $closure 闭包 + * @param string $aggregate 聚合查询方法 + * @param string $field 字段 + * @param string $name 统计字段别名 * @return string */ - public function getRelationCountQuery($closure, $aggregate = 'count', $field = '*', &$aggregateAlias = '') + public function getRelationCountQuery(Closure $closure = null, string $aggregate = 'count', string $field = '*', string &$name = null): string { if ($closure) { - $return = $closure($this->query); - - if ($return && is_string($return)) { - $aggregateAlias = $return; - } + $closure($this->getClosureType($closure), $name); } return $this->query @@ -96,14 +101,14 @@ class HasOne extends OneToOne /** * 关联统计 * @access public - * @param Model $result 数据对象 - * @param \Closure $closure 闭包 - * @param string $aggregate 聚合查询方法 - * @param string $field 字段 - * @param string $name 统计字段别名 + * @param Model $result 数据对象 + * @param Closure $closure 闭包 + * @param string $aggregate 聚合查询方法 + * @param string $field 字段 + * @param string $name 统计字段别名 * @return integer */ - public function relationCount($result, $closure, $aggregate = 'count', $field = '*', &$name = '') + public function relationCount(Model $result, Closure $closure = null, string $aggregate = 'count', string $field = '*', string &$name = null) { $localKey = $this->localKey; @@ -112,10 +117,7 @@ class HasOne extends OneToOne } if ($closure) { - $return = $closure($this->query); - if ($return && is_string($return)) { - $name = $return; - } + $closure($this->getClosureType($closure), $name); } return $this->query @@ -130,61 +132,76 @@ class HasOne extends OneToOne * @param integer $count 个数 * @param string $id 关联表的统计字段 * @param string $joinType JOIN类型 + * @param Query $query Query对象 * @return Query */ - public function has($operator = '>=', $count = 1, $id = '*', $joinType = 'INNER') + public function has(string $operator = '>=', int $count = 1, string $id = '*', string $joinType = '', Query $query = null): Query { $table = $this->query->getTable(); - $model = basename(str_replace('\\', '/', get_class($this->parent))); - $relation = basename(str_replace('\\', '/', $this->model)); + $model = class_basename($this->parent); + $relation = class_basename($this->model); $localKey = $this->localKey; $foreignKey = $this->foreignKey; + $softDelete = $this->query->getOptions('soft_delete'); + $query = $query ?: $this->parent->db()->alias($model); - return $this->parent->db() - ->alias($model) - ->whereExists(function ($query) use ($table, $model, $relation, $localKey, $foreignKey) { - $query->table([$table => $relation]) - ->field($relation . '.' . $foreignKey) - ->whereExp($model . '.' . $localKey, '=' . $relation . '.' . $foreignKey); - }); + return $query->whereExists(function ($query) use ($table, $model, $relation, $localKey, $foreignKey, $softDelete) { + $query->table([$table => $relation]) + ->field($relation . '.' . $foreignKey) + ->whereExp($model . '.' . $localKey, '=' . $relation . '.' . $foreignKey) + ->when($softDelete, function ($query) use ($softDelete, $relation) { + $query->where($relation . strstr($softDelete[0], '.'), '=' == $softDelete[1][0] ? $softDelete[1][1] : null); + }); + }); } /** * 根据关联条件查询当前模型 * @access public - * @param mixed $where 查询条件(数组或者闭包) - * @param mixed $fields 字段 + * @param mixed $where 查询条件(数组或者闭包) + * @param mixed $fields 字段 + * @param string $joinType JOIN类型 + * @param Query $query Query对象 * @return Query */ - public function hasWhere($where = [], $fields = null) + public function hasWhere($where = [], $fields = null, string $joinType = '', Query $query = null): Query { $table = $this->query->getTable(); - $model = basename(str_replace('\\', '/', get_class($this->parent))); - $relation = basename(str_replace('\\', '/', $this->model)); + $model = class_basename($this->parent); + $relation = class_basename($this->model); if (is_array($where)) { $this->getQueryWhere($where, $relation); + } elseif ($where instanceof Query) { + $where->via($relation); + } elseif ($where instanceof Closure) { + $where($this->query->via($relation)); + $where = $this->query; } - $fields = $this->getRelationQueryFields($fields, $model); + $fields = $this->getRelationQueryFields($fields, $model); + $softDelete = $this->query->getOptions('soft_delete'); + $query = $query ? $query->alias($model) : $this->parent->db()->alias($model); - return $this->parent->db() - ->alias($model) - ->field($fields) - ->join([$table => $relation], $model . '.' . $this->localKey . '=' . $relation . '.' . $this->foreignKey, $this->joinType) + return $query->field($fields) + ->join([$table => $relation], $model . '.' . $this->localKey . '=' . $relation . '.' . $this->foreignKey, $joinType ?: $this->joinType) + ->when($softDelete, function ($query) use ($softDelete, $relation) { + $query->where($relation . strstr($softDelete[0], '.'), '=' == $softDelete[1][0] ? $softDelete[1][1] : null); + }) ->where($where); } /** * 预载入关联查询(数据集) * @access protected - * @param array $resultSet 数据集 - * @param string $relation 当前关联名 - * @param string $subRelation 子关联名 - * @param \Closure $closure 闭包 + * @param array $resultSet 数据集 + * @param string $relation 当前关联名 + * @param array $subRelation 子关联名 + * @param Closure $closure 闭包 + * @param array $cache 关联缓存 * @return void */ - protected function eagerlySet(&$resultSet, $relation, $subRelation, $closure) + protected function eagerlySet(array &$resultSet, string $relation, array $subRelation = [], Closure $closure = null, array $cache = []): void { $localKey = $this->localKey; $foreignKey = $this->foreignKey; @@ -202,10 +219,7 @@ class HasOne extends OneToOne $data = $this->eagerlyWhere([ [$foreignKey, 'in', $range], - ], $foreignKey, $relation, $subRelation, $closure); - - // 关联属性名 - $attr = Loader::parseName($relation); + ], $foreignKey, $subRelation, $closure, $cache); // 关联数据封装 foreach ($resultSet as $result) { @@ -215,15 +229,15 @@ class HasOne extends OneToOne } else { $relationModel = $data[$result->$localKey]; $relationModel->setParent(clone $result); - $relationModel->isUpdate(true); + $relationModel->exists(true); } if (!empty($this->bindAttr)) { // 绑定关联属性 - $this->bindAttr($relationModel, $result, $this->bindAttr); + $this->bindAttr($result, $relationModel); } else { // 设置关联属性 - $result->setRelation($attr, $relationModel); + $result->setRelation($relation, $relationModel); } } } @@ -232,13 +246,14 @@ class HasOne extends OneToOne /** * 预载入关联查询(数据) * @access protected - * @param Model $result 数据对象 - * @param string $relation 当前关联名 - * @param string $subRelation 子关联名 - * @param \Closure $closure 闭包 + * @param Model $result 数据对象 + * @param string $relation 当前关联名 + * @param array $subRelation 子关联名 + * @param Closure $closure 闭包 + * @param array $cache 关联缓存 * @return void */ - protected function eagerlyOne(&$result, $relation, $subRelation, $closure) + protected function eagerlyOne(Model $result, string $relation, array $subRelation = [], Closure $closure = null, array $cache = []): void { $localKey = $this->localKey; $foreignKey = $this->foreignKey; @@ -247,7 +262,7 @@ class HasOne extends OneToOne $data = $this->eagerlyWhere([ [$foreignKey, '=', $result->$localKey], - ], $foreignKey, $relation, $subRelation, $closure); + ], $foreignKey, $subRelation, $closure, $cache); // 关联模型 if (!isset($data[$result->$localKey])) { @@ -255,14 +270,14 @@ class HasOne extends OneToOne } else { $relationModel = $data[$result->$localKey]; $relationModel->setParent(clone $result); - $relationModel->isUpdate(true); + $relationModel->exists(true); } if (!empty($this->bindAttr)) { // 绑定关联属性 - $this->bindAttr($relationModel, $result, $this->bindAttr); + $this->bindAttr($result, $relationModel); } else { - $result->setRelation(Loader::parseName($relation), $relationModel); + $result->setRelation($relation, $relationModel); } } @@ -271,7 +286,7 @@ class HasOne extends OneToOne * @access protected * @return void */ - protected function baseQuery() + protected function baseQuery(): void { if (empty($this->baseQuery)) { if (isset($this->parent->{$this->localKey})) { diff --git a/vendor/topthink/think-orm/src/model/relation/HasOneThrough.php b/vendor/topthink/think-orm/src/model/relation/HasOneThrough.php new file mode 100644 index 000000000..8ec42df47 --- /dev/null +++ b/vendor/topthink/think-orm/src/model/relation/HasOneThrough.php @@ -0,0 +1,163 @@ + +// +---------------------------------------------------------------------- + +namespace think\model\relation; + +use Closure; +use think\helper\Str; +use think\Model; + +/** + * 远程一对一关联类 + */ +class HasOneThrough extends HasManyThrough +{ + + /** + * 延迟获取关联数据 + * @access public + * @param array $subRelation 子关联名 + * @param Closure $closure 闭包查询条件 + * @return Model + */ + public function getRelation(array $subRelation = [], Closure $closure = null) + { + if ($closure) { + $closure($this->getClosureType($closure)); + } + + $this->baseQuery(); + + $relationModel = $this->query->relation($subRelation)->find(); + + if ($relationModel) { + $relationModel->setParent(clone $this->parent); + } + + return $relationModel; + } + + /** + * 预载入关联查询(数据集) + * @access protected + * @param array $resultSet 数据集 + * @param string $relation 当前关联名 + * @param array $subRelation 子关联名 + * @param Closure $closure 闭包 + * @param array $cache 关联缓存 + * @return void + */ + public function eagerlyResultSet(array &$resultSet, string $relation, array $subRelation = [], Closure $closure = null, array $cache = []): void + { + $localKey = $this->localKey; + $foreignKey = $this->foreignKey; + + $range = []; + foreach ($resultSet as $result) { + // 获取关联外键列表 + if (isset($result->$localKey)) { + $range[] = $result->$localKey; + } + } + + if (!empty($range)) { + $this->query->removeWhereField($foreignKey); + + $data = $this->eagerlyWhere([ + [$this->foreignKey, 'in', $range], + ], $foreignKey, $subRelation, $closure, $cache); + + // 关联数据封装 + foreach ($resultSet as $result) { + // 关联模型 + if (!isset($data[$result->$localKey])) { + $relationModel = null; + } else { + $relationModel = $data[$result->$localKey]; + $relationModel->setParent(clone $result); + $relationModel->exists(true); + } + + // 设置关联属性 + $result->setRelation($relation, $relationModel); + } + } + } + + /** + * 预载入关联查询(数据) + * @access protected + * @param Model $result 数据对象 + * @param string $relation 当前关联名 + * @param array $subRelation 子关联名 + * @param Closure $closure 闭包 + * @param array $cache 关联缓存 + * @return void + */ + public function eagerlyResult(Model $result, string $relation, array $subRelation = [], Closure $closure = null, array $cache = []): void + { + $localKey = $this->localKey; + $foreignKey = $this->foreignKey; + + $this->query->removeWhereField($foreignKey); + + $data = $this->eagerlyWhere([ + [$foreignKey, '=', $result->$localKey], + ], $foreignKey, $subRelation, $closure, $cache); + + // 关联模型 + if (!isset($data[$result->$localKey])) { + $relationModel = null; + } else { + $relationModel = $data[$result->$localKey]; + $relationModel->setParent(clone $result); + $relationModel->exists(true); + } + + $result->setRelation($relation, $relationModel); + } + + /** + * 关联模型预查询 + * @access public + * @param array $where 关联预查询条件 + * @param string $key 关联键名 + * @param array $subRelation 子关联 + * @param Closure $closure + * @param array $cache 关联缓存 + * @return array + */ + protected function eagerlyWhere(array $where, string $key, array $subRelation = [], Closure $closure = null, array $cache = []): array + { + // 预载入关联查询 支持嵌套预载入 + $keys = $this->through->where($where)->column($this->throughPk, $this->foreignKey); + + if ($closure) { + $closure($this->getClosureType($closure)); + } + + $list = $this->query + ->where($this->throughKey, 'in', $keys) + ->cache($cache[0] ?? false, $cache[1] ?? null, $cache[2] ?? null) + ->select(); + + // 组装模型数据 + $data = []; + $keys = array_flip($keys); + + foreach ($list as $set) { + $data[$keys[$set->{$this->throughKey}]] = $set; + } + + return $data; + } + +} diff --git a/thinkphp/library/think/model/relation/MorphMany.php b/vendor/topthink/think-orm/src/model/relation/MorphMany.php old mode 100755 new mode 100644 similarity index 53% rename from thinkphp/library/think/model/relation/MorphMany.php rename to vendor/topthink/think-orm/src/model/relation/MorphMany.php index a1f54889b..82910cbc5 --- a/thinkphp/library/think/model/relation/MorphMany.php +++ b/vendor/topthink/think-orm/src/model/relation/MorphMany.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -11,18 +11,35 @@ namespace think\model\relation; -use think\db\Query; -use think\Exception; -use think\Loader; +use Closure; +use think\Collection; +use think\db\BaseQuery as Query; +use think\db\exception\DbException as Exception; +use think\helper\Str; use think\Model; use think\model\Relation; +/** + * 多态一对多关联 + */ class MorphMany extends Relation { - // 多态字段 + + /** + * 多态关联外键 + * @var string + */ protected $morphKey; + /** + * 多态字段名 + * @var string + */ protected $morphType; - // 多态类型 + + /** + * 多态类型 + * @var string + */ protected $type; /** @@ -34,7 +51,7 @@ class MorphMany extends Relation * @param string $morphType 多态字段名 * @param string $type 多态类型 */ - public function __construct(Model $parent, $model, $morphKey, $morphType, $type) + public function __construct(Model $parent, string $model, string $morphKey, string $morphType, string $type) { $this->parent = $parent; $this->model = $model; @@ -47,26 +64,25 @@ class MorphMany extends Relation /** * 延迟获取关联数据 * @access public - * @param string $subRelation 子关联名 - * @param \Closure $closure 闭包查询条件 - * @return \think\Collection + * @param array $subRelation 子关联名 + * @param Closure $closure 闭包查询条件 + * @return Collection */ - public function getRelation($subRelation = '', $closure = null) + public function getRelation(array $subRelation = [], Closure $closure = null): Collection { if ($closure) { - $closure($this->query); + $closure($this->getClosureType($closure)); } $this->baseQuery(); - $list = $this->query->relation($subRelation)->select(); - $parent = clone $this->parent; - - foreach ($list as &$model) { - $model->setParent($parent); + if ($this->withLimit) { + $this->query->limit($this->withLimit); } - return $list; + return $this->query->relation($subRelation) + ->select() + ->setParent(clone $this->parent); } /** @@ -76,9 +92,10 @@ class MorphMany extends Relation * @param integer $count 个数 * @param string $id 关联表的统计字段 * @param string $joinType JOIN类型 + * @param Query $query Query对象 * @return Query */ - public function has($operator = '>=', $count = 1, $id = '*', $joinType = 'INNER') + public function has(string $operator = '>=', int $count = 1, string $id = '*', string $joinType = '', Query $query = null) { throw new Exception('relation not support: has'); } @@ -86,11 +103,13 @@ class MorphMany extends Relation /** * 根据关联条件查询当前模型 * @access public - * @param mixed $where 查询条件(数组或者闭包) - * @param mixed $fields 字段 + * @param mixed $where 查询条件(数组或者闭包) + * @param mixed $fields 字段 + * @param string $joinType JOIN类型 + * @param Query $query Query对象 * @return Query */ - public function hasWhere($where = [], $fields = null) + public function hasWhere($where = [], $fields = null, string $joinType = '', Query $query = null) { throw new Exception('relation not support: hasWhere'); } @@ -98,13 +117,14 @@ class MorphMany extends Relation /** * 预载入关联查询 * @access public - * @param array $resultSet 数据集 - * @param string $relation 当前关联名 - * @param string $subRelation 子关联名 - * @param \Closure $closure 闭包 + * @param array $resultSet 数据集 + * @param string $relation 当前关联名 + * @param array $subRelation 子关联名 + * @param Closure $closure 闭包 + * @param array $cache 关联缓存 * @return void */ - public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure) + public function eagerlyResultSet(array &$resultSet, string $relation, array $subRelation, Closure $closure = null, array $cache = []): void { $morphType = $this->morphType; $morphKey = $this->morphKey; @@ -124,10 +144,7 @@ class MorphMany extends Relation [$morphKey, 'in', $range], [$morphType, '=', $type], ]; - $data = $this->eagerlyMorphToMany($where, $relation, $subRelation, $closure); - - // 关联属性名 - $attr = Loader::parseName($relation); + $data = $this->eagerlyMorphToMany($where, $subRelation, $closure, $cache); // 关联数据封装 foreach ($resultSet as $result) { @@ -135,12 +152,7 @@ class MorphMany extends Relation $data[$result->$pk] = []; } - foreach ($data[$result->$pk] as &$relationModel) { - $relationModel->setParent(clone $result); - $relationModel->isUpdate(true); - } - - $result->setRelation($attr, $this->resultSetBuild($data[$result->$pk])); + $result->setRelation($relation, $this->resultSetBuild($data[$result->$pk], clone $this->parent)); } } } @@ -148,48 +160,43 @@ class MorphMany extends Relation /** * 预载入关联查询 * @access public - * @param Model $result 数据对象 - * @param string $relation 当前关联名 - * @param string $subRelation 子关联名 - * @param \Closure $closure 闭包 + * @param Model $result 数据对象 + * @param string $relation 当前关联名 + * @param array $subRelation 子关联名 + * @param Closure $closure 闭包 + * @param array $cache 关联缓存 * @return void */ - public function eagerlyResult(&$result, $relation, $subRelation, $closure) + public function eagerlyResult(Model $result, string $relation, array $subRelation = [], Closure $closure = null, array $cache = []): void { $pk = $result->getPk(); if (isset($result->$pk)) { - $key = $result->$pk; - $where = [ + $key = $result->$pk; + $data = $this->eagerlyMorphToMany([ [$this->morphKey, '=', $key], [$this->morphType, '=', $this->type], - ]; - $data = $this->eagerlyMorphToMany($where, $relation, $subRelation, $closure); + ], $subRelation, $closure, $cache); if (!isset($data[$key])) { $data[$key] = []; } - foreach ($data[$key] as &$relationModel) { - $relationModel->setParent(clone $result); - $relationModel->isUpdate(true); - } - - $result->setRelation(Loader::parseName($relation), $this->resultSetBuild($data[$key])); + $result->setRelation($relation, $this->resultSetBuild($data[$key], clone $this->parent)); } } /** * 关联统计 * @access public - * @param Model $result 数据对象 - * @param \Closure $closure 闭包 - * @param string $aggregate 聚合查询方法 - * @param string $field 字段 - * @param string $name 统计字段别名 - * @return integer + * @param Model $result 数据对象 + * @param Closure $closure 闭包 + * @param string $aggregate 聚合查询方法 + * @param string $field 字段 + * @param string $name 统计字段别名 + * @return mixed */ - public function relationCount($result, $closure, $aggregate = 'count', $field = '*', &$name = '') + public function relationCount(Model $result, Closure $closure = null, string $aggregate = 'count', string $field = '*', string &$name = null) { $pk = $result->getPk(); @@ -198,11 +205,7 @@ class MorphMany extends Relation } if ($closure) { - $return = $closure($this->query); - - if ($return && is_string($return)) { - $name = $return; - } + $closure($this->getClosureType($closure), $name); } return $this->query @@ -216,20 +219,16 @@ class MorphMany extends Relation /** * 获取关联统计子查询 * @access public - * @param \Closure $closure 闭包 - * @param string $aggregate 聚合查询方法 - * @param string $field 字段 - * @param string $aggregateAlias 聚合字段别名 + * @param Closure $closure 闭包 + * @param string $aggregate 聚合查询方法 + * @param string $field 字段 + * @param string $name 统计字段别名 * @return string */ - public function getRelationCountQuery($closure, $aggregate = 'count', $field = '*', &$aggregateAlias = '') + public function getRelationCountQuery(Closure $closure = null, string $aggregate = 'count', string $field = '*', string &$name = null): string { if ($closure) { - $return = $closure($this->query); - - if ($return && is_string($return)) { - $aggregateAlias = $return; - } + $closure($this->getClosureType($closure), $name); } return $this->query @@ -242,28 +241,39 @@ class MorphMany extends Relation /** * 多态一对多 关联模型预查询 * @access protected - * @param array $where 关联预查询条件 - * @param string $relation 关联名 - * @param string $subRelation 子关联 - * @param \Closure $closure 闭包 + * @param array $where 关联预查询条件 + * @param array $subRelation 子关联 + * @param Closure $closure 闭包 + * @param array $cache 关联缓存 * @return array */ - protected function eagerlyMorphToMany($where, $relation, $subRelation = '', $closure = null) + protected function eagerlyMorphToMany(array $where, array $subRelation = [], Closure $closure = null, array $cache = []): array { // 预载入关联查询 支持嵌套预载入 $this->query->removeOption('where'); if ($closure) { - $closure($this->query); + $this->baseQuery = true; + $closure($this->getClosureType($closure)); } - $list = $this->query->where($where)->with($subRelation)->select(); + $list = $this->query + ->where($where) + ->with($subRelation) + ->cache($cache[0] ?? false, $cache[1] ?? null, $cache[2] ?? null) + ->select(); $morphKey = $this->morphKey; // 组装模型数据 $data = []; foreach ($list as $set) { - $data[$set->$morphKey][] = $set; + $key = $set->$morphKey; + + if ($this->withLimit && isset($data[$key]) && count($data[$key]) >= $this->withLimit) { + continue; + } + + $data[$key][] = $set; } return $data; @@ -272,22 +282,23 @@ class MorphMany extends Relation /** * 保存(新增)当前关联数据对象 * @access public - * @param mixed $data 数据 + * @param mixed $data 数据 可以使用数组 关联模型对象 + * @param bool $replace 是否自动识别更新和写入 * @return Model|false */ - public function save($data) + public function save($data, bool $replace = true) { $model = $this->make(); - return $model->save($data) ? $model : false; + return $model->replace($replace)->save($data) ? $model : false; } /** * 创建关联对象实例 - * @param array $data + * @param array|Model $data * @return Model */ - public function make($data = []) + public function make($data = []): Model { if ($data instanceof Model) { $data = $data->getData(); @@ -305,15 +316,16 @@ class MorphMany extends Relation /** * 批量保存当前关联数据对象 * @access public - * @param array $dataSet 数据集 + * @param iterable $dataSet 数据集 + * @param boolean $replace 是否自动识别更新和写入 * @return array|false */ - public function saveAll(array $dataSet) + public function saveAll(iterable $dataSet, bool $replace = true) { $result = []; foreach ($dataSet as $key => $data) { - $result[] = $this->save($data); + $result[] = $this->save($data, $replace); } return empty($result) ? false : $result; @@ -324,7 +336,7 @@ class MorphMany extends Relation * @access protected * @return void */ - protected function baseQuery() + protected function baseQuery(): void { if (empty($this->baseQuery) && $this->parent->getData()) { $pk = $this->parent->getPk(); diff --git a/thinkphp/library/think/model/relation/MorphOne.php b/vendor/topthink/think-orm/src/model/relation/MorphOne.php old mode 100755 new mode 100644 similarity index 50% rename from thinkphp/library/think/model/relation/MorphOne.php rename to vendor/topthink/think-orm/src/model/relation/MorphOne.php index 775b2dfd7..bc89c0ba1 --- a/thinkphp/library/think/model/relation/MorphOne.php +++ b/vendor/topthink/think-orm/src/model/relation/MorphOne.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -11,20 +11,42 @@ namespace think\model\relation; -use think\db\Query; -use think\Exception; -use think\Loader; +use Closure; +use think\db\BaseQuery as Query; +use think\db\exception\DbException as Exception; +use think\helper\Str; use think\Model; use think\model\Relation; +/** + * 多态一对一关联类 + */ class MorphOne extends Relation { - // 多态字段 + /** + * 多态关联外键 + * @var string + */ protected $morphKey; + + /** + * 多态字段 + * @var string + */ protected $morphType; - // 多态类型 + + /** + * 多态类型 + * @var string + */ protected $type; + /** + * 绑定的关联属性 + * @var array + */ + protected $bindAttr = []; + /** * 构造函数 * @access public @@ -34,7 +56,7 @@ class MorphOne extends Relation * @param string $morphType 多态字段名 * @param string $type 多态类型 */ - public function __construct(Model $parent, $model, $morphKey, $morphType, $type) + public function __construct(Model $parent, string $model, string $morphKey, string $morphType, string $type) { $this->parent = $parent; $this->model = $model; @@ -47,14 +69,14 @@ class MorphOne extends Relation /** * 延迟获取关联数据 * @access public - * @param string $subRelation 子关联名 - * @param \Closure $closure 闭包查询条件 + * @param array $subRelation 子关联名 + * @param Closure $closure 闭包查询条件 * @return Model */ - public function getRelation($subRelation = '', $closure = null) + public function getRelation(array $subRelation = [], Closure $closure = null) { if ($closure) { - $closure($this->query); + $closure($this->getClosureType($closure)); } $this->baseQuery(); @@ -62,6 +84,11 @@ class MorphOne extends Relation $relationModel = $this->query->relation($subRelation)->find(); if ($relationModel) { + if (!empty($this->bindAttr)) { + // 绑定关联属性 + $this->bindAttr($this->parent, $relationModel); + } + $relationModel->setParent(clone $this->parent); } @@ -75,9 +102,10 @@ class MorphOne extends Relation * @param integer $count 个数 * @param string $id 关联表的统计字段 * @param string $joinType JOIN类型 + * @param Query $query Query对象 * @return Query */ - public function has($operator = '>=', $count = 1, $id = '*', $joinType = 'INNER') + public function has(string $operator = '>=', int $count = 1, string $id = '*', string $joinType = '', Query $query = null) { return $this->parent; } @@ -85,11 +113,13 @@ class MorphOne extends Relation /** * 根据关联条件查询当前模型 * @access public - * @param mixed $where 查询条件(数组或者闭包) - * @param mixed $fields 字段 + * @param mixed $where 查询条件(数组或者闭包) + * @param mixed $fields 字段 + * @param string $joinType JOIN类型 + * @param Query $query Query对象 * @return Query */ - public function hasWhere($where = [], $fields = null) + public function hasWhere($where = [], $fields = null, string $joinType = '', Query $query = null) { throw new Exception('relation not support: hasWhere'); } @@ -97,13 +127,14 @@ class MorphOne extends Relation /** * 预载入关联查询 * @access public - * @param array $resultSet 数据集 - * @param string $relation 当前关联名 - * @param string $subRelation 子关联名 - * @param \Closure $closure 闭包 + * @param array $resultSet 数据集 + * @param string $relation 当前关联名 + * @param array $subRelation 子关联名 + * @param Closure $closure 闭包 + * @param array $cache 关联缓存 * @return void */ - public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure) + public function eagerlyResultSet(array &$resultSet, string $relation, array $subRelation, Closure $closure = null, array $cache = []): void { $morphType = $this->morphType; $morphKey = $this->morphKey; @@ -122,10 +153,7 @@ class MorphOne extends Relation $data = $this->eagerlyMorphToOne([ [$morphKey, 'in', $range], [$morphType, '=', $type], - ], $relation, $subRelation, $closure); - - // 关联属性名 - $attr = Loader::parseName($relation); + ], $subRelation, $closure, $cache); // 关联数据封装 foreach ($resultSet as $result) { @@ -134,10 +162,16 @@ class MorphOne extends Relation } else { $relationModel = $data[$result->$pk]; $relationModel->setParent(clone $result); - $relationModel->isUpdate(true); + $relationModel->exists(true); } - $result->setRelation($attr, $relationModel); + if (!empty($this->bindAttr)) { + // 绑定关联属性 + $this->bindAttr($result, $relationModel); + } else { + // 设置关联属性 + $result->setRelation($relation, $relationModel); + } } } } @@ -145,13 +179,14 @@ class MorphOne extends Relation /** * 预载入关联查询 * @access public - * @param Model $result 数据对象 - * @param string $relation 当前关联名 - * @param string $subRelation 子关联名 - * @param \Closure $closure 闭包 + * @param Model $result 数据对象 + * @param string $relation 当前关联名 + * @param array $subRelation 子关联名 + * @param Closure $closure 闭包 + * @param array $cache 关联缓存 * @return void */ - public function eagerlyResult(&$result, $relation, $subRelation, $closure) + public function eagerlyResult(Model $result, string $relation, array $subRelation = [], Closure $closure = null, array $cache = []): void { $pk = $result->getPk(); @@ -160,37 +195,48 @@ class MorphOne extends Relation $data = $this->eagerlyMorphToOne([ [$this->morphKey, '=', $pk], [$this->morphType, '=', $this->type], - ], $relation, $subRelation, $closure); + ], $subRelation, $closure, $cache); if (isset($data[$pk])) { $relationModel = $data[$pk]; $relationModel->setParent(clone $result); - $relationModel->isUpdate(true); + $relationModel->exists(true); } else { $relationModel = null; } - $result->setRelation(Loader::parseName($relation), $relationModel); + if (!empty($this->bindAttr)) { + // 绑定关联属性 + $this->bindAttr($result, $relationModel); + } else { + // 设置关联属性 + $result->setRelation($relation, $relationModel); + } } } /** * 多态一对一 关联模型预查询 * @access protected - * @param array $where 关联预查询条件 - * @param string $relation 关联名 - * @param string $subRelation 子关联 - * @param \Closure $closure 闭包 + * @param array $where 关联预查询条件 + * @param array $subRelation 子关联 + * @param Closure $closure 闭包 + * @param array $cache 关联缓存 * @return array */ - protected function eagerlyMorphToOne($where, $relation, $subRelation = '', $closure = null) + protected function eagerlyMorphToOne(array $where, array $subRelation = [], $closure = null, array $cache = []): array { // 预载入关联查询 支持嵌套预载入 if ($closure) { - $closure($this->query); + $this->baseQuery = true; + $closure($this->getClosureType($closure)); } - $list = $this->query->where($where)->with($subRelation)->select(); + $list = $this->query + ->where($where) + ->with($subRelation) + ->cache($cache[0] ?? false, $cache[1] ?? null, $cache[2] ?? null) + ->select(); $morphKey = $this->morphKey; // 组装模型数据 @@ -206,21 +252,22 @@ class MorphOne extends Relation /** * 保存(新增)当前关联数据对象 * @access public - * @param mixed $data 数据 + * @param mixed $data 数据 可以使用数组 关联模型对象 + * @param boolean $replace 是否自动识别更新和写入 * @return Model|false */ - public function save($data) + public function save($data, bool $replace = true) { $model = $this->make(); - return $model->save($data) ? $model : false; + return $model->replace($replace)->save($data) ? $model : false; } /** * 创建关联对象实例 - * @param array $data + * @param array|Model $data * @return Model */ - public function make($data = []) + public function make($data = []): Model { if ($data instanceof Model) { $data = $data->getData(); @@ -240,7 +287,7 @@ class MorphOne extends Relation * @access protected * @return void */ - protected function baseQuery() + protected function baseQuery(): void { if (empty($this->baseQuery) && $this->parent->getData()) { $pk = $this->parent->getPk(); @@ -253,4 +300,48 @@ class MorphOne extends Relation } } + /** + * 绑定关联表的属性到父模型属性 + * @access public + * @param array $attr 要绑定的属性列表 + * @return $this + */ + public function bind(array $attr) + { + $this->bindAttr = $attr; + + return $this; + } + + /** + * 获取绑定属性 + * @access public + * @return array + */ + public function getBindAttr(): array + { + return $this->bindAttr; + } + + /** + * 绑定关联属性到父模型 + * @access protected + * @param Model $result 父模型对象 + * @param Model $model 关联模型对象 + * @return void + * @throws Exception + */ + protected function bindAttr(Model $result, Model $model = null): void + { + foreach ($this->bindAttr as $key => $attr) { + $key = is_numeric($key) ? $attr : $key; + $value = $result->getOrigin($key); + + if (!is_null($value)) { + throw new Exception('bind attr has exists:' . $key); + } + + $result->setAttr($key, $model ? $model->$attr : null); + } + } } diff --git a/thinkphp/library/think/model/relation/MorphTo.php b/vendor/topthink/think-orm/src/model/relation/MorphTo.php old mode 100755 new mode 100644 similarity index 62% rename from thinkphp/library/think/model/relation/MorphTo.php rename to vendor/topthink/think-orm/src/model/relation/MorphTo.php index 6da6a0252..eaa98902a --- a/thinkphp/library/think/model/relation/MorphTo.php +++ b/vendor/topthink/think-orm/src/model/relation/MorphTo.php @@ -1,307 +1,332 @@ - -// +---------------------------------------------------------------------- - -namespace think\model\relation; - -use think\Exception; -use think\Loader; -use think\Model; -use think\model\Relation; - -class MorphTo extends Relation -{ - // 多态字段 - protected $morphKey; - protected $morphType; - // 多态别名 - protected $alias; - // 关联名 - protected $relation; - - /** - * 架构函数 - * @access public - * @param Model $parent 上级模型对象 - * @param string $morphType 多态字段名 - * @param string $morphKey 外键名 - * @param array $alias 多态别名定义 - * @param string $relation 关联名 - */ - public function __construct(Model $parent, $morphType, $morphKey, $alias = [], $relation = null) - { - $this->parent = $parent; - $this->morphType = $morphType; - $this->morphKey = $morphKey; - $this->alias = $alias; - $this->relation = $relation; - } - - /** - * 获取当前的关联模型类的实例 - * @access public - * @return Model - */ - public function getModel() - { - $morphType = $this->morphType; - $model = $this->parseModel($this->parent->$morphType); - - return (new $model); - } - - /** - * 延迟获取关联数据 - * @access public - * @param string $subRelation 子关联名 - * @param \Closure $closure 闭包查询条件 - * @return Model - */ - public function getRelation($subRelation = '', $closure = null) - { - $morphKey = $this->morphKey; - $morphType = $this->morphType; - - // 多态模型 - $model = $this->parseModel($this->parent->$morphType); - - // 主键数据 - $pk = $this->parent->$morphKey; - - $relationModel = (new $model)->relation($subRelation)->find($pk); - - if ($relationModel) { - $relationModel->setParent(clone $this->parent); - } - - return $relationModel; - } - - /** - * 根据关联条件查询当前模型 - * @access public - * @param string $operator 比较操作符 - * @param integer $count 个数 - * @param string $id 关联表的统计字段 - * @param string $joinType JOIN类型 - * @return Query - */ - public function has($operator = '>=', $count = 1, $id = '*', $joinType = 'INNER') - { - return $this->parent; - } - - /** - * 根据关联条件查询当前模型 - * @access public - * @param mixed $where 查询条件(数组或者闭包) - * @param mixed $fields 字段 - * @return Query - */ - public function hasWhere($where = [], $fields = null) - { - throw new Exception('relation not support: hasWhere'); - } - - /** - * 解析模型的完整命名空间 - * @access protected - * @param string $model 模型名(或者完整类名) - * @return string - */ - protected function parseModel($model) - { - if (isset($this->alias[$model])) { - $model = $this->alias[$model]; - } - - if (false === strpos($model, '\\')) { - $path = explode('\\', get_class($this->parent)); - array_pop($path); - array_push($path, Loader::parseName($model, 1)); - $model = implode('\\', $path); - } - - return $model; - } - - /** - * 设置多态别名 - * @access public - * @param array $alias 别名定义 - * @return $this - */ - public function setAlias($alias) - { - $this->alias = $alias; - - return $this; - } - - /** - * 移除关联查询参数 - * @access public - * @return $this - */ - public function removeOption() - { - return $this; - } - - /** - * 预载入关联查询 - * @access public - * @param array $resultSet 数据集 - * @param string $relation 当前关联名 - * @param string $subRelation 子关联名 - * @param \Closure $closure 闭包 - * @return void - * @throws Exception - */ - public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure) - { - $morphKey = $this->morphKey; - $morphType = $this->morphType; - $range = []; - - foreach ($resultSet as $result) { - // 获取关联外键列表 - if (!empty($result->$morphKey)) { - $range[$result->$morphType][] = $result->$morphKey; - } - } - - if (!empty($range)) { - // 关联属性名 - $attr = Loader::parseName($relation); - - foreach ($range as $key => $val) { - // 多态类型映射 - $model = $this->parseModel($key); - $obj = new $model; - $pk = $obj->getPk(); - $list = $obj->all($val, $subRelation); - $data = []; - - foreach ($list as $k => $vo) { - $data[$vo->$pk] = $vo; - } - - foreach ($resultSet as $result) { - if ($key == $result->$morphType) { - // 关联模型 - if (!isset($data[$result->$morphKey])) { - $relationModel = null; - } else { - $relationModel = $data[$result->$morphKey]; - $relationModel->setParent(clone $result); - $relationModel->isUpdate(true); - } - - $result->setRelation($attr, $relationModel); - } - } - } - } - } - - /** - * 预载入关联查询 - * @access public - * @param Model $result 数据对象 - * @param string $relation 当前关联名 - * @param string $subRelation 子关联名 - * @param \Closure $closure 闭包 - * @return void - */ - public function eagerlyResult(&$result, $relation, $subRelation, $closure) - { - $morphKey = $this->morphKey; - $morphType = $this->morphType; - // 多态类型映射 - $model = $this->parseModel($result->{$this->morphType}); - - $this->eagerlyMorphToOne($model, $relation, $result, $subRelation); - } - - /** - * 关联统计 - * @access public - * @param Model $result 数据对象 - * @param \Closure $closure 闭包 - * @param string $aggregate 聚合查询方法 - * @param string $field 字段 - * @param string $name 统计字段别名 - * @return integer - */ - public function relationCount($result, $closure, $aggregate = 'count', $field = '*', &$name = '') - {} - - /** - * 多态MorphTo 关联模型预查询 - * @access protected - * @param string $model 关联模型对象 - * @param string $relation 关联名 - * @param Model $result - * @param string $subRelation 子关联 - * @return void - */ - protected function eagerlyMorphToOne($model, $relation, &$result, $subRelation = '') - { - // 预载入关联查询 支持嵌套预载入 - $pk = $this->parent->{$this->morphKey}; - $data = (new $model)->with($subRelation)->find($pk); - - if ($data) { - $data->setParent(clone $result); - $data->isUpdate(true); - } - - $result->setRelation(Loader::parseName($relation), $data ?: null); - } - - /** - * 添加关联数据 - * @access public - * @param Model $model 关联模型对象 - * @param string $type 多态类型 - * @return Model - */ - public function associate($model, $type = '') - { - $morphKey = $this->morphKey; - $morphType = $this->morphType; - $pk = $model->getPk(); - - $this->parent->setAttr($morphKey, $model->$pk); - $this->parent->setAttr($morphType, $type ?: get_class($model)); - $this->parent->save(); - - return $this->parent->setRelation($this->relation, $model); - } - - /** - * 注销关联数据 - * @access public - * @return Model - */ - public function dissociate() - { - $morphKey = $this->morphKey; - $morphType = $this->morphType; - - $this->parent->setAttr($morphKey, null); - $this->parent->setAttr($morphType, null); - $this->parent->save(); - - return $this->parent->setRelation($this->relation, null); - } - -} + +// +---------------------------------------------------------------------- + +namespace think\model\relation; + +use Closure; +use think\db\exception\DbException as Exception; +use think\helper\Str; +use think\Model; +use think\model\Relation; + +/** + * 多态关联类 + */ +class MorphTo extends Relation +{ + /** + * 多态关联外键 + * @var string + */ + protected $morphKey; + + /** + * 多态字段 + * @var string + */ + protected $morphType; + + /** + * 多态别名 + * @var array + */ + protected $alias = []; + + /** + * 关联名 + * @var string + */ + protected $relation; + + /** + * 架构函数 + * @access public + * @param Model $parent 上级模型对象 + * @param string $morphType 多态字段名 + * @param string $morphKey 外键名 + * @param array $alias 多态别名定义 + * @param string $relation 关联名 + */ + public function __construct(Model $parent, string $morphType, string $morphKey, array $alias = [], string $relation = null) + { + $this->parent = $parent; + $this->morphType = $morphType; + $this->morphKey = $morphKey; + $this->alias = $alias; + $this->relation = $relation; + } + + /** + * 获取当前的关联模型类的实例 + * @access public + * @return Model + */ + public function getModel(): Model + { + $morphType = $this->morphType; + $model = $this->parseModel($this->parent->$morphType); + + return (new $model); + } + + /** + * 延迟获取关联数据 + * @access public + * @param array $subRelation 子关联名 + * @param Closure $closure 闭包查询条件 + * @return Model + */ + public function getRelation(array $subRelation = [], Closure $closure = null) + { + $morphKey = $this->morphKey; + $morphType = $this->morphType; + + // 多态模型 + $model = $this->parseModel($this->parent->$morphType); + + // 主键数据 + $pk = $this->parent->$morphKey; + + $relationModel = (new $model)->relation($subRelation)->find($pk); + + if ($relationModel) { + $relationModel->setParent(clone $this->parent); + } + + return $relationModel; + } + + /** + * 根据关联条件查询当前模型 + * @access public + * @param string $operator 比较操作符 + * @param integer $count 个数 + * @param string $id 关联表的统计字段 + * @param string $joinType JOIN类型 + * @param Query $query Query对象 + * @return Query + */ + public function has(string $operator = '>=', int $count = 1, string $id = '*', string $joinType = '', Query $query = null) + { + return $this->parent; + } + + /** + * 根据关联条件查询当前模型 + * @access public + * @param mixed $where 查询条件(数组或者闭包) + * @param mixed $fields 字段 + * @param string $joinType JOIN类型 + * @param Query $query Query对象 + * @return Query + */ + public function hasWhere($where = [], $fields = null, string $joinType = '', Query $query = null) + { + throw new Exception('relation not support: hasWhere'); + } + + /** + * 解析模型的完整命名空间 + * @access protected + * @param string $model 模型名(或者完整类名) + * @return string + */ + protected function parseModel(string $model): string + { + if (isset($this->alias[$model])) { + $model = $this->alias[$model]; + } + + if (false === strpos($model, '\\')) { + $path = explode('\\', get_class($this->parent)); + array_pop($path); + array_push($path, Str::studly($model)); + $model = implode('\\', $path); + } + + return $model; + } + + /** + * 设置多态别名 + * @access public + * @param array $alias 别名定义 + * @return $this + */ + public function setAlias(array $alias) + { + $this->alias = $alias; + + return $this; + } + + /** + * 移除关联查询参数 + * @access public + * @return $this + */ + public function removeOption() + { + return $this; + } + + /** + * 预载入关联查询 + * @access public + * @param array $resultSet 数据集 + * @param string $relation 当前关联名 + * @param array $subRelation 子关联名 + * @param Closure $closure 闭包 + * @param array $cache 关联缓存 + * @return void + * @throws Exception + */ + public function eagerlyResultSet(array &$resultSet, string $relation, array $subRelation, Closure $closure = null, array $cache = []): void + { + $morphKey = $this->morphKey; + $morphType = $this->morphType; + $range = []; + + foreach ($resultSet as $result) { + // 获取关联外键列表 + if (!empty($result->$morphKey)) { + $range[$result->$morphType][] = $result->$morphKey; + } + } + + if (!empty($range)) { + + foreach ($range as $key => $val) { + // 多态类型映射 + $model = $this->parseModel($key); + $obj = new $model; + $pk = $obj->getPk(); + $list = $obj->with($subRelation) + ->cache($cache[0] ?? false, $cache[1] ?? null, $cache[2] ?? null) + ->select($val); + $data = []; + + foreach ($list as $k => $vo) { + $data[$vo->$pk] = $vo; + } + + foreach ($resultSet as $result) { + if ($key == $result->$morphType) { + // 关联模型 + if (!isset($data[$result->$morphKey])) { + $relationModel = null; + } else { + $relationModel = $data[$result->$morphKey]; + $relationModel->setParent(clone $result); + $relationModel->exists(true); + } + + $result->setRelation($relation, $relationModel); + } + } + } + } + } + + /** + * 预载入关联查询 + * @access public + * @param Model $result 数据对象 + * @param string $relation 当前关联名 + * @param array $subRelation 子关联名 + * @param Closure $closure 闭包 + * @param array $cache 关联缓存 + * @return void + */ + public function eagerlyResult(Model $result, string $relation, array $subRelation = [], Closure $closure = null, array $cache = []): void + { + // 多态类型映射 + $model = $this->parseModel($result->{$this->morphType}); + + $this->eagerlyMorphToOne($model, $relation, $result, $subRelation, $cache); + } + + /** + * 关联统计 + * @access public + * @param Model $result 数据对象 + * @param Closure $closure 闭包 + * @param string $aggregate 聚合查询方法 + * @param string $field 字段 + * @return integer + */ + public function relationCount(Model $result, Closure $closure = null, string $aggregate = 'count', string $field = '*') + {} + + /** + * 多态MorphTo 关联模型预查询 + * @access protected + * @param string $model 关联模型对象 + * @param string $relation 关联名 + * @param Model $result + * @param array $subRelation 子关联 + * @param array $cache 关联缓存 + * @return void + */ + protected function eagerlyMorphToOne(string $model, string $relation, Model $result, array $subRelation = [], array $cache = []): void + { + // 预载入关联查询 支持嵌套预载入 + $pk = $this->parent->{$this->morphKey}; + $data = (new $model)->with($subRelation) + ->cache($cache[0] ?? false, $cache[1] ?? null, $cache[2] ?? null) + ->find($pk); + + if ($data) { + $data->setParent(clone $result); + $data->exists(true); + } + + $result->setRelation($relation, $data ?: null); + } + + /** + * 添加关联数据 + * @access public + * @param Model $model 关联模型对象 + * @param string $type 多态类型 + * @return Model + */ + public function associate(Model $model, string $type = ''): Model + { + $morphKey = $this->morphKey; + $morphType = $this->morphType; + $pk = $model->getPk(); + + $this->parent->setAttr($morphKey, $model->$pk); + $this->parent->setAttr($morphType, $type ?: get_class($model)); + $this->parent->save(); + + return $this->parent->setRelation($this->relation, $model); + } + + /** + * 注销关联数据 + * @access public + * @return Model + */ + public function dissociate(): Model + { + $morphKey = $this->morphKey; + $morphType = $this->morphType; + + $this->parent->setAttr($morphKey, null); + $this->parent->setAttr($morphType, null); + $this->parent->save(); + + return $this->parent->setRelation($this->relation, null); + } + +} diff --git a/vendor/topthink/think-orm/src/model/relation/MorphToMany.php b/vendor/topthink/think-orm/src/model/relation/MorphToMany.php new file mode 100644 index 000000000..88bbf9aa7 --- /dev/null +++ b/vendor/topthink/think-orm/src/model/relation/MorphToMany.php @@ -0,0 +1,458 @@ + +// +---------------------------------------------------------------------- + +namespace think\model\relation; + +use Closure; +use Exception; +use think\db\BaseQuery as Query; +use think\db\Raw; +use think\Model; +use think\model\Pivot; + +/** + * 多态多对多关联 + */ +class MorphToMany extends BelongsToMany +{ + + /** + * 多态字段名 + * @var string + */ + protected $morphType; + + /** + * 多态模型名 + * @var string + */ + protected $morphClass; + + /** + * 是否反向关联 + * @var bool + */ + protected $inverse; + + /** + * 架构函数 + * @access public + * @param Model $parent 上级模型对象 + * @param string $model 模型名 + * @param string $middle 中间表名/模型名 + * @param string $morphKey 关联外键 + * @param string $morphType 多态字段名 + * @param string $localKey 当前模型关联键 + * @param bool $inverse 反向关联 + */ + public function __construct(Model $parent, string $model, string $middle, string $morphType, string $morphKey, string $localKey, bool $inverse = false) + { + $this->morphType = $morphType; + $this->inverse = $inverse; + $this->morphClass = $inverse ? $model : get_class($parent); + + $foreignKey = $inverse ? $morphKey : $localKey; + $localKey = $inverse ? $localKey : $morphKey; + + parent::__construct($parent, $model, $middle, $foreignKey, $localKey); + } + + /** + * 预载入关联查询(数据集) + * @access public + * @param array $resultSet 数据集 + * @param string $relation 当前关联名 + * @param array $subRelation 子关联名 + * @param Closure $closure 闭包 + * @param array $cache 关联缓存 + * @return void + */ + public function eagerlyResultSet(array &$resultSet, string $relation, array $subRelation, Closure $closure = null, array $cache = []): void + { + $pk = $resultSet[0]->getPk(); + $range = []; + + foreach ($resultSet as $result) { + // 获取关联外键列表 + if (isset($result->$pk)) { + $range[] = $result->$pk; + } + } + + if (!empty($range)) { + // 查询关联数据 + $data = $this->eagerlyManyToMany([ + ['pivot.' . $this->localKey, 'in', $range], + ['pivot.' . $this->morphType, '=', $this->morphClass], + ], $subRelation, $closure, $cache); + + // 关联数据封装 + foreach ($resultSet as $result) { + if (!isset($data[$result->$pk])) { + $data[$result->$pk] = []; + } + + $result->setRelation($relation, $this->resultSetBuild($data[$result->$pk], clone $this->parent)); + } + } + } + + /** + * 预载入关联查询(单个数据) + * @access public + * @param Model $result 数据对象 + * @param string $relation 当前关联名 + * @param array $subRelation 子关联名 + * @param Closure $closure 闭包 + * @param array $cache 关联缓存 + * @return void + */ + public function eagerlyResult(Model $result, string $relation, array $subRelation, Closure $closure = null, array $cache = []): void + { + $pk = $result->getPk(); + + if (isset($result->$pk)) { + $pk = $result->$pk; + // 查询管理数据 + $data = $this->eagerlyManyToMany([ + ['pivot.' . $this->localKey, '=', $pk], + ['pivot.' . $this->morphType, '=', $this->morphClass], + ], $subRelation, $closure, $cache); + + // 关联数据封装 + if (!isset($data[$pk])) { + $data[$pk] = []; + } + + $result->setRelation($relation, $this->resultSetBuild($data[$pk], clone $this->parent)); + } + } + + /** + * 关联统计 + * @access public + * @param Model $result 数据对象 + * @param Closure $closure 闭包 + * @param string $aggregate 聚合查询方法 + * @param string $field 字段 + * @param string $name 统计字段别名 + * @return integer + */ + public function relationCount(Model $result, Closure $closure = null, string $aggregate = 'count', string $field = '*', string &$name = null): float + { + $pk = $result->getPk(); + + if (!isset($result->$pk)) { + return 0; + } + + $pk = $result->$pk; + + if ($closure) { + $closure($this->getClosureType($closure), $name); + } + + return $this->belongsToManyQuery($this->foreignKey, $this->localKey, [ + ['pivot.' . $this->localKey, '=', $pk], + ['pivot.' . $this->morphType, '=', $this->morphClass], + ])->$aggregate($field); + } + + /** + * 获取关联统计子查询 + * @access public + * @param Closure $closure 闭包 + * @param string $aggregate 聚合查询方法 + * @param string $field 字段 + * @param string $name 统计字段别名 + * @return string + */ + public function getRelationCountQuery(Closure $closure = null, string $aggregate = 'count', string $field = '*', string &$name = null): string + { + if ($closure) { + $closure($this->getClosureType($closure), $name); + } + + return $this->belongsToManyQuery($this->foreignKey, $this->localKey, [ + ['pivot.' . $this->localKey, 'exp', new Raw('=' . $this->parent->db(false)->getTable() . '.' . $this->parent->getPk())], + ['pivot.' . $this->morphType, '=', $this->morphClass], + ])->fetchSql()->$aggregate($field); + } + + /** + * BELONGS TO MANY 关联查询 + * @access protected + * @param string $foreignKey 关联模型关联键 + * @param string $localKey 当前模型关联键 + * @param array $condition 关联查询条件 + * @return Query + */ + protected function belongsToManyQuery(string $foreignKey, string $localKey, array $condition = []): Query + { + // 关联查询封装 + $tableName = $this->query->getTable(); + $table = $this->pivot->db()->getTable(); + $fields = $this->getQueryFields($tableName); + + if ($this->withLimit) { + $this->query->limit($this->withLimit); + } + + $query = $this->query + ->field($fields) + ->tableField(true, $table, 'pivot', 'pivot__'); + + if (empty($this->baseQuery)) { + $relationFk = $this->query->getPk(); + $query->join([$table => 'pivot'], 'pivot.' . $foreignKey . '=' . $tableName . '.' . $relationFk) + ->where($condition); + } + + return $query; + } + + /** + * 多对多 关联模型预查询 + * @access protected + * @param array $where 关联预查询条件 + * @param array $subRelation 子关联 + * @param Closure $closure 闭包 + * @param array $cache 关联缓存 + * @return array + */ + protected function eagerlyManyToMany(array $where, array $subRelation = [], Closure $closure = null, array $cache = []): array + { + if ($closure) { + $closure($this->getClosureType($closure)); + } + + // 预载入关联查询 支持嵌套预载入 + $list = $this->belongsToManyQuery($this->foreignKey, $this->localKey, $where) + ->with($subRelation) + ->cache($cache[0] ?? false, $cache[1] ?? null, $cache[2] ?? null) + ->select(); + + // 组装模型数据 + $data = []; + foreach ($list as $set) { + $pivot = []; + foreach ($set->getData() as $key => $val) { + if (strpos($key, '__')) { + [$name, $attr] = explode('__', $key, 2); + if ('pivot' == $name) { + $pivot[$attr] = $val; + unset($set->$key); + } + } + } + + $key = $pivot[$this->localKey]; + + if ($this->withLimit && isset($data[$key]) && count($data[$key]) >= $this->withLimit) { + continue; + } + + $set->setRelation($this->pivotDataName, $this->newPivot($pivot)); + + $data[$key][] = $set; + } + + return $data; + } + + /** + * 附加关联的一个中间表数据 + * @access public + * @param mixed $data 数据 可以使用数组、关联模型对象 或者 关联对象的主键 + * @param array $pivot 中间表额外数据 + * @return array|Pivot + */ + public function attach($data, array $pivot = []) + { + if (is_array($data)) { + if (key($data) === 0) { + $id = $data; + } else { + // 保存关联表数据 + $model = new $this->model; + $id = $model->insertGetId($data); + } + } else if (is_numeric($data) || is_string($data)) { + // 根据关联表主键直接写入中间表 + $id = $data; + } else if ($data instanceof Model) { + // 根据关联表主键直接写入中间表 + $id = $data->getKey(); + } + + if (!empty($id)) { + // 保存中间表数据 + $pivot[$this->localKey] = $this->parent->getKey(); + $pivot[$this->morphType] = $this->morphClass; + $ids = (array) $id; + + $result = []; + + foreach ($ids as $id) { + $pivot[$this->foreignKey] = $id; + + $this->pivot->replace() + ->exists(false) + ->data([]) + ->save($pivot); + $result[] = $this->newPivot($pivot); + } + + if (count($result) == 1) { + // 返回中间表模型对象 + $result = $result[0]; + } + + return $result; + } else { + throw new Exception('miss relation data'); + } + } + + /** + * 判断是否存在关联数据 + * @access public + * @param mixed $data 数据 可以使用关联模型对象 或者 关联对象的主键 + * @return Pivot|false + */ + public function attached($data) + { + if ($data instanceof Model) { + $id = $data->getKey(); + } else { + $id = $data; + } + + $pivot = $this->pivot + ->where($this->localKey, $this->parent->getKey()) + ->where($this->morphType, $this->morphClass) + ->where($this->foreignKey, $id) + ->find(); + + return $pivot ?: false; + } + + /** + * 解除关联的一个中间表数据 + * @access public + * @param integer|array $data 数据 可以使用关联对象的主键 + * @param bool $relationDel 是否同时删除关联表数据 + * @return integer + */ + public function detach($data = null, bool $relationDel = false): int + { + if (is_array($data)) { + $id = $data; + } else if (is_numeric($data) || is_string($data)) { + // 根据关联表主键直接写入中间表 + $id = $data; + } else if ($data instanceof Model) { + // 根据关联表主键直接写入中间表 + $id = $data->getKey(); + } + + // 删除中间表数据 + $pivot = [ + [$this->localKey, '=', $this->parent->getKey()], + [$this->morphType, '=', $this->morphClass], + ]; + + if (isset($id)) { + $pivot[] = [$this->foreignKey, is_array($id) ? 'in' : '=', $id]; + } + + $result = $this->pivot->where($pivot)->delete(); + + // 删除关联表数据 + if (isset($id) && $relationDel) { + $model = $this->model; + $model::destroy($id); + } + + return $result; + } + + /** + * 数据同步 + * @access public + * @param array $ids + * @param bool $detaching + * @return array + */ + public function sync(array $ids, bool $detaching = true): array + { + $changes = [ + 'attached' => [], + 'detached' => [], + 'updated' => [], + ]; + + $current = $this->pivot + ->where($this->localKey, $this->parent->getKey()) + ->where($this->morphType, $this->morphClass) + ->column($this->foreignKey); + + $records = []; + + foreach ($ids as $key => $value) { + if (!is_array($value)) { + $records[$value] = []; + } else { + $records[$key] = $value; + } + } + + $detach = array_diff($current, array_keys($records)); + + if ($detaching && count($detach) > 0) { + $this->detach($detach); + $changes['detached'] = $detach; + } + + foreach ($records as $id => $attributes) { + if (!in_array($id, $current)) { + $this->attach($id, $attributes); + $changes['attached'][] = $id; + } else if (count($attributes) > 0 && $this->attach($id, $attributes)) { + $changes['updated'][] = $id; + } + } + + return $changes; + } + + /** + * 执行基础查询(仅执行一次) + * @access protected + * @return void + */ + protected function baseQuery(): void + { + if (empty($this->baseQuery)) { + $foreignKey = $this->foreignKey; + $localKey = $this->localKey; + + // 关联查询 + $this->belongsToManyQuery($foreignKey, $localKey, [ + ['pivot.' . $localKey, '=', $this->parent->getKey()], + ['pivot.' . $this->morphType, '=', $this->morphClass], + ]); + + $this->baseQuery = true; + } + } + +} diff --git a/thinkphp/library/think/model/relation/OneToOne.php b/vendor/topthink/think-orm/src/model/relation/OneToOne.php old mode 100755 new mode 100644 similarity index 53% rename from thinkphp/library/think/model/relation/OneToOne.php rename to vendor/topthink/think-orm/src/model/relation/OneToOne.php index 59fce77fb..65bbfdae8 --- a/thinkphp/library/think/model/relation/OneToOne.php +++ b/vendor/topthink/think-orm/src/model/relation/OneToOne.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -11,26 +11,35 @@ namespace think\model\relation; -use think\db\Query; -use think\Exception; -use think\Loader; +use Closure; +use think\db\BaseQuery as Query; +use think\db\exception\DbException as Exception; +use think\helper\Str; use think\Model; use think\model\Relation; /** - * Class OneToOne + * 一对一关联基础类 * @package think\model\relation - * */ abstract class OneToOne extends Relation { - // 预载入方式 0 -JOIN 1 -IN - protected $eagerlyType = 1; - // 当前关联的JOIN类型 - protected $joinType; - // 要绑定的属性 + /** + * JOIN类型 + * @var string + */ + protected $joinType = 'INNER'; + + /** + * 绑定的关联属性 + * @var array + */ protected $bindAttr = []; - // 关联名 + + /** + * 关联名 + * @var string + */ protected $relation; /** @@ -39,7 +48,7 @@ abstract class OneToOne extends Relation * @param string $type JOIN类型 * @return $this */ - public function joinType($type) + public function joinType(string $type) { $this->joinType = $type; return $this; @@ -48,17 +57,17 @@ abstract class OneToOne extends Relation /** * 预载入关联查询(JOIN方式) * @access public - * @param Query $query 查询对象 - * @param string $relation 关联名 - * @param mixed $field 关联字段 - * @param string $joinType JOIN方式 - * @param \Closure $closure 闭包条件 - * @param bool $first + * @param Query $query 查询对象 + * @param string $relation 关联名 + * @param mixed $field 关联字段 + * @param string $joinType JOIN方式 + * @param Closure $closure 闭包条件 + * @param bool $first * @return void */ - public function eagerly(Query $query, $relation, $field, $joinType, $closure, $first) + public function eagerly(Query $query, string $relation, $field = true, string $joinType = '', Closure $closure = null, bool $first = false): void { - $name = Loader::parseName(basename(str_replace('\\', '/', get_class($this->parent)))); + $name = Str::snake(class_basename($this->parent)); if ($first) { $table = $query->getTable(); @@ -71,7 +80,7 @@ abstract class OneToOne extends Relation $masterField = true; } - $query->field($masterField, false, $table, $name); + $query->tableField($masterField, $table, $name); } // 预载入封装 @@ -89,92 +98,94 @@ abstract class OneToOne extends Relation if ($closure) { // 执行闭包查询 - $closure($query); - // 使用withField指定获取关联的字段,如 - // $query->where(['id'=>1])->withField('id,name'); - if ($query->getOptions('with_field')) { - $field = $query->getOptions('with_field'); - $query->removeOption('with_field'); + $closure($this->getClosureType($closure)); + + // 使用withField指定获取关联的字段 + if ($this->withField) { + $field = $this->withField; } } $query->join([$joinTable => $joinAlias], $joinOn, $joinType) - ->field($field, false, $joinTable, $joinAlias, $relation . '__'); + ->tableField($field, $joinTable, $joinAlias, $relation . '__'); } /** * 预载入关联查询(数据集) * @access protected - * @param array $resultSet - * @param string $relation - * @param string $subRelation - * @param \Closure $closure + * @param array $resultSet + * @param string $relation + * @param array $subRelation + * @param Closure $closure * @return mixed */ - abstract protected function eagerlySet(&$resultSet, $relation, $subRelation, $closure); + abstract protected function eagerlySet(array &$resultSet, string $relation, array $subRelation = [], Closure $closure = null); /** * 预载入关联查询(数据) * @access protected - * @param Model $result - * @param string $relation - * @param string $subRelation - * @param \Closure $closure + * @param Model $result + * @param string $relation + * @param array $subRelation + * @param Closure $closure * @return mixed */ - abstract protected function eagerlyOne(&$result, $relation, $subRelation, $closure); + abstract protected function eagerlyOne(Model $result, string $relation, array $subRelation = [], Closure $closure = null); /** * 预载入关联查询(数据集) * @access public - * @param array $resultSet 数据集 - * @param string $relation 当前关联名 - * @param string $subRelation 子关联名 - * @param \Closure $closure 闭包 - * @param bool $join 是否为JOIN方式 + * @param array $resultSet 数据集 + * @param string $relation 当前关联名 + * @param array $subRelation 子关联名 + * @param Closure $closure 闭包 + * @param array $cache 关联缓存 + * @param bool $join 是否为JOIN方式 * @return void */ - public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure, $join = false) + public function eagerlyResultSet(array &$resultSet, string $relation, array $subRelation = [], Closure $closure = null, array $cache = [], bool $join = false): void { - if ($join || 0 == $this->eagerlyType) { + if ($join) { // 模型JOIN关联组装 foreach ($resultSet as $result) { $this->match($this->model, $relation, $result); } } else { // IN查询 - $this->eagerlySet($resultSet, $relation, $subRelation, $closure); + $this->eagerlySet($resultSet, $relation, $subRelation, $closure, $cache); } } /** * 预载入关联查询(数据) * @access public - * @param Model $result 数据对象 - * @param string $relation 当前关联名 - * @param string $subRelation 子关联名 - * @param \Closure $closure 闭包 - * @param bool $join 是否为JOIN方式 + * @param Model $result 数据对象 + * @param string $relation 当前关联名 + * @param array $subRelation 子关联名 + * @param Closure $closure 闭包 + * @param array $cache 关联缓存 + * @param bool $join 是否为JOIN方式 * @return void */ - public function eagerlyResult(&$result, $relation, $subRelation, $closure, $join = false) + public function eagerlyResult(Model $result, string $relation, array $subRelation = [], Closure $closure = null, array $cache = [], bool $join = false): void { - if (0 == $this->eagerlyType || $join) { + if ($join) { // 模型JOIN关联组装 $this->match($this->model, $relation, $result); } else { // IN查询 - $this->eagerlyOne($result, $relation, $subRelation, $closure); + $this->eagerlyOne($result, $relation, $subRelation, $closure, $cache); } } /** * 保存(新增)当前关联数据对象 * @access public - * @param mixed $data 数据 可以使用数组 关联模型对象 和 关联对象的主键 + * @param mixed $data 数据 可以使用数组 关联模型对象 + * @param boolean $replace 是否自动识别更新和写入 * @return Model|false */ - public function save($data) + public function save($data, bool $replace = true) { if ($data instanceof Model) { $data = $data->getData(); @@ -184,43 +195,17 @@ abstract class OneToOne extends Relation // 保存关联表数据 $data[$this->foreignKey] = $this->parent->{$this->localKey}; - return $model->save($data) ? $model : false; - } - - /** - * 设置预载入方式 - * @access public - * @param integer $type 预载入方式 0 JOIN查询 1 IN查询 - * @return $this - */ - public function setEagerlyType($type) - { - $this->eagerlyType = $type; - - return $this; - } - - /** - * 获取预载入方式 - * @access public - * @return integer - */ - public function getEagerlyType() - { - return $this->eagerlyType; + return $model->replace($replace)->save($data) ? $model : false; } /** * 绑定关联表的属性到父模型属性 * @access public - * @param mixed $attr 要绑定的属性列表 + * @param array $attr 要绑定的属性列表 * @return $this */ - public function bind($attr) + public function bind(array $attr) { - if (is_string($attr)) { - $attr = explode(',', $attr); - } $this->bindAttr = $attr; return $this; @@ -231,7 +216,7 @@ abstract class OneToOne extends Relation * @access public * @return array */ - public function getBindAttr() + public function getBindAttr(): array { return $this->bindAttr; } @@ -244,12 +229,12 @@ abstract class OneToOne extends Relation * @param Model $result 模型对象实例 * @return void */ - protected function match($model, $relation, &$result) + protected function match(string $model, string $relation, Model $result): void { // 重新组装模型数据 foreach ($result->getData() as $key => $val) { if (strpos($key, '__')) { - list($name, $attr) = explode('__', $key, 2); + [$name, $attr] = explode('__', $key, 2); if ($name == $relation) { $list[$name][$attr] = $val; unset($result->$key); @@ -265,67 +250,76 @@ abstract class OneToOne extends Relation } else { $relationModel = new $model($list[$relation]); $relationModel->setParent(clone $result); - $relationModel->isUpdate(true); + $relationModel->exists(true); } if (!empty($this->bindAttr)) { - $this->bindAttr($relationModel, $result, $this->bindAttr); + $this->bindAttr($result, $relationModel); } } else { $relationModel = null; } - $result->setRelation(Loader::parseName($relation), $relationModel); + $result->setRelation($relation, $relationModel); } /** * 绑定关联属性到父模型 * @access protected - * @param Model $model 关联模型对象 - * @param Model $result 父模型对象 + * @param Model $result 父模型对象 + * @param Model $model 关联模型对象 * @return void * @throws Exception */ - protected function bindAttr($model, &$result) + protected function bindAttr(Model $result, Model $model = null): void { foreach ($this->bindAttr as $key => $attr) { - $key = is_numeric($key) ? $attr : $key; - if (isset($result->$key)) { + $key = is_numeric($key) ? $attr : $key; + $value = $result->getOrigin($key); + + if (!is_null($value)) { throw new Exception('bind attr has exists:' . $key); - } else { - $result->setAttr($key, $model ? $model->$attr : null); } + + $result->setAttr($key, $model ? $model->$attr : null); } } /** * 一对一 关联模型预查询(IN方式) * @access public - * @param array $where 关联预查询条件 - * @param string $key 关联键名 - * @param string $relation 关联名 - * @param string $subRelation 子关联 - * @param \Closure $closure + * @param array $where 关联预查询条件 + * @param string $key 关联键名 + * @param array $subRelation 子关联 + * @param Closure $closure + * @param array $cache 关联缓存 * @return array */ - protected function eagerlyWhere($where, $key, $relation, $subRelation = '', $closure = null) + protected function eagerlyWhere(array $where, string $key, array $subRelation = [], Closure $closure = null, array $cache = []) { // 预载入关联查询 支持嵌套预载入 if ($closure) { - $closure($this->query); - - if ($field = $this->query->getOptions('with_field')) { - $this->query->field($field)->removeOption('with_field'); - } + $this->baseQuery = true; + $closure($this->getClosureType($closure)); } - $list = $this->query->where($where)->with($subRelation)->select(); + if ($this->withField) { + $this->query->field($this->withField); + } + + $list = $this->query + ->where($where) + ->with($subRelation) + ->cache($cache[0] ?? false, $cache[1] ?? null, $cache[2] ?? null) + ->select(); // 组装模型数据 $data = []; foreach ($list as $set) { - $data[$set->$key] = $set; + if (!isset($data[$set->$key])) { + $data[$set->$key] = $set; + } } return $data; diff --git a/thinkphp/library/think/paginator/driver/Bootstrap.php b/vendor/topthink/think-orm/src/paginator/driver/Bootstrap.php old mode 100755 new mode 100644 similarity index 86% rename from thinkphp/library/think/paginator/driver/Bootstrap.php rename to vendor/topthink/think-orm/src/paginator/driver/Bootstrap.php index ab5315c06..6d55c3944 --- a/thinkphp/library/think/paginator/driver/Bootstrap.php +++ b/vendor/topthink/think-orm/src/paginator/driver/Bootstrap.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -13,6 +13,9 @@ namespace think\paginator\driver; use think\Paginator; +/** + * Bootstrap 分页驱动 + */ class Bootstrap extends Paginator { @@ -21,7 +24,7 @@ class Bootstrap extends Paginator * @param string $text * @return string */ - protected function getPreviousButton($text = "«") + protected function getPreviousButton(string $text = "«"): string { if ($this->currentPage() <= 1) { @@ -40,7 +43,7 @@ class Bootstrap extends Paginator * @param string $text * @return string */ - protected function getNextButton($text = '»') + protected function getNextButton(string $text = '»'): string { if (!$this->hasMore) { return $this->getDisabledTextWrapper($text); @@ -55,7 +58,7 @@ class Bootstrap extends Paginator * 页码按钮 * @return string */ - protected function getLinks() + protected function getLinks(): string { if ($this->simple) { return ''; @@ -131,10 +134,10 @@ class Bootstrap extends Paginator * 生成一个可点击的按钮 * * @param string $url - * @param int $page + * @param string $page * @return string */ - protected function getAvailablePageWrapper($url, $page) + protected function getAvailablePageWrapper(string $url, string $page): string { return '
  • ' . $page . '
  • '; } @@ -145,7 +148,7 @@ class Bootstrap extends Paginator * @param string $text * @return string */ - protected function getDisabledTextWrapper($text) + protected function getDisabledTextWrapper(string $text): string { return '
  • ' . $text . '
  • '; } @@ -156,7 +159,7 @@ class Bootstrap extends Paginator * @param string $text * @return string */ - protected function getActivePageWrapper($text) + protected function getActivePageWrapper(string $text): string { return '
  • ' . $text . '
  • '; } @@ -166,7 +169,7 @@ class Bootstrap extends Paginator * * @return string */ - protected function getDots() + protected function getDots(): string { return $this->getDisabledTextWrapper('...'); } @@ -177,7 +180,7 @@ class Bootstrap extends Paginator * @param array $urls * @return string */ - protected function getUrlLinks(array $urls) + protected function getUrlLinks(array $urls): string { $html = ''; @@ -192,10 +195,10 @@ class Bootstrap extends Paginator * 生成普通页码按钮 * * @param string $url - * @param int $page + * @param string $page * @return string */ - protected function getPageLinkWrapper($url, $page) + protected function getPageLinkWrapper(string $url, string $page): string { if ($this->currentPage() == $page) { return $this->getActivePageWrapper($page); diff --git a/vendor/topthink/think-orm/stubs/Exception.php b/vendor/topthink/think-orm/stubs/Exception.php new file mode 100644 index 000000000..0fdba9c55 --- /dev/null +++ b/vendor/topthink/think-orm/stubs/Exception.php @@ -0,0 +1,59 @@ + +// +---------------------------------------------------------------------- +declare (strict_types=1); + +namespace think; + +/** + * 异常基础类 + * @package think + */ +class Exception extends \Exception +{ + /** + * 保存异常页面显示的额外Debug数据 + * @var array + */ + protected $data = []; + + /** + * 设置异常额外的Debug数据 + * 数据将会显示为下面的格式 + * + * Exception Data + * -------------------------------------------------- + * Label 1 + * key1 value1 + * key2 value2 + * Label 2 + * key1 value1 + * key2 value2 + * + * @access protected + * @param string $label 数据分类,用于异常页面显示 + * @param array $data 需要显示的数据,必须为关联数组 + */ + final protected function setData(string $label, array $data) + { + $this->data[$label] = $data; + } + + /** + * 获取异常额外Debug数据 + * 主要用于输出到异常页面便于调试 + * @access public + * @return array 由setData设置的Debug数据 + */ + final public function getData() + { + return $this->data; + } +} diff --git a/vendor/topthink/think-orm/stubs/Facade.php b/vendor/topthink/think-orm/stubs/Facade.php new file mode 100644 index 000000000..d801d8b0f --- /dev/null +++ b/vendor/topthink/think-orm/stubs/Facade.php @@ -0,0 +1,65 @@ + +// +---------------------------------------------------------------------- +declare(strict_types=1); + +namespace think; + +class Facade +{ + /** + * 始终创建新的对象实例 + * @var bool + */ + protected static $alwaysNewInstance; + + protected static $instance; + + /** + * 获取当前Facade对应类名 + * @access protected + * @return string + */ + protected static function getFacadeClass() + {} + + /** + * 创建Facade实例 + * @static + * @access protected + * @param bool $newInstance 是否每次创建新的实例 + * @return object + */ + protected static function createFacade(bool $newInstance = false) + { + $class = static::getFacadeClass() ?: 'think\DbManager'; + + if (static::$alwaysNewInstance) { + $newInstance = true; + } + + if ($newInstance) { + return new $class(); + } + + if (!self::$instance) { + self::$instance = new $class(); + } + + return self::$instance; + + } + + // 调用实际类的方法 + public static function __callStatic($method, $params) + { + return call_user_func_array([static::createFacade(), $method], $params); + } +} diff --git a/vendor/topthink/think-orm/stubs/load_stubs.php b/vendor/topthink/think-orm/stubs/load_stubs.php new file mode 100644 index 000000000..5854cda56 --- /dev/null +++ b/vendor/topthink/think-orm/stubs/load_stubs.php @@ -0,0 +1,9 @@ + './template/', + 'cache_path' => './runtime/', + 'view_suffix' => 'html', +]; + +$template = new Template($config); +// 模板变量赋值 +$template->assign(['name' => 'think']); +// 读取模板文件渲染输出 +$template->fetch('index'); +// 完整模板文件渲染 +$template->fetch('./template/test.php'); +// 渲染内容输出 +$template->display($content); +~~~ + +支持静态调用 + +~~~ +use think\facade\Template; + +Template::config([ + 'view_path' => './template/', + 'cache_path' => './runtime/', + 'view_suffix' => 'html', +]); +Template::assign(['name' => 'think']); +Template::fetch('index',['name' => 'think']); +Template::display($content,['name' => 'think']); +~~~ + +详细用法参考[开发手册](https://www.kancloud.cn/manual/think-template/content) \ No newline at end of file diff --git a/vendor/topthink/think-template/composer.json b/vendor/topthink/think-template/composer.json new file mode 100644 index 000000000..f4e1205c0 --- /dev/null +++ b/vendor/topthink/think-template/composer.json @@ -0,0 +1,20 @@ +{ + "name": "topthink/think-template", + "description": "the php template engine", + "license": "Apache-2.0", + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "require": { + "php": ">=7.1.0", + "psr/simple-cache": "^1.0" + }, + "autoload": { + "psr-4": { + "think\\": "src" + } + } +} \ No newline at end of file diff --git a/thinkphp/library/think/Template.php b/vendor/topthink/think-template/src/Template.php old mode 100755 new mode 100644 similarity index 84% rename from thinkphp/library/think/Template.php rename to vendor/topthink/think-template/src/Template.php index dc1acfa51..0feca8e20 --- a/thinkphp/library/think/Template.php +++ b/vendor/topthink/think-template/src/Template.php @@ -2,16 +2,18 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- +declare (strict_types = 1); namespace think; -use think\exception\TemplateNotFoundException; +use Exception; +use Psr\SimpleCache\CacheInterface; /** * ThinkPHP分离出来的模板引擎 @@ -20,7 +22,6 @@ use think\exception\TemplateNotFoundException; */ class Template { - protected $app; /** * 模板变量 * @var array @@ -33,9 +34,9 @@ class Template */ protected $config = [ 'view_path' => '', // 模板路径 - 'view_base' => '', 'view_suffix' => 'html', // 默认模板文件后缀 'view_depr' => DIRECTORY_SEPARATOR, + 'cache_path' => '', 'cache_suffix' => 'php', // 默认模板缓存后缀 'tpl_deny_func_list' => 'echo,exit', // 模板引擎禁用函数 'tpl_deny_php' => false, // 默认模板引擎是否禁用PHP原生代码 @@ -67,6 +68,12 @@ class Template */ private $literal = []; + /** + * 扩展解析规则 + * @var array + */ + private $extend = []; + /** * 模板包含信息 * @var array @@ -79,16 +86,20 @@ class Template */ protected $storage; + /** + * 查询缓存对象 + * @var CacheInterface + */ + protected $cache; + /** * 架构函数 * @access public * @param array $config */ - public function __construct(App $app, array $config = []) + public function __construct(array $config = []) { - $this->app = $app; - $this->config['cache_path'] = $app->getRuntimePath() . 'temp/'; - $this->config = array_merge($this->config, $config); + $this->config = array_merge($this->config, $config); $this->config['taglib_begin_origin'] = $this->config['taglib_begin']; $this->config['taglib_end_origin'] = $this->config['taglib_end']; @@ -99,37 +110,29 @@ class Template $this->config['tpl_end'] = preg_quote($this->config['tpl_end'], '/'); // 初始化模板编译存储器 - $type = $this->config['compile_type'] ? $this->config['compile_type'] : 'File'; + $type = $this->config['compile_type'] ? $this->config['compile_type'] : 'File'; + $class = false !== strpos($type, '\\') ? $type : '\\think\\template\\driver\\' . ucwords($type); - $this->storage = Loader::factory($type, '\\think\\template\\driver\\', null); - } - - public static function __make(Config $config) - { - return new static($config->pull('template')); + $this->storage = new $class(); } /** * 模板变量赋值 * @access public - * @param mixed $name - * @param mixed $value - * @return void + * @param array $vars 模板变量 + * @return $this */ - public function assign($name, $value = '') + public function assign(array $vars = []) { - if (is_array($name)) { - $this->data = array_merge($this->data, $name); - } else { - $this->data[$name] = $value; - } + $this->data = array_merge($this->data, $vars); + return $this; } /** * 模板引擎参数赋值 * @access public - * @param mixed $name - * @param mixed $value + * @param string $name + * @param mixed $value */ public function __set($name, $value) { @@ -137,18 +140,37 @@ class Template } /** - * 模板引擎配置项 + * 设置缓存对象 * @access public - * @param array|string $config - * @return void|array + * @param CacheInterface $cache 缓存对象 + * @return void */ - public function config($config) + public function setCache(CacheInterface $cache): void { - if (is_array($config)) { - $this->config = array_merge($this->config, $config); - } elseif (isset($this->config[$config])) { - return $this->config[$config]; - } + $this->cache = $cache; + } + + /** + * 模板引擎配置 + * @access public + * @param array $config + * @return $this + */ + public function config(array $config) + { + $this->config = array_merge($this->config, $config); + return $this; + } + + /** + * 获取模板引擎配置项 + * @access public + * @param string $name + * @return mixed + */ + public function getConfig(string $name) + { + return $this->config[$name] ?? null; } /** @@ -157,7 +179,7 @@ class Template * @param string $name 变量名 * @return mixed */ - public function get($name = '') + public function get(string $name = '') { if ('' == $name) { return $this->data; @@ -178,31 +200,34 @@ class Template } /** - * 渲染模板文件 + * 扩展模板解析规则 * @access public - * @param string $template 模板文件 - * @param array $vars 模板变量 - * @param array $config 模板参数 + * @param string $rule 解析规则 + * @param callable $callback 解析规则 * @return void */ - public function fetch($template, $vars = [], $config = []) + public function extend(string $rule, callable $callback = null): void + { + $this->extend[$rule] = $callback; + } + + /** + * 渲染模板文件 + * @access public + * @param string $template 模板文件 + * @param array $vars 模板变量 + * @return void + */ + public function fetch(string $template, array $vars = []): void { if ($vars) { - $this->data = $vars; + $this->data = array_merge($this->data, $vars); } - if ($config) { - $this->config($config); - } - - $cache = $this->app['cache']; - - if (!empty($this->config['cache_id']) && $this->config['display_cache']) { + if (!empty($this->config['cache_id']) && $this->config['display_cache'] && $this->cache) { // 读取渲染缓存 - $cacheContent = $cache->get($this->config['cache_id']); - - if (false !== $cacheContent) { - echo $cacheContent; + if ($this->cache->has($this->config['cache_id'])) { + echo $this->cache->get($this->config['cache_id']); return; } } @@ -220,7 +245,11 @@ class Template // 页面缓存 ob_start(); - ob_implicit_flush(0); + if (PHP_VERSION > 8.0) { + ob_implicit_flush(false); + } else { + ob_implicit_flush(0); + } // 读取编译存储 $this->storage->read($cacheFile, $this->data); @@ -228,9 +257,9 @@ class Template // 获取并清空缓存 $content = ob_get_clean(); - if (!empty($this->config['cache_id']) && $this->config['display_cache']) { + if (!empty($this->config['cache_id']) && $this->config['display_cache'] && $this->cache) { // 缓存页面输出 - $cache->set($this->config['cache_id'], $content, $this->config['cache_time']); + $this->cache->set($this->config['cache_id'], $content, $this->config['cache_time']); } echo $content; @@ -238,21 +267,32 @@ class Template } /** - * 渲染模板内容 + * 检查编译缓存是否存在 * @access public - * @param string $content 模板内容 - * @param array $vars 模板变量 - * @param array $config 模板参数 - * @return void + * @param string $cacheId 缓存的id + * @return boolean */ - public function display($content, $vars = [], $config = []) + public function isCache(string $cacheId): bool { - if ($vars) { - $this->data = $vars; + if ($cacheId && $this->cache && $this->config['display_cache']) { + // 缓存页面输出 + return $this->cache->has($cacheId); } - if ($config) { - $this->config($config); + return false; + } + + /** + * 渲染模板内容 + * @access public + * @param string $content 模板内容 + * @param array $vars 模板变量 + * @return void + */ + public function display(string $content, array $vars = []): void + { + if ($vars) { + $this->data = array_merge($this->data, $vars); } $cacheFile = $this->config['cache_path'] . $this->config['cache_prefix'] . md5($content) . '.' . ltrim($this->config['cache_suffix'], '.'); @@ -269,11 +309,11 @@ class Template /** * 设置布局 * @access public - * @param mixed $name 布局模板名称 false 则关闭布局 - * @param string $replace 布局模板内容替换标识 - * @return object + * @param mixed $name 布局模板名称 false 则关闭布局 + * @param string $replace 布局模板内容替换标识 + * @return $this */ - public function layout($name, $replace = '') + public function layout($name, string $replace = '') { if (false === $name) { // 关闭布局 @@ -300,16 +340,22 @@ class Template * 如果无效则需要重新编译 * @access private * @param string $cacheFile 缓存文件名 - * @return boolean + * @return bool */ - private function checkCache($cacheFile) + private function checkCache(string $cacheFile): bool { if (!$this->config['tpl_cache'] || !is_file($cacheFile) || !$handle = @fopen($cacheFile, "r")) { return false; } // 读取第一行 - preg_match('/\/\*(.+?)\*\//', fgets($handle), $matches); + $line = fgets($handle); + + if (false === $line) { + return false; + } + + preg_match('/\/\*(.+?)\*\//', $line, $matches); if (!isset($matches[1])) { return false; @@ -333,30 +379,14 @@ class Template return $this->storage->check($cacheFile, $this->config['cache_time']); } - /** - * 检查编译缓存是否存在 - * @access public - * @param string $cacheId 缓存的id - * @return boolean - */ - public function isCache($cacheId) - { - if ($cacheId && $this->config['display_cache']) { - // 缓存页面输出 - return $this->app['cache']->has($cacheId); - } - - return false; - } - /** * 编译模板文件内容 * @access private - * @param string $content 模板内容 - * @param string $cacheFile 缓存文件名 + * @param string $content 模板内容 + * @param string $cacheFile 缓存文件名 * @return void */ - private function compiler(&$content, $cacheFile) + private function compiler(string &$content, string $cacheFile): void { // 判断是否启用布局 if ($this->config['layout_on']) { @@ -408,7 +438,7 @@ class Template * @param string $content 要解析的模板内容 * @return void */ - public function parse(&$content) + public function parse(string &$content): void { // 内容为空不解析 if (empty($content)) { @@ -477,9 +507,9 @@ class Template * @access private * @param string $content 要解析的模板内容 * @return void - * @throws \think\Exception + * @throws Exception */ - private function parsePhp(&$content) + private function parsePhp(string &$content): void { // 短标签的情况要将' . "\n", $content); @@ -496,7 +526,7 @@ class Template * @param string $content 要解析的模板内容 * @return void */ - private function parseLayout(&$content) + private function parseLayout(string &$content): void { // 读取模板中的布局标签 if (preg_match($this->getRegex('layout'), $content, $matches)) { @@ -526,7 +556,7 @@ class Template * @param string $content 要解析的模板内容 * @return void */ - private function parseInclude(&$content) + private function parseInclude(string &$content): void { $regex = $this->getRegex('include'); $func = function ($template) use (&$func, &$regex, &$content) { @@ -566,7 +596,7 @@ class Template * @param string $content 要解析的模板内容 * @return void */ - private function parseExtend(&$content) + private function parseExtend(string &$content): void { $regex = $this->getRegex('extend'); $array = $blocks = $baseBlocks = []; @@ -655,7 +685,7 @@ class Template * @param boolean $restore 是否为还原 * @return void */ - private function parseLiteral(&$content, $restore = false) + private function parseLiteral(string &$content, bool $restore = false): void { $regex = $this->getRegex($restore ? 'restoreliteral' : 'literal'); @@ -690,7 +720,7 @@ class Template * @param boolean $sort 是否排序 * @return array */ - private function parseBlock(&$content, $sort = false) + private function parseBlock(string &$content, bool $sort = false): array { $regex = $this->getRegex('block'); $result = []; @@ -742,7 +772,7 @@ class Template * @param string $content 模板内容 * @return array|null */ - private function getIncludeTagLib(&$content) + private function getIncludeTagLib(string &$content) { // 搜索是否有TagLib标签 if (preg_match($this->getRegex('taglib'), $content, $matches)) { @@ -761,7 +791,7 @@ class Template * @param boolean $hide 是否隐藏标签库前缀 * @return void */ - public function parseTagLib($tagLib, &$content, $hide = false) + public function parseTagLib(string $tagLib, string &$content, bool $hide = false): void { if (false !== strpos($tagLib, '\\')) { // 支持指定标签库的命名空间 @@ -783,7 +813,7 @@ class Template * @param string $name 不为空时返回指定的属性名 * @return array */ - public function parseAttr($str, $name = null) + public function parseAttr(string $str, string $name = null): array { $regex = '/\s+(?>(?P[\w-]+)\s*)=(?>\s*)([\"\'])(?P(?:(?!\\2).)*)\\2/is'; $array = []; @@ -809,7 +839,7 @@ class Template * @param string $content 要解析的模板内容 * @return void */ - private function parseTag(&$content) + private function parseTag(string &$content): void { $regex = $this->getRegex('tag'); @@ -945,7 +975,7 @@ class Template * @param string $varStr 变量数据 * @return void */ - public function parseVar(&$varStr) + public function parseVar(string &$varStr): void { $varStr = trim($varStr); @@ -963,22 +993,15 @@ class Template $vars = explode('.', $match[0]); $first = array_shift($vars); - if ('$Think' == $first) { + if (isset($this->extend[$first])) { + $callback = $this->extend[$first]; + $parseStr = $callback($vars); + } elseif ('$Request' == $first) { + // 输出请求变量 + $parseStr = $this->parseRequestVar($vars); + } elseif ('$Think' == $first) { // 所有以Think.打头的以特殊变量对待 无需模板赋值就可以输出 $parseStr = $this->parseThinkVar($vars); - } elseif ('$Request' == $first) { - // 获取Request请求对象参数 - $method = array_shift($vars); - if (!empty($vars)) { - $params = implode('.', $vars); - if ('true' != $params) { - $params = '\'' . $params . '\''; - } - } else { - $params = ''; - } - - $parseStr = 'app(\'request\')->' . $method . '(' . $params . ')'; } else { switch ($this->config['tpl_var_identify']) { case 'array': // 识别为数组 @@ -1008,11 +1031,11 @@ class Template * 对模板中使用了函数的变量进行解析 * 格式 {$varname|function1|function2=arg1,arg2} * @access public - * @param string $varStr 变量字符串 - * @param bool $autoescape 自动转义 - * @return void + * @param string $varStr 变量字符串 + * @param bool $autoescape 自动转义 + * @return string */ - public function parseVarFunction(&$varStr, $autoescape = true) + public function parseVarFunction(string &$varStr, bool $autoescape = true): string { if (!$autoescape && false === strpos($varStr, '|')) { return $varStr; @@ -1098,6 +1121,47 @@ class Template return $varStr; } + /** + * 请求变量解析 + * 格式 以 $Request. 打头的变量属于请求变量 + * @access public + * @param array $vars 变量数组 + * @return string + */ + public function parseRequestVar(array $vars): string + { + $type = strtoupper(trim(array_shift($vars))); + $param = implode('.', $vars); + + switch ($type) { + case 'SERVER': + $parseStr = '$_SERVER[\'' . $param . '\']'; + break; + case 'GET': + $parseStr = '$_GET[\'' . $param . '\']'; + break; + case 'POST': + $parseStr = '$_POST[\'' . $param . '\']'; + break; + case 'COOKIE': + $parseStr = '$_COOKIE[\'' . $param . '\']'; + break; + case 'SESSION': + $parseStr = '$_SESSION[\'' . $param . '\']'; + break; + case 'ENV': + $parseStr = '$_ENV[\'' . $param . '\']'; + break; + case 'REQUEST': + $parseStr = '$_REQUEST[\'' . $param . '\']'; + break; + default: + $parseStr = '\'\''; + } + + return $parseStr; + } + /** * 特殊模板变量解析 * 格式 以 $Think. 打头的变量属于特殊模板变量 @@ -1105,68 +1169,26 @@ class Template * @param array $vars 变量数组 * @return string */ - public function parseThinkVar($vars) + public function parseThinkVar(array $vars): string { $type = strtoupper(trim(array_shift($vars))); $param = implode('.', $vars); - if ($vars) { - switch ($type) { - case 'SERVER': - $parseStr = 'app(\'request\')->server(\'' . $param . '\')'; - break; - case 'GET': - $parseStr = 'app(\'request\')->get(\'' . $param . '\')'; - break; - case 'POST': - $parseStr = 'app(\'request\')->post(\'' . $param . '\')'; - break; - case 'COOKIE': - $parseStr = 'app(\'cookie\')->get(\'' . $param . '\')'; - break; - case 'SESSION': - $parseStr = 'app(\'session\')->get(\'' . $param . '\')'; - break; - case 'ENV': - $parseStr = 'app(\'request\')->env(\'' . $param . '\')'; - break; - case 'REQUEST': - $parseStr = 'app(\'request\')->request(\'' . $param . '\')'; - break; - case 'CONST': - $parseStr = strtoupper($param); - break; - case 'LANG': - $parseStr = 'app(\'lang\')->get(\'' . $param . '\')'; - break; - case 'CONFIG': - $parseStr = 'app(\'config\')->get(\'' . $param . '\')'; - break; - default: - $parseStr = '\'\''; - break; - } - } else { - switch ($type) { - case 'NOW': - $parseStr = "date('Y-m-d g:i a',time())"; - break; - case 'VERSION': - $parseStr = 'app()->version()'; - break; - case 'LDELIM': - $parseStr = '\'' . ltrim($this->config['tpl_begin'], '\\') . '\''; - break; - case 'RDELIM': - $parseStr = '\'' . ltrim($this->config['tpl_end'], '\\') . '\''; - break; - default: - if (defined($type)) { - $parseStr = $type; - } else { - $parseStr = ''; - } - } + switch ($type) { + case 'CONST': + $parseStr = strtoupper($param); + break; + case 'NOW': + $parseStr = "date('Y-m-d g:i a',time())"; + break; + case 'LDELIM': + $parseStr = '\'' . ltrim($this->config['tpl_begin'], '\\') . '\''; + break; + case 'RDELIM': + $parseStr = '\'' . ltrim($this->config['tpl_end'], '\\') . '\''; + break; + default: + $parseStr = defined($type) ? $type : '\'\''; } return $parseStr; @@ -1178,7 +1200,7 @@ class Template * @param string $templateName 模板文件名 * @return string */ - private function parseTemplateName($templateName) + private function parseTemplateName(string $templateName): string { $array = explode(',', $templateName); $parseStr = ''; @@ -1208,14 +1230,11 @@ class Template * 解析模板文件名 * @access private * @param string $template 文件名 - * @return string|false + * @return string */ - private function parseTemplateFile($template) + private function parseTemplateFile(string $template): string { if ('' == pathinfo($template, PATHINFO_EXTENSION)) { - if (strpos($template, '@')) { - list($module, $template) = explode('@', $template); - } if (0 !== strpos($template, '/')) { $template = str_replace(['/', ':'], $this->config['view_depr'], $template); @@ -1223,14 +1242,7 @@ class Template $template = str_replace(['/', ':'], $this->config['view_depr'], substr($template, 1)); } - if ($this->config['view_base']) { - $module = isset($module) ? $module : $this->app['request']->module(); - $path = $this->config['view_base'] . ($module ? $module . DIRECTORY_SEPARATOR : ''); - } else { - $path = isset($module) ? $this->app->getAppPath() . $module . DIRECTORY_SEPARATOR . basename($this->config['view_path']) . DIRECTORY_SEPARATOR : $this->config['view_path']; - } - - $template = $path . $template . '.' . ltrim($this->config['view_suffix'], '.'); + $template = $this->config['view_path'] . $template . '.' . ltrim($this->config['view_suffix'], '.'); } if (is_file($template)) { @@ -1240,7 +1252,7 @@ class Template return $template; } - throw new TemplateNotFoundException('template not exists:' . $template, $template); + throw new Exception('template not exists:' . $template); } /** @@ -1249,7 +1261,7 @@ class Template * @param string $tagName 标签名 * @return string */ - private function getRegex($tagName) + private function getRegex(string $tagName): string { $regex = ''; if ('tag' == $tagName) { @@ -1311,7 +1323,7 @@ class Template public function __debugInfo() { $data = get_object_vars($this); - unset($data['app'], $data['storege']); + unset($data['storage']); return $data; } diff --git a/vendor/topthink/think-template/src/facade/Template.php b/vendor/topthink/think-template/src/facade/Template.php new file mode 100644 index 000000000..665a180a8 --- /dev/null +++ b/vendor/topthink/think-template/src/facade/Template.php @@ -0,0 +1,83 @@ + +// +---------------------------------------------------------------------- + +namespace think\facade; + +if (class_exists('think\Facade')) { + class Facade extends \think\Facade + {} +} else { + class Facade + { + /** + * 始终创建新的对象实例 + * @var bool + */ + protected static $alwaysNewInstance; + + protected static $instance; + + /** + * 获取当前Facade对应类名 + * @access protected + * @return string + */ + protected static function getFacadeClass() + {} + + /** + * 创建Facade实例 + * @static + * @access protected + * @return object + */ + protected static function createFacade() + { + $class = static::getFacadeClass() ?: 'think\Template'; + + if (static::$alwaysNewInstance) { + return new $class(); + } + + if (!self::$instance) { + self::$instance = new $class(); + } + + return self::$instance; + + } + + // 调用实际类的方法 + public static function __callStatic($method, $params) + { + return call_user_func_array([static::createFacade(), $method], $params); + } + } +} + +/** + * @see \think\Template + * @mixin \think\Template + */ +class Template extends Facade +{ + protected static $alwaysNewInstance = true; + + /** + * 获取当前Facade对应类名(或者已经绑定的容器对象标识) + * @access protected + * @return string + */ + protected static function getFacadeClass() + { + return 'think\Template'; + } +} diff --git a/thinkphp/library/think/template/TagLib.php b/vendor/topthink/think-template/src/template/TagLib.php old mode 100755 new mode 100644 similarity index 91% rename from thinkphp/library/think/template/TagLib.php rename to vendor/topthink/think-template/src/template/TagLib.php index bbbb2c035..f6c8fbb84 --- a/thinkphp/library/think/template/TagLib.php +++ b/vendor/topthink/think-template/src/template/TagLib.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -11,7 +11,8 @@ namespace think\template; -use think\Exception; +use Exception; +use think\Template; /** * ThinkPHP标签库TagLib解析基类 @@ -70,9 +71,9 @@ class TagLib /** * 架构函数 * @access public - * @param \stdClass $template 模板引擎对象 + * @param Template $template 模板引擎对象 */ - public function __construct($template) + public function __construct(Template $template) { $this->tpl = $template; } @@ -84,7 +85,7 @@ class TagLib * @param string $lib 标签库名 * @return void */ - public function parseTag(&$content, $lib = '') + public function parseTag(string &$content, string $lib = ''): void { $tags = []; $lib = $lib ? strtolower($lib) . ':' : ''; @@ -185,8 +186,6 @@ class TagLib return $this->$method($attrs, ''); }, $content); } - - return; } /** @@ -196,10 +195,10 @@ class TagLib * @param boolean $close 是否为闭合标签 * @return string */ - public function getRegex($tags, $close) + public function getRegex($tags, bool $close): string { - $begin = $this->tpl->config('taglib_begin'); - $end = $this->tpl->config('taglib_end'); + $begin = $this->tpl->getConfig('taglib_begin'); + $end = $this->tpl->getConfig('taglib_end'); $single = strlen(ltrim($begin, '\\')) == 1 && strlen(ltrim($end, '\\')) == 1 ? true : false; $tagName = is_array($tags) ? implode('|', $tags) : $tags; @@ -230,7 +229,7 @@ class TagLib * @param string $alias 别名 * @return array */ - public function parseAttr($str, $name, $alias = '') + public function parseAttr(string $str, string $name, string $alias = ''): array { $regex = '/\s+(?>(?P[\w-]+)\s*)=(?>\s*)([\"\'])(?P(?:(?!\\2).)*)\\2/is'; $result = []; @@ -275,8 +274,8 @@ class TagLib if (!empty($this->tags[$name]['expression'])) { static $_taglibs; if (!isset($_taglibs[$name])) { - $_taglibs[$name][0] = strlen($this->tpl->config('taglib_begin_origin') . $name); - $_taglibs[$name][1] = strlen($this->tpl->config('taglib_end_origin')); + $_taglibs[$name][0] = strlen($this->tpl->getConfig('taglib_begin_origin') . $name); + $_taglibs[$name][1] = strlen($this->tpl->getConfig('taglib_end_origin')); } $result['expression'] = substr($str, $_taglibs[$name][0], -$_taglibs[$name][1]); // 清除自闭合标签尾部/ @@ -296,16 +295,15 @@ class TagLib * @param string $condition 表达式标签内容 * @return string */ - public function parseCondition($condition) + public function parseCondition(string $condition): string { - if (!strpos($condition, '::') && strpos($condition, ':')) { + if (strpos($condition, ':')) { $condition = ' ' . substr(strstr($condition, ':'), 1); } $condition = str_ireplace(array_keys($this->comparison), array_values($this->comparison), $condition); $this->tpl->parseVar($condition); - // $this->tpl->parseVarFunction($condition); // XXX: 此句能解析表达式中用|分隔的函数,但表达式中如果有|、||这样的逻辑运算就产生了歧异 return $condition; } @@ -315,7 +313,7 @@ class TagLib * @param string $name 变量描述 * @return string */ - public function autoBuildVar(&$name) + public function autoBuildVar(string &$name): string { $flag = substr($name, 0, 1); @@ -344,7 +342,7 @@ class TagLib * @access public * @return array */ - public function getTags() + public function getTags(): array { return $this->tags; } diff --git a/thinkphp/library/think/template/driver/File.php b/vendor/topthink/think-template/src/template/driver/File.php old mode 100755 new mode 100644 similarity index 86% rename from thinkphp/library/think/template/driver/File.php rename to vendor/topthink/think-template/src/template/driver/File.php index 3b96a0f3b..510d10a0b --- a/thinkphp/library/think/template/driver/File.php +++ b/vendor/topthink/think-template/src/template/driver/File.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -11,7 +11,7 @@ namespace think\template\driver; -use think\Exception; +use Exception; class File { @@ -22,9 +22,9 @@ class File * @access public * @param string $cacheFile 缓存的文件名 * @param string $content 缓存的内容 - * @return void|array + * @return void */ - public function write($cacheFile, $content) + public function write(string $cacheFile, string $content): void { // 检测模板目录 $dir = dirname($cacheFile); @@ -46,7 +46,7 @@ class File * @param array $vars 变量数组 * @return void */ - public function read($cacheFile, $vars = []) + public function read(string $cacheFile, array $vars = []): void { $this->cacheFile = $cacheFile; @@ -64,9 +64,9 @@ class File * @access public * @param string $cacheFile 缓存的文件名 * @param int $cacheTime 缓存时间 - * @return boolean + * @return bool */ - public function check($cacheFile, $cacheTime) + public function check(string $cacheFile, int $cacheTime): bool { // 缓存文件不存在, 直接返回false if (!file_exists($cacheFile)) { diff --git a/thinkphp/library/think/exception/TemplateNotFoundException.php b/vendor/topthink/think-template/src/template/exception/TemplateNotFoundException.php old mode 100755 new mode 100644 similarity index 75% rename from thinkphp/library/think/exception/TemplateNotFoundException.php rename to vendor/topthink/think-template/src/template/exception/TemplateNotFoundException.php index 420206931..dd88b327d --- a/thinkphp/library/think/exception/TemplateNotFoundException.php +++ b/vendor/topthink/think-template/src/template/exception/TemplateNotFoundException.php @@ -2,20 +2,20 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006-2019 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- -// | Author: yunwuxin <448901948@qq.com> +// | Author: liu21st // +---------------------------------------------------------------------- -namespace think\exception; +namespace think\template\exception; class TemplateNotFoundException extends \RuntimeException { protected $template; - public function __construct($message, $template = '') + public function __construct(string $message, string $template = '') { $this->message = $message; $this->template = $template; @@ -26,7 +26,7 @@ class TemplateNotFoundException extends \RuntimeException * @access public * @return string */ - public function getTemplate() + public function getTemplate(): string { return $this->template; } diff --git a/thinkphp/library/think/template/taglib/Cx.php b/vendor/topthink/think-template/src/template/taglib/Cx.php old mode 100755 new mode 100644 similarity index 93% rename from thinkphp/library/think/template/taglib/Cx.php rename to vendor/topthink/think-template/src/template/taglib/Cx.php index ad741f289..bccafc1be --- a/thinkphp/library/think/template/taglib/Cx.php +++ b/vendor/topthink/think-template/src/template/taglib/Cx.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006-2019 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -60,7 +60,7 @@ class Cx extends Taglib * @param string $content 标签内容 * @return string */ - public function tagPhp($tag, $content) + public function tagPhp(array $tag, string $content): string { $parseStr = ''; return $parseStr; @@ -76,9 +76,9 @@ class Cx extends Taglib * @access public * @param array $tag 标签属性 * @param string $content 标签内容 - * @return string|void + * @return string */ - public function tagVolist($tag, $content) + public function tagVolist(array $tag, string $content): string { $name = $tag['name']; $id = $tag['id']; @@ -116,11 +116,7 @@ class Cx extends Taglib $parseStr .= $content; $parseStr .= ''; - if (!empty($parseStr)) { - return $parseStr; - } - - return; + return $parseStr; } /** @@ -132,9 +128,9 @@ class Cx extends Taglib * @access public * @param array $tag 标签属性 * @param string $content 标签内容 - * @return string|void + * @return string */ - public function tagForeach($tag, $content) + public function tagForeach(array $tag, string $content): string { // 直接使用表达式 if (!empty($tag['expression'])) { @@ -203,11 +199,7 @@ class Cx extends Taglib $parseStr .= $content; $parseStr .= ''; - if (!empty($parseStr)) { - return $parseStr; - } - - return; + return $parseStr; } /** @@ -223,7 +215,7 @@ class Cx extends Taglib * @param string $content 标签内容 * @return string */ - public function tagIf($tag, $content) + public function tagIf(array $tag, string $content): string { $condition = !empty($tag['expression']) ? $tag['expression'] : $tag['condition']; $condition = $this->parseCondition($condition); @@ -240,7 +232,7 @@ class Cx extends Taglib * @param string $content 标签内容 * @return string */ - public function tagElseif($tag, $content) + public function tagElseif(array $tag, string $content): string { $condition = !empty($tag['expression']) ? $tag['expression'] : $tag['condition']; $condition = $this->parseCondition($condition); @@ -256,7 +248,7 @@ class Cx extends Taglib * @param array $tag 标签属性 * @return string */ - public function tagElse($tag) + public function tagElse(array $tag): string { $parseStr = ''; @@ -276,7 +268,7 @@ class Cx extends Taglib * @param string $content 标签内容 * @return string */ - public function tagSwitch($tag, $content) + public function tagSwitch(array $tag, string $content): string { $name = !empty($tag['expression']) ? $tag['expression'] : $tag['name']; $name = $this->autoBuildVar($name); @@ -292,7 +284,7 @@ class Cx extends Taglib * @param string $content 标签内容 * @return string */ - public function tagCase($tag, $content) + public function tagCase(array $tag, string $content): string { $value = isset($tag['expression']) ? $tag['expression'] : $tag['value']; $flag = substr($value, 0, 1); @@ -325,10 +317,9 @@ class Cx extends Taglib * 使用: {default /}ddfdf * @access public * @param array $tag 标签属性 - * @param string $content 标签内容 * @return string */ - public function tagDefault($tag) + public function tagDefault(array $tag): string { $parseStr = ''; @@ -344,7 +335,7 @@ class Cx extends Taglib * @param string $content 标签内容 * @return string */ - public function tagCompare($tag, $content) + public function tagCompare(array $tag, string $content): string { $name = $tag['name']; $value = $tag['value']; @@ -382,7 +373,7 @@ class Cx extends Taglib * @param string $content 标签内容 * @return string */ - public function tagRange($tag, $content) + public function tagRange(array $tag, string $content): string { $name = $tag['name']; $value = $tag['value']; @@ -420,7 +411,7 @@ class Cx extends Taglib * @param string $content 标签内容 * @return string */ - public function tagPresent($tag, $content) + public function tagPresent(array $tag, string $content): string { $name = $tag['name']; $name = $this->autoBuildVar($name); @@ -438,7 +429,7 @@ class Cx extends Taglib * @param string $content 标签内容 * @return string */ - public function tagNotpresent($tag, $content) + public function tagNotpresent(array $tag, string $content): string { $name = $tag['name']; $name = $this->autoBuildVar($name); @@ -456,7 +447,7 @@ class Cx extends Taglib * @param string $content 标签内容 * @return string */ - public function tagEmpty($tag, $content) + public function tagEmpty(array $tag, string $content): string { $name = $tag['name']; $name = $this->autoBuildVar($name); @@ -474,7 +465,7 @@ class Cx extends Taglib * @param string $content 标签内容 * @return string */ - public function tagNotempty($tag, $content) + public function tagNotempty(array $tag, string $content): string { $name = $tag['name']; $name = $this->autoBuildVar($name); @@ -491,7 +482,7 @@ class Cx extends Taglib * @param string $content * @return string */ - public function tagDefined($tag, $content) + public function tagDefined(array $tag, string $content): string { $name = $tag['name']; $parseStr = '' . $content . ''; @@ -507,7 +498,7 @@ class Cx extends Taglib * @param string $content * @return string */ - public function tagNotdefined($tag, $content) + public function tagNotdefined(array $tag, string $content): string { $name = $tag['name']; $parseStr = '' . $content . ''; @@ -523,7 +514,7 @@ class Cx extends Taglib * @param string $content 标签内容 * @return string */ - public function tagLoad($tag, $content) + public function tagLoad(array $tag, string $content): string { $file = isset($tag['file']) ? $tag['file'] : $tag['href']; $type = isset($tag['type']) ? strtolower($tag['type']) : ''; @@ -570,7 +561,7 @@ class Cx extends Taglib * @param string $content 标签内容 * @return string */ - public function tagAssign($tag, $content) + public function tagAssign(array $tag, string $content): string { $name = $this->autoBuildVar($tag['name']); $flag = substr($tag['value'], 0, 1); @@ -595,7 +586,7 @@ class Cx extends Taglib * @param string $content 标签内容 * @return string */ - public function tagDefine($tag, $content) + public function tagDefine(array $tag, string $content): string { $name = '\'' . $tag['name'] . '\''; $flag = substr($tag['value'], 0, 1); @@ -622,7 +613,7 @@ class Cx extends Taglib * @param string $content 标签内容 * @return string */ - public function tagFor($tag, $content) + public function tagFor(array $tag, string $content): string { //设置默认值 $start = 0; @@ -675,7 +666,7 @@ class Cx extends Taglib * @param string $content 标签内容 * @return string */ - public function tagUrl($tag, $content) + public function tagUrl(array $tag, string $content): string { $url = isset($tag['link']) ? $tag['link'] : ''; $vars = isset($tag['vars']) ? $tag['vars'] : ''; @@ -702,7 +693,7 @@ class Cx extends Taglib * @param string $content 标签内容 * @return string */ - public function tagFunction($tag, $content) + public function tagFunction(array $tag, string $content): string { $name = !empty($tag['name']) ? $tag['name'] : 'func'; $vars = !empty($tag['vars']) ? $tag['vars'] : ''; diff --git a/vendor/topthink/think-trace/.gitignore b/vendor/topthink/think-trace/.gitignore new file mode 100644 index 000000000..485dee64b --- /dev/null +++ b/vendor/topthink/think-trace/.gitignore @@ -0,0 +1 @@ +.idea diff --git a/vendor/topthink/think-trace/LICENSE b/vendor/topthink/think-trace/LICENSE new file mode 100644 index 000000000..261eeb9e9 --- /dev/null +++ b/vendor/topthink/think-trace/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/topthink/think-trace/README.md b/vendor/topthink/think-trace/README.md new file mode 100644 index 000000000..6ed63ec42 --- /dev/null +++ b/vendor/topthink/think-trace/README.md @@ -0,0 +1,15 @@ +# think-trace + +用于ThinkPHP6+的页面Trace扩展,支持Html页面和浏览器控制台两种方式输出。 + +## 安装 + +~~~ +composer require topthink/think-trace +~~~ + +## 配置 + +安装后config目录下会自带trace.php配置文件。 + +type参数用于指定trace类型,支持html和console两种方式。 \ No newline at end of file diff --git a/vendor/topthink/think-trace/composer.json b/vendor/topthink/think-trace/composer.json new file mode 100644 index 000000000..5af58545e --- /dev/null +++ b/vendor/topthink/think-trace/composer.json @@ -0,0 +1,31 @@ +{ + "name": "topthink/think-trace", + "description": "thinkphp debug trace", + "license": "Apache-2.0", + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "require": { + "php": ">=7.1.0", + "topthink/framework": "^6.0.0" + }, + "autoload": { + "psr-4": { + "think\\trace\\": "src" + } + }, + "extra": { + "think":{ + "services":[ + "think\\trace\\Service" + ], + "config":{ + "trace": "src/config.php" + } + } + }, + "minimum-stability": "dev" +} diff --git a/thinkphp/library/think/debug/Console.php b/vendor/topthink/think-trace/src/Console.php old mode 100755 new mode 100644 similarity index 66% rename from thinkphp/library/think/debug/Console.php rename to vendor/topthink/think-trace/src/Console.php index 5cbaa0f2f..179d4ea2b --- a/thinkphp/library/think/debug/Console.php +++ b/vendor/topthink/think-trace/src/Console.php @@ -1,156 +1,173 @@ - -// +---------------------------------------------------------------------- - -namespace think\debug; - -use think\Container; -use think\Db; -use think\Response; - -/** - * 浏览器调试输出 - */ -class Console -{ - protected $config = [ - 'tabs' => ['base' => '基本', 'file' => '文件', 'info' => '流程', 'notice|error' => '错误', 'sql' => 'SQL', 'debug|log' => '调试'], - ]; - - // 实例化并传入参数 - public function __construct($config = []) - { - if (is_array($config)) { - $this->config = array_merge($this->config, $config); - } - } - - /** - * 调试输出接口 - * @access public - * @param Response $response Response对象 - * @param array $log 日志信息 - * @return bool - */ - public function output(Response $response, array $log = []) - { - $request = Container::get('request'); - $contentType = $response->getHeader('Content-Type'); - $accept = $request->header('accept'); - if (strpos($accept, 'application/json') === 0 || $request->isAjax()) { - return false; - } elseif (!empty($contentType) && strpos($contentType, 'html') === false) { - return false; - } - // 获取基本信息 - $runtime = number_format(microtime(true) - Container::get('app')->getBeginTime(), 10); - $reqs = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞'; - $mem = number_format((memory_get_usage() - Container::get('app')->getBeginMem()) / 1024, 2); - - if ($request->host()) { - $uri = $request->protocol() . ' ' . $request->method() . ' : ' . $request->url(true); - } else { - $uri = 'cmd:' . implode(' ', $_SERVER['argv']); - } - - // 页面Trace信息 - $base = [ - '请求信息' => date('Y-m-d H:i:s', $_SERVER['REQUEST_TIME']) . ' ' . $uri, - '运行时间' => number_format($runtime, 6) . 's [ 吞吐率:' . $reqs . 'req/s ] 内存消耗:' . $mem . 'kb 文件加载:' . count(get_included_files()), - '查询信息' => Db::$queryTimes . ' queries ' . Db::$executeTimes . ' writes ', - '缓存信息' => Container::get('cache')->getReadTimes() . ' reads,' . Container::get('cache')->getWriteTimes() . ' writes', - ]; - - if (session_id()) { - $base['会话信息'] = 'SESSION_ID=' . session_id(); - } - - $info = Container::get('debug')->getFile(true); - - // 页面Trace信息 - $trace = []; - foreach ($this->config['tabs'] as $name => $title) { - $name = strtolower($name); - switch ($name) { - case 'base': // 基本信息 - $trace[$title] = $base; - break; - case 'file': // 文件信息 - $trace[$title] = $info; - break; - default: // 调试信息 - if (strpos($name, '|')) { - // 多组信息 - $names = explode('|', $name); - $result = []; - foreach ($names as $name) { - $result = array_merge($result, isset($log[$name]) ? $log[$name] : []); - } - $trace[$title] = $result; - } else { - $trace[$title] = isset($log[$name]) ? $log[$name] : ''; - } - } - } - - //输出到控制台 - $lines = ''; - foreach ($trace as $type => $msg) { - $lines .= $this->console($type, $msg); - } - $js = << -{$lines} - -JS; - return $js; - } - - protected function console($type, $msg) - { - $type = strtolower($type); - $trace_tabs = array_values($this->config['tabs']); - $line[] = ($type == $trace_tabs[0] || '调试' == $type || '错误' == $type) - ? "console.group('{$type}');" - : "console.groupCollapsed('{$type}');"; - - foreach ((array) $msg as $key => $m) { - switch ($type) { - case '调试': - $var_type = gettype($m); - if (in_array($var_type, ['array', 'string'])) { - $line[] = "console.log(" . json_encode($m) . ");"; - } else { - $line[] = "console.log(" . json_encode(var_export($m, 1)) . ");"; - } - break; - case '错误': - $msg = str_replace("\n", '\n', addslashes(is_scalar($m) ? $m : json_encode($m))); - $style = 'color:#F4006B;font-size:14px;'; - $line[] = "console.error(\"%c{$msg}\", \"{$style}\");"; - break; - case 'sql': - $msg = str_replace("\n", '\n', addslashes($m)); - $style = "color:#009bb4;"; - $line[] = "console.log(\"%c{$msg}\", \"{$style}\");"; - break; - default: - $m = is_string($key) ? $key . ' ' . $m : $key + 1 . ' ' . $m; - $msg = json_encode($m); - $line[] = "console.log({$msg});"; - break; - } - } - $line[] = "console.groupEnd();"; - return implode(PHP_EOL, $line); - } - -} + +// +---------------------------------------------------------------------- +declare (strict_types = 1); +namespace think\trace; + +use think\App; +use think\Response; + +/** + * 浏览器调试输出 + */ +class Console +{ + protected $config = [ + 'tabs' => ['base' => '基本', 'file' => '文件', 'info' => '流程', 'notice|error' => '错误', 'sql' => 'SQL', 'debug|log' => '调试'], + ]; + + // 实例化并传入参数 + public function __construct(array $config = []) + { + $this->config = array_merge($this->config, $config); + } + + /** + * 调试输出接口 + * @access public + * @param Response $response Response对象 + * @param array $log 日志信息 + * @return string|bool + */ + public function output(App $app, Response $response, array $log = []) + { + $request = $app->request; + $contentType = $response->getHeader('Content-Type'); + + if ($request->isJson() || $request->isAjax()) { + return false; + } elseif (!empty($contentType) && strpos($contentType, 'html') === false) { + return false; + } elseif ($response->getCode() == 204) { + return false; + } + + // 获取基本信息 + $runtime = number_format(microtime(true) - $app->getBeginTime(), 10, '.', ''); + $reqs = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞'; + $mem = number_format((memory_get_usage() - $app->getBeginMem()) / 1024, 2); + + if ($request->host()) { + $uri = $request->protocol() . ' ' . $request->method() . ' : ' . $request->url(true); + } else { + $uri = 'cmd:' . implode(' ', $_SERVER['argv']); + } + + // 页面Trace信息 + $base = [ + '请求信息' => date('Y-m-d H:i:s', $request->time() ?: time()) . ' ' . $uri, + '运行时间' => number_format((float) $runtime, 6) . 's [ 吞吐率:' . $reqs . 'req/s ] 内存消耗:' . $mem . 'kb 文件加载:' . count(get_included_files()), + '查询信息' => $app->db->getQueryTimes() . ' queries', + '缓存信息' => $app->cache->getReadTimes() . ' reads,' . $app->cache->getWriteTimes() . ' writes', + ]; + + if (isset($app->session)) { + $base['会话信息'] = 'SESSION_ID=' . $app->session->getId(); + } + + $info = $this->getFileInfo(); + + // 页面Trace信息 + $trace = []; + foreach ($this->config['tabs'] as $name => $title) { + $name = strtolower($name); + switch ($name) { + case 'base': // 基本信息 + $trace[$title] = $base; + break; + case 'file': // 文件信息 + $trace[$title] = $info; + break; + default: // 调试信息 + if (strpos($name, '|')) { + // 多组信息 + $names = explode('|', $name); + $result = []; + foreach ($names as $item) { + $result = array_merge($result, $log[$item] ?? []); + } + $trace[$title] = $result; + } else { + $trace[$title] = $log[$name] ?? ''; + } + } + } + + //输出到控制台 + $lines = ''; + foreach ($trace as $type => $msg) { + $lines .= $this->console($type, empty($msg) ? [] : $msg); + } + $js = << +{$lines} + +JS; + return $js; + } + + protected function console(string $type, $msg) + { + $type = strtolower($type); + $trace_tabs = array_values($this->config['tabs']); + $line = []; + $line[] = ($type == $trace_tabs[0] || '调试' == $type || '错误' == $type) + ? "console.group('{$type}');" + : "console.groupCollapsed('{$type}');"; + + foreach ((array) $msg as $key => $m) { + switch ($type) { + case '调试': + $var_type = gettype($m); + if (in_array($var_type, ['array', 'string'])) { + $line[] = "console.log(" . json_encode($m) . ");"; + } else { + $line[] = "console.log(" . json_encode(var_export($m, true)) . ");"; + } + break; + case '错误': + $msg = str_replace("\n", '\n', addslashes(is_scalar($m) ? $m : json_encode($m))); + $style = 'color:#F4006B;font-size:14px;'; + $line[] = "console.error(\"%c{$msg}\", \"{$style}\");"; + break; + case 'sql': + $msg = str_replace("\n", '\n', addslashes($m)); + $style = "color:#009bb4;"; + $line[] = "console.log(\"%c{$msg}\", \"{$style}\");"; + break; + default: + $m = is_string($key) ? $key . ' ' . $m : $key + 1 . ' ' . $m; + $msg = json_encode($m); + $line[] = "console.log({$msg});"; + break; + } + } + $line[] = "console.groupEnd();"; + return implode(PHP_EOL, $line); + } + + /** + * 获取文件加载信息 + * @access protected + * @return integer|array + */ + protected function getFileInfo() + { + $files = get_included_files(); + $info = []; + + foreach ($files as $key => $file) { + $info[] = $file . ' ( ' . number_format(filesize($file) / 1024, 2) . ' KB )'; + } + + return $info; + } +} diff --git a/thinkphp/library/think/debug/Html.php b/vendor/topthink/think-trace/src/Html.php old mode 100755 new mode 100644 similarity index 55% rename from thinkphp/library/think/debug/Html.php rename to vendor/topthink/think-trace/src/Html.php index a123762ee..bcb2f50d8 --- a/thinkphp/library/think/debug/Html.php +++ b/vendor/topthink/think-trace/src/Html.php @@ -1,106 +1,126 @@ - -// +---------------------------------------------------------------------- - -namespace think\debug; - -use think\Container; -use think\Db; -use think\Response; - -/** - * 页面Trace调试 - */ -class Html -{ - protected $config = [ - 'file' => '', - 'tabs' => ['base' => '基本', 'file' => '文件', 'info' => '流程', 'notice|error' => '错误', 'sql' => 'SQL', 'debug|log' => '调试'], - ]; - - // 实例化并传入参数 - public function __construct(array $config = []) - { - $this->config = array_merge($this->config, $config); - } - - /** - * 调试输出接口 - * @access public - * @param Response $response Response对象 - * @param array $log 日志信息 - * @return bool - */ - public function output(Response $response, array $log = []) - { - $request = Container::get('request'); - $contentType = $response->getHeader('Content-Type'); - $accept = $request->header('accept'); - if (strpos($accept, 'application/json') === 0 || $request->isAjax()) { - return false; - } elseif (!empty($contentType) && strpos($contentType, 'html') === false) { - return false; - } - // 获取基本信息 - $runtime = number_format(microtime(true) - Container::get('app')->getBeginTime(), 10, '.', ''); - $reqs = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞'; - $mem = number_format((memory_get_usage() - Container::get('app')->getBeginMem()) / 1024, 2); - - // 页面Trace信息 - if ($request->host()) { - $uri = $request->protocol() . ' ' . $request->method() . ' : ' . $request->url(true); - } else { - $uri = 'cmd:' . implode(' ', $_SERVER['argv']); - } - $base = [ - '请求信息' => date('Y-m-d H:i:s', $_SERVER['REQUEST_TIME']) . ' ' . $uri, - '运行时间' => number_format($runtime, 6) . 's [ 吞吐率:' . $reqs . 'req/s ] 内存消耗:' . $mem . 'kb 文件加载:' . count(get_included_files()), - '查询信息' => Db::$queryTimes . ' queries ' . Db::$executeTimes . ' writes ', - '缓存信息' => Container::get('cache')->getReadTimes() . ' reads,' . Container::get('cache')->getWriteTimes() . ' writes', - ]; - - if (session_id()) { - $base['会话信息'] = 'SESSION_ID=' . session_id(); - } - - $info = Container::get('debug')->getFile(true); - - // 页面Trace信息 - $trace = []; - foreach ($this->config['tabs'] as $name => $title) { - $name = strtolower($name); - switch ($name) { - case 'base': // 基本信息 - $trace[$title] = $base; - break; - case 'file': // 文件信息 - $trace[$title] = $info; - break; - default: // 调试信息 - if (strpos($name, '|')) { - // 多组信息 - $names = explode('|', $name); - $result = []; - foreach ($names as $name) { - $result = array_merge($result, isset($log[$name]) ? $log[$name] : []); - } - $trace[$title] = $result; - } else { - $trace[$title] = isset($log[$name]) ? $log[$name] : ''; - } - } - } - // 调用Trace页面模板 - ob_start(); - include $this->config['file']; - return ob_get_clean(); - } - -} + +// +---------------------------------------------------------------------- +declare (strict_types = 1); +namespace think\trace; + +use think\App; +use think\Response; + +/** + * 页面Trace调试 + */ +class Html +{ + protected $config = [ + 'file' => '', + 'tabs' => ['base' => '基本', 'file' => '文件', 'info' => '流程', 'notice|error' => '错误', 'sql' => 'SQL', 'debug|log' => '调试'], + ]; + + // 实例化并传入参数 + public function __construct(array $config = []) + { + $this->config = array_merge($this->config, $config); + } + + /** + * 调试输出接口 + * @access public + * @param App $app 应用实例 + * @param Response $response Response对象 + * @param array $log 日志信息 + * @return bool|string + */ + public function output(App $app, Response $response, array $log = []) + { + $request = $app->request; + $contentType = $response->getHeader('Content-Type'); + + if ($request->isJson() || $request->isAjax()) { + return false; + } elseif (!empty($contentType) && strpos($contentType, 'html') === false) { + return false; + } elseif ($response->getCode() == 204) { + return false; + } + + // 获取基本信息 + $runtime = number_format(microtime(true) - $app->getBeginTime(), 10, '.', ''); + $reqs = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞'; + $mem = number_format((memory_get_usage() - $app->getBeginMem()) / 1024, 2); + + // 页面Trace信息 + if ($request->host()) { + $uri = $request->protocol() . ' ' . $request->method() . ' : ' . $request->url(true); + } else { + $uri = 'cmd:' . implode(' ', $_SERVER['argv']); + } + + $base = [ + '请求信息' => date('Y-m-d H:i:s', $request->time() ?: time()) . ' ' . $uri, + '运行时间' => number_format((float) $runtime, 6) . 's [ 吞吐率:' . $reqs . 'req/s ] 内存消耗:' . $mem . 'kb 文件加载:' . count(get_included_files()), + '查询信息' => $app->db->getQueryTimes() . ' queries', + '缓存信息' => $app->cache->getReadTimes() . ' reads,' . $app->cache->getWriteTimes() . ' writes', + ]; + + if (isset($app->session)) { + $base['会话信息'] = 'SESSION_ID=' . $app->session->getId(); + } + + $info = $this->getFileInfo(); + + // 页面Trace信息 + $trace = []; + foreach ($this->config['tabs'] as $name => $title) { + $name = strtolower($name); + switch ($name) { + case 'base': // 基本信息 + $trace[$title] = $base; + break; + case 'file': // 文件信息 + $trace[$title] = $info; + break; + default: // 调试信息 + if (strpos($name, '|')) { + // 多组信息 + $names = explode('|', $name); + $result = []; + foreach ($names as $item) { + $result = array_merge($result, $log[$item] ?? []); + } + $trace[$title] = $result; + } else { + $trace[$title] = $log[$name] ?? ''; + } + } + } + // 调用Trace页面模板 + ob_start(); + include $this->config['file'] ?: __DIR__ . '/tpl/page_trace.tpl'; + return ob_get_clean(); + } + + /** + * 获取文件加载信息 + * @access protected + * @return integer|array + */ + protected function getFileInfo() + { + $files = get_included_files(); + $info = []; + + foreach ($files as $key => $file) { + $info[] = $file . ' ( ' . number_format(filesize($file) / 1024, 2) . ' KB )'; + } + + return $info; + } +} diff --git a/vendor/topthink/think-trace/src/Service.php b/vendor/topthink/think-trace/src/Service.php new file mode 100644 index 000000000..3e78ecc72 --- /dev/null +++ b/vendor/topthink/think-trace/src/Service.php @@ -0,0 +1,21 @@ + +// +---------------------------------------------------------------------- +namespace think\trace; + +use think\Service as BaseService; + +class Service extends BaseService +{ + public function register() + { + $this->app->middleware->add(TraceDebug::class); + } +} diff --git a/vendor/topthink/think-trace/src/TraceDebug.php b/vendor/topthink/think-trace/src/TraceDebug.php new file mode 100644 index 000000000..5ed9cbfcf --- /dev/null +++ b/vendor/topthink/think-trace/src/TraceDebug.php @@ -0,0 +1,109 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\trace; + +use Closure; +use think\App; +use think\Config; +use think\event\LogWrite; +use think\Request; +use think\Response; +use think\response\Redirect; + +/** + * 页面Trace中间件 + */ +class TraceDebug +{ + + /** + * Trace日志 + * @var array + */ + protected $log = []; + + /** + * 配置参数 + * @var array + */ + protected $config = []; + + /** @var App */ + protected $app; + + public function __construct(App $app, Config $config) + { + $this->app = $app; + $this->config = $config->get('trace'); + } + + /** + * 页面Trace调试 + * @access public + * @param Request $request + * @param Closure $next + * @return void + */ + public function handle($request, Closure $next) + { + $debug = $this->app->isDebug(); + + // 注册日志监听 + if ($debug) { + $this->log = []; + $this->app->event->listen(LogWrite::class, function ($event) { + if (empty($this->config['channel']) || $this->config['channel'] == $event->channel) { + $this->log = array_merge_recursive($this->log, $event->log); + } + }); + } + + $response = $next($request); + + // Trace调试注入 + if ($debug) { + $data = $response->getContent(); + $this->traceDebug($response, $data); + $response->content($data); + } + + return $response; + } + + public function traceDebug(Response $response, &$content) + { + $config = $this->config; + $type = $config['type'] ?? 'Html'; + + unset($config['type']); + + $trace = App::factory($type, '\\think\\trace\\', $config); + + if ($response instanceof Redirect) { + //TODO 记录 + } else { + $log = $this->app->log->getLog($config['channel'] ?? ''); + $log = array_merge_recursive($this->log, $log); + $output = $trace->output($this->app, $response, $log); + if (is_string($output)) { + // trace调试信息注入 + $pos = strripos($content, ''); + if (false !== $pos) { + $content = substr($content, 0, $pos) . $output . substr($content, $pos); + } else { + $content = $content . $output; + } + } + } + } +} diff --git a/vendor/topthink/think-trace/src/config.php b/vendor/topthink/think-trace/src/config.php new file mode 100644 index 000000000..fad2392d9 --- /dev/null +++ b/vendor/topthink/think-trace/src/config.php @@ -0,0 +1,10 @@ + 'Html', + // 读取的日志通道名 + 'channel' => '', +]; diff --git a/thinkphp/tpl/page_trace.tpl b/vendor/topthink/think-trace/src/tpl/page_trace.tpl old mode 100755 new mode 100644 similarity index 98% rename from thinkphp/tpl/page_trace.tpl rename to vendor/topthink/think-trace/src/tpl/page_trace.tpl index 2e5afbab9..6b1b9a12f --- a/thinkphp/tpl/page_trace.tpl +++ b/vendor/topthink/think-trace/src/tpl/page_trace.tpl @@ -24,7 +24,7 @@
    -
    getUseTime().'s ';?>
    +
    diff --git a/vendor/topthink/think-view/.gitignore b/vendor/topthink/think-view/.gitignore new file mode 100644 index 000000000..485dee64b --- /dev/null +++ b/vendor/topthink/think-view/.gitignore @@ -0,0 +1 @@ +.idea diff --git a/vendor/topthink/think-view/LICENSE b/vendor/topthink/think-view/LICENSE new file mode 100644 index 000000000..8dada3eda --- /dev/null +++ b/vendor/topthink/think-view/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/topthink/think-view/README.md b/vendor/topthink/think-view/README.md new file mode 100644 index 000000000..4e52defd5 --- /dev/null +++ b/vendor/topthink/think-view/README.md @@ -0,0 +1,36 @@ +# think-view + +ThinkPHP6.0 Think-Template模板引擎驱动 + + +## 安装 + +~~~php +composer require topthink/think-view +~~~ + +## 用法示例 + +本扩展不能单独使用,依赖ThinkPHP6.0+ + +首先配置config目录下的template.php配置文件,然后可以按照下面的用法使用。 + +~~~php + +use think\facade\View; + +// 模板变量赋值和渲染输出 +View::assign(['name' => 'think']) + // 输出过滤 + ->filter(function($content){ + return str_replace('search', 'replace', $content); + }) + // 读取模板文件渲染输出 + ->fetch('index'); + + +// 或者使用助手函数 +view('index', ['name' => 'think']); +~~~ + +具体的模板引擎配置请参考think-template库。 \ No newline at end of file diff --git a/vendor/topthink/think-view/composer.json b/vendor/topthink/think-view/composer.json new file mode 100644 index 000000000..f4e6431bd --- /dev/null +++ b/vendor/topthink/think-view/composer.json @@ -0,0 +1,20 @@ +{ + "name": "topthink/think-view", + "description": "thinkphp template driver", + "license": "Apache-2.0", + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "require": { + "php": ">=7.1.0", + "topthink/think-template": "^2.0" + }, + "autoload": { + "psr-4": { + "think\\view\\driver\\": "src" + } + } +} diff --git a/vendor/topthink/think-view/src/Think.php b/vendor/topthink/think-view/src/Think.php new file mode 100644 index 000000000..562b54aec --- /dev/null +++ b/vendor/topthink/think-view/src/Think.php @@ -0,0 +1,259 @@ + +// +---------------------------------------------------------------------- +declare (strict_types = 1); + +namespace think\view\driver; + +use think\App; +use think\helper\Str; +use think\Template; +use think\template\exception\TemplateNotFoundException; + +class Think +{ + // 模板引擎实例 + private $template; + private $app; + + // 模板引擎参数 + protected $config = [ + // 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写 3 保持操作方法 + 'auto_rule' => 1, + // 视图目录名 + 'view_dir_name' => 'view', + // 模板起始路径 + 'view_path' => '', + // 模板文件后缀 + 'view_suffix' => 'html', + // 模板文件名分隔符 + 'view_depr' => DIRECTORY_SEPARATOR, + // 是否开启模板编译缓存,设为false则每次都会重新编译 + 'tpl_cache' => true, + ]; + + public function __construct(App $app, array $config = []) + { + $this->app = $app; + + $this->config = array_merge($this->config, (array) $config); + + if (empty($this->config['cache_path'])) { + $this->config['cache_path'] = $app->getRuntimePath() . 'temp' . DIRECTORY_SEPARATOR; + } + + $this->template = new Template($this->config); + $this->template->setCache($app->cache); + $this->template->extend('$Think', function (array $vars) { + $type = strtoupper(trim(array_shift($vars))); + $param = implode('.', $vars); + + switch ($type) { + case 'CONST': + $parseStr = strtoupper($param); + break; + case 'CONFIG': + $parseStr = 'config(\'' . $param . '\')'; + break; + case 'LANG': + $parseStr = 'lang(\'' . $param . '\')'; + break; + case 'NOW': + $parseStr = "date('Y-m-d g:i a',time())"; + break; + case 'LDELIM': + $parseStr = '\'' . ltrim($this->getConfig('tpl_begin'), '\\') . '\''; + break; + case 'RDELIM': + $parseStr = '\'' . ltrim($this->getConfig('tpl_end'), '\\') . '\''; + break; + default: + $parseStr = defined($type) ? $type : '\'\''; + } + + return $parseStr; + }); + + $this->template->extend('$Request', function (array $vars) { + // 获取Request请求对象参数 + $method = array_shift($vars); + if (!empty($vars)) { + $params = implode('.', $vars); + if ('true' != $params) { + $params = '\'' . $params . '\''; + } + } else { + $params = ''; + } + + return 'app(\'request\')->' . $method . '(' . $params . ')'; + }); + } + + /** + * 检测是否存在模板文件 + * @access public + * @param string $template 模板文件或者模板规则 + * @return bool + */ + public function exists(string $template): bool + { + if ('' == pathinfo($template, PATHINFO_EXTENSION)) { + // 获取模板文件名 + $template = $this->parseTemplate($template); + } + + return is_file($template); + } + + /** + * 渲染模板文件 + * @access public + * @param string $template 模板文件 + * @param array $data 模板变量 + * @return void + */ + public function fetch(string $template, array $data = []): void + { + if (empty($this->config['view_path'])) { + $view = $this->config['view_dir_name']; + + if (is_dir($this->app->getAppPath() . $view)) { + $path = $this->app->getAppPath() . $view . DIRECTORY_SEPARATOR; + } else { + $appName = $this->app->http->getName(); + $path = $this->app->getRootPath() . $view . DIRECTORY_SEPARATOR . ($appName ? $appName . DIRECTORY_SEPARATOR : ''); + } + + $this->config['view_path'] = $path; + $this->template->view_path = $path; + } + + if ('' == pathinfo($template, PATHINFO_EXTENSION)) { + // 获取模板文件名 + $template = $this->parseTemplate($template); + } + + // 模板不存在 抛出异常 + if (!is_file($template)) { + throw new TemplateNotFoundException('template not exists:' . $template, $template); + } + + $this->template->fetch($template, $data); + } + + /** + * 渲染模板内容 + * @access public + * @param string $template 模板内容 + * @param array $data 模板变量 + * @return void + */ + public function display(string $template, array $data = []): void + { + $this->template->display($template, $data); + } + + /** + * 自动定位模板文件 + * @access private + * @param string $template 模板文件规则 + * @return string + */ + private function parseTemplate(string $template): string + { + // 分析模板文件规则 + $request = $this->app['request']; + + // 获取视图根目录 + if (strpos($template, '@')) { + // 跨模块调用 + list($app, $template) = explode('@', $template); + } + + if (isset($app)) { + $view = $this->config['view_dir_name']; + $viewPath = $this->app->getBasePath() . $app . DIRECTORY_SEPARATOR . $view . DIRECTORY_SEPARATOR; + + if (is_dir($viewPath)) { + $path = $viewPath; + } else { + $path = $this->app->getRootPath() . $view . DIRECTORY_SEPARATOR . $app . DIRECTORY_SEPARATOR; + } + + $this->template->view_path = $path; + } else { + $path = $this->config['view_path']; + } + + $depr = $this->config['view_depr']; + + if (0 !== strpos($template, '/')) { + $template = str_replace(['/', ':'], $depr, $template); + $controller = $request->controller(); + + if (strpos($controller, '.')) { + $pos = strrpos($controller, '.'); + $controller = substr($controller, 0, $pos) . '.' . Str::snake(substr($controller, $pos + 1)); + } else { + $controller = Str::snake($controller); + } + + if ($controller) { + if ('' == $template) { + // 如果模板文件名为空 按照默认模板渲染规则定位 + if (2 == $this->config['auto_rule']) { + $template = $request->action(true); + } elseif (3 == $this->config['auto_rule']) { + $template = $request->action(); + } else { + $template = Str::snake($request->action()); + } + + $template = str_replace('.', DIRECTORY_SEPARATOR, $controller) . $depr . $template; + } elseif (false === strpos($template, $depr)) { + $template = str_replace('.', DIRECTORY_SEPARATOR, $controller) . $depr . $template; + } + } + } else { + $template = str_replace(['/', ':'], $depr, substr($template, 1)); + } + + return $path . ltrim($template, '/') . '.' . ltrim($this->config['view_suffix'], '.'); + } + + /** + * 配置模板引擎 + * @access private + * @param array $config 参数 + * @return void + */ + public function config(array $config): void + { + $this->template->config($config); + $this->config = array_merge($this->config, $config); + } + + /** + * 获取模板引擎配置 + * @access public + * @param string $name 参数名 + * @return void + */ + public function getConfig(string $name) + { + return $this->template->getConfig($name); + } + + public function __call($method, $params) + { + return call_user_func_array([$this->template, $method], $params); + } +}