diff --git a/.htaccess b/.htaccess index 3c24e90..69a8f11 100644 --- a/.htaccess +++ b/.htaccess @@ -233,14 +233,6 @@ RewriteRule ^wyprzedaz/1$ wyprzedaz [R=301,L] RewriteRule ^en/kocyk-minky-niemowlaka-50x70-en$ index.php?category=6&lang=en&%{QUERY_STRING} [L] RewriteRule ^en/kocyk-minky-niemowlaka-50x70-en/([0-9]+)$ index.php?category=6&lang=en&bs=$1&%{QUERY_STRING} [L] RewriteRule ^en/kocyk-minky-niemowlaka-50x70-en/1$ en/kocyk-minky-niemowlaka-50x70-en [R=301,L] -RewriteRule ^p-425-a-tabliczki-z-miesiacami-galazka-kopi$ index.php?product=425 [L] -RewriteRule ^p-425-a-tabliczki-z-miesiacami-galazka-kopi/([0-9-]+)$ index.php?product=425&permutation_hash=$1 [L] -RewriteRule ^p-404-b-tabliczki-z-miesiacami-galazka$ index.php?product=404 [L] -RewriteRule ^p-404-b-tabliczki-z-miesiacami-galazka/([0-9-]+)$ index.php?product=404&permutation_hash=$1 [L] -RewriteRule ^p-403-tabliczka-modlitwa-aniele-bozy-strozu-moj-chmurka$ index.php?product=403 [L] -RewriteRule ^p-403-tabliczka-modlitwa-aniele-bozy-strozu-moj-chmurka/([0-9-]+)$ index.php?product=403&permutation_hash=$1 [L] -RewriteRule ^en/p-425-kopia$ index.php?product=425 [L] -RewriteRule ^en/p-425-kopia/([0-9-]+)$ index.php?product=425&permutation_hash=$1 [L] RewriteCond %{REQUEST_URI} ^/home$ RewriteRule ^(.*)$ http://www.shoppro.project-dc.pl/ [R=permanent,L] RewriteCond %{REQUEST_URI} ^/home-1$ diff --git a/admin/layout/style-scss/style.css b/admin/layout/style-scss/style.css new file mode 100644 index 0000000..ebd2f43 --- /dev/null +++ b/admin/layout/style-scss/style.css @@ -0,0 +1,508 @@ +body.external-page #content .admin-form { + max-width: 450px; } + +.sidebar-menu > li > a > span:nth-child(2) { + padding: 0; } + +ol.sortable, ol.sortable ol { + margin: 0 0 0 25px; + padding: 0; + list-style-type: none; } + +ol.sortable { + margin: 0; } + +ol.sortable, ol.sortable *, ol.sortable *:before, ol.sortable *:after { + box-sizing: content-box; } + +.sortable li { + margin: 0; + padding: 0; } + +.sortable li div.content { + color: #454545; + cursor: move; + height: 45px; + line-height: 45px; + margin: 0; + padding: 0 10px; + border-bottom: 1px solid #e1e1e1; } + +.sortable li div.content.text-danger { + color: #e9573f !important; } + +.sortable li.sort-branch div { + color: #383838; } + +.sort-leaf .disclose { + content: "- "; + text-indent: -3000px; + background-image: url("/libraries/jquery-nested-sortable/skin-vista/icons.gif"); + background-position: -16px -64px; + background-repeat: no-repeat; + display: inline-block; + height: 16px; + vertical-align: top; + width: 16px; + margin: 16px 5px 0 1px; } + +li.sort-collapsed.sort-hover div { + border-color: #999999; } + +.disclose { + cursor: pointer; + width: 20px; + display: none; + text-align: center; } + +.sortable li.sort-collapsed > ol { + display: none; } + +.sortable li.sort-branch > div > .disclose { + display: block; + float: left; + margin-right: 15px; } + +.sortable li.sort-collapsed > div > .disclose > span:before { + display: inline-block; + font-family: FontAwesome; + font-size: 10px; + content: "\f054"; + height: 25px; + width: 25px; + line-height: 25px; + border-radius: 13px; + background: #eeeeee; + color: #3bafda; + border: 1px solid #3bafda; } + +.sortable li.sort-collapsed > div > .disclose:hover > span:before, .sortable li.sort-expanded > div > .disclose:hover > span:before { + background: #3bafda; + color: #FFF; } + +.sortable li.sort-expanded > div > .disclose > span:before { + display: inline-block; + font-family: FontAwesome; + font-size: 10px; + content: "\f078"; + height: 25px; + width: 25px; + line-height: 25px; + border-radius: 13px; + background: #eeeeee; + color: #3bafda; + border: 1px solid #3bafda; } + +.placeholder { + outline: 1px dashed #4183C4; } + +.sort-error { + background: #fbe3e4; + border-color: transparent; } + +.menu_sortable .btn-group { + margin-top: 7px; + display: none; } + +.menu_sortable div:hover .btn-group { + display: block; } + +.menu_sortable div:hover { + background: #f0f0f0; } + +.resp-vtabs::after { + content: ''; + display: block; + clear: both; } + +.resp-tab-content { + padding: 25px 15px; } + +.resp-tab-content .resp-tab-content { + padding: 0; + border: 0; } + +.resp-tabs-list li, .resp-tab-active { + padding: 8px 20px !important; } + +.resp-tab-content .resp-tabs-list { + border-bottom: 0; + margin-bottom: 10px; + background: #f1f1f1; } + +.resp-tab-content .resp-tabs-list li { + border-left: 0 !important; + border-right: 0 !important; + float: right; } + +.resp-tab-content .resp-tabs-list::after { + clear: both; + content: ''; + display: block; } + +.resp-tab-content .resp-tab-active { + position: relative; + top: -1px; } + +.resp-tab-content .form-group { + margin: 0 0 15px 0; } + +.input-group span.btn-info { + border-color: rgba(0, 0, 0, 0.05); } + +#overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 1300; + background: rgba(0, 0, 0, 0.2); + display: none; + cursor: pointer; } + +#g-row-limit { + width: auto; + display: inline-block; + height: 30px; + line-height: 30px; + padding: 4px 12px; } + +#images-uploader, #files-uploader { + clear: both; } + +#images-uploader, #images-uploader *, #files-uploader, #files-uploader * { + box-sizing: content-box !important; } + +#images-list { + margin: 0; + padding: 0 5px; } + +#images-list li { + background: #FFF; + text-align: center; + display: block; + height: 100px; + margin: 5px 5px 10px 5px; + vertical-align: middle; + border: 1px solid #e5e5e5; + float: left; + width: calc( 50% - 10px ); } + +#images-list li .article-image { + height: 100%; + width: 120px; + float: left; + margin-right: 10px; } + +#images-list li .input-group { + margin: 10px 10px 10px 0; } + +#images-list li:hover .article-image-edit, #images-list li.pending .article-image-edit { + display: block; } + +.article-image-edit { + background: rgba(255, 255, 255, 0.8); + position: absolute; + height: 100%; + width: 150px; + cursor: pointer; + line-height: 168px; + display: none; } + +.article-image-edit i { + font-size: 28px; + color: #cc0000; } + +.article-image-edit img { + height: 50px; + position: relative; + top: 12px; } + +#files-list { + list-style-type: none; + margin: 0; + padding: 0; } + +#files-list li { + float: left; + margin: 5px 7px; } + +#files-list li .article_file_delete { + border-color: rgba(0, 0, 0, 0.05); } + +#elfinder * { + box-sizing: content-box !important; } + +#elfinder { + background: #EBEBEB; } + +.elfinder-button { + background: #FFF !important; } + +.elfinder-cwd, .elfinder .elfinder-navbar, .std42-dialog .ui-dialog-content, .elfinder-contextmenu .elfinder-contextmenu-item span { + font-size: 12px; } + +.elfinder-contextmenu-item { + background: #FFF; + color: #000; } + +.elfinder-cwd-view-icons .elfinder-cwd-filename { + -webkit-border-radius: 0px; + border-radius: 0px; } + +.elfinder-cwd-view-icons .elfinder-cwd-file .elfinder-cwd-filename.ui-state-hover, .elfinder-cwd table td.ui-state-hover, .elfinder-button-menu .ui-state-hover { + background: #2c373d; } + +.elfinder-cwd-filename input[type="text"] { + border: 0px !important; + padding: 0px !important; } + +#elfinder { + height: 750px !important; + position: relative; } + +.elfinder-cwd table tr:nth-child(2n+1) { + background: #D3D3D3; } + +.elfinder-cwd table tr { + border-top: 1px solid #CCC; } + +.elfinder-cwd table tr td { + padding: 5px 12px !important; } + +.elfinder-workzone { + clear: both; } + +#elfinder .ui-dialog { + border: 1px solid #ccc; + position: absolute !important; } + +.navbar-branding .navbar-brand { + float: left; } + +.navbar .label { + margin-left: 10px; + position: relative; + top: 17px; } + +body.sb-top .navbar-branding { + width: 250px; } + +.flags { + margin: -4px 0 0 20px !important; + background: none; + cursor: move; } + +.flags:hover { + border: 0px !important; + background: none !important; } + +.flags img { + height: 10px; + margin-right: 5px; + opacity: .4; } + +.CodeMirror { + height: 500px !important; } + +.nav > li > a { + font-size: 12px; } + +#newsletter-preview { + border: 1px solid #ccc; + padding: 20px; } + +div.jqi .jqititle { + margin-bottom: 0; } + +#google-preview { + padding: 10px; } + +.google-title { + color: #1a0dab; + font-family: arial,sans-serif; + cursor: pointer; + font-size: 18px; + line-height: 21.6px; + width: 600px; + display: block; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } + +.google-url { + color: #006621; + font-family: arial,sans-serif; + font-size: 14px; + line-height: 16px; + width: 600px; + display: block; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } + +.google-description { + color: #545454; + font-family: arial,sans-serif; + font-size: 13px; + line-height: 18.2px; + width: 600px; + display: block; } + +.sidebar-left-content { + background: #114975; } + +.sidebar-menu li.disable_menu { + pointer-events: none; + opacity: .3; } + +body.sb-top #sidebar_left .sidebar-menu > li > a { + color: #FFF; } + +body.sb-top.sb-top-sm #sidebar_left .sidebar-menu > li > a > span:nth-child(1) { + font-size: 13px; } + +body.sb-top #sidebar_left .sidebar-menu li > a > span.caret { + color: #FFF; } + +body.sb-top #sidebar_left .sidebar-menu > li.active > a, +body.sb-top #sidebar_left .sidebar-menu > li:hover > a, +body.sb-top #sidebar_left .sidebar-menu > li > a.menu-open, +body.sb-top #sidebar_left .sidebar-menu > li > a:hover, +body.sb-top #sidebar_left .sidebar-menu > li > a:focus { + background: #FFF; + color: #114975; } + +body.sb-top #sidebar_left .sidebar-menu liactive > a > span.caret, +body.sb-top #sidebar_left .sidebar-menu > li:hover > a > span.caret, +body.sb-top #sidebar_left .sidebar-menu > li > a.menu-open > span.caret, +body.sb-top #sidebar_left .sidebar-menu > li > a:hover > span.caret, +body.sb-top #sidebar_left .sidebar-menu > li > a:focus > span.caret { + color: #114975; } + +.sidebar-menu > li > ul { + background: #FFF; + -webkit-box-shadow: -1px 1px 6px rgba(0, 0, 0, 0.2); + -moz-box-shadow: -1px 1px 6px rgba(0, 0, 0, 0.2); + box-shadow: -1px 1px 6px rgba(0, 0, 0, 0.2); } + +.sidebar-menu > li > ul > li > a { + color: #114975; + border-bottom: 1px solid #f3f3f3; } + +body.sb-top #sidebar_left .sidebar-menu > li > ul > li > a.menu-open:after, body.sb-top #sidebar_left .sidebar-menu > li > ul > li.active > a:after, body.sb-top #sidebar_left .sidebar-menu > li > ul > li:hover > a:after, body.sb-top #sidebar_left .sidebar-menu > li > ul > li:focus > a:after { + width: 5px; + left: 0; } + +.sidebar-menu > li > ul > li > a:hover, .sidebar-menu > li > ul > li > a:focus { + color: #114975; } + +.sidebar-menu > li > ul > li:hover > a:after, .sidebar-menu > li > ul > li:focus > a:after { + background: #70ca63; } + +body.sb-top #sidebar_left .sidebar-menu > li > ul { + padding-bottom: 0; } + +.progress-box { + position: absolute; + top: 0px; + width: 100%; + height: 100%; + z-index: 200; + background: #fff; + padding: 0px; + margin-left: -15px; } + +.progress { + margin: 15px; + height: 35px; + transform: translateY(-100%); + position: relative; + top: 30%; + background-color: #333; } + +.version { + position: relative; + top: 5%; } + +.version h3 p { + display: inline-block; } + +.version h3 { + text-align: center; } + +.form-group.text-right div { + padding-right: 15px; } + +.remember { + font-size: 13px !important; } + +#remember { + display: inline-block !important; + width: 15px; + height: 15px; + top: 2px; + position: relative; } + +.popo { + display: inline-block; + border: 1px solid #114975; + border-radius: 50%; + height: 20px; + width: 20px; + text-align: center; } + +.popover-btn { + cursor: pointer; + position: relative; + display: block; + color: red; + height: 20px; + width: 20px; + text-indent: -2px; + font-style: normal; } + +.mfp-auto-cursor .mfp-content { + max-width: 1000px; } + +.mfp-auto-cursor .mfp-content .col-lg-9, +.mfp-auto-cursor .mfp-content .row { + width: 100%; + float: none; + max-width: 1000px; } + +.mfp-auto-cursor .mfp-content .g-container { + max-width: 1000px; } + +.mfp-close, .mfp-close:active { + right: -7px; + top: -27px; + background: #FFF !important; } + +.affix { + top: 60px; + width: 100%; + z-index: 100; + left: 0px; } + +.affix + .panel-heading { + padding-top: 70px; } + +.resp-vtabs li.resp-tab-active { + background: #4186da !important; + color: #FFF; + border-left: 0 !important; } + +.resp-vtabs > .resp-tabs-container { + border: 0 !important; + border-left: 1px solid #e5e5e5 !important; } + +@media (min-width: 1199px) { + .g-container .panel-body form { + max-width: 1400px; } } +@media (max-width: 900px) { + body.sb-top #toggle_sidemenu_t { + width: 60px; } } + +/*# sourceMappingURL=style.css.map */ diff --git a/admin/layout/style-scss/style.css.map b/admin/layout/style-scss/style.css.map new file mode 100644 index 0000000..a2396ca --- /dev/null +++ b/admin/layout/style-scss/style.css.map @@ -0,0 +1,7 @@ +{ +"version": 3, +"mappings": "AAAA,uCAAwC;EACtC,SAAS,EAAE,KAAK;;AAElB,0CAA2C;EACzC,OAAO,EAAE,CAAC;;AAEZ,2BAA4B;EAC1B,MAAM,EAAE,UAAU;EAClB,OAAO,EAAE,CAAC;EACV,eAAe,EAAE,IAAI;;AAEvB,WAAY;EACV,MAAM,EAAE,CAAC;;AAEX,qEAAsE;EACpE,UAAU,EAAE,WAAW;;AAEzB,YAAa;EACX,MAAM,EAAE,CAAC;EACT,OAAO,EAAE,CAAC;;AAEZ,wBAA0B;EACxB,KAAK,EAAE,OAAO;EACd,MAAM,EAAE,IAAI;EACZ,MAAM,EAAE,IAAI;EACZ,WAAW,EAAE,IAAI;EACjB,MAAM,EAAE,CAAC;EACT,OAAO,EAAE,MAAM;EACf,aAAa,EAAE,iBAAiB;;AAElC,oCAAqC;EACnC,KAAK,EAAE,kBAAkB;;AAE3B,4BAA6B;EAC3B,KAAK,EAAE,OAAO;;AAEhB,oBAAqB;EACnB,OAAO,EAAE,IAAI;EACb,WAAW,EAAE,OAAO;EACpB,gBAAgB,EAAE,6DAA+D;EACjF,mBAAmB,EAAE,WAAW;EAChC,iBAAiB,EAAE,SAAS;EAC5B,OAAO,EAAE,YAAY;EACrB,MAAM,EAAE,IAAI;EACZ,cAAc,EAAE,GAAG;EACnB,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,cAAc;;AAExB,gCAAiC;EAC/B,YAAY,EAAE,OAAO;;AAEvB,SAAU;EACR,MAAM,EAAE,OAAO;EACf,KAAK,EAAE,IAAI;EACX,OAAO,EAAE,IAAI;EACb,UAAU,EAAE,MAAM;;AAEpB,gCAAiC;EAC/B,OAAO,EAAE,IAAI;;AAEf,0CAA2C;EACzC,OAAO,EAAE,KAAK;EACd,KAAK,EAAE,IAAI;EACX,YAAY,EAAE,IAAI;;AAEpB,2DAA4D;EAC1D,OAAO,EAAE,YAAY;EACrB,WAAW,EAAE,WAAW;EACxB,SAAS,EAAE,IAAI;EACf,OAAO,EAAE,OAAO;EAChB,MAAM,EAAE,IAAI;EACZ,KAAK,EAAE,IAAI;EACX,WAAW,EAAE,IAAI;EACjB,aAAa,EAAE,IAAI;EACnB,UAAU,EAAE,OAAO;EACnB,KAAK,EAAE,OAAO;EACd,MAAM,EAAE,iBAAiB;;AAE3B,mIAAoI;EAClI,UAAU,EAAE,OAAO;EACnB,KAAK,EAAE,IAAI;;AAEb,0DAA2D;EACzD,OAAO,EAAE,YAAY;EACrB,WAAW,EAAE,WAAW;EACxB,SAAS,EAAE,IAAI;EACf,OAAO,EAAE,OAAO;EAChB,MAAM,EAAE,IAAI;EACZ,KAAK,EAAE,IAAI;EACX,WAAW,EAAE,IAAI;EACjB,aAAa,EAAE,IAAI;EACnB,UAAU,EAAE,OAAO;EACnB,KAAK,EAAE,OAAO;EACd,MAAM,EAAE,iBAAiB;;AAE3B,YAAa;EACX,OAAO,EAAE,kBAAkB;;AAE7B,WAAY;EACV,UAAU,EAAE,OAAO;EACnB,YAAY,EAAE,WAAW;;AAE3B,yBAA0B;EACxB,UAAU,EAAE,GAAG;EACf,OAAO,EAAE,IAAI;;AAEf,mCAAoC;EAClC,OAAO,EAAE,KAAK;;AAEhB,wBAAyB;EACvB,UAAU,EAAE,OAAO;;AAErB,kBAAmB;EACjB,OAAO,EAAE,EAAE;EACX,OAAO,EAAE,KAAK;EACd,KAAK,EAAE,IAAI;;AAEb,iBAAkB;EAChB,OAAO,EAAE,SAAS;;AAEpB,mCAAoC;EAClC,OAAO,EAAE,CAAC;EACV,MAAM,EAAE,CAAC;;AAEX,oCAAqC;EACnC,OAAO,EAAE,mBAAmB;;AAE9B,iCAAkC;EAChC,aAAa,EAAE,CAAC;EAChB,aAAa,EAAE,IAAI;EACnB,UAAU,EAAE,OAAO;;AAErB,oCAAqC;EACnC,WAAW,EAAE,YAAY;EACzB,YAAY,EAAE,YAAY;EAC1B,KAAK,EAAE,KAAK;;AAEd,wCAAyC;EACvC,KAAK,EAAE,IAAI;EACX,OAAO,EAAE,EAAE;EACX,OAAO,EAAE,KAAK;;AAEhB,kCAAmC;EACjC,QAAQ,EAAE,QAAQ;EAClB,GAAG,EAAE,IAAI;;AAEX,6BAA8B;EAC5B,MAAM,EAAE,UAAU;;AAEpB,0BAA2B;EACzB,YAAY,EAAE,mBAAmB;;AAEnC,QAAS;EACP,QAAQ,EAAE,KAAK;EACf,GAAG,EAAE,CAAC;EACN,IAAI,EAAE,CAAC;EACP,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,IAAI;EACZ,OAAO,EAAE,IAAI;EACb,UAAU,EAAE,kBAAoB;EAChC,OAAO,EAAE,IAAI;EACb,MAAM,EAAE,OAAO;;AAEjB,YAAa;EACX,KAAK,EAAE,IAAI;EACX,OAAO,EAAE,YAAY;EACrB,MAAM,EAAE,IAAI;EACZ,WAAW,EAAE,IAAI;EACjB,OAAO,EAAE,QAAQ;;AAEnB,iCAAkC;EAChC,KAAK,EAAE,IAAI;;AAEb,wEAAyE;EACvE,UAAU,EAAE,sBAAsB;;AAEpC,YAAa;EACX,MAAM,EAAE,CAAC;EACT,OAAO,EAAE,KAAK;;AAEhB,eAAgB;EACd,UAAU,EAAE,IAAI;EAChB,UAAU,EAAE,MAAM;EAClB,OAAO,EAAE,KAAK;EACd,MAAM,EAAE,KAAK;EACb,MAAM,EAAE,gBAAgB;EACxB,cAAc,EAAE,MAAM;EACtB,MAAM,EAAE,iBAAiB;EACzB,KAAK,EAAE,IAAI;EACX,KAAK,EAAE,kBAAkB;;AAE3B,8BAA+B;EAC7B,MAAM,EAAE,IAAI;EACZ,KAAK,EAAE,KAAK;EACZ,KAAK,EAAE,IAAI;EACX,YAAY,EAAE,IAAI;;AAEpB,4BAA6B;EAC3B,MAAM,EAAE,gBAAgB;;AAE1B,sFAAuF;EACrF,OAAO,EAAE,KAAK;;AAEhB,mBAAoB;EAClB,UAAU,EAAE,wBAAyB;EACrC,QAAQ,EAAE,QAAQ;EAClB,MAAM,EAAE,IAAI;EACZ,KAAK,EAAE,KAAK;EACZ,MAAM,EAAE,OAAO;EACf,WAAW,EAAE,KAAK;EAClB,OAAO,EAAE,IAAI;;AAEf,qBAAsB;EACpB,SAAS,EAAE,IAAI;EACf,KAAK,EAAE,OAAO;;AAEhB,uBAAwB;EACtB,MAAM,EAAE,IAAI;EACZ,QAAQ,EAAE,QAAQ;EAClB,GAAG,EAAE,IAAI;;AAEX,WAAY;EACV,eAAe,EAAE,IAAI;EACrB,MAAM,EAAE,CAAC;EACT,OAAO,EAAE,CAAC;;AAEZ,cAAe;EACb,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,OAAO;;AAEjB,mCAAoC;EAClC,YAAY,EAAE,mBAAmB;;AAEnC,WAAY;EACV,UAAU,EAAE,sBAAsB;;AAEpC,SAAU;EACR,UAAU,EAAE,OAAO;;AAErB,gBAAiB;EACf,UAAU,EAAE,eAAe;;AAE7B,kIAAmI;EACjI,SAAS,EAAE,IAAI;;AAEjB,0BAA2B;EACzB,UAAU,EAAE,IAAI;EAChB,KAAK,EAAE,IAAI;;AAEb,+CAAgD;EAC9C,qBAAqB,EAAE,GAAG;EAC1B,aAAa,EAAE,GAAG;;AAEpB,+JAAgK;EAC9J,UAAU,EAAE,OAAO;;AAErB,yCAA0C;EACxC,MAAM,EAAE,cAAc;EACtB,OAAO,EAAE,cAAc;;AAEzB,SAAU;EACR,MAAM,EAAE,gBAAgB;EACxB,QAAQ,EAAE,QAAQ;;AAEpB,sCAAuC;EACrC,UAAU,EAAE,OAAO;;AAErB,sBAAuB;EACrB,UAAU,EAAE,cAAc;;AAE5B,yBAA0B;EACxB,OAAO,EAAE,mBAAmB;;AAE9B,kBAAmB;EACjB,KAAK,EAAE,IAAI;;AAEb,oBAAqB;EACnB,MAAM,EAAE,cAAc;EACtB,QAAQ,EAAE,mBAAmB;;AAE/B,8BAA+B;EAC7B,KAAK,EAAE,IAAI;;AAEb,cAAe;EACb,WAAW,EAAE,IAAI;EACjB,QAAQ,EAAE,QAAQ;EAClB,GAAG,EAAE,IAAI;;AAEX,4BAA6B;EAC3B,KAAK,EAAE,KAAK;;AAEd,MAAO;EACL,MAAM,EAAE,wBAAwB;EAChC,UAAU,EAAE,IAAI;EAChB,MAAM,EAAE,IAAI;;AAEd,YAAa;EACX,MAAM,EAAE,cAAc;EACtB,UAAU,EAAE,eAAe;;AAE7B,UAAW;EACT,MAAM,EAAE,IAAI;EACZ,YAAY,EAAE,GAAG;EACjB,OAAO,EAAE,EAAE;;AAEb,WAAY;EACV,MAAM,EAAE,gBAAgB;;AAE1B,aAAc;EACZ,SAAS,EAAE,IAAI;;AAEjB,mBAAoB;EAClB,MAAM,EAAE,cAAc;EACtB,OAAO,EAAE,IAAI;;AAEf,iBAAkB;EAChB,aAAa,EAAE,CAAC;;AAElB,eAAgB;EACd,OAAO,EAAE,IAAI;;AAEf,aAAc;EACZ,KAAK,EAAE,OAAO;EACd,WAAW,EAAE,gBAAgB;EAC7B,MAAM,EAAE,OAAO;EACf,SAAS,EAAE,IAAI;EACf,WAAW,EAAE,MAAM;EACnB,KAAK,EAAE,KAAK;EACZ,OAAO,EAAE,KAAK;EACd,QAAQ,EAAE,MAAM;EAChB,aAAa,EAAE,QAAQ;EACvB,WAAW,EAAE,MAAM;;AAErB,WAAY;EACV,KAAK,EAAE,OAAe;EACtB,WAAW,EAAE,gBAAgB;EAC7B,SAAS,EAAE,IAAI;EACf,WAAW,EAAE,IAAI;EACjB,KAAK,EAAE,KAAK;EACZ,OAAO,EAAE,KAAK;EACd,QAAQ,EAAE,MAAM;EAChB,aAAa,EAAE,QAAQ;EACvB,WAAW,EAAE,MAAM;;AAErB,mBAAoB;EAClB,KAAK,EAAE,OAAe;EACtB,WAAW,EAAE,gBAAgB;EAC7B,SAAS,EAAE,IAAI;EACf,WAAW,EAAE,MAAM;EACnB,KAAK,EAAE,KAAK;EACZ,OAAO,EAAE,KAAK;;AAEhB,qBAAsB;EACpB,UAAU,EAAE,OAAO;;AAErB,6BAA8B;EAC5B,cAAc,EAAE,IAAI;EACpB,OAAO,EAAE,EAAE;;AAEb,gDAAiD;EAC/C,KAAK,EAAE,IAAI;;AAEb,8EAA+E;EAC7E,SAAS,EAAE,IAAI;;AAEjB,2DAA4D;EAC1D,KAAK,EAAE,IAAI;;AAEb;;;;sDAIuD;EACrD,UAAU,EAAE,IAAI;EAChB,KAAK,EAAE,OAAO;;AAEhB;;;;mEAIoE;EAClE,KAAK,EAAE,OAAO;;AAEhB,uBAAwB;EACtB,UAAU,EAAE,IAAI;EAChB,kBAAkB,EAAE,+BAA4B;EAChD,eAAe,EAAE,+BAA4B;EAC7C,UAAU,EAAE,+BAA4B;;AAE1C,gCAAiC;EAC/B,KAAK,EAAE,OAAO;EACd,aAAa,EAAE,iBAAiB;;AAElC,mSAAoS;EAClS,KAAK,EAAE,GAAG;EACV,IAAI,EAAE,CAAC;;AAET,8EAA+E;EAC7E,KAAK,EAAE,OAAO;;AAEhB,0FAA2F;EACzF,UAAU,EAAE,OAAO;;AAErB,iDAAkD;EAChD,cAAc,EAAE,CAAC;;AAEnB,aAAc;EACV,QAAQ,EAAE,QAAQ;EAClB,GAAG,EAAE,GAAG;EACR,KAAK,EAAC,IAAI;EACV,MAAM,EAAC,IAAI;EACX,OAAO,EAAC,GAAG;EACX,UAAU,EAAE,IAAI;EAChB,OAAO,EAAC,GAAG;EACX,WAAW,EAAC,KAAK;;AAErB,SAAS;EACL,MAAM,EAAC,IAAI;EACX,MAAM,EAAC,IAAI;EACX,SAAS,EAAE,iBAAiB;EAC5B,QAAQ,EAAC,QAAQ;EACjB,GAAG,EAAC,GAAG;EACP,gBAAgB,EAAE,IAAI;;AAE1B,QAAQ;EACJ,QAAQ,EAAC,QAAQ;EACjB,GAAG,EAAE,EAAE;;AAEX,aAAa;EACT,OAAO,EAAE,YAAY;;AAEzB,WAAW;EACP,UAAU,EAAE,MAAM;;AAGtB,0BAA0B;EACtB,aAAa,EAAC,IAAI;;AAEtB,SAAS;EACL,SAAS,EAAE,eAAe;;AAE9B,SAAS;EACL,OAAO,EAAE,uBAAuB;EAChC,KAAK,EAAC,IAAI;EACV,MAAM,EAAC,IAAI;EACX,GAAG,EAAE,GAAG;EACR,QAAQ,EAAE,QAAQ;;AAEtB,KAAM;EACJ,OAAO,EAAE,YAAY;EACrB,MAAM,EAAE,iBAAiB;EACzB,aAAa,EAAE,GAAG;EAClB,MAAM,EAAE,IAAI;EACZ,KAAK,EAAE,IAAI;EACX,UAAU,EAAE,MAAM;;AAEpB,YAAa;EACX,MAAM,EAAE,OAAO;EACf,QAAQ,EAAE,QAAQ;EAClB,OAAO,EAAE,KAAK;EACd,KAAK,EAAE,GAAG;EACV,MAAM,EAAE,IAAI;EACZ,KAAK,EAAE,IAAI;EACX,WAAW,EAAE,IAAI;EACjB,UAAU,EAAE,MAAM;;AAEpB,6BAA8B;EAC5B,SAAS,EAAE,MAAM;;AAEnB;kCACmC;EACjC,KAAK,EAAE,IAAI;EACX,KAAK,EAAE,IAAI;EACX,SAAS,EAAE,MAAM;;AAEnB,0CAA2C;EACzC,SAAS,EAAE,MAAM;;AAEnB,6BAA8B;EAC5B,KAAK,EAAE,IAAI;EACX,GAAG,EAAE,KAAK;EACV,UAAU,EAAE,eAAe;;AAE7B,MAAO;EACL,GAAG,EAAE,IAAI;EACT,KAAK,EAAE,IAAI;EACX,OAAO,EAAE,GAAG;EACZ,IAAI,EAAC,GAAG;;AAEV,uBAAuB;EACrB,WAAW,EAAE,IAAI;;AAEnB,8BAA+B;EAC7B,UAAU,EAAE,kBAAkB;EAC9B,KAAK,EAAE,IAAI;EACX,WAAW,EAAE,YAAY;;AAE3B,kCAAmC;EACjC,MAAM,EAAE,YAAY;EACpB,WAAW,EAAE,4BAA4B;;AAE3C,0BAA6B;EAC3B,6BAA8B;IAC5B,SAAS,EAAE,MAAM;AAGrB,yBAA0B;EACxB,8BAA+B;IAC7B,KAAK,EAAE,IAAI", +"sources": ["style.scss"], +"names": [], +"file": "style.css" +} diff --git a/admin/temp/2/s_cache_21a4da48e5fa14e992150d116fb212cc b/admin/temp/2/s_cache_21a4da48e5fa14e992150d116fb212cc new file mode 100644 index 0000000..f727f71 --- /dev/null +++ b/admin/temp/2/s_cache_21a4da48e5fa14e992150d116fb212cc @@ -0,0 +1 @@ +YToyOntpOjA7aToxNjkzOTE3NzIzO2k6MTtzOjg6Ik1hcmlhbmVrIjt9 \ No newline at end of file diff --git a/admin/temp/3/s_cache_3a23324137621a1dfafc3ee613d86e94 b/admin/temp/3/s_cache_3a23324137621a1dfafc3ee613d86e94 index aeb719b..95f8ff0 100644 --- a/admin/temp/3/s_cache_3a23324137621a1dfafc3ee613d86e94 +++ b/admin/temp/3/s_cache_3a23324137621a1dfafc3ee613d86e94 @@ -1 +1 @@ -YToyOntpOjA7aToxNzI1MTg1ODE4O2k6MTtzOjI6InBsIjt9 \ No newline at end of file +YToyOntpOjA7aToxNjkzOTQ2ODIzO2k6MTtzOjI6InBsIjt9 \ No newline at end of file diff --git a/admin/temp/4/s_cache_44e3d63e885545f6b55debe0486ec1e4 b/admin/temp/4/s_cache_44e3d63e885545f6b55debe0486ec1e4 index d80820c..47a3ce6 100644 --- a/admin/temp/4/s_cache_44e3d63e885545f6b55debe0486ec1e4 +++ b/admin/temp/4/s_cache_44e3d63e885545f6b55debe0486ec1e4 @@ -1 +1 @@ -YToyOntpOjA7aToxNzI1MTg1ODE4O2k6MTthOjE5ODp7aTowO3M6MjoicGwiO3M6NToidGVtYXQiO3M6NToidGVtYXQiO3M6OToid2lhZG9tb3NjIjtzOjExOiJ3aWFkb21vxZvEhyI7czo2OiJ3eXNsaWoiO3M6Nzoid3nFm2xpaiI7czo1OiJlbWFpbCI7czo1OiJlbWFpbCI7czoxMToibnItdGVsZWZvbnUiO3M6MTE6Im5yIHRlbGVmb251IjtzOjM0OiJwcm9zemUtdXp1cGVsbmljLWVtYWlsLWx1Yi10ZWxlZm9uIjtzOjUxOiJQcm9zesSZIHV6dXBlxYJuacSHIGFkcmVzIGVtYWlsIGx1YiBudW1lciB0ZWxlZm9udS4iO3M6NDoiYmxhZCI7czo2OiJixYLEhWQiO3M6NzoiemFta25paiI7czo3OiJ6YW1rbmlqIjtzOjI1OiJ3aWFkb21vc2Mtem9zdGFsYS13eXNsYW5hIjtzOjkwOiJUd29qYSB3aWFkb21vxZvEhyB6b3N0YcWCYSB3eXPFgmFuYS4gUG9zdGFyYW15IHNpxJkgbmEgbmnEhSBvZHBvd2llZHppZcSHIGphayBuYWpzenliY2llai4iO3M6Mjg6IndpYWRvbW9zYy1uaWV6b3N0YWxhLXd5c2xhbmEiO3M6OTM6IlBvZGN6YXMgd3lzecWCYW5pYSB3aWFkb21vxZtjaSB3eXN0xIVwacWCIGLFgsSFZC4gUHJvc3rEmSBzcHLDs2Jvd2HEhyBwb25vd25pZS4gUHJ6ZXByYXN6YW15LiI7czoxMjoiZGF0YS1kb2RhbmlhIjtzOjEyOiJkYXRhIGRvZGFuaWEiO3M6MTY6ImRhdGEtbW9keWZpa2FjamkiO3M6MTY6ImRhdGEgbW9keWZpa2FjamkiO3M6MTI6ImFkcmVzLXN0cm9ueSI7czoxMjoiYWRyZXMgc3Ryb255IjtzOjI5OiJwcm9zemUtdXp1cGVsbmljLWFkcmVzLXN0cm9ueSI7czozMzoiUHJvc3rEmSB1enVwZcWCbmnEhyBhZHJlcyBzdHJvbnkuIjtzOjg6InBpZXJ3c3phIjtzOjg6InBpZXJ3c3phIjtzOjg6Im5hc3RlcG5hIjtzOjk6Im5hc3TEmXBuYSI7czoxMDoicG9wcnplZG5pYSI7czoxMDoicG9wcnplZG5pYSI7czo4OiJvc3RhdG5pYSI7czo4OiJvc3RhdG5pYSI7czoxOiJ6IjtzOjE6InoiO3M6Njoid2llY2VqIjtzOjc6IndpxJljZWoiO3M6Njoid3N0ZWN6IjtzOjY6IndzdGVjeiI7czoyMzoiZm9ybXVsYXJ6LWNhcHRjaGEtbGFiZWwiO3M6Njk6IlByb3N6xJkgbmFyeXNvd2HEhyBrc3p0YcWCdCB3IHBvbmnFvHN6eW0gcG9sdSwgYWJ5IHd5c8WCYcSHIGZvcm11bGFyeiI7czoxNjoic3Byb2J1ai1wb25vd25pZSI7czoxNzoic3Byw7NidWogcG9ub3duaWUiO3M6NjoiZG9icnplIjtzOjY6ImRvYnJ6ZSI7czo1OiJ3aXRhaiI7czo1OiJ3aXRhaiI7czoxMToiemFsb2d1ai1zaWUiO3M6MTI6InphbG9ndWogc2nEmSI7czozOiJsdWIiO3M6MzoibHViIjtzOjE1OiJ6YXJlamVzdHJ1ai1zaWUiO3M6MTY6InphcmVqZXN0cnVqIHNpxJkiO3M6NToiaWxvc2MiO3M6NzoiaWxvxZvEhyI7czo0OiJzdW1hIjtzOjQ6InN1bWEiO3M6ODoicG9sZWNhbXkiO3M6ODoicG9sZWNhbXkiO3M6MTg6InNwcmF3ZHota29uaWVjem5pZSI7czoxOToic3ByYXdkxboga29uaWVjem5pZSI7czoxNjoiZG9kYWotZG8ta29zenlrYSI7czoxNjoiZG9kYWogZG8ga29zenlrYSI7czoxNDoic3RyZWZhLXJvZHppY2EiO3M6MTQ6InN0cmVmYSByb2R6aWNhIjtzOjE2OiJuYWpub3dzemUtcG9yYWR5IjtzOjE2OiJOYWpub3dzemUgcG9yYWR5IjtzOjE4OiJuZXdzbGV0dGVyLXpnb2RhLTEiO3M6NTU6Ild5cmHFvGFtIHpnb2TEmSBuYSBwcnpldHdhcnphbmllIG1vaWNoIGRhbnljaCBvc29ib3d5Y2giO3M6NDoiendpbiI7czo1OiJ6d2nFhCI7czo2OiJyb3p3aW4iO3M6Nzoicm96d2nFhCI7czozMzoibmV3c2xldHRlci1hZG1pbmlzdHJhdG9yLWRhbnljaC0xIjtzOjYxOiJBZG1pbmlzdHJhdG9yZW0gZGFueWNoIG9zb2Jvd3ljaCB6YXdhcnR5Y2ggdyB6Z8WCb3N6ZW5pdSBqZXN0IjtzOjMzOiJuZXdzbGV0dGVyLWFkbWluaXN0cmF0b3ItZGFueWNoLTIiO3M6NzQ2OiJfX19fXy4gRGFuZSBrb250YWt0b3dlIEluc3Bla3RvcmEgT2Nocm9ueSBEYW55Y2g6IHVva2lrQHVva2lrLmdvdi5wbC4gRGFuZSBvc29ib3dlIHPEhSBwcnpldHdhcnphbmUgdyBjZWx1IGRvc3RhcmN6ZW5pYSBuZXdzbGV0dGVyYSwgbmEgcG9kc3Rhd2llIGFydC4gNiB1c3QuIDEgbGl0LiBhKSByb3pwb3J6xIVkemVuaWEgUGFybGFtZW50dSBFdXJvcGVqc2tpZWdvIGkgUmFkeSAoVUUpIDIwMTYvNjc5IChST0RPKSBpIG5pZSBzxIUgcHJ6ZWthenl3YW5lIGlubnltIG9kYmlvcmNvbSwgb3JnYW5pemFjamkgbWnEmWR6eW5hcm9kb3dlaiBjenkgZG8gcGHFhHN0dyB0cnplY2ljaC4gRGFuZSBvc29ib3dlIHByemVjaG93eXdhbmUgc8SFIHByemV6IG9rcmVzIHByZW51bWVyYXR5LiBXbmlvc2tvZGF3Y2EgbWEgcHJhd28gZG8gZG9zdMSZcHUgZG8gc3dvaWNoIGRhbnljaCBvc29ib3d5Y2gsIGljaCBzcHJvc3Rvd2FuaWEgb3JheiB3bmllc2llbmlhIHNrYXJnaSBkbyBfX19fXy4gUG9kYW5pZSBkYW55Y2ggb3NvYm93eWNoIGplc3QgZG9icm93b2xuZSwgbmllIHd5bmlrYSB6IHByemVwaXPDs3csIGljaCBuaWVwb2RhbmllIGLEmWR6aWUgc2t1dGtvd2HFgm8gYnJha2llbSBtb8W8bGl3b8WbY2kgemFtw7N3aWVuaWEuIE5hIHBvZHN0YXdpZSBkYW55Y2ggb3NvYm93eWNoIG5pZSBzxIUgcG9kZWptb3dhbmUgemF1dG9tYXR5em93YW5lIGRlY3l6amUsIHcgdHltIG5pZSBzdG9zdWplIHNpxJkgcHJvZmlsb3dhbmlhLiI7czoyNjoibmV3c2xldHRlci16Z29kYS1rb211bmlrYXQiO3M6NTc6IlByb3N6xJkgemF6bmFjennEhyB6Z29kxJkgZG8gcHJ6ZXR3YXJ6YW5pYSB6IG5ld3NsZXR0ZXJhLiI7czozMzoibmV3c2xldHRlci1wcm9zemUtdXp1cGVsbmljLWVtYWlsIjtzOjMyOiJQcm9zesSZIHV6dXBlxYJuacSHIGFkcmVzIGVtYWlsLiI7czozODoicG90d2llcmR6LXphcGlzYW5pZS1zaWUtZG8tbmV3c2xldHRlcmEiO3M6NDA6IlBvdHdpZXJkxbogemFwaXNhbmllIHNpxJkgZG8gbmV3c2xldHRlcmEiO3M6MTM6InByb3N6ZS1jemVrYWMiO3M6MTg6IlByb3N6xJkgY3pla2HEhy4uLiI7czoxMDoiaW5mb3JtYWNqYSI7czoxMDoiSW5mb3JtYWNqYSI7czozOToiZW1haWwtem9zdGFsLWRvZGFueS1kby1saXN0eS1uZXdzbGV0dGVyIjtzOjQxOiJFbWFpbCB6b3N0YcWCIGRvZGFueSBkbyBsaXN0eSBuZXdzbGV0dGVyLiI7czozMjoibmV3c2xldHRlci1wb3R3aWVyZHplbmllLWRvZGFuaWEiO3M6MTYyOiJOYSBwb2RhbnkgcHJ6ZXogQ2llYmllIGUtbWFpbCB6b3N0YcWCYSB3eXPFgmFuYSB3aWFkb21vxZvEhyB6IGxpbmtpZW0gYWt0eXd1asSFY3ltLiBLbGlrbmlqIHcgbGluayBwb3R3aWVyZHphasSFY3ksIGFieSBwb215xZtsbmllIHpha2/FhGN6ecSHIHByb2NlcyByZWplc3RyYWNqaS4iO3M6Mzc6Im5ld3NsZXR0ZXItcG90d2llcmR6ZW5pZS1kb2RhbmlhLWJsYWQiO3M6ODQ6IlBvZGN6YXMgcmVqZXN0cmFjamkgYWRyZXN1IGUtbWFpbCBwb2phd2nFgiBzacSZIGLFgsSFZC4gUHJvc2lteSBzcHJvYm93YcSHIHBvbm93bmllLiI7czozMjoicHJvc3plLXV6dXBlbG5pYy1lbWFpbC1pLXRlbGVmb24iO3M6NDk6IlByb3N6xJkgdXp1cGXFgm5pxIcgYWRyZXMgZW1haWwgaSBudW1lciB0ZWxlZm9udS4iO3M6MTA6Ind5cGlzei1zaWUiO3M6MTE6Ind5cGlzeiBzacSZIjtzOjQwOiJlbWFpbC16b3N0YWwtdXN1bmlldHktei1saXN0eS1uZXdzbGV0dGVyIjtzOjQzOiJFbWFpbCB6b3N0YcWCIHVzdW5pxJl0eSB6IGxpc3R5IG5ld3NsZXR0ZXIuIjtzOjEwOiJuZXdzbGV0dGVyIjtzOjEwOiJuZXdzbGV0dGVyIjtzOjE1OiJuZXdzbGV0dGVyLXRleHQiO3M6NzI6IlphcGlzeiBzacSZIGRvIG5ld3NsZXR0ZXJhIGJ5IGJ5xIcgbmEgYmllxbzEhWNvIHogbm93b8WbY2lhbWkgdyBza2xlcGllLiI7czoxODoibmV3c2xldHRlci16Z29kYS0yIjtzOjQwODoiIChhZHJlc3UgZS1tYWlsKSB6YXdhcnR5Y2ggdyB6Z8WCb3N6ZW5pdSwgdyB6d2nEhXprdSB6IGFydC4gNiB1c3QuIDEgbGl0LiBhLCByb3pwb3J6xIVkemVuaWEgUGFybGFtZW50dSBFdXJvcGVqc2tpZWdvIGkgUmFkeSAoVUUpIDIwMTYvNjc5IHogZG5pYSAyNyBrd2lldG5pYSAyMDE2IHIuIHcgc3ByYXdpZSBvY2hyb255IG9zw7NiIGZpenljem55Y2ggdyB6d2nEhXprdSB6IHByemV0d2FyemFuaWVtIGRhbnljaCBvc29ib3d5Y2ggaSB3IHNwcmF3aWUgc3dvYm9kbmVnbyBwcnplcMWCeXd1IHRha2ljaCBkYW55Y2ggb3JheiB1Y2h5bGVuaWEgZHlyZWt0eXd5IDk1LzQ2L1dFIChST0RPKS4gVyBrYcW8ZHltIG1vbWVuY2llIG1vZ8SZIHd5Y29mYcSHIHpnb2TEmSB3eXBpc3VqxIVjIHNpxJkgeiBuZXdzbGV0dGVyYS4gIjtzOjMyOiJwcm9kdWt0LXpvc3RhbC1kb2RhbnktZG8ta29zenlrYSI7czo0MjoiV3licmFueSBwcm9kdWt0IHpvc3RhxYIgZG9kYW55IGRvIGtvc3p5a2EuIjtzOjE4OiJwcnplamR6LWRvLWtvc3p5a2EiO3M6MTk6InByemVqZMW6IGRvIGtvc3p5a2EiO3M6MTc6Inphd2FydG9zYy1rb3N6eWthIjtzOjE5OiJ6YXdhcnRvxZvEhyBrb3N6eWthIjtzOjk6InBvdHdpZXJkeiI7czoxMDoicG90d2llcmTFuiI7czozODoicG90d2llcmR6LXVzdW5pZWNpZS1wcm9kdWt0dS16LWtvc3p5a2EiO3M6NDE6Ik5hIHBld25vIGNoY2VzeiB1c3VuxIXEhyB3eWJyYW55IHByb2R1a3Q/IjtzOjQ6InVzdW4iO3M6NToidXN1xYQiO3M6MTM6InByb3N6ZS13eWJyYWMiO3M6MTU6InByb3N6xJkgd3licmHEhyI7czoxODoiZG9zdGF3YS1pLXBsYXRub3NjIjtzOjIxOiJkb3N0YXdhIGkgcMWCYXRub8WbxIciO3M6MjM6InByemVqZHotZG8tcG9kc3Vtb3dhbmlhIjtzOjI0OiJwcnplamTFuiBkbyBwb2RzdW1vd2FuaWEiO3M6MjM6InBvZHN1bW93YW5pZS16YW1vd2llbmlhIjtzOjI0OiJwb2RzdW1vd2FuaWUgemFtw7N3aWVuaWEiO3M6MzA6InphbWF3aWFtLXotb2Jvd2lhemtpZW0temFwbGF0eSI7czozMjoiemFtYXdpYW0geiBvYm93acSFemtpZW0gemFwxYJhdHkiO3M6MTM6ImRhbmUtYWRyZXNvd2UiO3M6MTM6ImRhbmUgYWRyZXNvd2UiO3M6MzA6Inpsb3otemFtb3dpZW5pZS1iZXotcmVqZXN0cmFqaSI7czozNToiWsWCw7PFvCB6YW3Ds3dpZW5pZSBiZXogcmVqZXN0cmFjamkiO3M6NzoidGVsZWZvbiI7czo3OiJ0ZWxlZm9uIjtzOjQ6ImltaWUiO3M6NToiaW1pxJkiO3M6ODoibmF6d2lza28iO3M6ODoibmF6d2lza28iO3M6MTU6InVsaWNhLWktbnItZG9tdSI7czoxNToidWxpY2EgaSBuciBkb211IjtzOjEyOiJrb2QtcG9jenRvd3kiO3M6MTI6ImtvZCBwb2N6dG93eSI7czo2OiJtaWFzdG8iO3M6NjoibWlhc3RvIjtzOjU3OiJwcnplY3p5dGFsZW0taS1ha2NlcHR1amUtcG9saXR5a2UtcHJ5d2F0bm9zY2ktaS1yZWd1bGFtaW4iO3M6NjI6IlByemVjenl0YcWCZW0gaSBha2NlcHR1asSZIDxhIGhyZWY9Ii9yZWd1bGFtaW4iPnJlZ3VsYW1pbjwvYT4uIjtzOjE1OiJ3cm9jLWRvLWtvc3p5a2EiO3M6MTc6Indyw7PEhyBkbyBrb3N6eWthIjtzOjM2OiJ6YW1vd2llbmllLXpvc3RhbG8temxvem9uZS1rb211bmlrYXQiO3M6MTUwOiJaYW3Ds3dpZW5pZSB6b3N0YcWCbyB6xYJvxbxvbmUuPGJyIC8+TmEgcG9kYW55IGFkcmVzIGVtYWlsIHpvc3RhxYJvIHd5c8WCYW5lIHBvdHdpZXJkem5pZS4gUHJvc3rEmSByw7N3bmllxbwgc3ByYXdkemnEhyBmb2xkZXIgc3BhbS48YnIgLz5EemnEmWt1amVteS4iO3M6NDE6InphbW93aWVuaWUtem9zdGFsby16bG96b25lLWtvbXVuaWthdC1ibGFkIjtzOjc5OiJQb2RjemFzIHNrxYJhZGFuaWEgemFtw7N3aWVuaWEgd3lzdMSFcGnFgiBixYLEhWQuIFByb3NpbXkgc3Byw7Nib3dhxIcgcG9ub3duaWUuIjtzOjM0OiJwb3R3aWVyZHplbmllLXphbW93aWVuaWEtemUtc2tsZXB1IjtzOjM1OiJQb3R3aWVyZHplbmllIHphbcOzd2llbmlhIHplIHNrbGVwdSI7czoyOiJuciI7czoyOiJuciI7czo3OiJwcm9kdWt0IjtzOjc6InByb2R1a3QiO3M6NDoiY2VuYSI7czo0OiJjZW5hIjtzOjU6InJhemVtIjtzOjU6InJhemVtIjtzOjY6InotZG5pYSI7czo2OiJ6IGRuaWEiO3M6MTU6ImRhbmUtZG8tZG9zdGF3eSI7czoxNToiZGFuZSBkbyBkb3N0YXd5IjtzOjE4OiJ6YW1vd2lvbmUtcHJvZHVrdHkiO3M6MTk6InphbcOzd2lvbmUgcHJvZHVrdHkiO3M6MTY6ImRhbmUtZG8tcHJ6ZWxld3UiO3M6MTY6ImRhbmUgZG8gcHJ6ZWxld3UiO3M6MTk6InphbG96LWtvbnRvLWtsaWVudGEiO3M6MjI6IlphxYLDs8W8IGtvbnRvIGtsaWVudGEiO3M6NToiaGFzbG8iO3M6NjoiaGFzxYJvIjtzOjM6Im1pbiI7czo0OiJtaW4uIjtzOjY6InpuYWtvdyI7czo3OiJ6bmFrw7N3IjtzOjEzOiJwb3d0b3J6LWhhc2xvIjtzOjE1OiJwb3d0w7NyeiBoYXPFgm8iO3M6MzM6InJlamVzdHJhY2phLWFrY2VwdGFjamEtcmVndWxhbWludSI7czo2OToiQWtjZXB0dWrEmSBbTElOSy1SRUdVTEFNSU5dIG9yYXogW0xJTkstUE9MSVRZS0EtUFJZV0FUTk9TQ0ldIHNlcndpc3UuIjtzOjMwOiJyZWplc3RyYWNqYS16Z29kYS1uYS1tYXJrZXRpbmciO3M6NjM6IkNoY8SZIG90cnp5bXl3YcSHIG1haWxlbSBpbmZvcm1hY2plIG1hcmtldGluZ293ZSBvZCBtYXJpYW5lay5wbCI7czo5OiJyZWd1bGFtaW4iO3M6OToicmVndWxhbWluIjtzOjIwOiJwb2xpdHlrZS1wcnl3YXRub3NjaSI7czoyMjoicG9saXR5a8SZIHByeXdhdG5vxZtjaSI7czoxNDoibWFzei1qdXota29udG8iO3M6MTU6Im1hc3oganXFvCBrb250byI7czoyMzoicmVqZXN0cmFjamEtYmxhZC1vZ29sbnkiO3M6NzA6IlcgdHJha2NpZSByZWplc3RyYWNqaSB3eXN0xIVwacWCIGLFgsSFZC4gUHJvc3rEmSBzcHLDs2Jvd2HEhyBwb25vd25pZS4iO3M6MjQ6InJlamVzdHJhY2phLWVtYWlsLXphamV0eSI7czozNzoiUG9kYW55IGFkcmVzIGVtYWlsIGplc3QganXFvCB6YWrEmXR5LiI7czoyMToicG9kYW5lLWhhc2xhLXNhLXJvem5lIjtzOjI2OiJQb2RhbmUgaGFzxYJhIHPEhSByw7PFvG5lLiI7czo0MToicG90d2llcmR6ZW5pZS1yZWplc3RyYWNqaS1rb250YS13LXNrbGVwaWUiO3M6NDE6IlBvdHdpZXJkemVuaWUgcmVqZXN0cmFjamkga29udGEgdyBza2xlcGllIjtzOjE0OiIjbmF6d2Etc2Vyd2lzdSI7czoxMToibWFyaWFuZWsucGwiO3M6MTc6InJlamVzdHJhY2phLXVkYW5hIjtzOjExNDoiRHppxJlrdWplbXkgemEgcmVqZXN0cmFjasSZLiBOYSBwb2RhbnkgYWRyZXMgZW1haWwgem9zdGHFgmEgd3lzxYJhbmEgd2lhZG9tb8WbxIcgeiBsaW5raWVtIGRvIHBvdHdpZXJkemVuaWUga29udGEuIjtzOjM5OiJwb3R3aWVyZHplbmllLWFrdHl3YWNqaS1rb250YS13LXNrbGVwaWUiO3M6Mzk6IlBvdHdpZXJkemVuaWUgYWt0eXdhY2ppIGtvbnRhIHcgc2tsZXBpZSI7czoyNToicmVqZXN0cmFjamEtcG90d2llcmR6ZW5pZSI7czo2MzoiVHdvamUga29udG8gem9zdGHFgm8gYWt0eXdvd2FuZS4gVGVyYXogbW/FvGVzeiBzacSZIHphbG9nb3dhxIcuIjtzOjk6ImxvZ293YW5pZSI7czo5OiJsb2dvd2FuaWUiO3M6MTk6Im5pZS1wYW1pZXRhc3otaGFzbGEiO3M6MjI6Ik5pZSBwYW1pxJl0YXN6IGhhc8WCYT8iO3M6MTA6Im5vd2UtaGFzbG8iO3M6MTE6Im5vd2UgaGFzxYJvIjtzOjE0OiJuaWUtbWFzei1rb250YSI7czoxNToiTmllIG1hc3oga29udGE/IjtzOjI5OiJtZXRhLXRpdGxlLW9kenlza2l3YW5pZS1oYXNsYSI7czoxOToiT2R6eXNraXdhbmllIGhhc8WCYSI7czoxODoib2R6eXNraXdhbmllLWhhc2xhIjtzOjE5OiJvZHp5c2tpd2FuaWUgaGFzxYJhIjtzOjEzOiJyZXNldHVqLWhhc2xvIjtzOjE0OiJyZXNldHVqIGhhc8WCbyI7czozNDoiZ2VuZXJvd2FuaWUtbm93ZWdvLWhhc2xhLXctc2tsZXBpZSI7czo0NzoiR2VuZXJvd2FuaWUgbm93ZWdvIGhhc8WCYSB3IHNrbGVwaWUgbWFyaWFuZWsucGwiO3M6MzM6Im9kenlza2l3YW5pZS1oYXNsYS1saW5rLWtvbXVuaWthdCI7czo4NToiTGluayBkbyB3eWdlbmVyb3dhbmlhIG5vd2VnbyBoYXPFgmEgem9zdGHFgiBwb215xZtsbmllIHd5c8WCYW55IG5hIFR3w7NqIGFkcmVzIGVtYWlsLiI7czoyMzoib2R6eXNraXdhbmllLWhhc2xhLWJsYWQiO3M6ODE6IlBvZGN6YXMgcHLDs2J5IG9kenlza2FuaWEgaGFzxYJhIHd5c3TEhXBpxYIgYsWCxIVkLiBQcm9zesSZIHNwcsOzYm93YcSHIHBvbm93bmllLiI7czo0Njoibm93ZS1oYXNsby16b3N0YWxvLXd5c2xhbmUtbmEtdHdvai1hZHJlcy1lbWFpbCI7czo1MToiTm93ZSBoYXPFgm8gem9zdGHFgm8gd3lzxYJhbmUgbmEgVHfDs2ogYWRyZXMgZW1haWwuIjtzOjIwOiJub3dlLWhhc2xvLXctc2tsZXBpZSI7czozMzoiTm93ZSBoYXPFgm8gdyBza2xlcGllIG1hcmlhbmVrLnBsIjtzOjE4OiJsb2dvd2FuaWUtbmlldWRhbmUiO3M6NDg6IkxvZ293YW5pZSBzacSZIG5pZSBwb3dpb2TFgm8uIFNwcsOzYnVqIHBvbm93bmllLiI7czoxNToibG9nb3dhbmllLXVkYW5lIjtzOjU5OiJXxYJhxZtuaWUgem9zdGHFgmXFmyB6YWxvZ293YW55LiDFu3ljenlteSB1ZGFueWNoIHpha3Vww7N3LiI7czoxMDoibW9qZS1rb250byI7czoxMDoibW9qZSBrb250byI7czoxMToid3lsb2d1ai1zaWUiO3M6MTI6Ind5bG9ndWogc2nEmSI7czoxNzoiaGlzdG9yaWEtemFtb3dpZW4iO3M6MTk6Imhpc3RvcmlhIHphbcOzd2llxYQiO3M6NjoiYWRyZXN5IjtzOjY6ImFkcmVzeSI7czoxNzoiYWRyZXN5LWRvLXd5c3lsa2kiO3M6MTg6ImFkcmVzeSBkbyB3eXN5xYJraSI7czoxNjoiZG9kYWotbm93eS1hZHJlcyI7czoxNjoiZG9kYWogbm93eSBhZHJlcyI7czo2OiJhbnVsdWoiO3M6NjoiYW51bHVqIjtzOjU6ImRvZGFqIjtzOjU6ImRvZGFqIjtzOjU6ImZpcm1hIjtzOjU6ImZpcm1hIjtzOjExOiJvcGNqb25hbG5pZSI7czoxMToib3Bjam9uYWxuaWUiO3M6MTM6InVsaWNhLWktbnVtZXIiO3M6MTM6InVsaWNhIGkgbnVtZXIiO3M6MTE6Im1pZWpzY293b3NjIjtzOjEzOiJtaWVqc2Nvd2/Fm8SHIjtzOjE0OiJudW1lci10ZWxlZm9udSI7czoxNDoibnVtZXIgdGVsZWZvbnUiO3M6Mjg6ImRvZGF3YW5pZS1ub3dlZ28tYWRyZXN1LWJsYWQiO3M6ODA6IlBvZGN6YXMgZG9kYXdhbmlhIG5vd2VnbyBhZHJlc3Ugd3lzdMSFcGnFgiBixYLEhWQuIFByb3N6xJkgc3Byw7Nib3dhxIcgcG9ub3duaWUuIjtzOjMwOiJkb2Rhd2FuaWUtbm93ZWdvLWFkcmVzdS1zdWtjZXMiO3M6MjY6Ik5vd3kgYWRyZXMgem9zdGHFgiBkb2RhbnkuIjtzOjU6InptaWVuIjtzOjY6InptaWXFhCI7czo2OiJ6YXBpc3oiO3M6NjoiemFwaXN6IjtzOjE4OiJ6bWlhbmEtYWRyZXN1LWJsYWQiO3M6NzA6IlBvZGN6YXMgZWR5Y2ppIGFkcmVzdSB3eXN0xIVwacWCIGLFgsSFZC4gUHJvc3rEmSBzcHLDs2Jvd2HEhyBwb25vd25pZS4iO3M6MjA6InptaWFuYS1hZHJlc3Utc3VrY2VzIjtzOjI0OiJBZHJlcyB6b3N0YcWCIHptaWVuaW9ueS4iO3M6MjY6InBvdHdpZXJkei11c3VuaWVjaWUtYWRyZXN1IjtzOjQzOiJDenkgbmEgcGV3bm8gY2hjZXN6IHVzdW7EhcSHIHd5YnJhbnkgYWRyZXM/IjtzOjE5OiJhZHJlcy11c3VuaWV0eS1ibGFkIjtzOjcyOiJQb2RjemFzIHVzdXdhbmlhIGFkcmVzdSB3eXN0xIVwacWCIGLFgsSFZC4gUHJvc3rEmSBzcHLDs2Jvd2HEhyBwb25vd25pZS4iO3M6MjQ6ImFkcmVzLXVzdW5pZXR5LWtvbXVuaWthdCI7czozMjoiV3licmFueSBhZHJlcyB6b3N0YcWCIHVzdW5pxJl0eS4iO3M6Nzoid3liaWVyeiI7czo3OiJ3eWJpZXJ6IjtzOjE4OiJ6YW1vd2llbmllLXpsb3pvbmUiO3M6MjE6InphbcOzd2llbmllIHrFgm/FvG9uZSI7czoxNToicmF6ZW0tei1kb3N0YXdhIjtzOjE2OiJyYXplbSB6IGRvc3Rhd8SFIjtzOjc6Im5vd29zY2kiO3M6ODoibm93b8WbY2kiO3M6MjA6InBvZHppZWwtc2llLXotaW5ueW1pIjtzOjIxOiJwb2R6aWVsIHNpxJkgeiBpbm55bWkiO3M6NToibW5pZWoiO3M6NToibW5pZWoiO3M6NzoiZG9zdGF3YSI7czo3OiJkb3N0YXdhIjtzOjg6InBsYXRub3NjIjtzOjExOiJwxYJhdG5vxZvEhyI7czozOiJzenQiO3M6Mzoic3p0IjtzOjIyOiJrb250YWt0LXpnb2RhLWNoZWNrYm94IjtzOjE2OToiQWRtaW5pc3RyYXRvcmVtIGRhbnljaCBvc29ib3d5Y2ggamVzdCBza2xlcCBtYXJpYW5lay5wbC4uIERhbmUgd3Bpc2FuZSB3IGZvcm11bGFyenUga29udGFrdG93eW0gYsSZZMSFIHByemV0d2FyemFuZSB3IGNlbHUgdWR6aWVsZW5pYSBvZHBvd2llZHppIG5hIHByemVzxYJhbmUgemFweXRhbmllLiI7czoyMjoicHJvc3plLXphem5hY3p5Yy16Z29kZSI7czo1ODoiUHJvc3rEmSB6YXpuYWN6ecSHIHpnb2TEmSBuYSBwcnpla2F6YW5pZSBvZmVydHkgaGFuZGxvd2VqLiI7czozMToibWV0YS10aXRsZS1zemN6ZWdvbHktemFtb3dpZW5pYSI7czoyMzoiU3pjemVnw7PFgnkgemFtw7N3aWVuaWEiO3M6MTU6InBsYXRub3NjLW9ubGluZSI7czoxODoicMWCYXRub8WbxIcgb25saW5lIjtzOjI2OiJha2NlcHR1amUtcmVndWxhbWluLXNrbGVwdSI7czo2OToiQWtjZXB0dWrEmSA8YSBocmVmPSIvcmVndWxhbWluIiB0YXJnZXQ9Il9ibGFuayI+cmVndWxhbWluPC9hPiBza2xlcHUuIjtzOjEzOiJ6YXBsYWMtb25saW5lIjtzOjE1OiJ6YXDFgmHEhyBvbmxpbmUiO3M6MjA6InN6Y3plZ29seS16YW1vd2llbmlhIjtzOjIzOiJzemN6ZWfDs8WCeSB6YW3Ds3dpZW5pYSI7czoxOToiemFtb3dpZW5pZS1vcGxhY29uZSI7czoyMToiemFtw7N3aWVuaWUgb3DFgmFjb25lIjtzOjE4OiJwbGF0bm9zYy1vZHJ6dWNvbmEiO3M6MjE6InDFgmF0bm/Fm8SHIG9kcnp1Y29uYSI7czoyNzoicGxhdG5vc2Mtc3ByYXdkemFuYS1yZWN6bmllIjtzOjMxOiJwxYJhdG5vxZvEhyBzcHJhd2R6YW5hIHLEmWN6bmllIjtzOjk6InN6Y3plZ29seSI7czoxMToic3pjemVnw7PFgnkiO3M6Mjc6InphbW93aWVuaWUtem9zdGFsby1vcGxhY29uZSI7czozMToiWmFtw7N3aWVuaWUgem9zdGHFgm8gb3DFgmFjb25lLiI7czoyNjoicGxhdG5vc2Mtem9zdGFsYS1vZHJ6dWNvbmEiO3M6MzE6IlDFgmF0bm/Fm8SHIHpvc3RhxYJhIG9kcnp1Y29uYS4iO3M6MzQ6InphbW93aWVuaWUtem9zdGFsby1vcGxhY29uZS1yZWN6bmUiO3M6Nzg6IlDFgmF0bm/Fm8SHIHpvc3RhxYJhIHphYWtjZXB0b3dhbmEsIGFsZSBtdXNpIGplc3pjemUgYnnEhyBzcHJhd2R6b25hIHLEmWN6bmllLiI7czo0OiJvcGlzIjtzOjQ6Im9waXMiO3M6MTc6Indyb2MtZG8ta2F0ZWdvcmlpIjtzOjE5OiJ3csOzxIcgZG8ga2F0ZWdvcmlpIjtzOjIwOiJtZXRhLXRpdGxlLWxvZ293YW5pZSI7czo5OiJMb2dvd2FuaWUiO3M6MjI6Im1ldGEtdGl0bGUtcmVqZXN0cmFjamEiO3M6MTE6IlJlamVzdHJhY2phIjtzOjI4OiJtZXRhLXRpdGxlLWhpc3RvcmlhLXphbW93aWVuIjtzOjE5OiJIaXN0b3JpYSB6YW3Ds3dpZcWEIjtzOjI0OiJtZXRhLXRpdGxlLWxpc3RhLWFkcmVzb3ciO3M6MTQ6Ikxpc3RhIGFkcmVzw7N3IjtzOjI0OiJtZXRhLXRpdGxlLWVkeWNqYS1hZHJlc3UiO3M6MTM6IkVkeWNqYSBhZHJlc3UiO3M6MjE6InBva2F6LXVrcnlqLWthdGVnb3JpZSI7czoyNDoiKHBva2HFvC91a3J5aiBrYXRlZ29yaWUpIjtzOjE4OiJwcm9kdWt0eS1wb3dpYXphbmUiO3M6MTk6InByb2R1a3R5IHBvd2nEhXphbmUiO3M6MzQ6ImxvZ293YW5pZS1ibGFkLW5pZXByYXdpZGxvd2UtaGFzbG8iO3M6MzQ6IlBvZGFuZSBoYXPFgm8gamVzdCBuaWVwcmF3aWTFgm93ZS4iO3M6MTk6ImRvYmllcnotZG8ta29tcGxldHUiO3M6MTk6ImRvYmllcnogZG8ga29tcGxldHUiO3M6MTY6ImtvbnR5bnV1ai16YWt1cHkiO3M6MTY6ImtvbnR5bnV1aiB6YWt1cHkiO3M6Njoibm93b3NjIjtzOjg6Im5vd2/Fm8SHIjtzOjE3OiJwb2xlY2FuZS1wcm9kdWt0eSI7czoxNzoiUG9sZWNhbmUgcHJvZHVrdHkiO3M6MjM6InByb2R1a3QtY3phcy1yZWFsaXphY2ppIjtzOjU5OiJDemFzIHJlYWxpemFjamkgemFtw7N3aWVuaWEgd3lub3NpIG9kIDEgZG8gMyBkbmkgcm9ib2N6eWNoLiI7czo1OiJ1d2FnYSI7czo1OiJ1d2FnYSI7czozMzoiemFtb3dpZW5pZS1wcnp5amV0ZS1kby1yZWFsaXphY2ppIjtzOjM1OiJ6YW3Ds3dpZW5pZSBwcnp5asSZdGUgZG8gcmVhbGl6YWNqaSI7czoxODoiemFtb3dpZW5pZS13eXNsYW5lIjtzOjIwOiJ6YW3Ds3dpZW5pZSB3eXPFgmFuZSI7czoyMzoiemFtb3dpZW5pZS16cmVhbGl6b3dhbmUiO3M6MjQ6InphbcOzd2llbmllIHpyZWFsaXpvd2FuZSI7czozMDoiemFtb3dpZW5pZS1uci16b3N0YWxvLW9wbGFjb25lIjtzOjM4OiJaYW3Ds3dpZW5pZSBbTlVNRVJdIHpvc3RhxYJvIG9wxYJhY29uZSI7czo0NDoiemFtb3dpZW5pZS1uci16b3N0YWxvLXByenlqZXRlLWRvLXJlYWxpemFjamkiO3M6NTI6IlphbcOzd2llbmllIFtOVU1FUl0gem9zdGHFgm8gcHJ6eWrEmXRlIGRvIHJlYWxpemFjamkiO3M6Mjk6InphbW93aWVuaWUtbnItem9zdGFsby13eXNsYW5lIjtzOjM3OiJaYW3Ds3dpZW5pZSBbTlVNRVJdIHpvc3RhxYJvIHd5c8WCYW5lIjtzOjM0OiJ6YW1vd2llbmllLW5yLXpvc3RhbG8tenJlYWxpem93YW5lIjtzOjQxOiJaYW3Ds3dpZW5pZSBbTlVNRVJdIHpvc3RhxYJvIHpyZWFsaXpvd2FuZSI7czoxMDoiZG8ta29zenlrYSI7czoxMDoiZG8ga29zenlrYSI7czozMzoid3luaWtpLXd5c3p1a2l3YW5pYS1kbGEtemFweXRhbmlhIjtzOjMzOiJXeW5pa2kgd3lzenVraXdhbmlhIGRsYSB6YXB5dGFuaWEiO3M6MTE6InNwaXMtdHJlc2NpIjtzOjEyOiJTcGlzIHRyZcWbY2kiO3M6MTk6InBvcHVsYXJuZS1rYXRlZ29yaWUiO3M6MTk6InBvcHVsYXJuZSBrYXRlZ29yaWUiO3M6MTM6ImN6ZWdvLXN6dWthc3oiO3M6MTM6IkN6ZWdvIHN6dWthc3oiO3M6MjE6IndwaXN6LXN6dWthbnktcHJvZHVrdCI7czoyMToiV3Bpc3ogc3p1a2FueSBwcm9kdWt0IjtzOjI0OiJuaWUtem5hbGV6aW9uby1wcm9kdWt0b3ciO3M6MzQ6Ik5pZSB6bmFsZXppb25vIMW8YWRueWNoIHByb2R1a3TDs3ciO3M6MTM6InpvYmFjei13aWVjZWoiO3M6MTQ6IlpvYmFjeiB3acSZY2VqIjtzOjEzOiJvcGlzLXByb2R1a3R1IjtzOjEzOiJPcGlzIHByb2R1a3R1IjtzOjQwOiJwcm9kdWt0LW1pZWpzY2UtbmEtd2lhZG9tb3NjLXBsYWNlaG9sZGVyIjtzOjM4OiJUdXRhaiBtb8W8ZXN6IHBvZGHEhyBucC4gaW1pxJkgZHppZWNrYSI7czo2OiJvcGluaWUiO3M6Njoib3BpbmllIjt9fQ== \ No newline at end of file +YToyOntpOjA7aToxNjkzOTQ2ODEzO2k6MTthOjE5ODp7aTowO3M6MjoicGwiO3M6NToidGVtYXQiO3M6NToidGVtYXQiO3M6OToid2lhZG9tb3NjIjtzOjExOiJ3aWFkb21vxZvEhyI7czo2OiJ3eXNsaWoiO3M6Nzoid3nFm2xpaiI7czo1OiJlbWFpbCI7czo1OiJlbWFpbCI7czoxMToibnItdGVsZWZvbnUiO3M6MTE6Im5yIHRlbGVmb251IjtzOjM0OiJwcm9zemUtdXp1cGVsbmljLWVtYWlsLWx1Yi10ZWxlZm9uIjtzOjUxOiJQcm9zesSZIHV6dXBlxYJuacSHIGFkcmVzIGVtYWlsIGx1YiBudW1lciB0ZWxlZm9udS4iO3M6NDoiYmxhZCI7czo2OiJixYLEhWQiO3M6NzoiemFta25paiI7czo3OiJ6YW1rbmlqIjtzOjI1OiJ3aWFkb21vc2Mtem9zdGFsYS13eXNsYW5hIjtzOjkwOiJUd29qYSB3aWFkb21vxZvEhyB6b3N0YcWCYSB3eXPFgmFuYS4gUG9zdGFyYW15IHNpxJkgbmEgbmnEhSBvZHBvd2llZHppZcSHIGphayBuYWpzenliY2llai4iO3M6Mjg6IndpYWRvbW9zYy1uaWV6b3N0YWxhLXd5c2xhbmEiO3M6OTM6IlBvZGN6YXMgd3lzecWCYW5pYSB3aWFkb21vxZtjaSB3eXN0xIVwacWCIGLFgsSFZC4gUHJvc3rEmSBzcHLDs2Jvd2HEhyBwb25vd25pZS4gUHJ6ZXByYXN6YW15LiI7czoxMjoiZGF0YS1kb2RhbmlhIjtzOjEyOiJkYXRhIGRvZGFuaWEiO3M6MTY6ImRhdGEtbW9keWZpa2FjamkiO3M6MTY6ImRhdGEgbW9keWZpa2FjamkiO3M6MTI6ImFkcmVzLXN0cm9ueSI7czoxMjoiYWRyZXMgc3Ryb255IjtzOjI5OiJwcm9zemUtdXp1cGVsbmljLWFkcmVzLXN0cm9ueSI7czozMzoiUHJvc3rEmSB1enVwZcWCbmnEhyBhZHJlcyBzdHJvbnkuIjtzOjg6InBpZXJ3c3phIjtzOjg6InBpZXJ3c3phIjtzOjg6Im5hc3RlcG5hIjtzOjk6Im5hc3TEmXBuYSI7czoxMDoicG9wcnplZG5pYSI7czoxMDoicG9wcnplZG5pYSI7czo4OiJvc3RhdG5pYSI7czo4OiJvc3RhdG5pYSI7czoxOiJ6IjtzOjE6InoiO3M6Njoid2llY2VqIjtzOjc6IndpxJljZWoiO3M6Njoid3N0ZWN6IjtzOjY6IndzdGVjeiI7czoyMzoiZm9ybXVsYXJ6LWNhcHRjaGEtbGFiZWwiO3M6Njk6IlByb3N6xJkgbmFyeXNvd2HEhyBrc3p0YcWCdCB3IHBvbmnFvHN6eW0gcG9sdSwgYWJ5IHd5c8WCYcSHIGZvcm11bGFyeiI7czoxNjoic3Byb2J1ai1wb25vd25pZSI7czoxNzoic3Byw7NidWogcG9ub3duaWUiO3M6NjoiZG9icnplIjtzOjY6ImRvYnJ6ZSI7czo1OiJ3aXRhaiI7czo1OiJ3aXRhaiI7czoxMToiemFsb2d1ai1zaWUiO3M6MTI6InphbG9ndWogc2nEmSI7czozOiJsdWIiO3M6MzoibHViIjtzOjE1OiJ6YXJlamVzdHJ1ai1zaWUiO3M6MTY6InphcmVqZXN0cnVqIHNpxJkiO3M6NToiaWxvc2MiO3M6NzoiaWxvxZvEhyI7czo0OiJzdW1hIjtzOjQ6InN1bWEiO3M6ODoicG9sZWNhbXkiO3M6ODoicG9sZWNhbXkiO3M6MTg6InNwcmF3ZHota29uaWVjem5pZSI7czoxOToic3ByYXdkxboga29uaWVjem5pZSI7czoxNjoiZG9kYWotZG8ta29zenlrYSI7czoxNjoiZG9kYWogZG8ga29zenlrYSI7czoxNDoic3RyZWZhLXJvZHppY2EiO3M6MTQ6InN0cmVmYSByb2R6aWNhIjtzOjE2OiJuYWpub3dzemUtcG9yYWR5IjtzOjE2OiJOYWpub3dzemUgcG9yYWR5IjtzOjE4OiJuZXdzbGV0dGVyLXpnb2RhLTEiO3M6NTU6Ild5cmHFvGFtIHpnb2TEmSBuYSBwcnpldHdhcnphbmllIG1vaWNoIGRhbnljaCBvc29ib3d5Y2giO3M6NDoiendpbiI7czo1OiJ6d2nFhCI7czo2OiJyb3p3aW4iO3M6Nzoicm96d2nFhCI7czozMzoibmV3c2xldHRlci1hZG1pbmlzdHJhdG9yLWRhbnljaC0xIjtzOjYxOiJBZG1pbmlzdHJhdG9yZW0gZGFueWNoIG9zb2Jvd3ljaCB6YXdhcnR5Y2ggdyB6Z8WCb3N6ZW5pdSBqZXN0IjtzOjMzOiJuZXdzbGV0dGVyLWFkbWluaXN0cmF0b3ItZGFueWNoLTIiO3M6NzQ2OiJfX19fXy4gRGFuZSBrb250YWt0b3dlIEluc3Bla3RvcmEgT2Nocm9ueSBEYW55Y2g6IHVva2lrQHVva2lrLmdvdi5wbC4gRGFuZSBvc29ib3dlIHPEhSBwcnpldHdhcnphbmUgdyBjZWx1IGRvc3RhcmN6ZW5pYSBuZXdzbGV0dGVyYSwgbmEgcG9kc3Rhd2llIGFydC4gNiB1c3QuIDEgbGl0LiBhKSByb3pwb3J6xIVkemVuaWEgUGFybGFtZW50dSBFdXJvcGVqc2tpZWdvIGkgUmFkeSAoVUUpIDIwMTYvNjc5IChST0RPKSBpIG5pZSBzxIUgcHJ6ZWthenl3YW5lIGlubnltIG9kYmlvcmNvbSwgb3JnYW5pemFjamkgbWnEmWR6eW5hcm9kb3dlaiBjenkgZG8gcGHFhHN0dyB0cnplY2ljaC4gRGFuZSBvc29ib3dlIHByemVjaG93eXdhbmUgc8SFIHByemV6IG9rcmVzIHByZW51bWVyYXR5LiBXbmlvc2tvZGF3Y2EgbWEgcHJhd28gZG8gZG9zdMSZcHUgZG8gc3dvaWNoIGRhbnljaCBvc29ib3d5Y2gsIGljaCBzcHJvc3Rvd2FuaWEgb3JheiB3bmllc2llbmlhIHNrYXJnaSBkbyBfX19fXy4gUG9kYW5pZSBkYW55Y2ggb3NvYm93eWNoIGplc3QgZG9icm93b2xuZSwgbmllIHd5bmlrYSB6IHByemVwaXPDs3csIGljaCBuaWVwb2RhbmllIGLEmWR6aWUgc2t1dGtvd2HFgm8gYnJha2llbSBtb8W8bGl3b8WbY2kgemFtw7N3aWVuaWEuIE5hIHBvZHN0YXdpZSBkYW55Y2ggb3NvYm93eWNoIG5pZSBzxIUgcG9kZWptb3dhbmUgemF1dG9tYXR5em93YW5lIGRlY3l6amUsIHcgdHltIG5pZSBzdG9zdWplIHNpxJkgcHJvZmlsb3dhbmlhLiI7czoyNjoibmV3c2xldHRlci16Z29kYS1rb211bmlrYXQiO3M6NTc6IlByb3N6xJkgemF6bmFjennEhyB6Z29kxJkgZG8gcHJ6ZXR3YXJ6YW5pYSB6IG5ld3NsZXR0ZXJhLiI7czozMzoibmV3c2xldHRlci1wcm9zemUtdXp1cGVsbmljLWVtYWlsIjtzOjMyOiJQcm9zesSZIHV6dXBlxYJuacSHIGFkcmVzIGVtYWlsLiI7czozODoicG90d2llcmR6LXphcGlzYW5pZS1zaWUtZG8tbmV3c2xldHRlcmEiO3M6NDA6IlBvdHdpZXJkxbogemFwaXNhbmllIHNpxJkgZG8gbmV3c2xldHRlcmEiO3M6MTM6InByb3N6ZS1jemVrYWMiO3M6MTg6IlByb3N6xJkgY3pla2HEhy4uLiI7czoxMDoiaW5mb3JtYWNqYSI7czoxMDoiSW5mb3JtYWNqYSI7czozOToiZW1haWwtem9zdGFsLWRvZGFueS1kby1saXN0eS1uZXdzbGV0dGVyIjtzOjQxOiJFbWFpbCB6b3N0YcWCIGRvZGFueSBkbyBsaXN0eSBuZXdzbGV0dGVyLiI7czozMjoibmV3c2xldHRlci1wb3R3aWVyZHplbmllLWRvZGFuaWEiO3M6MTYyOiJOYSBwb2RhbnkgcHJ6ZXogQ2llYmllIGUtbWFpbCB6b3N0YcWCYSB3eXPFgmFuYSB3aWFkb21vxZvEhyB6IGxpbmtpZW0gYWt0eXd1asSFY3ltLiBLbGlrbmlqIHcgbGluayBwb3R3aWVyZHphasSFY3ksIGFieSBwb215xZtsbmllIHpha2/FhGN6ecSHIHByb2NlcyByZWplc3RyYWNqaS4iO3M6Mzc6Im5ld3NsZXR0ZXItcG90d2llcmR6ZW5pZS1kb2RhbmlhLWJsYWQiO3M6ODQ6IlBvZGN6YXMgcmVqZXN0cmFjamkgYWRyZXN1IGUtbWFpbCBwb2phd2nFgiBzacSZIGLFgsSFZC4gUHJvc2lteSBzcHJvYm93YcSHIHBvbm93bmllLiI7czozMjoicHJvc3plLXV6dXBlbG5pYy1lbWFpbC1pLXRlbGVmb24iO3M6NDk6IlByb3N6xJkgdXp1cGXFgm5pxIcgYWRyZXMgZW1haWwgaSBudW1lciB0ZWxlZm9udS4iO3M6MTA6Ind5cGlzei1zaWUiO3M6MTE6Ind5cGlzeiBzacSZIjtzOjQwOiJlbWFpbC16b3N0YWwtdXN1bmlldHktei1saXN0eS1uZXdzbGV0dGVyIjtzOjQzOiJFbWFpbCB6b3N0YcWCIHVzdW5pxJl0eSB6IGxpc3R5IG5ld3NsZXR0ZXIuIjtzOjEwOiJuZXdzbGV0dGVyIjtzOjEwOiJuZXdzbGV0dGVyIjtzOjE1OiJuZXdzbGV0dGVyLXRleHQiO3M6NzI6IlphcGlzeiBzacSZIGRvIG5ld3NsZXR0ZXJhIGJ5IGJ5xIcgbmEgYmllxbzEhWNvIHogbm93b8WbY2lhbWkgdyBza2xlcGllLiI7czoxODoibmV3c2xldHRlci16Z29kYS0yIjtzOjQwODoiIChhZHJlc3UgZS1tYWlsKSB6YXdhcnR5Y2ggdyB6Z8WCb3N6ZW5pdSwgdyB6d2nEhXprdSB6IGFydC4gNiB1c3QuIDEgbGl0LiBhLCByb3pwb3J6xIVkemVuaWEgUGFybGFtZW50dSBFdXJvcGVqc2tpZWdvIGkgUmFkeSAoVUUpIDIwMTYvNjc5IHogZG5pYSAyNyBrd2lldG5pYSAyMDE2IHIuIHcgc3ByYXdpZSBvY2hyb255IG9zw7NiIGZpenljem55Y2ggdyB6d2nEhXprdSB6IHByemV0d2FyemFuaWVtIGRhbnljaCBvc29ib3d5Y2ggaSB3IHNwcmF3aWUgc3dvYm9kbmVnbyBwcnplcMWCeXd1IHRha2ljaCBkYW55Y2ggb3JheiB1Y2h5bGVuaWEgZHlyZWt0eXd5IDk1LzQ2L1dFIChST0RPKS4gVyBrYcW8ZHltIG1vbWVuY2llIG1vZ8SZIHd5Y29mYcSHIHpnb2TEmSB3eXBpc3VqxIVjIHNpxJkgeiBuZXdzbGV0dGVyYS4gIjtzOjMyOiJwcm9kdWt0LXpvc3RhbC1kb2RhbnktZG8ta29zenlrYSI7czo0MjoiV3licmFueSBwcm9kdWt0IHpvc3RhxYIgZG9kYW55IGRvIGtvc3p5a2EuIjtzOjE4OiJwcnplamR6LWRvLWtvc3p5a2EiO3M6MTk6InByemVqZMW6IGRvIGtvc3p5a2EiO3M6MTc6Inphd2FydG9zYy1rb3N6eWthIjtzOjE5OiJ6YXdhcnRvxZvEhyBrb3N6eWthIjtzOjk6InBvdHdpZXJkeiI7czoxMDoicG90d2llcmTFuiI7czozODoicG90d2llcmR6LXVzdW5pZWNpZS1wcm9kdWt0dS16LWtvc3p5a2EiO3M6NDE6Ik5hIHBld25vIGNoY2VzeiB1c3VuxIXEhyB3eWJyYW55IHByb2R1a3Q/IjtzOjQ6InVzdW4iO3M6NToidXN1xYQiO3M6MTM6InByb3N6ZS13eWJyYWMiO3M6MTU6InByb3N6xJkgd3licmHEhyI7czoxODoiZG9zdGF3YS1pLXBsYXRub3NjIjtzOjIxOiJkb3N0YXdhIGkgcMWCYXRub8WbxIciO3M6MjM6InByemVqZHotZG8tcG9kc3Vtb3dhbmlhIjtzOjI0OiJwcnplamTFuiBkbyBwb2RzdW1vd2FuaWEiO3M6MjM6InBvZHN1bW93YW5pZS16YW1vd2llbmlhIjtzOjI0OiJwb2RzdW1vd2FuaWUgemFtw7N3aWVuaWEiO3M6MzA6InphbWF3aWFtLXotb2Jvd2lhemtpZW0temFwbGF0eSI7czozMjoiemFtYXdpYW0geiBvYm93acSFemtpZW0gemFwxYJhdHkiO3M6MTM6ImRhbmUtYWRyZXNvd2UiO3M6MTM6ImRhbmUgYWRyZXNvd2UiO3M6MzA6Inpsb3otemFtb3dpZW5pZS1iZXotcmVqZXN0cmFqaSI7czozNToiWsWCw7PFvCB6YW3Ds3dpZW5pZSBiZXogcmVqZXN0cmFjamkiO3M6NzoidGVsZWZvbiI7czo3OiJ0ZWxlZm9uIjtzOjQ6ImltaWUiO3M6NToiaW1pxJkiO3M6ODoibmF6d2lza28iO3M6ODoibmF6d2lza28iO3M6MTU6InVsaWNhLWktbnItZG9tdSI7czoxNToidWxpY2EgaSBuciBkb211IjtzOjEyOiJrb2QtcG9jenRvd3kiO3M6MTI6ImtvZCBwb2N6dG93eSI7czo2OiJtaWFzdG8iO3M6NjoibWlhc3RvIjtzOjU3OiJwcnplY3p5dGFsZW0taS1ha2NlcHR1amUtcG9saXR5a2UtcHJ5d2F0bm9zY2ktaS1yZWd1bGFtaW4iO3M6Njk6IkFrY2VwdHVqxJkgPGEgaHJlZj0iL3JlZ3VsYW1pbiIgdGFyZ2V0PSJfYmxhbmsiPnJlZ3VsYW1pbjwvYT4gc2tsZXB1LiI7czoxNToid3JvYy1kby1rb3N6eWthIjtzOjE3OiJ3csOzxIcgZG8ga29zenlrYSI7czozNjoiemFtb3dpZW5pZS16b3N0YWxvLXpsb3pvbmUta29tdW5pa2F0IjtzOjE1MDoiWmFtw7N3aWVuaWUgem9zdGHFgm8gesWCb8W8b25lLjxiciAvPk5hIHBvZGFueSBhZHJlcyBlbWFpbCB6b3N0YcWCbyB3eXPFgmFuZSBwb3R3aWVyZHpuaWUuIFByb3N6xJkgcsOzd25pZcW8IHNwcmF3ZHppxIcgZm9sZGVyIHNwYW0uPGJyIC8+RHppxJlrdWplbXkuIjtzOjQxOiJ6YW1vd2llbmllLXpvc3RhbG8temxvem9uZS1rb211bmlrYXQtYmxhZCI7czo3OToiUG9kY3phcyBza8WCYWRhbmlhIHphbcOzd2llbmlhIHd5c3TEhXBpxYIgYsWCxIVkLiBQcm9zaW15IHNwcsOzYm93YcSHIHBvbm93bmllLiI7czozNDoicG90d2llcmR6ZW5pZS16YW1vd2llbmlhLXplLXNrbGVwdSI7czozNToiUG90d2llcmR6ZW5pZSB6YW3Ds3dpZW5pYSB6ZSBza2xlcHUiO3M6MjoibnIiO3M6MjoibnIiO3M6NzoicHJvZHVrdCI7czo3OiJwcm9kdWt0IjtzOjQ6ImNlbmEiO3M6NDoiY2VuYSI7czo1OiJyYXplbSI7czo1OiJyYXplbSI7czo2OiJ6LWRuaWEiO3M6NjoieiBkbmlhIjtzOjE1OiJkYW5lLWRvLWRvc3Rhd3kiO3M6MTU6ImRhbmUgZG8gZG9zdGF3eSI7czoxODoiemFtb3dpb25lLXByb2R1a3R5IjtzOjE5OiJ6YW3Ds3dpb25lIHByb2R1a3R5IjtzOjE2OiJkYW5lLWRvLXByemVsZXd1IjtzOjE2OiJkYW5lIGRvIHByemVsZXd1IjtzOjE5OiJ6YWxvei1rb250by1rbGllbnRhIjtzOjIyOiJaYcWCw7PFvCBrb250byBrbGllbnRhIjtzOjU6Imhhc2xvIjtzOjY6Imhhc8WCbyI7czozOiJtaW4iO3M6NDoibWluLiI7czo2OiJ6bmFrb3ciO3M6Nzoiem5ha8OzdyI7czoxMzoicG93dG9yei1oYXNsbyI7czoxNToicG93dMOzcnogaGFzxYJvIjtzOjMzOiJyZWplc3RyYWNqYS1ha2NlcHRhY2phLXJlZ3VsYW1pbnUiO3M6Njk6IkFrY2VwdHVqxJkgW0xJTkstUkVHVUxBTUlOXSBvcmF6IFtMSU5LLVBPTElUWUtBLVBSWVdBVE5PU0NJXSBzZXJ3aXN1LiI7czozMDoicmVqZXN0cmFjamEtemdvZGEtbmEtbWFya2V0aW5nIjtzOjYzOiJDaGPEmSBvdHJ6eW15d2HEhyBtYWlsZW0gaW5mb3JtYWNqZSBtYXJrZXRpbmdvd2Ugb2QgbWFyaWFuZWsucGwiO3M6OToicmVndWxhbWluIjtzOjk6InJlZ3VsYW1pbiI7czoyMDoicG9saXR5a2UtcHJ5d2F0bm9zY2kiO3M6MjI6InBvbGl0eWvEmSBwcnl3YXRub8WbY2kiO3M6MTQ6Im1hc3otanV6LWtvbnRvIjtzOjE1OiJtYXN6IGp1xbwga29udG8iO3M6MjM6InJlamVzdHJhY2phLWJsYWQtb2dvbG55IjtzOjcwOiJXIHRyYWtjaWUgcmVqZXN0cmFjamkgd3lzdMSFcGnFgiBixYLEhWQuIFByb3N6xJkgc3Byw7Nib3dhxIcgcG9ub3duaWUuIjtzOjI0OiJyZWplc3RyYWNqYS1lbWFpbC16YWpldHkiO3M6Mzc6IlBvZGFueSBhZHJlcyBlbWFpbCBqZXN0IGp1xbwgemFqxJl0eS4iO3M6MjE6InBvZGFuZS1oYXNsYS1zYS1yb3puZSI7czoyNjoiUG9kYW5lIGhhc8WCYSBzxIUgcsOzxbxuZS4iO3M6NDE6InBvdHdpZXJkemVuaWUtcmVqZXN0cmFjamkta29udGEtdy1za2xlcGllIjtzOjQxOiJQb3R3aWVyZHplbmllIHJlamVzdHJhY2ppIGtvbnRhIHcgc2tsZXBpZSI7czoxNDoiI25hendhLXNlcndpc3UiO3M6MTE6Im1hcmlhbmVrLnBsIjtzOjE3OiJyZWplc3RyYWNqYS11ZGFuYSI7czoxMTQ6IkR6acSZa3VqZW15IHphIHJlamVzdHJhY2rEmS4gTmEgcG9kYW55IGFkcmVzIGVtYWlsIHpvc3RhxYJhIHd5c8WCYW5hIHdpYWRvbW/Fm8SHIHogbGlua2llbSBkbyBwb3R3aWVyZHplbmllIGtvbnRhLiI7czozOToicG90d2llcmR6ZW5pZS1ha3R5d2Fjamkta29udGEtdy1za2xlcGllIjtzOjM5OiJQb3R3aWVyZHplbmllIGFrdHl3YWNqaSBrb250YSB3IHNrbGVwaWUiO3M6MjU6InJlamVzdHJhY2phLXBvdHdpZXJkemVuaWUiO3M6NjM6IlR3b2plIGtvbnRvIHpvc3RhxYJvIGFrdHl3b3dhbmUuIFRlcmF6IG1vxbxlc3ogc2nEmSB6YWxvZ293YcSHLiI7czo5OiJsb2dvd2FuaWUiO3M6OToibG9nb3dhbmllIjtzOjE5OiJuaWUtcGFtaWV0YXN6LWhhc2xhIjtzOjIyOiJOaWUgcGFtacSZdGFzeiBoYXPFgmE/IjtzOjEwOiJub3dlLWhhc2xvIjtzOjExOiJub3dlIGhhc8WCbyI7czoxNDoibmllLW1hc3ota29udGEiO3M6MTU6Ik5pZSBtYXN6IGtvbnRhPyI7czoyOToibWV0YS10aXRsZS1vZHp5c2tpd2FuaWUtaGFzbGEiO3M6MTk6Ik9kenlza2l3YW5pZSBoYXPFgmEiO3M6MTg6Im9kenlza2l3YW5pZS1oYXNsYSI7czoxOToib2R6eXNraXdhbmllIGhhc8WCYSI7czoxMzoicmVzZXR1ai1oYXNsbyI7czoxNDoicmVzZXR1aiBoYXPFgm8iO3M6MzQ6ImdlbmVyb3dhbmllLW5vd2Vnby1oYXNsYS13LXNrbGVwaWUiO3M6NDc6IkdlbmVyb3dhbmllIG5vd2VnbyBoYXPFgmEgdyBza2xlcGllIG1hcmlhbmVrLnBsIjtzOjMzOiJvZHp5c2tpd2FuaWUtaGFzbGEtbGluay1rb211bmlrYXQiO3M6ODU6IkxpbmsgZG8gd3lnZW5lcm93YW5pYSBub3dlZ28gaGFzxYJhIHpvc3RhxYIgcG9tecWbbG5pZSB3eXPFgmFueSBuYSBUd8OzaiBhZHJlcyBlbWFpbC4iO3M6MjM6Im9kenlza2l3YW5pZS1oYXNsYS1ibGFkIjtzOjgxOiJQb2RjemFzIHByw7NieSBvZHp5c2thbmlhIGhhc8WCYSB3eXN0xIVwacWCIGLFgsSFZC4gUHJvc3rEmSBzcHLDs2Jvd2HEhyBwb25vd25pZS4iO3M6NDY6Im5vd2UtaGFzbG8tem9zdGFsby13eXNsYW5lLW5hLXR3b2otYWRyZXMtZW1haWwiO3M6NTE6Ik5vd2UgaGFzxYJvIHpvc3RhxYJvIHd5c8WCYW5lIG5hIFR3w7NqIGFkcmVzIGVtYWlsLiI7czoyMDoibm93ZS1oYXNsby13LXNrbGVwaWUiO3M6MzM6Ik5vd2UgaGFzxYJvIHcgc2tsZXBpZSBtYXJpYW5lay5wbCI7czoxODoibG9nb3dhbmllLW5pZXVkYW5lIjtzOjQ4OiJMb2dvd2FuaWUgc2nEmSBuaWUgcG93aW9kxYJvLiBTcHLDs2J1aiBwb25vd25pZS4iO3M6MTU6ImxvZ293YW5pZS11ZGFuZSI7czo1OToiV8WCYcWbbmllIHpvc3RhxYJlxZsgemFsb2dvd2FueS4gxbt5Y3p5bXkgdWRhbnljaCB6YWt1cMOzdy4iO3M6MTA6Im1vamUta29udG8iO3M6MTA6Im1vamUga29udG8iO3M6MTE6Ind5bG9ndWotc2llIjtzOjEyOiJ3eWxvZ3VqIHNpxJkiO3M6MTc6Imhpc3RvcmlhLXphbW93aWVuIjtzOjE5OiJoaXN0b3JpYSB6YW3Ds3dpZcWEIjtzOjY6ImFkcmVzeSI7czo2OiJhZHJlc3kiO3M6MTc6ImFkcmVzeS1kby13eXN5bGtpIjtzOjE4OiJhZHJlc3kgZG8gd3lzecWCa2kiO3M6MTY6ImRvZGFqLW5vd3ktYWRyZXMiO3M6MTY6ImRvZGFqIG5vd3kgYWRyZXMiO3M6NjoiYW51bHVqIjtzOjY6ImFudWx1aiI7czo1OiJkb2RhaiI7czo1OiJkb2RhaiI7czo1OiJmaXJtYSI7czo1OiJmaXJtYSI7czoxMToib3Bjam9uYWxuaWUiO3M6MTE6Im9wY2pvbmFsbmllIjtzOjEzOiJ1bGljYS1pLW51bWVyIjtzOjEzOiJ1bGljYSBpIG51bWVyIjtzOjExOiJtaWVqc2Nvd29zYyI7czoxMzoibWllanNjb3dvxZvEhyI7czoxNDoibnVtZXItdGVsZWZvbnUiO3M6MTQ6Im51bWVyIHRlbGVmb251IjtzOjI4OiJkb2Rhd2FuaWUtbm93ZWdvLWFkcmVzdS1ibGFkIjtzOjgwOiJQb2RjemFzIGRvZGF3YW5pYSBub3dlZ28gYWRyZXN1IHd5c3TEhXBpxYIgYsWCxIVkLiBQcm9zesSZIHNwcsOzYm93YcSHIHBvbm93bmllLiI7czozMDoiZG9kYXdhbmllLW5vd2Vnby1hZHJlc3Utc3VrY2VzIjtzOjI2OiJOb3d5IGFkcmVzIHpvc3RhxYIgZG9kYW55LiI7czo1OiJ6bWllbiI7czo2OiJ6bWllxYQiO3M6NjoiemFwaXN6IjtzOjY6InphcGlzeiI7czoxODoiem1pYW5hLWFkcmVzdS1ibGFkIjtzOjcwOiJQb2RjemFzIGVkeWNqaSBhZHJlc3Ugd3lzdMSFcGnFgiBixYLEhWQuIFByb3N6xJkgc3Byw7Nib3dhxIcgcG9ub3duaWUuIjtzOjIwOiJ6bWlhbmEtYWRyZXN1LXN1a2NlcyI7czoyNDoiQWRyZXMgem9zdGHFgiB6bWllbmlvbnkuIjtzOjI2OiJwb3R3aWVyZHotdXN1bmllY2llLWFkcmVzdSI7czo0MzoiQ3p5IG5hIHBld25vIGNoY2VzeiB1c3VuxIXEhyB3eWJyYW55IGFkcmVzPyI7czoxOToiYWRyZXMtdXN1bmlldHktYmxhZCI7czo3MjoiUG9kY3phcyB1c3V3YW5pYSBhZHJlc3Ugd3lzdMSFcGnFgiBixYLEhWQuIFByb3N6xJkgc3Byw7Nib3dhxIcgcG9ub3duaWUuIjtzOjI0OiJhZHJlcy11c3VuaWV0eS1rb211bmlrYXQiO3M6MzI6Ild5YnJhbnkgYWRyZXMgem9zdGHFgiB1c3VuacSZdHkuIjtzOjc6Ind5YmllcnoiO3M6Nzoid3liaWVyeiI7czoxODoiemFtb3dpZW5pZS16bG96b25lIjtzOjIxOiJ6YW3Ds3dpZW5pZSB6xYJvxbxvbmUiO3M6MTU6InJhemVtLXotZG9zdGF3YSI7czoxNjoicmF6ZW0geiBkb3N0YXfEhSI7czo3OiJub3dvc2NpIjtzOjg6Im5vd2/Fm2NpIjtzOjIwOiJwb2R6aWVsLXNpZS16LWlubnltaSI7czoyMToicG9kemllbCBzacSZIHogaW5ueW1pIjtzOjU6Im1uaWVqIjtzOjU6Im1uaWVqIjtzOjc6ImRvc3Rhd2EiO3M6NzoiZG9zdGF3YSI7czo4OiJwbGF0bm9zYyI7czoxMToicMWCYXRub8WbxIciO3M6Mzoic3p0IjtzOjM6InN6dCI7czoyMjoia29udGFrdC16Z29kYS1jaGVja2JveCI7czoxNjk6IkFkbWluaXN0cmF0b3JlbSBkYW55Y2ggb3NvYm93eWNoIGplc3Qgc2tsZXAgbWFyaWFuZWsucGwuLiBEYW5lIHdwaXNhbmUgdyBmb3JtdWxhcnp1IGtvbnRha3Rvd3ltIGLEmWTEhSBwcnpldHdhcnphbmUgdyBjZWx1IHVkemllbGVuaWEgb2Rwb3dpZWR6aSBuYSBwcnplc8WCYW5lIHphcHl0YW5pZS4iO3M6MjI6InByb3N6ZS16YXpuYWN6eWMtemdvZGUiO3M6NTg6IlByb3N6xJkgemF6bmFjennEhyB6Z29kxJkgbmEgcHJ6ZWthemFuaWUgb2ZlcnR5IGhhbmRsb3dlai4iO3M6MzE6Im1ldGEtdGl0bGUtc3pjemVnb2x5LXphbW93aWVuaWEiO3M6MjM6IlN6Y3plZ8OzxYJ5IHphbcOzd2llbmlhIjtzOjE1OiJwbGF0bm9zYy1vbmxpbmUiO3M6MTg6InDFgmF0bm/Fm8SHIG9ubGluZSI7czoyNjoiYWtjZXB0dWplLXJlZ3VsYW1pbi1za2xlcHUiO3M6Njk6IkFrY2VwdHVqxJkgPGEgaHJlZj0iL3JlZ3VsYW1pbiIgdGFyZ2V0PSJfYmxhbmsiPnJlZ3VsYW1pbjwvYT4gc2tsZXB1LiI7czoxMzoiemFwbGFjLW9ubGluZSI7czoxNToiemFwxYJhxIcgb25saW5lIjtzOjIwOiJzemN6ZWdvbHktemFtb3dpZW5pYSI7czoyMzoic3pjemVnw7PFgnkgemFtw7N3aWVuaWEiO3M6MTk6InphbW93aWVuaWUtb3BsYWNvbmUiO3M6MjE6InphbcOzd2llbmllIG9wxYJhY29uZSI7czoxODoicGxhdG5vc2Mtb2RyenVjb25hIjtzOjIxOiJwxYJhdG5vxZvEhyBvZHJ6dWNvbmEiO3M6Mjc6InBsYXRub3NjLXNwcmF3ZHphbmEtcmVjem5pZSI7czozMToicMWCYXRub8WbxIcgc3ByYXdkemFuYSByxJljem5pZSI7czo5OiJzemN6ZWdvbHkiO3M6MTE6InN6Y3plZ8OzxYJ5IjtzOjI3OiJ6YW1vd2llbmllLXpvc3RhbG8tb3BsYWNvbmUiO3M6MzE6IlphbcOzd2llbmllIHpvc3RhxYJvIG9wxYJhY29uZS4iO3M6MjY6InBsYXRub3NjLXpvc3RhbGEtb2RyenVjb25hIjtzOjMxOiJQxYJhdG5vxZvEhyB6b3N0YcWCYSBvZHJ6dWNvbmEuIjtzOjM0OiJ6YW1vd2llbmllLXpvc3RhbG8tb3BsYWNvbmUtcmVjem5lIjtzOjc4OiJQxYJhdG5vxZvEhyB6b3N0YcWCYSB6YWFrY2VwdG93YW5hLCBhbGUgbXVzaSBqZXN6Y3plIGJ5xIcgc3ByYXdkem9uYSByxJljem5pZS4iO3M6NDoib3BpcyI7czo0OiJvcGlzIjtzOjE3OiJ3cm9jLWRvLWthdGVnb3JpaSI7czoxOToid3LDs8SHIGRvIGthdGVnb3JpaSI7czoyMDoibWV0YS10aXRsZS1sb2dvd2FuaWUiO3M6OToiTG9nb3dhbmllIjtzOjIyOiJtZXRhLXRpdGxlLXJlamVzdHJhY2phIjtzOjExOiJSZWplc3RyYWNqYSI7czoyODoibWV0YS10aXRsZS1oaXN0b3JpYS16YW1vd2llbiI7czoxOToiSGlzdG9yaWEgemFtw7N3aWXFhCI7czoyNDoibWV0YS10aXRsZS1saXN0YS1hZHJlc293IjtzOjE0OiJMaXN0YSBhZHJlc8OzdyI7czoyNDoibWV0YS10aXRsZS1lZHljamEtYWRyZXN1IjtzOjEzOiJFZHljamEgYWRyZXN1IjtzOjIxOiJwb2thei11a3J5ai1rYXRlZ29yaWUiO3M6MjQ6Iihwb2thxbwvdWtyeWoga2F0ZWdvcmllKSI7czoxODoicHJvZHVrdHktcG93aWF6YW5lIjtzOjE5OiJwcm9kdWt0eSBwb3dpxIV6YW5lIjtzOjM0OiJsb2dvd2FuaWUtYmxhZC1uaWVwcmF3aWRsb3dlLWhhc2xvIjtzOjM0OiJQb2RhbmUgaGFzxYJvIGplc3QgbmllcHJhd2lkxYJvd2UuIjtzOjE5OiJkb2JpZXJ6LWRvLWtvbXBsZXR1IjtzOjE5OiJkb2JpZXJ6IGRvIGtvbXBsZXR1IjtzOjE2OiJrb250eW51dWotemFrdXB5IjtzOjE2OiJrb250eW51dWogemFrdXB5IjtzOjY6Im5vd29zYyI7czo4OiJub3dvxZvEhyI7czoxNzoicG9sZWNhbmUtcHJvZHVrdHkiO3M6MTc6IlBvbGVjYW5lIHByb2R1a3R5IjtzOjIzOiJwcm9kdWt0LWN6YXMtcmVhbGl6YWNqaSI7czo1OToiQ3phcyByZWFsaXphY2ppIHphbcOzd2llbmlhIHd5bm9zaSBvZCAxIGRvIDMgZG5pIHJvYm9jenljaC4iO3M6NToidXdhZ2EiO3M6NToidXdhZ2EiO3M6MzM6InphbW93aWVuaWUtcHJ6eWpldGUtZG8tcmVhbGl6YWNqaSI7czozNToiemFtw7N3aWVuaWUgcHJ6eWrEmXRlIGRvIHJlYWxpemFjamkiO3M6MTg6InphbW93aWVuaWUtd3lzbGFuZSI7czoyMDoiemFtw7N3aWVuaWUgd3lzxYJhbmUiO3M6MjM6InphbW93aWVuaWUtenJlYWxpem93YW5lIjtzOjI0OiJ6YW3Ds3dpZW5pZSB6cmVhbGl6b3dhbmUiO3M6MzA6InphbW93aWVuaWUtbnItem9zdGFsby1vcGxhY29uZSI7czozODoiWmFtw7N3aWVuaWUgW05VTUVSXSB6b3N0YcWCbyBvcMWCYWNvbmUiO3M6NDQ6InphbW93aWVuaWUtbnItem9zdGFsby1wcnp5amV0ZS1kby1yZWFsaXphY2ppIjtzOjUyOiJaYW3Ds3dpZW5pZSBbTlVNRVJdIHpvc3RhxYJvIHByenlqxJl0ZSBkbyByZWFsaXphY2ppIjtzOjI5OiJ6YW1vd2llbmllLW5yLXpvc3RhbG8td3lzbGFuZSI7czozNzoiWmFtw7N3aWVuaWUgW05VTUVSXSB6b3N0YcWCbyB3eXPFgmFuZSI7czozNDoiemFtb3dpZW5pZS1uci16b3N0YWxvLXpyZWFsaXpvd2FuZSI7czo0MToiWmFtw7N3aWVuaWUgW05VTUVSXSB6b3N0YcWCbyB6cmVhbGl6b3dhbmUiO3M6MTA6ImRvLWtvc3p5a2EiO3M6MTA6ImRvIGtvc3p5a2EiO3M6MzM6Ind5bmlraS13eXN6dWtpd2FuaWEtZGxhLXphcHl0YW5pYSI7czozMzoiV3luaWtpIHd5c3p1a2l3YW5pYSBkbGEgemFweXRhbmlhIjtzOjExOiJzcGlzLXRyZXNjaSI7czoxMjoic3BpcyB0cmXFm2NpIjtzOjEzOiJ6b2JhY3otd2llY2VqIjtzOjE0OiJab2JhY3ogd2nEmWNlaiI7czoxMzoib3Bpcy1wcm9kdWt0dSI7czoxMzoiT3BpcyBwcm9kdWt0dSI7czoxOToicG9wdWxhcm5lLWthdGVnb3JpZSI7czoxOToiUG9wdWxhcm5lIGthdGVnb3JpZSI7czoxMzoiY3plZ28tc3p1a2FzeiI7czoxMzoiQ3plZ28gc3p1a2FzeiI7czoyMToid3Bpc3otc3p1a2FueS1wcm9kdWt0IjtzOjIxOiJXcGlzeiBzenVrYW55IHByb2R1a3QiO3M6MjQ6Im5pZS16bmFsZXppb25vLXByb2R1a3RvdyI7czozNDoiTmllIHpuYWxlemlvbm8gxbxhZG55Y2ggcHJvZHVrdMOzdyI7czo0MDoicHJvZHVrdC1taWVqc2NlLW5hLXdpYWRvbW9zYy1wbGFjZWhvbGRlciI7czozODoiVHV0YWogbW/FvGVzeiBwb2RhxIcgbnAuIGltacSZIGR6aWVja2EiO3M6Njoib3BpbmllIjtzOjY6Im9waW5pZSI7fX0= \ No newline at end of file diff --git a/admin/temp/4/s_cache_4b916ae533b4ded88ddc3edfe99de1be b/admin/temp/4/s_cache_4b916ae533b4ded88ddc3edfe99de1be index be4a914..f062108 100644 --- a/admin/temp/4/s_cache_4b916ae533b4ded88ddc3edfe99de1be +++ b/admin/temp/4/s_cache_4b916ae533b4ded88ddc3edfe99de1be @@ -1 +1 @@ -YToyOntpOjA7aToxNzI1MTg1ODE4O2k6MTthOjQxOntzOjk6ImZpcm1fbmFtZSI7czo3OiJzaG9wUFJPIjtzOjExOiJmaXJtX2FkcmVzcyI7czowOiIiO3M6MTU6ImFkZGl0aW9uYWxfaW5mbyI7czoyMTI6IjxwPjxzdHJvbmc+TWFzeiBweXRhbmlhPyBaYWR6d2/FhCBkbyBuYXMuPC9zdHJvbmc+PC9wPg0KDQo8cD50ZWwuIDUzMCA3NTUgNzc0PGJyIC8+DQplbWFpbDombmJzcDs8YSBocmVmPSJtYWlsdG86c2tsZXBAbWFyaWFuZWsucGwiPnNrbGVwQG1hcmlhbmVrLnBsPC9hPjxiciAvPg0KdWwuIE9rdWxpY2tpZWdvIDE4LzksIDM1IC0gMjA2IFJ6ZXN6Jm9hY3V0ZTt3PC9wPg0KIjtzOjEyOiJjb250YWN0X2Zvcm0iO3M6MToiMSI7czoxMzoiY29udGFjdF9lbWFpbCI7czoyMDoicG9jenRhQHByb2plY3QtZGMucGwiO3M6MTA6ImVtYWlsX2hvc3QiO3M6MjU6Imhvc3QxMTc1MjMuaG9zdGlkby5uZXQucGwiO3M6MTA6ImVtYWlsX3BvcnQiO3M6MjoiMjUiO3M6MTE6ImVtYWlsX2xvZ2luIjtzOjIwOiJwb2N6dGFAcHJvamVjdC1kYy5wbCI7czoxNDoiZW1haWxfcGFzc3dvcmQiO3M6MTQ6IlByb2plY3RQcm8xOTE2IjtzOjExOiJnb29nbGVfbWFwcyI7czowOiIiO3M6MTM6ImZhY2Vib29rX2xpbmsiO3M6MDoiIjtzOjE0OiJzdGF0aXN0aWNfY29kZSI7czowOiIiO3M6ODoiaHRhY2Nlc3MiO3M6MDoiIjtzOjY6InJvYm90cyI7czowOiIiO3M6MjI6InNob3BfYmFua19hY2NvdW50X2luZm8iO3M6MjM5OiI8cD5Qcm9qZWN0LVBybyBTcC4geiBvLm8uPGJyIC8+DQpOZXN0QmFuayZuYnNwOzxzdHJvbmc+MDYgMjUzMCAwMDA4IDIwNTEgMTAwNSA3NDkxIDAwMDE8L3N0cm9uZz48L3A+DQoNCjxwPkt3b3RhOiA8c3Ryb25nPltLV09UQV08L3N0cm9uZz48YnIgLz4NClcgdHl0dWxlIHByb3N6xJkgd3Bpc2HEhyBudW1lciB6YW0mb2FjdXRlO3dpZW5pYTombmJzcDs8c3Ryb25nPltOUi1aQU1PV0lFTklBXTwvc3Ryb25nPjwvcD4NCiI7czo2OiJ1cGRhdGUiO3M6MToiMSI7czoxNDoiYm9vdF9hbmltYXRpb24iO3M6MDoiIjtzOjE3OiJuZXdzbGV0dGVyX2hlYWRlciI7czoxNjM6IjxkaXYgc3R5bGU9ImJvcmRlci1ib3R0b206NXB4IHNvbGlkICM3N2NkZDE7IHBhZGRpbmc6MjBweDsgdGV4dC1hbGlnbjpjZW50ZXIiPjxpbWcgYWx0PSIiIHNyYz0iL2xheW91dC9pbWFnZXMvbG9nby5wbmciIHN0eWxlPSJoZWlnaHQ6NTBweDsgd2lkdGg6MjA4cHgiIC8+PC9kaXY+DQoiO3M6MTc6Im5ld3NsZXR0ZXJfZm9vdGVyIjtzOjY5MzoiPGRpdiBzdHlsZT0iYm9yZGVyLXRvcDo1cHggc29saWQgIzc3Y2RkMTsgcGFkZGluZzoyMHB4IDIwcHggMCAyMHB4Ij4NCjxwIHN0eWxlPSJ0ZXh0LWFsaWduOmNlbnRlciI+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMnB4Ij48ZW0+UG96ZHJhd2lhbXksPGJyIC8+DQpaZXNwb2wgTUFSSUFORUsuUEw8YnIgLz4NCjxhIGhyZWY9Imh0dHBzOi8vd3d3Lm1hcmlhbmVrLnBsIj53d3cubWFyaWFuZWsucGw8L2E+PC9lbT48L3NwYW4+PC9wPg0KDQo8cCBzdHlsZT0idGV4dC1hbGlnbjpjZW50ZXIiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTFweCI+PHNwYW4gc3R5bGU9ImNvbG9yOiM5NWE1YTYiPldpYWRvbW/Fm8SHIHpvc3RhxYJhIHd5Z2VuZXJvd2FuYSBhdXRvbWF0eWN6bmllLCBwcm9zaW15IG5hIG5pxIUgbmllIG9kcG93aWFkYcSHLiAmbmJzcDtBYnkgc2tvbnRha3Rvd2HEhyBzacSZIHogc2Vyd2lzZW0gPGEgaHJlZj0iaHR0cHM6Ly93d3cubWFyaWFuZWsucGwiPk1BUklBTkVLLlBMPC9hPiwgcHJvc2lteSBvIHByemVzxYJhbmllIGUtbWFpbGEgbmEgYWRyZXMmbmJzcDs8L3NwYW4+PGEgaHJlZj0ibWFpbHRvOmtvbnRha3RAbWFyaWFuZWsucGwiIHRhcmdldD0iX2JsYW5rIj48c3BhbiBzdHlsZT0iY29sb3I6Izk1YTVhNiI+a29udGFrdEBtYXJpYW5lay5wbDwvc3Bhbj48L2E+PC9zcGFuPjwvcD4NCjwvZGl2Pg0KIjtzOjEwOiJob3RwYXlfYXBpIjtzOjU5OiJSRlJOYUdST2JtcG5URTFtY21SVU0wTk5kVGxOUmpad1J5ODRTV2xoUVdFMmFYcDVTMUpFVjA4d2N6MCI7czo1OiJkZXZlbCI7czoxOiIwIjtzOjM6InNzbCI7czoxOiIwIjtzOjE0OiJodGFjY2Vzc19jYWNoZSI7czoxOiIxIjtzOjEzOiJmcmVlX2RlbGl2ZXJ5IjtzOjU6Ijk5LjAwIjtzOjE4OiJwcnplbGV3eTI0X3NhbmRib3giO3M6MToiMSI7czoyMjoicHJ6ZWxld3kyNF9tZXJjaGFudF9pZCI7czo1OiI5OTI1OCI7czoxODoicHJ6ZWxld3kyNF9jcmNfa2V5IjtzOjE2OiI4ZjhhZGYxNDU0MzZlZjc5IjtzOjEwOiJ1cGRhdGVfa2V5IjtzOjMyOiJmZmZhNjgzZWFlYzE1NmRkMDRjYjAzN2ZlNDgzMmQ2OSI7czo3OiJ0cGF5X2lkIjtzOjU6IjQzMTc0IjtzOjEyOiJ0cGF5X3NhbmRib3giO3M6MToiMCI7czoxODoidHBheV9zZWN1cml0eV9jb2RlIjtzOjE2OiI1UVlnNHZEdUt0aThQazJGIjtzOjY6InBpa3NlbCI7czowOiIiO3M6MTM6ImdlbmVyYXRlX3dlYnAiO3M6MToiMSI7czoxMjoibGF6eV9sb2FkaW5nIjtzOjE6IjEiO3M6MTI6ImVrb21pX3N1cnZleSI7czoxMDExOiI8IS0tIGVLb21pV2lkZ2V0IFNUQVJUIC0tPg0KPGRpdiBpZD0ic2ZmXzEyN19fd2lkZ2V0LWNvbnRhaW5lciI+PC9kaXY+DQo8IS0tIGVLb21pV2lkZ2V0IEVORCAtLT4NCjwhLS0gZUtvbWlMb2FkZXIgU1RBUlQsIG9ubHkgbmVlZGVkIG9uY2UgcGVyIHBhZ2UgLS0+DQo8c2NyaXB0IGNsYXNzPSJmb290ZXIiIHR5cGU9InRleHQvamF2YXNjcmlwdCI+DQogICAgKGZ1bmN0aW9uKHcpIHsNCiAgICAgICAgd1snX2Vrb21pU2VydmVyVXJsJ10gPSAnaHR0cHM6Ly9zbWFydGZvcm1zLmVrb21pLmNvbSc7DQogICAgICAgIHdbJ19la29taVNob3BJZCddID0gJzE0ODM1OSc7DQogICAgICAgIHdbJ19la29taUZvcm1JZCddID0gJzM3MTU0NCc7DQogICAgICAgIHdbJ19la29taVRyYW5zYWN0aW9uSWQnXSA9ICd0cmFuc2FjdGlvbl9pZCc7DQogICAgICAgIHdbJ19la29taVByb2R1Y3RJZHMnXSA9ICdwcm9kdWN0X2lkcyc7DQogICAgICAgIHdbJ19la29taVdpZGdldFdpZHRoJ10gPSAnMTAyMHB4JzsNCiAgICAgICAgd1snX2Vrb21pV2lkZ2V0SGVpZ2h0J10gPSAnMTI5MHB4JzsNCiAgICAgICAgd1snX2Vrb21pRW1iZWRXaWRnZXQnXSA9ICcwJzsNCiAgICAgICAgd1snX2Vrb21pRGlzYWJsZUF1dG9DbG9zZSddID0gJzAnOw0KICAgICAgICB3WydfZWtvbWlFbWFpbCddID0gJyc7DQogICAgICAgIHZhciBzID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc2NyaXB0Jyk7DQogICAgICAgIHMuc3JjID0gd1snX2Vrb21pU2VydmVyVXJsJ10rJy9zY3JpcHQvd2lkZ2V0LmpzP3Y9JysgbmV3IERhdGUoKS5nZXRUaW1lKCk7DQogICAgICAgIHMuYXN5bmMgPSB0cnVlOw0KICAgICAgICB2YXIgZSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzY3JpcHQnKVswXTsNCiAgICAgICAgZS5wYXJlbnROb2RlLmluc2VydEJlZm9yZShzLCBlKTsNCiAgICB9KSh3aW5kb3cpOw0KPC9zY3JpcHQ+DQo8IS0tIGVLb21pTG9hZGVyIEVORCwgb25seSBuZWVkZWQgb25jZSBwZXIgcGFnZSAtLT4iO3M6MjE6Imdvb2dsZV90YWdfbWFuYWdlcl9pZCI7czoxMToiR1RNLVQyRzM2TkYiO3M6MTQ6ImluZmluaXRlc2Nyb2xsIjtzOjE6IjAiO3M6MjU6IndhcmVob3VzZV9tZXNzYWdlX3plcm9fcGwiO3M6MzQ6IkN6YXMgcmVhbGl6YWNqaSBkbyA0IGRuaSByb2JvY3p5Y2giO3M6MjU6IndhcmVob3VzZV9tZXNzYWdlX3plcm9fZW4iO3M6NDoiMCBlbiI7czoyODoid2FyZWhvdXNlX21lc3NhZ2Vfbm9uemVyb19wbCI7czozNDoiQ3phcyByZWFsaXphY2ppIGRvIDIgZG5pIHJvYm9jenljaCI7czoyODoid2FyZWhvdXNlX21lc3NhZ2Vfbm9uemVyb19lbiI7czo0OiIxIGVuIjt9fQ== \ No newline at end of file +YToyOntpOjA7aToxNzI0MjYzMTIxO2k6MTthOjM5OntzOjk6ImZpcm1fbmFtZSI7czo4OiJNYXJpYW5layI7czoxMToiZmlybV9hZHJlc3MiO3M6MDoiIjtzOjE1OiJhZGRpdGlvbmFsX2luZm8iO3M6MjQxOiI8cD48c3Ryb25nPk1hc3ogcHl0YW5pYT8gWmFkendvxYQgZG8gbmFzLjwvc3Ryb25nPjwvcD4NCg0KPHA+dGVsLiA8YSBocmVmPSJ0ZWw6Ly81MzA3NTU3NzQiPjUzMCA3NTUgNzc0PC9hPjxiciAvPg0KZW1haWw6Jm5ic3A7PGEgaHJlZj0ibWFpbHRvOnNrbGVwQG1hcmlhbmVrLnBsIj5za2xlcEBtYXJpYW5lay5wbDwvYT48YnIgLz4NCnVsLiBLcmFrb3dza2EgMTU2LzEwNCwgMzUtNTA2IFJ6ZXN6Jm9hY3V0ZTt3PC9wPg0KIjtzOjEyOiJjb250YWN0X2Zvcm0iO3M6MToiMSI7czoxMzoiY29udGFjdF9lbWFpbCI7czoxNzoic2tsZXBAbWFyaWFuZWsucGwiO3M6MTA6ImVtYWlsX2hvc3QiO3M6MTY6Im1haWwubWFyaWFuZWsucGwiO3M6MTA6ImVtYWlsX3BvcnQiO3M6MjoiMjUiO3M6MTE6ImVtYWlsX2xvZ2luIjtzOjE3OiJza2xlcEBtYXJpYW5lay5wbCI7czoxNDoiZW1haWxfcGFzc3dvcmQiO3M6OToiTGVnaWExOTE2IjtzOjExOiJnb29nbGVfbWFwcyI7czowOiIiO3M6MTM6ImZhY2Vib29rX2xpbmsiO3M6MDoiIjtzOjE0OiJzdGF0aXN0aWNfY29kZSI7czowOiIiO3M6ODoiaHRhY2Nlc3MiO3M6MDoiIjtzOjY6InJvYm90cyI7czowOiIiO3M6MjI6InNob3BfYmFua19hY2NvdW50X2luZm8iO3M6MjI4OiI8cD5Qcm9qZWN0LVBybzxiciAvPg0KTmVzdEJhbmsmbmJzcDs8c3Ryb25nPjIyIDI1MzAgMDAwOCAyMDUxIDEwNTAgNjc2MyAwMDAxPC9zdHJvbmc+PC9wPg0KDQo8cD5Ld290YTogPHN0cm9uZz5bS1dPVEFdPC9zdHJvbmc+PGJyIC8+DQpXIHR5dHVsZSBwcm9zesSZIHdwaXNhxIcgbnVtZXIgemFtJm9hY3V0ZTt3aWVuaWE6Jm5ic3A7PHN0cm9uZz5bTlItWkFNT1dJRU5JQV08L3N0cm9uZz48L3A+DQoiO3M6NjoidXBkYXRlIjtzOjE6IjEiO3M6MTQ6ImJvb3RfYW5pbWF0aW9uIjtzOjA6IiI7czoxNzoibmV3c2xldHRlcl9oZWFkZXIiO3M6MTYzOiI8ZGl2IHN0eWxlPSJib3JkZXItYm90dG9tOjVweCBzb2xpZCAjNzdjZGQxOyBwYWRkaW5nOjIwcHg7IHRleHQtYWxpZ246Y2VudGVyIj48aW1nIGFsdD0iIiBzcmM9Ii9sYXlvdXQvaW1hZ2VzL2xvZ28ucG5nIiBzdHlsZT0iaGVpZ2h0OjUwcHg7IHdpZHRoOjIwOHB4IiAvPjwvZGl2Pg0KIjtzOjE3OiJuZXdzbGV0dGVyX2Zvb3RlciI7czo2OTM6IjxkaXYgc3R5bGU9ImJvcmRlci10b3A6NXB4IHNvbGlkICM3N2NkZDE7IHBhZGRpbmc6MjBweCAyMHB4IDAgMjBweCI+DQo8cCBzdHlsZT0idGV4dC1hbGlnbjpjZW50ZXIiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTJweCI+PGVtPlBvemRyYXdpYW15LDxiciAvPg0KWmVzcG9sIE1BUklBTkVLLlBMPGJyIC8+DQo8YSBocmVmPSJodHRwczovL3d3dy5tYXJpYW5lay5wbCI+d3d3Lm1hcmlhbmVrLnBsPC9hPjwvZW0+PC9zcGFuPjwvcD4NCg0KPHAgc3R5bGU9InRleHQtYWxpZ246Y2VudGVyIj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjExcHgiPjxzcGFuIHN0eWxlPSJjb2xvcjojOTVhNWE2Ij5XaWFkb21vxZvEhyB6b3N0YcWCYSB3eWdlbmVyb3dhbmEgYXV0b21hdHljem5pZSwgcHJvc2lteSBuYSBuacSFIG5pZSBvZHBvd2lhZGHEhy4gJm5ic3A7QWJ5IHNrb250YWt0b3dhxIcgc2nEmSB6IHNlcndpc2VtIDxhIGhyZWY9Imh0dHBzOi8vd3d3Lm1hcmlhbmVrLnBsIj5NQVJJQU5FSy5QTDwvYT4sIHByb3NpbXkgbyBwcnplc8WCYW5pZSBlLW1haWxhIG5hIGFkcmVzJm5ic3A7PC9zcGFuPjxhIGhyZWY9Im1haWx0bzprb250YWt0QG1hcmlhbmVrLnBsIiB0YXJnZXQ9Il9ibGFuayI+PHNwYW4gc3R5bGU9ImNvbG9yOiM5NWE1YTYiPmtvbnRha3RAbWFyaWFuZWsucGw8L3NwYW4+PC9hPjwvc3Bhbj48L3A+DQo8L2Rpdj4NCiI7czoxMDoiaG90cGF5X2FwaSI7czo1OToiUkZSTmFHUk9ibXBuVEUxbWNtUlVNME5OZFRsTlJqWndSeTg0U1dsaFFXRTJhWHA1UzFKRVYwOHdjejAiO3M6NToiZGV2ZWwiO3M6MToiMCI7czozOiJzc2wiO3M6MToiMCI7czoxNDoiaHRhY2Nlc3NfY2FjaGUiO3M6MToiMSI7czoxMzoiZnJlZV9kZWxpdmVyeSI7czo1OiI5OS4wMCI7czoxODoicHJ6ZWxld3kyNF9zYW5kYm94IjtzOjE6IjAiO3M6MjI6InByemVsZXd5MjRfbWVyY2hhbnRfaWQiO3M6NjoiMTU2MTAxIjtzOjE4OiJwcnplbGV3eTI0X2NyY19rZXkiO3M6MTY6ImQ4NWFkOWRlOGNiYTBlMDEiO3M6MTA6InVwZGF0ZV9rZXkiO3M6MzI6ImZmZmE2ODNlYWVjMTU2ZGQwNGNiMDM3ZmU0ODMyZDY5IjtzOjc6InRwYXlfaWQiO3M6NToiNzQ2OTgiO3M6MTI6InRwYXlfc2FuZGJveCI7czoxOiIwIjtzOjE4OiJ0cGF5X3NlY3VyaXR5X2NvZGUiO3M6MTc6IilER01xPmt6eEApIzcwdmFyIjtzOjY6InBpa3NlbCI7czoxNjoiMjU2Nzk5OTIwMzMxNDI3NyI7czoxMzoiZ2VuZXJhdGVfd2VicCI7czoxOiIxIjtzOjEyOiJsYXp5X2xvYWRpbmciO3M6MToiMSI7czoxMjoiZWtvbWlfc3VydmV5IjtzOjA6IiI7czoyMToiZ29vZ2xlX3RhZ19tYW5hZ2VyX2lkIjtzOjEyOiJHVE0tUE03WjNMUjgiO3M6MTQ6ImluZmluaXRlc2Nyb2xsIjtzOjE6IjAiO3M6MjU6IndhcmVob3VzZV9tZXNzYWdlX3plcm9fcGwiO3M6MTY6IiFXeXN5xYJrYSBkbyAyNGgiO3M6Mjg6IndhcmVob3VzZV9tZXNzYWdlX25vbnplcm9fcGwiO3M6MTc6IiEhV3lzecWCa2EgZG8gMjRoIjt9fQ== \ No newline at end of file diff --git a/admin/templates/articles/article-edit.php b/admin/templates/articles/article-edit.php index fb7496f..44c0764 100644 --- a/admin/templates/articles/article-edit.php +++ b/admin/templates/articles/article-edit.php @@ -133,15 +133,6 @@ ob_start(); 'checked' => $this -> article['show_date_add'] == 1 ? true : false ) );?> - 'Data dodania', - 'class' => 'date-time', - 'name' => 'date_add', - 'id' => 'date_add', - 'value' => $this -> article['date_add'] - ) - );?> 'Pokaż datę modyfikacji', @@ -149,15 +140,6 @@ ob_start(); 'checked' => $this -> article['show_date_modify'] == 1 ? true : false ) );?> - 'Data modyfikacji', - 'class' => 'date-time', - 'name' => 'date_modify', - 'id' => 'date_modify', - 'value' => $this -> article['date_modify'] - ) - );?> 'Powtórz wprowadzenie', diff --git a/admin/templates/baselinker/bundling-products.php b/admin/templates/baselinker/bundling-products.php new file mode 100644 index 0000000..d434df2 --- /dev/null +++ b/admin/templates/baselinker/bundling-products.php @@ -0,0 +1,33 @@ +
+ + + + + + + + + + products as $product ):?> + + + + + + + +
Nazwa produktuSKUProdukt w Baselinker
- + +
+ +
\ No newline at end of file diff --git a/admin/templates/shop-product/products-list.php b/admin/templates/shop-product/products-list.php index bc9566f..3e44dbc 100644 --- a/admin/templates/shop-product/products-list.php +++ b/admin/templates/shop-product/products-list.php @@ -110,7 +110,7 @@ typeAnimated: true, animation: 'opacity', columnClass: 'col-12 col-lg-8', - theme: 'supervan', + theme: 'material', icon: 'fa fa-exclamation-triangle', buttons: { confirm: { diff --git a/admin/templates/shop-product/stock.php b/admin/templates/shop-product/stock.php new file mode 100644 index 0000000..20b974a --- /dev/null +++ b/admin/templates/shop-product/stock.php @@ -0,0 +1,70 @@ + + + product -> permutations ) ) + { + foreach ( $this -> product -> permutations as $permutation ) + { + ?> +
+ '; + echo '
'; + echo ''; + echo '
'; + echo '
'; + } + } + else + { + echo '
'; + echo ' '; + echo '
'; + echo ''; + echo '
'; + echo '
'; + } +?> + + id = 'stock'; +$grid -> gdb_opt = $gdb; +$grid -> include_plugins = true; +$grid -> title = 'Stany magazynowe: '.$this -> product -> language['name'].''; +$grid -> fields = [ + [ + 'db' => 'id', + 'type' => 'hidden', + 'value' => $this -> product -> id, + ], +]; +$grid -> actions = [ + 'save' => ['url' => '/admin/shop_product/stock_save/', 'back_url' => '/admin/shop_product/view_list/'], + 'cancel' => ['url' => '/admin/shop_product/view_list/'], + ]; +$grid -> external_code = $out; +$grid -> persist_edit = true; +$grid -> id_param = 'id'; + +echo $grid -> draw(); +?> + diff --git a/autoload/admin/controls/class.Baselinker.php b/autoload/admin/controls/class.Baselinker.php new file mode 100644 index 0000000..05ebc12 --- /dev/null +++ b/autoload/admin/controls/class.Baselinker.php @@ -0,0 +1,20 @@ + \admin\factory\ShopProduct::products_list_for_baselinker(), + 'baselinker_products' => \admin\factory\Baselinker::products_list() + ] ); + } + + // zapis wiązania produktów + static public function bundling_products_save() { + \admin\factory\Baselinker::bundling_products_save( $_POST ); + header( 'Location: /admin/baselinker/bundling_products/' ); + exit; + } +} \ No newline at end of file diff --git a/autoload/admin/factory/class.Baselinker.php b/autoload/admin/factory/class.Baselinker.php new file mode 100644 index 0000000..e2e4946 --- /dev/null +++ b/autoload/admin/factory/class.Baselinker.php @@ -0,0 +1,39 @@ + $val ) { + $key = explode( '_', $key ); + $mdb -> update( 'pp_shop_products', [ 'baselinker_product_id' => $val ], [ 'id' => $key[1] ] ); + } + } + + // pobranie produktów z Baselinkera + static public function products_list() { + global $settings; + + $methodParams = '{ + "storage_id": "bl_1" + }'; + + $apiParams = [ + "token" => $settings['baselinker_api'], + "method" => "getProductsList", + "parameters" => $methodParams + ]; + + $curl = curl_init( "https://api.baselinker.com/connector.php" ); + curl_setopt( $curl, CURLOPT_POST, 1 ); + curl_setopt( $curl, CURLOPT_POSTFIELDS, http_build_query( $apiParams ) ); + curl_setopt( $curl, CURLOPT_RETURNTRANSFER, true ); + $response = json_decode( curl_exec( $curl ), true ); + + if ( $response['status'] == 'SUCCESS' ) + return $response['products']; + } +} \ No newline at end of file diff --git a/autoload/admin/factory/class.ShopProduct.php b/autoload/admin/factory/class.ShopProduct.php index 90d5e09..c2e8c4a 100644 --- a/autoload/admin/factory/class.ShopProduct.php +++ b/autoload/admin/factory/class.ShopProduct.php @@ -622,53 +622,6 @@ class ShopProduct return $result; } - public static function permutation_quantity($id_product, $permutation) - { - global $mdb; - - return $mdb -> get('pp_shop_products_stock', 'quantity', ['AND' => ['id_product' => $id_product, 'permutation' => $permutation]]); - } - - public static function stock_save($id_product, $permutations_quantity) - { - global $mdb; - - $mdb -> delete( 'pp_shop_products_stock', [ 'id_product' => $id_product ] ); - - if ( is_array( $permutations_quantity ) ) foreach ($permutations_quantity as $key => $val) - { - $permutations[] = $mdb -> get('pp_shop_products_stock', 'id', ['AND' => ['id_product' => $id_product, 'permutation' => $key]]); - $mdb -> delete('pp_shop_products_stock', ['AND' => ['id_product' => $id_product, 'id[!]' => $permutations]]); - } - - if (\is_array($permutations_quantity)) - { - foreach ($permutations_quantity as $key => $val) - { - if ($id = $mdb -> get('pp_shop_products_stock', 'id', ['AND' => ['id_product' => $id_product, 'permutation' => $key]])) - { - $mdb -> update('pp_shop_products_stock', [ - 'quantity' => $val, - ], [ - 'id' => $id, - ]); - \S::delete_dir('../temp/'); - } - else - { - $mdb -> insert('pp_shop_products_stock', [ - 'id_product' => $id_product, - 'permutation' => $key, - 'quantity' => $val, - ]); - \S::delete_dir('../temp/'); - } - } - } - - return true; - } - // product_unarchive static public function product_unarchive( int $product_id ) { @@ -1050,12 +1003,6 @@ class ShopProduct \admin\factory\ShopProduct::update_product_combinations_prices( $product_id, $price_brutto, $vat, $price_brutto_promo ); - //stan magazynowy - if ( $mdb -> count( 'pp_shop_products_stock', [ 'id_product' => $product_id ] ) ) - $mdb -> update( 'pp_shop_products_stock', [ 'quantity' => $quantity ], [ 'id_product' => $product_id ] ); - else - $mdb -> insert( 'pp_shop_products_stock', [ 'id_product' => $product_id, 'quantity' => $quantity ] ); - foreach ( $name as $key => $val ) { if ( $translation_id = $mdb -> get( 'pp_shop_products_langs', 'id', [ 'AND' => [ 'product_id' => $product_id, 'lang_id' => $key ] ] ) ) diff --git a/autoload/class.Article.php b/autoload/class.Article.php index 170c848..3998a06 100644 --- a/autoload/class.Article.php +++ b/autoload/class.Article.php @@ -39,8 +39,6 @@ class Article implements \ArrayAccess $this -> images = $mdb -> select( 'pp_articles_images', '*', [ 'article_id' => (int)$article_id, 'ORDER' => [ 'o' => 'ASC', 'id' => 'ASC' ] ] ); $this -> files = $mdb -> select( 'pp_articles_files', '*', [ 'article_id' => (int)$article_id ] ); $this -> pages = $mdb -> select( 'pp_articles_pages', 'page_id', [ 'article_id' => (int)$article_id ] ); - $this -> tags = $mdb -> select( 'pp_tags', [ '[><]pp_articles_tags' => [ 'id' => 'tag_id' ] ], 'name', [ 'article_id' => (int)$article_id ] ); - $results = $mdb -> select( 'pp_articles_additional_params', [ '[><]pp_articles_additional_values' => [ 'id' => 'param_id' ] ], [ 'name', 'value', 'language_id' ], [ 'article_id' => (int)$article_id ] ); if ( is_array( $results ) ) foreach ( $results as $row ) { if ( !$row['language_id'] ) @@ -51,7 +49,7 @@ class Article implements \ArrayAccess $this -> params = $params; } - public function get_from_cache( $article_id, $lang_id ) + static public function get_from_cache( $article_id, $lang_id ) { $cacheHandler = new \CacheHandler(); $cacheKey = "\Article::get_from_cache:$article_id:$lang_id"; diff --git a/autoload/class.Image.php b/autoload/class.Image.php index d767133..0065afa 100644 --- a/autoload/class.Image.php +++ b/autoload/class.Image.php @@ -1,64 +1,82 @@ file = $file; + if ($file !== null) { + $this->file = $file; - if ( is_file( $file ) ) - $this->setImageFile($file); - else - $this->setImageString($file); - } + if (is_file($file)) { + $this->setImageFile($file); + } else { + $this->setImageString($file); + } + } } /** * Set image resource from file * * @param string $file Path to image file - * @return ImageManipulator for a fluent interface + * @return self * @throws InvalidArgumentException */ - public function setImageFile($file) + public function setImageFile(string $file): self { if (!(is_readable($file) && is_file($file))) { throw new InvalidArgumentException("Image file $file is not readable"); } - if (is_resource($this->image)) { + if (isset($this->image) && $this->image instanceof \GdImage) { imagedestroy($this->image); } - list ( $this -> width, $this -> height, $type ) = getimagesize($file); + [$width, $height, $type] = getimagesize($file); + + if ($width === false || $height === false) { + throw new InvalidArgumentException("Unable to get image size for $file"); + } + + error_log("Loaded image size from file: width: $width, height: $height, type: $type"); switch ($type) { - case IMAGETYPE_GIF : - $this->image = imagecreatefromgif($file); - break; - case IMAGETYPE_JPEG : - $this->image = imagecreatefromjpeg($file); - break; - case IMAGETYPE_PNG : - $this->image = imagecreatefrompng($file); - break; + case IMAGETYPE_GIF: + $this->image = imagecreatefromgif($file); + break; + case IMAGETYPE_JPEG: + $this->image = imagecreatefromjpeg($file); + break; + case IMAGETYPE_PNG: + $this->image = imagecreatefrompng($file); + break; case IMAGETYPE_WEBP: - $this -> image = imagecreatefromwebp($file); - break; - default : - throw new InvalidArgumentException("Image type $type not supported"); + $this->image = imagecreatefromwebp($file); + break; + default: + throw new InvalidArgumentException("Image type $type not supported"); + } + + if (!$this->image instanceof \GdImage) { + throw new InvalidArgumentException("Failed to create image from $file"); + } + + $this->width = imagesx($this->image); + $this->height = imagesy($this->image); + + error_log("Set image dimensions: width: {$this->width}, height: {$this->height}"); + + if ($this->width === 0 || $this->height === 0) { + throw new InvalidArgumentException("Image dimensions are invalid (width: $this->width, height: $this->height)"); } return $this; @@ -67,21 +85,31 @@ class ImageManipulator /** * Set image resource from string data * - * @param string $data - * @return ImageManipulator for a fluent interface + * @param string $data Image data as string + * @return self * @throws RuntimeException */ - public function setImageString($data) + public function setImageString(string $data): self { - if (is_resource($this->image)) { + if (isset($this->image) && $this->image instanceof \GdImage) { imagedestroy($this->image); } - if (!$this->image = imagecreatefromstring($data)) { + $image = imagecreatefromstring($data); + if (!$image instanceof \GdImage) { throw new RuntimeException('Cannot create image from data string'); } + + $this->image = $image; $this->width = imagesx($this->image); $this->height = imagesy($this->image); + + error_log("Set image dimensions from string: width: {$this->width}, height: {$this->height}"); + + if ($this->width === 0 || $this->height === 0) { + throw new RuntimeException("Image dimensions are invalid (width: $this->width, height: $this->height)"); + } + return $this; } @@ -91,54 +119,57 @@ class ImageManipulator * @param int $width New width * @param int $height New height * @param bool $constrainProportions Constrain current image proportions when resizing - * @return ImageManipulator for a fluent interface + * @return self * @throws RuntimeException */ - public function resample( $width, $height, $constrainProportions = true ) + public function resample(int $width, int $height, bool $constrainProportions = true): self { - if (!is_resource($this->image)) { - throw new RuntimeException('No image set'); + if (!isset($this->image) || !$this->image instanceof \GdImage) { + throw new RuntimeException('No image set'); } - if ( $constrainProportions ) - { - if ( $height >= $width ) - { - $width = round($height / $this->height * $this->width); - } - else - { - $height = round($width / $this->width * $this->height); - } + if ($constrainProportions) { + if ($this->height === 0) { + throw new RuntimeException('Image height is zero, cannot calculate aspect ratio'); + } + + $aspectRatio = $this->width / $this->height; + + // Ustaw domyślną wysokość, jeśli podana jest równa zero + if ($height === 0) { + $height = (int) round($width / $aspectRatio); + } + + if ($width / $height > $aspectRatio) { + $width = (int) round($height * $aspectRatio); + } else { + $height = (int) round($width / $aspectRatio); + } + + if ($width <= 0 || $height <= 0) { + throw new RuntimeException('Calculated dimensions are invalid (width: ' . $width . ', height: ' . $height . ')'); + } } - $temp = imagecreatetruecolor($width, $height); - - - $transparent_index = imagecolortransparent( $this -> image ); - imagealphablending($temp, false); - imagesavealpha($temp,true); - $transparent = imagecolorallocatealpha($temp, 255, 255, 255, 127); - imagefilledrectangle($temp, 0, 0, $this->width, $this->height, $transparent); - imagecopyresampled($temp, $this->image, 0, 0, 0, 0, $width, $height, $this->width, $this->height); - - return $this->_replace($temp); + // reszta kodu metody + return $this; } + /** * Enlarge canvas * - * @param int $width Canvas width - * @param int $height Canvas height - * @param array $rgb RGB colour values - * @param int $xpos X-Position of image in new canvas, null for centre - * @param int $ypos Y-Position of image in new canvas, null for centre - * @return ImageManipulator for a fluent interface + * @param int $width Canvas width + * @param int $height Canvas height + * @param array $rgb RGB colour values [R, G, B] + * @param int|null $xpos X-Position of image in new canvas, null for centre + * @param int|null $ypos Y-Position of image in new canvas, null for centre + * @return self * @throws RuntimeException */ - public function enlargeCanvas($width, $height, array $rgb = array(), $xpos = null, $ypos = null) + public function enlargeCanvas(int $width, int $height, array $rgb = [], ?int $xpos = null, ?int $ypos = null): self { - if (!is_resource($this->image)) { + if (!isset($this->image) || !$this->image instanceof \GdImage) { throw new RuntimeException('No image set'); } @@ -146,52 +177,108 @@ class ImageManipulator $height = max($height, $this->height); $temp = imagecreatetruecolor($width, $height); - if (count($rgb) == 3) { - $bg = imagecolorallocate($temp, $rgb[0], $rgb[1], $rgb[2]); + if (!$temp instanceof \GdImage) { + throw new RuntimeException('Failed to create a new image for enlarging canvas'); + } + + // Fill background if RGB provided + if (count($rgb) === 3) { + [$r, $g, $b] = $rgb; + $bg = imagecolorallocate($temp, $r, $g, $b); imagefill($temp, 0, 0, $bg); + } else { + // Preserve transparency + imagealphablending($temp, false); + imagesavealpha($temp, true); + $transparent = imagecolorallocatealpha($temp, 255, 255, 255, 127); + imagefilledrectangle($temp, 0, 0, $width, $height, $transparent); } - if (null === $xpos) { - $xpos = round(($width - $this->width) / 2); + // Calculate positions + if ($xpos === null) { + $xpos = (int) round(($width - $this->width) / 2); } - if (null === $ypos) { - $ypos = round(($height - $this->height) / 2); + if ($ypos === null) { + $ypos = (int) round(($height - $this->height) / 2); + } + + // Logowanie przed kopiowaniem obrazu na nowe płótno + error_log("Enlarging canvas: xpos: $xpos, ypos: $ypos"); + + if (!imagecopy( + $temp, + $this->image, + $xpos, + $ypos, + 0, + 0, + $this->width, + $this->height + )) { + throw new RuntimeException('Failed to copy image onto enlarged canvas'); } - imagecopy($temp, $this->image, (int) $xpos, (int) $ypos, 0, 0, $this->width, $this->height); return $this->_replace($temp); } /** * Crop image * - * @param int|array $x1 Top left x-coordinate of crop box or array of coordinates + * @param int|array $x1 Top left x-coordinate of crop box or array of coordinates [x1, y1, x2, y2] * @param int $y1 Top left y-coordinate of crop box * @param int $x2 Bottom right x-coordinate of crop box * @param int $y2 Bottom right y-coordinate of crop box - * @return ImageManipulator for a fluent interface + * @return self * @throws RuntimeException */ - public function crop($x1, $y1 = 0, $x2 = 0, $y2 = 0) + public function crop($x1, int $y1 = 0, int $x2 = 0, int $y2 = 0): self { - if (!is_resource($this->image)) { + if (!isset($this->image) || !$this->image instanceof \GdImage) { throw new RuntimeException('No image set'); } - if (is_array($x1) && 4 == count($x1)) { - list($x1, $y1, $x2, $y2) = $x1; + + if (is_array($x1) && count($x1) === 4) { + [$x1, $y1, $x2, $y2] = $x1; } - $x1 = max($x1, 0); + $x1 = max((int)$x1, 0); $y1 = max($y1, 0); - $x2 = min($x2, $this->width); $y2 = min($y2, $this->height); - $width = $x2 - $x1; - $height = $y2 - $y1; + $cropWidth = $x2 - $x1; + $cropHeight = $y2 - $y1; - $temp = imagecreatetruecolor($width, $height); - imagecopy($temp, $this->image, 0, 0, $x1, $y1, $width, $height); + // Logowanie wymiarów do przycięcia + error_log("Cropping image: x1: $x1, y1: $y1, x2: $x2, y2: $y2, cropWidth: $cropWidth, cropHeight: $cropHeight"); + + if ($cropWidth <= 0 || $cropHeight <= 0) { + throw new RuntimeException('Invalid crop dimensions'); + } + + $temp = imagecreatetruecolor($cropWidth, $cropHeight); + if (!$temp instanceof \GdImage) { + throw new RuntimeException('Failed to create a new image for cropping'); + } + + // Preserve transparency + imagealphablending($temp, false); + imagesavealpha($temp, true); + $transparent = imagecolorallocatealpha($temp, 255, 255, 255, 127); + imagefilledrectangle($temp, 0, 0, $cropWidth, $cropHeight, $transparent); + + if (!imagecopy( + $temp, + $this->image, + 0, + 0, + $x1, + $y1, + $cropWidth, + $cropHeight + )) { + throw new RuntimeException('Failed to crop image'); + } return $this->_replace($temp); } @@ -199,82 +286,119 @@ class ImageManipulator /** * Replace current image resource with a new one * - * @param resource $res New image resource - * @return ImageManipulator for a fluent interface + * @param \GdImage $res New image resource + * @return self * @throws UnexpectedValueException */ - protected function _replace($res) + protected function _replace(\GdImage $res): self { - if (!is_resource($res)) { - throw new UnexpectedValueException('Invalid resource'); + if (!$res instanceof \GdImage) { + throw new UnexpectedValueException('Invalid image resource'); } - if (is_resource($this->image)) { + + if (isset($this->image) && $this->image instanceof \GdImage) { imagedestroy($this->image); } + $this->image = $res; $this->width = imagesx($res); $this->height = imagesy($res); + + error_log("Replaced image dimensions: width: {$this->width}, height: {$this->height}"); + + if ($this->width === 0 || $this->height === 0) { + throw new UnexpectedValueException("Replaced image has invalid dimensions (width: $this->width, height: $this->height)"); + } + return $this; } /** * Save current image to file * - * @param string $fileName + * @param string $fileName Path to save the image + * @param int|null $type Image type (IMAGETYPE_*) or null to auto-detect from file extension * @return void * @throws RuntimeException */ - public function save($fileName, $type = IMAGETYPE_JPEG) + public function save(string $fileName, ?int $type = null): void { $dir = dirname($fileName); if (!is_dir($dir)) { - if (!mkdir($dir, 0755, true)) { + if (!mkdir($dir, 0755, true) && !is_dir($dir)) { throw new RuntimeException('Error creating directory ' . $dir); } } + // Auto-detect type from file extension if not provided + if ($type === null) { + $extension = strtolower(pathinfo($fileName, PATHINFO_EXTENSION)); + switch ($extension) { + case 'gif': + $type = IMAGETYPE_GIF; + break; + case 'jpeg': + case 'jpg': + $type = IMAGETYPE_JPEG; + break; + case 'png': + $type = IMAGETYPE_PNG; + break; + case 'webp': + $type = IMAGETYPE_WEBP; + break; + default: + $type = IMAGETYPE_JPEG; + } + } + + error_log("Saving image to $fileName with type $type"); + try { switch ($type) { case IMAGETYPE_WEBP: - if ( !imagewebp( $this -> image, $fileName ) ) - throw new RuntimeException; - break; - case IMAGETYPE_GIF : - if ( !imagegif( $this -> image, $fileName ) ) - throw new RuntimeException; - break; - case 'image/png': - if (!imagepng($this->image, $fileName)) { - throw new RuntimeException; + if (!imagewebp($this->image, $fileName)) { + throw new RuntimeException('Failed to save image as WEBP'); } break; - case IMAGETYPE_JPEG : - default : + case IMAGETYPE_GIF: + if (!imagegif($this->image, $fileName)) { + throw new RuntimeException('Failed to save image as GIF'); + } + break; + case IMAGETYPE_PNG: + if (!imagepng($this->image, $fileName)) { + throw new RuntimeException('Failed to save image as PNG'); + } + break; + case IMAGETYPE_JPEG: + default: if (!imagejpeg($this->image, $fileName, 95)) { - throw new RuntimeException; + throw new RuntimeException('Failed to save image as JPEG'); } } - } catch (Exception $ex) { - throw new RuntimeException('Error saving image file to ' . $fileName); + error_log("Image saved successfully to $fileName"); + } catch (\Exception $ex) { + throw new RuntimeException('Error saving image file to ' . $fileName . ': ' . $ex->getMessage()); } } /** * Returns the GD image resource * - * @return resource + * @return \GdImage */ - public function getResource() + public function getResource(): \GdImage { return $this->image; } /** - * Get current image resource width + * Get current image width * * @return int */ - public function getWidth() + public function getWidth(): int { return $this->width; } @@ -284,8 +408,18 @@ class ImageManipulator * * @return int */ - public function getHeight() + public function getHeight(): int { return $this->height; } -} \ No newline at end of file + + /** + * Destructor to clean up the image resource + */ + public function __destruct() + { + if (isset($this->image) && $this->image instanceof \GdImage) { + imagedestroy($this->image); + } + } +} diff --git a/autoload/class.S.php b/autoload/class.S.php index 6d14e85..4495c14 100644 --- a/autoload/class.S.php +++ b/autoload/class.S.php @@ -170,7 +170,7 @@ class S public static function get_domain( $url ) { $parseUrl = parse_url( trim( $url ) ); - return trim( $parseUrl[host] ? str_replace( 'www.', '', $parseUrl[host] ) : str_replace( 'www.', '', array_shift( explode( '/', $parseUrl[path], 2 ) ) ) ); + return trim( $parseUrl['host'] ? str_replace( 'www.', '', $parseUrl['host'] ) : str_replace( 'www.', '', array_shift( explode( '/', $parseUrl['path'], 2 ) ) ) ); } static public function pre_dump( $value ) @@ -237,7 +237,7 @@ class S { $result = array(); - while ( list($key, $values) = each( $input ) ) + foreach ($array as $key => $value) { if ( empty( $values ) ) continue; diff --git a/autoload/front/controls/class.ShopBasket.php b/autoload/front/controls/class.ShopBasket.php index 93696cf..d7a6f42 100644 --- a/autoload/front/controls/class.ShopBasket.php +++ b/autoload/front/controls/class.ShopBasket.php @@ -202,8 +202,12 @@ class ShopBasket $values['wp'] = \front\factory\ShopProduct::product_wp( $values[ 'product-id' ] ); + $attributes_implode = ''; // generuj unikalny kod produktu dodanego do koszyka - $product_code = md5( $values['product-id'] . implode( '|', $attributes ) . $values['product-message'] . json_encode( $custom_fields ) ); + if ( is_array( $attributes ) ) + $attributes_implode = implode( '|', $attributes ); + + $product_code = md5( $values['product-id'] . $attributes_implode . $values['product-message'] . json_encode( $custom_fields ) ); if ( isset( $basket[ $product_code ] ) ) $basket[ $product_code ][ 'quantity' ] += $values[ 'quantity' ]; diff --git a/autoload/front/factory/class.Layouts.php b/autoload/front/factory/class.Layouts.php index 3b396ad..c23d930 100644 --- a/autoload/front/factory/class.Layouts.php +++ b/autoload/front/factory/class.Layouts.php @@ -65,18 +65,18 @@ class Layouts if ( !$objectData ) { - $layout = $mdb -> get( 'pp_layouts', '*', [ '[><]pp_layouts_categories' => [ 'id' => 'layout_id' ] ], [ 'category_id' => (int)$category_id ] ); + $layout = $mdb -> query( "SELECT pp_layouts.* FROM pp_layouts JOIN pp_layouts_categories ON pp_layouts.id = pp_layouts_categories.layout_id WHERE pp_layouts_categories.category_id = " . (int)$category_id ) -> fetchAll( \PDO::FETCH_ASSOC ); if ( !$layout ) $layout = $mdb -> get( 'pp_layouts', '*', [ 'categories_default' => 1 ] ); - $cacheHandler -> set( $cacheKey, $layout ); + $cacheHandler -> set( $cacheKey, $layout[0] ); } else { return unserialize( $objectData ); } - return $layout; + return $layout[0]; } static public function active_layout( $page_id ) diff --git a/autoload/front/factory/class.ShopProduct.php b/autoload/front/factory/class.ShopProduct.php index 070032f..3453a3d 100644 --- a/autoload/front/factory/class.ShopProduct.php +++ b/autoload/front/factory/class.ShopProduct.php @@ -248,11 +248,6 @@ class ShopProduct if ( is_array( $results ) ) foreach ( $results as $row ) { - $row[ 'require' ] = $mdb -> get( 'pp_shop_attributes', - 'required', - [ 'id' => $row[ 'attribute_id' ] ] - ); - $row[ 'type' ] = $mdb -> get( 'pp_shop_attributes', 'type', [ 'id' => $row[ 'attribute_id' ] ] @@ -301,9 +296,9 @@ class ShopProduct $product[ 'products_related' ] = $mdb -> select( 'pp_shop_products_related', 'product_related_id', [ 'product_id' => (int)$product_id ] ); - $products_sets_1 = $mdb -> select( 'pp_shop_products_sets', 'product_sets_id', [ 'product_id' => (int)$product_id ] ); - $products_sets_2 = $mdb -> select( 'pp_shop_products_sets', 'product_id', [ 'product_sets_id' => (int)$product_id ] ); - $products_sets = array_unique( array_merge( $products_sets_1, $products_sets_2 ) ); + $set_id = $mdb -> select( 'pp_shop_product_sets_products', 'set_id', [ 'product_id' => (int)$product_id ] ); + $products_sets = $mdb -> select( 'pp_shop_product_sets_products', 'product_id', [ 'set_id' => (int)$set_id ] ); + $products_sets = array_unique( $products_sets ); $product[ 'products_sets' ] = $products_sets; @@ -338,28 +333,6 @@ class ShopProduct return $mdb -> get( 'pp_shop_products_langs', 'warehouse_message_nonzero', [ 'AND' => [ 'product_id' => $id_product, 'lang_id' => $lang_id ] ] ); } - public static function permutation_quantity( $id_product, $permutation, bool $is_multichoice ) - { - global $mdb; - - if ( !$is_multichoice ) - return $mdb -> get( 'pp_shop_products_stock', 'quantity', [ 'AND' => [ 'id_product' => $id_product, 'permutation' => 0 ] ] ); - - if ( is_array( $permutation ) ) - { - foreach ( $permutation as $key => $val ) - { - $permutation_id .= $val; - if ( $val != end( $permutation ) ) - $permutation_id .= '_'; - } - } - else - $permutation_id = $permutation; - - return $mdb -> get( 'pp_shop_products_stock', 'quantity', [ 'AND' => [ 'id_product' => $id_product, 'permutation' => $permutation_id ] ] ); - } - //TO:DO do usunięcia public static function product_both_price( $product_id ) { diff --git a/autoload/front/view/class.ShopOrder.php b/autoload/front/view/class.ShopOrder.php new file mode 100644 index 0000000..d28356a --- /dev/null +++ b/autoload/front/view/class.ShopOrder.php @@ -0,0 +1,12 @@ + $val ) + $tpl -> $key = $val; + return $tpl -> render( 'shop-order/order-details' ); + } +} diff --git a/autoload/shop/class.Product.php b/autoload/shop/class.Product.php index d399870..2004ccc 100644 --- a/autoload/shop/class.Product.php +++ b/autoload/shop/class.Product.php @@ -795,7 +795,7 @@ class Product implements \ArrayAccess { $result = array(); - while ( list($key, $values) = each( $input ) ) + foreach ( $input as $key => $values ) { if ( empty( $values ) ) continue; @@ -834,7 +834,7 @@ class Product implements \ArrayAccess public function __get( $variable ) { - if ( array_key_exists( $variable, $this -> data ) ) + if ( is_array( $this -> data ) and array_key_exists( $variable, $this -> data ) ) return $this -> $variable; } diff --git a/config.php b/config.php index f3e9f2f..58007f2 100644 --- a/config.php +++ b/config.php @@ -10,9 +10,9 @@ $config['salt'] = 'dd6c0ee59bf35b208b6d9bf42dd60769'; $config['google-ads-id'] = 'AW-810084545'; $config['baselinker-start'] = '2031-06-09 21:26'; -$config['redis']['host'] = '127.0.0.1'; -$config['redis']['port'] = 44090; -$config['redis']['password'] = 'KvCb8A3OJl3JhML1IuD51tD6q9d3TJLu'; +$config['redis']['host'] = ''; +$config['redis']['port'] = 0; +$config['redis']['password'] = ''; $config['debug']['apilo'] = false; ?> diff --git a/libraries/grid/gdb.min.php b/libraries/grid/gdb.min.php index eb56f0f..f8a6c0e 100644 --- a/libraries/grid/gdb.min.php +++ b/libraries/grid/gdb.min.php @@ -3,7 +3,7 @@ * Medoo database framework * http://medoo.in * Version 0.9.7 - * + * * Copyright 2014, Angel Lai * Released under the MIT license */ @@ -33,7 +33,7 @@ class gdb protected $option = array(); - // Variable + // Variable protected $logs = array(); public function __construct($options = null) @@ -131,7 +131,7 @@ class gdb } $this->pdo = new PDO( - $dsn, + $dsn, $this->username, $this->password, $this->option @@ -148,14 +148,14 @@ class gdb } public function query($query) - { + { array_push($this->logs, $query); return $this->pdo->query($query); } public function exec($query) - { + { array_push($this->logs, $query); return $this->pdo->exec($query); @@ -199,7 +199,10 @@ class gdb } } - return implode($stack, ','); + if ( is_array( $stack ) ) + return implode( ',', $stack ); + else + return $stack; } protected function array_quote($array) @@ -318,11 +321,11 @@ class gdb } $value = '%' . $value . '%'; - + $wheres[] = $column . ' LIKE ' . $this->fn_quote($key, $value); } } - + if (in_array($operator, array('>', '>=', '<', '<='))) { if (is_numeric($value)) @@ -835,7 +838,7 @@ class gdb if (isset($data[0])) { $column = $where == null ? $join : $column; - + if (is_string($column) && $column != '*') { return $data[ 0 ][ $column ]; diff --git a/libraries/grid/grid.php b/libraries/grid/grid.php index d9624bb..f77c6e5 100644 --- a/libraries/grid/grid.php +++ b/libraries/grid/grid.php @@ -1,29 +1,29 @@ 'mysql', 'database_name' => 'db_name', 'server' => 'db_host', @@ -46,96 +46,97 @@ class grid 'password' => 'db_pass', 'port' => 'db_port' ); - + public $empty_txt = 'Brak danych w tabeli.'; - + public $multiselect = null; public $multidelete_url = null; - + public $buttons = null; - + public $actions = array( 'delete' => false, 'delete_url' => null, 'add' => false, 'add_url' => null, 'edit' => false ); - + function __construct( $table, $name = '' ) { $this -> table = $table; $this -> name = $name; $this -> dir = dirname( __FILE__ ); - + $this -> name ? $g_table = $this -> name : $g_table = $this -> table; - + if ( !empty( $_SESSION[ 'g' . $g_table . 'filters' ] ) ) $this -> filters = $_SESSION[ 'g' . $g_table . 'filters' ]; - + if ( !empty( $_SESSION[ 'g' . $g_table . 'limit' ] ) ) $this -> limit = $_SESSION[ 'g' . $g_table . 'limit' ]; - + if ( !empty( $_SESSION[ 'g' . $g_table . 'order' ] ) ) $this -> order = $_SESSION[ 'g' . $g_table . 'order' ]; - + if ( $this -> clear_cache ) { $this -> name ? $g_table = $this -> name : $g_table = $this -> table; if ( is_array( $_SESSION ) ) foreach ( $_SESSION as $key => $val ) { - if ( $key != 'g' . $g_table and @get_class( $val ) == '__PHP_Incomplete_Class' ) - unset( $_SESSION[ $key ] ); + if ($key != 'g' . $g_table && is_object($val) && get_class($val) == '__PHP_Incomplete_Class') { + unset($_SESSION[$key]); + } } } } - + public function hide_column( $column, $hidden ) { $this -> name ? $g_table = $this -> name : $g_table = $this -> table; - + $db = $this -> connectToDb(); - + $results = $db -> get( 'grid_settings', 'settings', [ 'name' => $g_table ] ); $results = unserialize( $results ); - + $results['hidden_columns'][ $column ] = $hidden; - + if ( $db -> count( 'grid_settings', [ 'name' => $g_table ] ) ) $db -> update( 'grid_settings', [ 'settings' => serialize( $results ) ], [ 'name' => $g_table ] ); else $db -> insert( 'grid_settings', [ 'settings' => serialize( $results ), 'name' => $g_table ] ); } - + public function drawEdit( $id ) { $values = get_object_vars( $this ); - + $view = new gridView( $this -> dir . '/templates/' ); $view -> values = $values; $view -> element = $this -> getElement( $id ); return $view -> render( 'edit' ); } - + public function draw() - { + { $this -> name ? $g_table = $this -> name : $g_table = $this -> table; - + $db = $this -> connectToDb(); - + $results = $db -> get( 'grid_settings', 'settings', [ 'name' => $g_table ] ); $results = unserialize( $results ); - + $this -> hidden_columns = $results['hidden_columns']; - - - - (int)$_SESSION[ 'g' . $g_table . 'cp' ] ? $this -> cp = (int)$_SESSION[ 'g' . $g_table . 'cp' ] : $this -> cp = 1; - + + + + (int)$_SESSION[ 'g' . $g_table . 'cp' ] ? $this -> cp = (int)$_SESSION[ 'g' . $g_table . 'cp' ] : $this -> cp = 1; + $_SESSION[ 'g' . $g_table ] = $this; - + $values = get_object_vars( $this ); $values['content'] = $this -> drawResults(); - + $view = new gridView( $this -> dir . '/templates/' ); $view -> values = $values; return $view -> render( 'container' ); } - + public function connectToDb() { return new gdb( [ @@ -148,14 +149,14 @@ class grid 'charset' => 'utf8' ] ); } - + public function getCSV() { if ( is_array( $this -> src ) ) $results = $this -> getDataSrc(); else $results = $this -> getData( true ); - + if ( is_array( $this -> columns_view ) ) foreach ( $this -> columns_view as $column ) { $array_row = array(); @@ -164,7 +165,7 @@ class grid $headers[] = $column['name']; } } - + if ( is_array( $results ) ) foreach ( $results as $row ) { $array_row = array(); @@ -208,15 +209,15 @@ class grid } $array[] = $array_row; } - + $now = gmdate( "D, d M Y H:i:s" ); - + header( 'Content-Encoding: UTF-8' ); header( "Expires: Tue, 03 Jul 2001 06:00:00 GMT" ); header( "Cache-Control: max-age=0, no-cache, must-revalidate, proxy-revalidate" ); header( "Last-Modified: {$now} GMT" ); - // force download + // force download header( "Content-Type: application/force-download" ); header( "Content-Type: application/octet-stream" ); header( "Content-Type: application/download" ); @@ -233,11 +234,11 @@ class grid fclose( $df ); return ob_get_clean(); } - + public function printResults() { $values = get_object_vars( $this ); - + if ( is_array( $this -> src ) ) { $values['count'] = $this -> getDataCountSrc(); @@ -247,30 +248,30 @@ class grid $values['count'] = $this -> getDataCount(); $values['summary'] = $this -> getDataSummary(); } - + $this -> cp = 1; $this -> limit = $values['count']; - + if ( is_array( $this -> src ) ) $values['results'] = $this -> getDataSrc(); else $values['results'] = $this -> getData(); - + $view = new gridView( $this -> dir . '/templates/' ); $view -> values = $values; return $view -> render( 'print' ); } - + public function get_data_count_sql() - { + { $db = $this ->connectToDb(); - + $where = $this -> getWhereCondition(); $where = $db -> where_clause( $where ); - + if ( strpos( $this -> sql_count, 'WHERE' ) !== false and !empty( $where ) ) $where = str_replace( 'WHERE', 'AND', $where ); - + $this -> sql_tmp = str_replace( '[where]', $where, $this -> sql_count ); $query = $db -> query( $this -> sql_tmp ); @@ -289,14 +290,14 @@ class grid return 0; } } - + public function get_data_sql( $print = false ) { $db = $this -> connectToDb(); - + $where = $this -> getWhereCondition(); $where = $db -> where_clause( $where ); - + if ( strpos( $this -> sql, 'WHERE' ) !== false and !empty( $where ) ) $where = str_replace( 'WHERE', 'AND', $where ); @@ -304,10 +305,10 @@ class grid $this -> sql_tmp = $this -> sql . ' LIMIT ' . $this -> limit . ' OFFSET ' . ( $this -> cp - 1 ) * $this -> limit; else $this -> sql_tmp = $this -> sql; - $this -> sql_tmp = str_replace( '[where]', $where, $this -> sql_tmp ); + $this -> sql_tmp = str_replace( '[where]', $where, $this -> sql_tmp ); $this -> sql_tmp = str_replace( '[order_p1]', $this -> order['column'], $this -> sql_tmp ); $this -> sql_tmp = str_replace( '[order_p2]', $this -> order['type'], $this -> sql_tmp ); - + $query = $db -> query( $this -> sql_tmp ); if ( $query ) { @@ -324,11 +325,11 @@ class grid return null; } } - + public function drawResults() { $values = get_object_vars( $this ); - + if ( is_array( $this -> src ) ) $values['count'] = $this -> getDataCountSrc(); else if ( isset( $this -> sql ) and isset( $this -> sql_count ) ) @@ -338,51 +339,51 @@ class grid $values['count'] = $this -> getDataCount(); $values['summary'] = $this -> getDataSummary(); } - + $ls = ceil( $values['count'] / $this -> limit ); - + if ( !(int)$ls ) $ls = 1; - + if ( $this -> cp > $ls ) { $this -> cp = $ls; $values['cp'] = $ls; } - + if ( is_array( $this -> src ) ) $values['results'] = $this -> getDataSrc(); else if ( isset( $this -> sql ) and isset( $this -> sql_count ) ) $values['results'] = $this -> get_data_sql(); else $values['results'] = $this -> getData(); - + $view = new gridView( $this -> dir . '/templates/' ); $view -> values = $values; return $view -> render( 'results' ); } - + public function delete( $id ) { return $this -> connectToDb() -> delete( $this -> table, [ $this -> id => $id ] ); } - + public function getWhereCondition() - { + { $where = array(); - + $where['AND'] = $this -> where; - + if ( $this -> filters ) { foreach ( $this -> filters as $key => $val ) { if ( $val['type'] == 'like' ) $where['AND'] = array_merge( $where['AND'], [ $key . '[~]' => $val['value'] ] ); - + if ( $val['type'] == 'equal' ) $where['AND'] = array_merge( $where['AND'], [ $key => $val['value'] ] ); - + if ( $val['type'] == 'date_range' ) { $dates = explode( ' - ', $val['value'] ); @@ -391,13 +392,13 @@ class grid } } } - + if ( count( $where['AND'] ) ) return $where; else return array(); } - + public static function searchSrc( $array, $column, $value, $type = 'equal' ) { if ( is_array( $array ) ) foreach ( $array as $key => $val ) @@ -407,7 +408,7 @@ class grid if ( $val[ $column ] == $value ) $array_tmp[] = $val; } - + if ( $type == 'like' ) { if ( strpos( mb_strtolower( $val[ $column ], 'UTF-8' ), mb_strtolower( $value, 'UTF-8' ) ) !== false ) @@ -416,28 +417,28 @@ class grid } return $array_tmp; } - + public function filtrDataSrc() { $this -> src_filtered = $this -> src; - + if ( $this -> filters ) { foreach ( $this -> filters as $key => $val ) { if ( $val['type'] == 'like' ) $this -> src_filtered = $this -> searchSrc( $this -> src_filtered, $key, $val['value'], 'like' ); - + if ( $val['type'] == 'equal' ) $this -> src_filtered = $this -> searchSrc( $this -> src_filtered, $key, $val['value'], 'equal' ); } } } - + public function getDataSummary() { $where = self::getWhereCondition(); - + if ( is_array( $this -> summary ) ) foreach ( $this -> summary as $key ) { if ( $this -> join ) @@ -447,48 +448,48 @@ class grid } return $summary; } - + public function getDataCountSrc() { $this -> filtrDataSrc(); return count( $this -> src_filtered ); } - + public function getDataCount() { $where = self::getWhereCondition(); - + if ( $this -> join ) $results = $this -> connectToDb() -> count( $this -> table, $this -> join, '*', $where ); else $results = $this -> connectToDb() -> count( $this -> table, $where ); - + if ( $results ) return $results; else return false; } - + public function getDataSrc() { if ( $this -> order ) $this -> src_filtered = $this -> sortByColumn( $this -> src_filtered, $this -> order['column'], $this -> order['type'] ); - + $array_tmp = $this -> src_filtered; - + if ( is_array( $array_tmp ) ) return array_splice( $array_tmp, ( $this -> cp - 1 ) * $this -> limit, $this -> limit ); else - return false; + return false; } - + public function getData( $csv = false ) { $where = self::getWhereCondition(); - + if ( $this -> order ) $where = array_merge( $where, [ 'ORDER' => $this -> order['column'] . ' ' . $this -> order['type'] ] ); - + if ( $this -> limit and $this -> show_paging === true and !$csv ) $where = array_merge( $where, [ 'LIMIT' => [ ( $this -> cp - 1 ) * $this -> limit, $this -> limit ] ] ); @@ -496,18 +497,18 @@ class grid $results = $this -> connectToDb() -> select( $this -> table, $this -> join, $this -> columns, $where ); else $results = $this -> connectToDb() -> select( $this -> table, $this -> columns, $where ); - + if ( $results ) return $results; else return false; } - + public function getElement( $id ) { return $this -> connectToDb() -> get( $this -> table, '*', [ $this -> id => $id ] ); } - + public function saveElement( $values ) { if ( !$values[ $this -> id ] ) @@ -518,12 +519,12 @@ class grid else return $this -> connectToDb() -> update( $this -> table, $values, [ $this -> id => $values[ $this -> id ] ] ); } - - public static function sortByColumn( &$arr, $col, $sort ) + + public static function sortByColumn( &$arr, $col, $sort ) { - setlocale( LC_COLLATE, 'pl_PL.utf-8' ); + setlocale( LC_COLLATE, 'pl_PL.utf-8' ); $sort == 'ASC' ? $dir = SORT_ASC : $dir = SORT_DESC; - + $sort_col = array(); if ( is_array( $arr ) ) { @@ -534,46 +535,46 @@ class grid } return $arr; } - + public static function validateDate( $date ) { if ( date( 'Y-m-d', strtotime( $date ) ) != '1970-01-01' ) return true; } - + public function save_limit( $limit ) { $this -> name ? $g_table = $this -> name : $g_table = $this -> table; - + $_SESSION[ 'g' . $g_table . 'limit' ] = $limit; } - + public function save_order() { $this -> name ? $g_table = $this -> name : $g_table = $this -> table; - + $_SESSION[ 'g' . $g_table . 'order' ] = $this -> order; } - + public function save_filters() { $this -> name ? $g_table = $this -> name : $g_table = $this -> table; - + $_SESSION[ 'g' . $g_table . 'filters' ] = $this -> filters; } - + public function set_cp( $cp ) { $this -> name ? $g_table = $this -> name : $g_table = $this -> table; - + $_SESSION[ 'g' . $g_table . 'cp'] = $cp; $this -> cp = $cp; } - + public function getParams( $string ) { $params = array(); - + preg_match_all( '/\[[a-zA-Z0-9_]*\]/', $string, $results_tmp1 ); if ( is_array( $results_tmp1[0] ) ) foreach ( $results_tmp1[0] as $row_tmp1 ) { @@ -584,7 +585,7 @@ class grid } return $params; } - + public function convertString( $string, $row ) { $out = $string; @@ -599,11 +600,11 @@ class grid } return $out; } - + public function convertStringJS( $string ) { $out = 'var out = "' . addslashes( $string ) . '";' . chr( 13 ); - + preg_match_all( '/\[[a-zA-Z0-9_]*\]/', $string, $results_tmp1 ); if ( is_array( $results_tmp1[0] ) ) foreach ( $results_tmp1[0] as $row_tmp1 ) { diff --git a/libraries/grid/js/grid.js b/libraries/grid/js/grid.js index 386a172..997153a 100644 --- a/libraries/grid/js/grid.js +++ b/libraries/grid/js/grid.js @@ -1,7 +1,7 @@ -function g_validate_form( id ) +function g_validate_form( id ) { var submit = true; - jQuery( '#fg-' + id ).find( "input[type=text], input[type=password], select, textarea" ).each( function() + jQuery( '#fg-' + id ).find( "input[type=text], input[type=password], select, textarea" ).each( function() { var min = parseInt( jQuery( this ).attr( 'min' ) ); var equal = jQuery( this ).attr( 'equal' ); @@ -34,7 +34,7 @@ function g_validate_form( id ) else if ( fun !== undefined ) { var response = window[fun](); - + if ( response['status'] === 'error' ) { submit = false; @@ -56,7 +56,7 @@ function g_validate_form( id ) return submit; } -function number_format( number, decimals, dec_point, thousands_sep ) +function number_format( number, decimals, dec_point, thousands_sep ) { number = ( number + '' ).replace( /[^0-9+\-Ee.]/g, '' ); var n = !isFinite(+number) ? 0 : +number, @@ -102,7 +102,7 @@ function hide_error() { }, 3000 ); } -function create_message( text ) +function create_message( text ) { hide_message(); jQuery( '#content' ).prepend( '
' + @@ -134,15 +134,15 @@ jQuery( 'body' ).on( 'click', '#g-message, #g-alert', function() { jQuery( 'body' ).on( 'change', '.g-double', function() { var value = jQuery( this ).val(); value = parseFloat( value.replace( ',', '.' ) * 1 ); - + if ( isNaN( value ) ) value = 0; - + if ( jQuery( this ).hasClass( 'g-plus' ) ) value = Math.abs( value ); - + value = number_format( value , 2 , '.' , '' ); - + jQuery( this ).val( value ); }); @@ -176,13 +176,13 @@ jQuery.datepicker.regional['pl'] = { jQuery.datepicker.setDefaults( jQuery.datepicker.regional[ 'pl' ] ); jQuery( 'body' ).on( 'focus', '.g-date', function() { - jQuery( this ).datepicker( { + jQuery( this ).datepicker( { dateFormat: 'yy-mm-dd', changeMonth: true, changeYear: true } ); }); - + jQuery( 'body' ).on( 'click', 'a.g-expand', function() { jQuery( this ).parents( '.g-form-edit' ).children( '.g-content' ).slideDown( 'fast' ); jQuery( this ).children( 'i' ).removeClass( 'fa-chevron-down' ).addClass( 'fa-chevron-up' ); @@ -195,34 +195,34 @@ jQuery( 'body' ).on( 'click', '.g-collapse', function() { jQuery( this ).removeClass( 'g-collapse' ).addClass( 'g-expand' ); }); -jQuery( 'body' ).on( 'click', '#g-columns-list-close', function() +jQuery( 'body' ).on( 'click', '#g-columns-list-close', function() { - jQuery( '#g-select-columns' ).show(); + jQuery( '#g-select-columns' ).show(); jQuery( "#g-columns-list-close" ).hide(); return false; }); -jQuery( 'body' ).on( 'click', '#g-select-columns', function() +jQuery( 'body' ).on( 'click', '#g-select-columns', function() { - jQuery( '#g-select-columns' ).hide(); + jQuery( '#g-select-columns' ).hide(); jQuery( "#g-columns-list-close" ).show(); jQuery( '#g-columns-list' ).show(); return false; }); jQuery( '.g-column-toggle' ).on( 'ifToggled', function() -{ +{ var data = jQuery( this ).parents( '#g-columns-list' ).attr( 'data' ); data = data.split( ";" ); - for ( index = 0; index < data.length; ++index ) + for ( index = 0; index < data.length; ++index ) { var vars = data[ index ].split( ':') ; if ( vars[0] === 'table' ) var gtable = vars[1]; } - + var i = jQuery( this ).parents( 'li' ).attr( 'i' ); jQuery.ajax( @@ -236,27 +236,27 @@ jQuery( '.g-column-toggle' ).on( 'ifToggled', function() hidden: !jQuery( this ).prop( 'checked' ), a: 'gdraw' }, - beforeSend: function() + beforeSend: function() { jQuery( '#g-' + gtable ).find( '#g-loader' ).show(); }, - success: function( data ) + success: function( data ) { - response = jQuery.parseJSON( data ); + response = jQuery.parseJSON( data ); jQuery( '#g-' + gtable ).find( '#g-loader' ).hide(); if ( response.status === 'ok' ) { if ( response.msg !== null ) create_message( response.msg ); - + jQuery( '#g-' + gtable ).find( '#g-results' ).empty().html( response.output ); - } - else + } + else { - if ( response.msg ) - var msg = response.msg; - else + if ( response.msg ) + var msg = response.msg; + else var msg = "Przepraszamy. Podczas wczytywania danych wystąpił błąd. Prosimy spróbować ponownie."; create_error( msg ); } @@ -264,7 +264,7 @@ jQuery( '.g-column-toggle' ).on( 'ifToggled', function() }); }); -jQuery( 'body' ).on( 'click', '#g-columns-list span', function() { +jQuery( 'body' ).on( 'click', '#g-columns-list span', function() { var input = jQuery( this ).attr( 'input' ); jQuery( '#' + input ).iCheck( 'toggle' ); }); @@ -295,33 +295,33 @@ jQuery( 'body' ).on( 'click', '.g-print', function() { window.open( dir + '/print.php?gtable=' + gtable, 'Drukowanie', "height=400,width=600" ); }); -jQuery( 'body' ).on( 'click', '#g-multidelete', function() -{ +jQuery( 'body' ).on( 'click', '#g-multidelete', function() +{ var url = jQuery( this ).attr( 'url' ); if ( typeof url === 'undefined' ) url = ''; - + var data = jQuery( this ).parents( '.g-container' ).attr( 'data' ); data = data.split( ";" ); - for ( index = 0; index < data.length; ++index ) + for ( index = 0; index < data.length; ++index ) { var vars = data[ index ].split( ':') ; if ( vars[0] === 'table' ) var gtable = vars[1]; } - - jQuery.prompt( 'Na pewno chcesz usunąć wybrane elementy?', - { + + jQuery.prompt( 'Na pewno chcesz usunąć wybrane elementy?', + { title: 'Potwierdź?', - submit: function(e,v,m,f) - { + submit: function(e,v,m,f) + { if ( v === true ) { var checkedVals = getCheckedIds( gtable ); - + if ( url !== '' ) { jQuery.ajax( @@ -329,62 +329,62 @@ jQuery( 'body' ).on( 'click', '#g-multidelete', function() type: 'POST', cache: false, url: url, - data: + data: { gdelete_multi: checkedVals }, - beforeSend: function() + beforeSend: function() { jQuery( '#g-' + gtable ).find( '#g-loader' ).show(); }, - success: function( data ) + success: function( data ) { - response = jQuery.parseJSON( data ); + response = jQuery.parseJSON( data ); if ( response.status === 'ok' ) { if ( response.msg !== null ) create_message( response.msg ); - + jQuery.ajax( { type: 'POST', cache: false, url: dir + '/ajax.php', - data: + data: { gtable: gtable, a: 'gdraw' }, - success: function( data ) + success: function( data ) { - response = jQuery.parseJSON( data ); + response = jQuery.parseJSON( data ); jQuery( '#g-' + gtable ).find( '#g-loader' ).hide(); if ( response.status === 'ok' ) { if ( response.msg !== null ) create_message( response.msg ); - + jQuery( '#g-multidelete' ).hide(); jQuery( '#g-' + gtable ).find( '#g-results' ).empty().html( response.output ); - } - else + } + else { - if ( response.msg ) - var msg = response.msg; - else + if ( response.msg ) + var msg = response.msg; + else var msg = "Przepraszamy. Podczas wczytywania danych wystąpił błąd. Prosimy spróbować ponownie."; create_error( msg ); } } }); - } - else + } + else { - if ( response.msg ) - var msg = response.msg; - else + if ( response.msg ) + var msg = response.msg; + else var msg = "Przepraszamy. Podczas wczytywania danych wystąpił błąd. Prosimy spróbować ponownie."; create_error( msg ); } @@ -398,19 +398,19 @@ jQuery( 'body' ).on( 'click', '#g-multidelete', function() type: 'POST', cache: false, url: dir + '/ajax.php', - data: + data: { gtable: gtable, gdelete_multi: checkedVals, a: 'gdraw' }, - beforeSend: function() + beforeSend: function() { jQuery( '#g-' + gtable ).find( '#g-loader' ).show(); }, - success: function( data ) + success: function( data ) { - response = jQuery.parseJSON( data ); + response = jQuery.parseJSON( data ); jQuery( '#g-' + gtable ).find( '#g-loader' ).hide(); if ( response.status === 'ok' ) @@ -419,12 +419,12 @@ jQuery( 'body' ).on( 'click', '#g-multidelete', function() create_message( response.msg ); jQuery( '#g-multidelete' ).hide(); jQuery( '#g-' + gtable ).find( '#g-results' ).empty().html( response.output ); - } - else + } + else { - if ( response.msg ) - var msg = response.msg; - else + if ( response.msg ) + var msg = response.msg; + else var msg = "Przepraszamy. Podczas wczytywania danych wystąpił błąd. Prosimy spróbować ponownie."; create_error( msg ); } @@ -432,18 +432,18 @@ jQuery( 'body' ).on( 'click', '#g-multidelete', function() }); } } - }, - buttons: { - 'tak': true, - 'nie': false - }, - focus: 1 + }, + buttons: { + 'tak': true, + 'nie': false + }, + focus: 1 }); - return false; + return false; }); jQuery( 'body' ).on( 'click', '#g-cancel', function() { - + var data = jQuery( this ).parents( '.g-container' ).attr( 'data' ); data = data.split( ";" ); @@ -467,17 +467,17 @@ jQuery( 'body' ).on( 'click', '#g-cancel', function() { }, success: function( data ) { response = jQuery.parseJSON( data ); jQuery( '#g-' + gtable ).find( '#g-loader' ).hide(); - if ( response.status === 'ok' ) + if ( response.status === 'ok' ) { jQuery( '#g-add, #g-search, .g-button, #g-select-columns' ).show(); jQuery( '#g-cancel, #g-save' ).hide(); jQuery( '#g-' + gtable ).find( '#g-results' ).empty().html( response.output ); - } - else + } + else { - if ( response.msg ) - var msg = response.msg; - else + if ( response.msg ) + var msg = response.msg; + else var msg = "Przepraszamy. Podczas wczytywania danych wystąpił błąd. Prosimy spróbować ponownie."; create_error( msg ); } @@ -485,46 +485,46 @@ jQuery( 'body' ).on( 'click', '#g-cancel', function() { }); }); -jQuery( 'body' ).on( 'click', '#g-save, #g-edit-save', function() -{ +jQuery( 'body' ).on( 'click', '#g-save, #g-edit-save', function() +{ var back_url = jQuery( this ).attr( 'back_url' ); var persist_edit = jQuery( this ).attr( 'persist_edit' ); var id_param = jQuery( this ).attr( 'id_param' ); if ( typeof back_url === 'undefined' ) back_url = ''; - + var data = jQuery( this ).parents( '.g-container' ).attr( 'data' ); data = data.split( ";" ); - for ( index = 0; index < data.length; ++index ) + for ( index = 0; index < data.length; ++index ) { var vars = data[ index ].split( ':') ; if ( vars[0] === 'table' ) var gtable = vars[1]; } - - if ( g_validate_form( gtable ) === true ) - { - var values = jQuery( '#fg-' + gtable ).serializeObject(); - + + if ( g_validate_form( gtable ) === true ) + { + var values = jQuery( '#fg-' + gtable ).serializeArray(); + var url = jQuery( this ).attr( 'url' ); - - if ( url !== '' ) + + if ( url !== '' ) { jQuery.ajax( { type: 'POST', cache: false, url: url, - data: + data: { gtable: gtable, values: JSON.stringify( values ), a: 'gsave' }, - beforeSend: function() + beforeSend: function() { jQuery( '#g-' + gtable ).find( '#g-loader' ).show(); jQuery( '#overlay' ).show(); @@ -533,7 +533,7 @@ jQuery( 'body' ).on( 'click', '#g-save, #g-edit-save', function() { jQuery( '#overlay' ).hide(); response = jQuery.parseJSON( data ); jQuery( '#g-' + gtable ).find( '#g-loader' ).hide(); - if ( response.status === 'ok' ) + if ( response.status === 'ok' ) { if ( back_url !== '' && persist_edit == 0 ) document.location.href = back_url; @@ -547,16 +547,16 @@ jQuery( 'body' ).on( 'click', '#g-save, #g-edit-save', function() type: 'POST', cache: false, url: dir + '/ajax.php', - data: + data: { gtable: gtable, a: 'gdraw' }, - beforeSend: function() + beforeSend: function() { jQuery( '#g-' + gtable ).find( '#g-loader' ).show(); }, - success: function( data ) + success: function( data ) { response = jQuery.parseJSON( data ); jQuery( '#g-' + gtable ).find( '#g-loader' ).hide(); if ( response.status === 'ok' ) @@ -564,12 +564,12 @@ jQuery( 'body' ).on( 'click', '#g-save, #g-edit-save', function() jQuery( '#g-add, #g-search, .g-button' ).show(); jQuery( '#g-cancel, #g-save' ).hide(); jQuery( '#g-' + gtable ).find( '#g-results' ).empty().html( response.output ); - } - else + } + else { - if ( response.msg ) - var msg = response.msg; - else + if ( response.msg ) + var msg = response.msg; + else var msg = "Przepraszamy. Podczas wczytywania danych wystąpił błąd. Prosimy spróbować ponownie."; create_error( msg ); } @@ -580,49 +580,49 @@ jQuery( 'body' ).on( 'click', '#g-save, #g-edit-save', function() { if ( response.msg !== null ) create_message( response.msg ); - + if ( id_param != '' ) jQuery( '#' + id_param ).val( response.id ); } - } - else + } + else { - if ( response.msg ) - var msg = response.msg; - else + if ( response.msg ) + var msg = response.msg; + else var msg = "Przepraszamy. Podczas wczytywania danych wystąpił błąd. Prosimy spróbować ponownie."; create_error( msg ); } } }); - } - else - { + } + else + { jQuery.ajax( { type: 'POST', cache: false, url: dir + '/ajax.php', - data: + data: { gtable: gtable, values: JSON.stringify( values ), a: 'gsave' }, - beforeSend: function() + beforeSend: function() { jQuery( '#g-' + gtable ).find( '#g-loader' ).show(); }, - success: function( data ) + success: function( data ) { response = jQuery.parseJSON( data ); jQuery( '#g-' + gtable ).find( '#g-loader' ).hide(); - if ( response.status === 'ok' ) + if ( response.status === 'ok' ) { - - if ( back_url !== '' ) + + if ( back_url !== '' ) { document.location.href=back_url; - } + } else { if ( response.msg !== null ) @@ -632,12 +632,12 @@ jQuery( 'body' ).on( 'click', '#g-save, #g-edit-save', function() jQuery( '#g-cancel, #g-save' ).hide(); jQuery( '#g-' + gtable ).find( '#g-results' ).empty().html( response.output ); } - } - else + } + else { - if ( response.msg ) - var msg = response.msg; - else + if ( response.msg ) + var msg = response.msg; + else var msg = "Przepraszamy. Podczas wczytywania danych wystąpił błąd. Prosimy spróbować ponownie."; create_error( msg ); } @@ -646,9 +646,9 @@ jQuery( 'body' ).on( 'click', '#g-save, #g-edit-save', function() } }; }); - + jQuery( 'body' ).on( 'click', '#g-add, .g-edit', function() { - + var data = jQuery( this ).parents( '.g-container' ).attr( 'data' ); data = data.split( ";" ); @@ -658,9 +658,9 @@ jQuery( 'body' ).on( 'click', '#g-add, .g-edit', function() { if ( vars[0] === 'table' ) var gtable = vars[1]; } - + var gedit = jQuery( this ).attr( 'element-id' ); - + jQuery.ajax({ type: 'POST', cache: false, @@ -675,17 +675,17 @@ jQuery( 'body' ).on( 'click', '#g-add, .g-edit', function() { }, success: function( data ) { response = jQuery.parseJSON( data ); jQuery( '#g-' + gtable ).find( '#g-loader' ).hide(); - if ( response.status === 'ok' ) + if ( response.status === 'ok' ) { jQuery( '#g-add, #g-search, .g-button, #g-select-columns' ).hide(); jQuery( '#g-cancel, #g-save' ).css( 'display', 'inline-block' ); jQuery( '#g-' + gtable ).find( '#g-results' ).empty().html( response.output ); - } - else + } + else { - if ( response.msg ) - var msg = response.msg; - else + if ( response.msg ) + var msg = response.msg; + else var msg = "Przepraszamy. Podczas wczytywania danych wystąpił błąd. Prosimy spróbować ponownie."; create_error( msg ); } @@ -693,7 +693,7 @@ jQuery( 'body' ).on( 'click', '#g-add, .g-edit', function() { }); }); -jQuery( 'body' ).on( 'click', '.g-delete', function() +jQuery( 'body' ).on( 'click', '.g-delete', function() { jQuery( this ).blur(); @@ -711,35 +711,35 @@ jQuery( 'body' ).on( 'click', '.g-delete', function() var back_url = jQuery( this ).attr( 'back-url' ); var url = jQuery( this ).attr( 'url' ).replace( '[ID]', gdelete ); - jQuery.prompt( 'Na pewno chcesz usunąć wybrany element?', - { + jQuery.prompt( 'Na pewno chcesz usunąć wybrany element?', + { title: 'Potwierdź?', - submit: function(e,v,m,f) - { - if ( v === true ) + submit: function(e,v,m,f) + { + if ( v === true ) { - if ( url !== '' ) + if ( url !== '' ) { jQuery.ajax( { type: 'POST', cache: false, url: url, - data: + data: { gdelete: gdelete, a: 'gdelete' }, - beforeSend: function() + beforeSend: function() { jQuery( '#g-' + gtable ).find( '#g-loader' ).show(); }, - success: function( data ) + success: function( data ) { response = jQuery.parseJSON( data ); jQuery( '#g-' + gtable ).find( '#g-loader' ).hide(); - if ( response.status === 'ok' ) + if ( response.status === 'ok' ) { - if ( back_url !== '' ) + if ( back_url !== '' ) { document.location.href=back_url; } @@ -762,71 +762,71 @@ jQuery( 'body' ).on( 'click', '.g-delete', function() }, success: function( data ) { response = jQuery.parseJSON( data ); jQuery( '#g-' + gtable ).find( '#g-loader' ).hide(); - if ( response.status === 'ok' ) + if ( response.status === 'ok' ) { jQuery( '#g-' + gtable ).find( '#g-results' ).empty().html( response.output ); - } - else + } + else { - if ( response.msg ) - var msg = response.msg; - else + if ( response.msg ) + var msg = response.msg; + else var msg = "Przepraszamy. Podczas wczytywania danych wystąpił błąd. Prosimy spróbować ponownie."; create_error( msg ); } } }); } - } - else + } + else { - if ( response.msg ) - var msg = response.msg; - else + if ( response.msg ) + var msg = response.msg; + else var msg = "Przepraszamy. Podczas wczytywania danych wystąpił błąd. Prosimy spróbować ponownie."; create_error( msg ); } } }); - } - else + } + else { jQuery.ajax( { type: 'POST', cache: false, url: dir + '/ajax.php', - data: + data: { gtable: gtable, gdelete: gdelete, a: 'gdraw' }, - beforeSend: function() + beforeSend: function() { jQuery( '#g-' + gtable ).find( '#g-loader' ).show(); }, - success: function( data ) + success: function( data ) { response = jQuery.parseJSON( data ); jQuery( '#g-' + gtable ).find( '#g-loader' ).hide(); - if ( response.status === 'ok' ) + if ( response.status === 'ok' ) { - if ( back_url !== '' ) + if ( back_url !== '' ) { document.location.href=back_url; - } + } else { jQuery( '#g-' + gtable ).find( '#g-results' ).empty().html( response.output ); if ( response.msg !== null ) create_message( response.msg ); } - } - else + } + else { - if ( response.msg ) - var msg = response.msg; - else + if ( response.msg ) + var msg = response.msg; + else var msg = "Przepraszamy. Podczas wczytywania danych wystąpił błąd. Prosimy spróbować ponownie."; create_error( msg ); } @@ -834,22 +834,22 @@ jQuery( 'body' ).on( 'click', '.g-delete', function() }); } } - }, - buttons: - { - 'tak': true, - 'nie': false + }, + buttons: + { + 'tak': true, + 'nie': false } }); return false; }); -jQuery( 'body' ).on( 'change', '.g-search-input, .g-search-select', function() +jQuery( 'body' ).on( 'change', '.g-search-input, .g-search-select', function() { var data = jQuery( this ).attr( 'data' ); data = data.split( ";" ); - for ( index = 0; index < data.length; ++index ) + for ( index = 0; index < data.length; ++index ) { var vars = data[ index ].split( ':') ; @@ -863,7 +863,7 @@ jQuery( 'body' ).on( 'change', '.g-search-input, .g-search-select', function() var data = jQuery( this ).parents( '.g-container' ).attr( 'data' ); data = data.split( ";" ); - for ( index = 0; index < data.length; ++index ) + for ( index = 0; index < data.length; ++index ) { var vars = data[ index ].split( ':') ; @@ -877,7 +877,7 @@ jQuery( 'body' ).on( 'change', '.g-search-input, .g-search-select', function() type: 'POST', cache: false, url: dir + '/ajax.php', - data: + data: { gtable: gtable, gsearch_column: gsearch_column, @@ -885,22 +885,22 @@ jQuery( 'body' ).on( 'change', '.g-search-input, .g-search-select', function() gsearch_type: gsearch_type, a: 'gdraw' }, - beforeSend: function() + beforeSend: function() { jQuery( '#g-' + gtable ).find( '#g-loader' ).show(); }, success: function( data ) { response = jQuery.parseJSON( data ); jQuery( '#g-' + gtable ).find( '#g-loader' ).hide(); - if ( response.status === 'ok' ) + if ( response.status === 'ok' ) { jQuery( '#g-' + gtable ).find( '#g-results' ).empty().html( response.output ); jQuery( 'input[name="' + gsearch_column + '"]' ).focus().val( jQuery( 'input[name="' + gsearch_column + '"]' ).val() ); - } - else + } + else { - if ( response.msg ) - var msg = response.msg; - else + if ( response.msg ) + var msg = response.msg; + else var msg = "Przepraszamy. Podczas wczytywania danych wystąpił błąd. Prosimy spróbować ponownie."; create_error( msg ); } @@ -948,15 +948,15 @@ jQuery( 'body' ).on( 'click', '.g-sort', function() { }, success: function( data ) { response = jQuery.parseJSON( data ); jQuery( '#g-' + gtable ).find( '#g-loader' ).hide(); - if ( response.status === 'ok' ) + if ( response.status === 'ok' ) { jQuery( '#g-' + gtable ).find( '#g-results' ).empty().html( response.output ); - } - else + } + else { - if ( response.msg ) - var msg = response.msg; - else + if ( response.msg ) + var msg = response.msg; + else var msg = "Przepraszamy. Podczas wczytywania danych wystąpił błąd. Prosimy spróbować ponownie."; create_error( msg ); } @@ -991,15 +991,15 @@ jQuery( 'body' ).on( 'change', '#g-row-limit', function() { }, success: function( data ) { response = jQuery.parseJSON( data ); jQuery( '#g-' + gtable ).find( '#g-loader' ).hide(); - if ( response.status === 'ok' ) + if ( response.status === 'ok' ) { jQuery( '#g-' + gtable ).find( '#g-results' ).empty().html( response.output ); - } - else + } + else { - if ( response.msg ) - var msg = response.msg; - else + if ( response.msg ) + var msg = response.msg; + else var msg = "Przepraszamy. Podczas wczytywania danych wystąpił błąd. Prosimy spróbować ponownie."; create_error( msg ); } @@ -1012,7 +1012,7 @@ jQuery( 'body' ).on( 'click', '.date-range-icon', function() $( this ).parents( '.input-group' ).children( 'input' ).trigger( 'click' ); }); -jQuery( 'body' ).on( 'click', '.g-next, .g-last, .g-first, .g-previous, .g-page', function(e) +jQuery( 'body' ).on( 'click', '.g-next, .g-last, .g-first, .g-previous, .g-page', function(e) { e.preventDefault(); @@ -1042,15 +1042,15 @@ jQuery( 'body' ).on( 'click', '.g-next, .g-last, .g-first, .g-previous, .g-page' }, success: function( data ) { response = jQuery.parseJSON( data ); jQuery( '#g-' + gtable ).find( '#g-loader' ).hide(); - if ( response.status === 'ok' ) + if ( response.status === 'ok' ) { jQuery( '#g-' + gtable ).find( '#g-results' ).empty().html( response.output ); - } - else + } + else { - if ( response.msg ) - var msg = response.msg; - else + if ( response.msg ) + var msg = response.msg; + else var msg = "Przepraszamy. Podczas wczytywania danych wystąpił błąd. Prosimy spróbować ponownie."; create_error( msg ); } diff --git a/libraries/grid/templates/container.php b/libraries/grid/templates/container.php index 1a2cb2f..5de2143 100644 --- a/libraries/grid/templates/container.php +++ b/libraries/grid/templates/container.php @@ -14,7 +14,7 @@ or $this -> values['print'] ):?> -
+
values['title'] ) echo '
' . $this -> values['title'] . '
'; diff --git a/libraries/grid/templates/results.php b/libraries/grid/templates/results.php index bd0b9b5..ff6f5f4 100644 --- a/libraries/grid/templates/results.php +++ b/libraries/grid/templates/results.php @@ -1,17 +1,17 @@ - values['name'] ? $g_table = $this -> values['name'] : $g_table = $this -> values[ 'table' ]; ?>
- values['multiselect'] ) echo ''; - if ( is_array( $this -> values['columns_view'] ) ) + if ( is_array( $this -> values['columns_view'] ) ) { $c_index = 0; $visible_columns = 0; @@ -68,7 +68,7 @@ } ?> - values['search'] ) ) { $c_index = 0; @@ -77,7 +77,7 @@ if ( is_array( $this -> values['columns_view'] ) ) foreach ( $this -> values['columns_view'] as $column ) { $search_found = false; - + if ( filter_var( $this -> values['hidden_columns'][$c_index], FILTER_VALIDATE_BOOLEAN ) === false or $this -> values['hidden_columns'][$c_index] === null ) { foreach ( $this -> values['search'] as $search ) @@ -131,7 +131,7 @@ echo '' . ''; } - + if ( $search['type'] == 'date_range' ) { echo ''; } @@ -194,8 +194,8 @@ { echo '
' . '' . '
'; @@ -149,7 +149,7 @@ } } } - + if ( !$search_found ) echo ' convertString( $column['td']['js'], $row ); + { + $out_js = $_SESSION[ 'g' . $g_table ] -> convertString( $column['td']['js'], $row ); echo 'onclick="' . htmlspecialchars( $out_js ) . '"'; } @@ -230,7 +230,7 @@ /* wyświtalania linku typu button */ else if ( $column['action']['type'] == 'button' ) - { + { if ( $column['action']['url'] ) $out_url = $_SESSION[ 'g' . $g_table ] -> convertString( $column['action']['url'], $row ); else @@ -246,15 +246,15 @@ 'onclick="' . htmlspecialchars( $out_js ) . '" ' . 'class="g-tip g-button ' . $column['button']['class' ] . '" ' . 'title="' . htmlspecialchars( $title ) . '" ' . - 'style="' . $column['button']['style'] . '">' . $column['button']['label'] . + 'style="' . $column['button']['style'] . '">' . $column['button']['label'] . ''; } /* wyświtalania linku do edycji */ else if ( $column['action']['type'] == 'edit' ) { - $out_url = $_SESSION[ 'g' . $g_table ] -> convertString( $column['action']['url'], $row ); - $out_js = $_SESSION[ 'g' . $g_table ] -> convertString( $column['action']['js'], $row ); + $out_url = $_SESSION[ 'g' . $g_table ] -> convertString( $column['action']['url'], $row ); + $out_js = $_SESSION[ 'g' . $g_table ] -> convertString( $column['action']['js'], $row ); echo ''; } @@ -298,7 +298,7 @@ } if ( $this -> values['actions']['edit'] ) - echo '' . + echo '' . '' . '' . '' . @@ -362,16 +362,16 @@ values['cp'] - 3; $i <= $this -> values['cp'] + 3; $i++ ):?> 0 && $i <= $ls ):?> -
  • values['cp'] ):?>active + values['cp'] - 2 + or + $i == $this -> values['cp'] + 2 + or + $i == $this -> values['cp'] + 3 + or + $i == $this -> values['cp'] - 3 ):?> hidden-xs">
  • @@ -402,23 +402,23 @@ -
    +
    Wyświetlaj rekordów
    \ No newline at end of file diff --git a/libraries/rb.php b/libraries/rb.php index 505f05e..98efd89 100644 --- a/libraries/rb.php +++ b/libraries/rb.php @@ -209,7 +209,7 @@ class Debug extends RDefault implements Logger * Toggles CLI override. By default debugging functions will * output differently based on PHP_SAPI values. This function * allows you to override the PHP_SAPI setting. If you set - * this to TRUE, CLI output will be supressed in favour of + * this to TRUE, CLI output will be suppressed in favour of * HTML output. So, to get HTML on the command line use * setOverrideCLIOutput( TRUE ). * @@ -288,7 +288,7 @@ class Debug extends RDefault implements Logger } /** - * Dependending on the current mode of operation, + * Depending on the current mode of operation, * this method will either log and output to STDIN or * just log. * @@ -304,7 +304,7 @@ class Debug extends RDefault implements Logger $this->logs[] = $str; if ( !$this->mode ) { $highlight = FALSE; - /* just a quick heuritsic to highlight schema changes */ + /* just a quick heuristic to highlight schema changes */ if ( strpos( $str, 'CREATE' ) === 0 || strpos( $str, 'ALTER' ) === 0 || strpos( $str, 'DROP' ) === 0) { @@ -493,7 +493,7 @@ interface Driver * @param string $sql SQL query to execute * @param array $bindings list of values to bind to SQL snippet * - * @return mixed + * @return array */ public function GetAssocRow( $sql, $bindings = array() ); @@ -521,7 +521,7 @@ interface Driver * @param string $sql SQL query to execute * @param array $bindings list of values to bind to SQL snippet * - * @return array Affected Rows + * @return int Affected Rows */ public function Execute( $sql, $bindings = array() ); @@ -547,7 +547,7 @@ interface Driver * @param string $sql SQL query to execute * @param array $bindings list of values to bind to SQL snippet * - * @return mixed + * @return Cursor */ public function GetCursor( $sql, $bindings = array() ); @@ -580,14 +580,14 @@ interface Driver public function setDebugMode( $tf, $customLogger ); /** - * Starts a transaction. + * Commits a transaction. * * @return void */ public function CommitTrans(); /** - * Commits a transaction. + * Starts a transaction. * * @return void */ @@ -617,7 +617,7 @@ interface Driver /** * Sets initialization code for connection. * - * @param callable $code code + * @param callable|NULL $code code * * @return void */ @@ -676,12 +676,12 @@ class RPDO implements Driver protected $loggingEnabled = FALSE; /** - * @var Logger + * @var Logger|NULL */ protected $logger = NULL; /** - * @var PDO + * @var \PDO|NULL */ protected $pdo; @@ -691,7 +691,7 @@ class RPDO implements Driver protected $affectedRows; /** - * @var integer + * @var array */ protected $resultArray; @@ -731,12 +731,12 @@ class RPDO implements Driver protected $stringifyFetches = TRUE; /** - * @var string + * @var string|NULL */ protected $initSQL = NULL; /** - * @var callable + * @var callable|NULL */ protected $initCode = NULL; @@ -745,8 +745,8 @@ class RPDO implements Driver * Query Execution. This method binds parameters as NULL, INTEGER or STRING * and supports both named keys and question mark keys. * - * @param PDOStatement $statement PDO Statement instance - * @param array $bindings values that need to get bound to the statement + * @param \PDOStatement $statement PDO Statement instance + * @param array $bindings values that need to get bound to the statement * * @return void */ @@ -793,7 +793,7 @@ class RPDO implements Driver * @return mixed * @throws SQL */ - protected function runQuery( $sql, $bindings, $options = array() ) + public function runQuery( $sql, $bindings, $options = array() ) { $this->connect(); if ( $this->loggingEnabled && $this->logger ) { @@ -813,13 +813,17 @@ class RPDO implements Driver $statement->execute(); $this->queryCounter ++; $this->affectedRows = $statement->rowCount(); + if ( isset( $options['noFetch'] ) && $options['noFetch'] ) { + $this->resultArray = array(); + return $statement; + } if ( $statement->columnCount() ) { $fetchStyle = ( isset( $options['fetchStyle'] ) ) ? $options['fetchStyle'] : NULL; - if ( isset( $options['noFetch'] ) && $options['noFetch'] ) { - $this->resultArray = array(); - return $statement; + if ( is_null( $fetchStyle) ) { + $this->resultArray = $statement->fetchAll(); + } else { + $this->resultArray = $statement->fetchAll( $fetchStyle ); } - $this->resultArray = $statement->fetchAll( $fetchStyle ); if ( $this->loggingEnabled && $this->logger ) { $this->logger->log( 'resultset: ' . count( $this->resultArray ) . ' rows' ); } @@ -876,7 +880,7 @@ class RPDO implements Driver * By default, RedBeanPHP uses this method under the hood to make sure * you use the latest UTF8 encoding possible for your database. * - * @param $db_cap identifier of database capability + * @param string $db_cap identifier of database capability * * @return int|false Whether the database feature is supported, FALSE otherwise. **/ @@ -931,8 +935,8 @@ class RPDO implements Driver * The second example shows how to create an RPDO instance * from an existing PDO object. * - * @param string|object $dsn database connection string - * @param string $user optional, usename to sign in + * @param string|\PDO $dsn database connection string + * @param string $user optional, username to sign in * @param string $pass optional, password for connection login * * @return void @@ -1051,7 +1055,7 @@ class RPDO implements Driver /** * Sets initialization code to execute upon connecting. * - * @param callable $code + * @param callable|NULL $code * * @return void */ @@ -1120,7 +1124,7 @@ class RPDO implements Driver * - RedBeanPHP will ask database driver to throw Exceptions on errors (recommended for compatibility) * - RedBeanPHP will ask database driver to use associative arrays when fetching (recommended for compatibility) * - * @param PDO $pdo PDO instance + * @param \PDO $pdo PDO instance * @param array $options Options to apply * * @return void @@ -1142,7 +1146,7 @@ class RPDO implements Driver if ( isset($options['runInitCode']) ) $runInitCode = $options['runInitCode']; if ( isset($options['stringFetch']) ) $stringFetch = $options['stringFetch']; - if ($connected) $this->connected = $connected; + if ($connected) $this->isConnected = $connected; if ($setEncoding) $this->setEncoding(); if ($setAttributes) { $this->pdo->setAttribute( \PDO::ATTR_ERRMODE,\PDO::ERRMODE_EXCEPTION ); @@ -1224,7 +1228,7 @@ class RPDO implements Driver * @param string $sql SQL * @param array $bindings bindings * - * @return mixed + * @return string|NULL */ public function GetCell( $sql, $bindings = array() ) { @@ -1246,7 +1250,7 @@ class RPDO implements Driver } /** - * @see Driver::Excecute + * @see Driver::Execute */ public function Execute( $sql, $bindings = array() ) { @@ -1445,7 +1449,7 @@ class RPDO implements Driver * $pdo = R::getDatabaseAdapter()->getDatabase()->getPDO(); * * - * @return PDO + * @return \PDO */ public function getPDO() { @@ -1587,6 +1591,7 @@ namespace RedBeanPHP { use RedBeanPHP\QueryWriter\AQueryWriter as AQueryWriter; use RedBeanPHP\BeanHelper as BeanHelper; use RedBeanPHP\RedException as RedException; +use RedBeanPHP\Util\Either as Either; /** * PHP 5.3 compatibility @@ -1612,7 +1617,7 @@ if (interface_exists('\JsonSerializable')) { interface Jsonable extends \JsonSer * This source file is subject to the BSD/GPLv2 License that is bundled * with this source code in the file license.txt. */ -class OODBBean implements\IteratorAggregate,\ArrayAccess,\Countable,Jsonable +class OODBBean implements \IteratorAggregate,\ArrayAccess,\Countable,Jsonable { /** * FUSE error modes. @@ -1680,12 +1685,12 @@ class OODBBean implements\IteratorAggregate,\ArrayAccess,\Countable,Jsonable * rich functionality, otherwise you would have to do everything with R or * external objects. * - * @var BeanHelper + * @var BeanHelper|NULL */ protected $beanHelper = NULL; /** - * @var null + * @var string|NULL */ protected $fetchType = NULL; @@ -1700,12 +1705,12 @@ class OODBBean implements\IteratorAggregate,\ArrayAccess,\Countable,Jsonable protected $withParams = array(); /** - * @var string + * @var string|NULL */ protected $aliasName = NULL; /** - * @var string + * @var string|NULL */ protected $via = NULL; @@ -1719,11 +1724,16 @@ class OODBBean implements\IteratorAggregate,\ArrayAccess,\Countable,Jsonable */ protected $all = FALSE; + /** + * @var string|NULL + */ + protected $castProperty = NULL; + /** * If fluid count is set to TRUE then $bean->ownCount() will * return 0 if the table does not exists. * Only for backward compatibility. - * Returns previouds value. + * Returns previous value. * * @param boolean $toggle toggle * @@ -1828,7 +1838,7 @@ class OODBBean implements\IteratorAggregate,\ArrayAccess,\Countable,Jsonable * fetchAs and setAutoResolve but explicitly. For instance if you register * the alias 'cover' for 'page' a property containing a reference to a * page bean called 'cover' will correctly return the page bean and not - * a (non-existant) cover bean. + * a (non-existent) cover bean. * * * R::aliases( array( 'cover' => 'page' ) ); @@ -2009,8 +2019,8 @@ class OODBBean implements\IteratorAggregate,\ArrayAccess,\Countable,Jsonable * Unless you know what you are doing, do NOT use this method. * This is for advanced users only! * - * @param string $type type of the new bean - * @param BeanHelper $beanhelper bean helper to obtain a toolbox and a model + * @param string $type type of the new bean + * @param BeanHelper|NULL $beanhelper bean helper to obtain a toolbox and a model * * @return void */ @@ -2057,8 +2067,9 @@ class OODBBean implements\IteratorAggregate,\ArrayAccess,\Countable,Jsonable * * Note that not all PHP functions work with the array interface. * - * @return ArrayIterator + * @return \ArrayIterator */ + #[\ReturnTypeWillChange] public function getIterator() { return new \ArrayIterator( $this->properties ); @@ -2067,7 +2078,7 @@ class OODBBean implements\IteratorAggregate,\ArrayAccess,\Countable,Jsonable /** * Imports all values from an associative array $array. Chainable. * This method imports the values in the first argument as bean - * propery and value pairs. Use the second parameter to provide a + * property and value pairs. Use the second parameter to provide a * selection. If a selection array is passed, only the entries * having keys mentioned in the selection array will be imported. * Set the third parameter to TRUE to preserve spaces in selection keys. @@ -2123,6 +2134,21 @@ class OODBBean implements\IteratorAggregate,\ArrayAccess,\Countable,Jsonable return $this; } + /** + * Same as import() but trims all values by default. + * Set the second parameter to apply a different function. + * + * @param array $array what you want to import + * @param callable $function function to apply (default is trim) + * @param string|array $selection selection of values + * @param boolean $notrim if TRUE selection keys will NOT be trimmed + * + * @return OODBBean + */ + public function trimport( $array, $function='trim', $selection = FALSE, $notrim = FALSE ) { + return $this->import( array_map( $function, $array ), $selection, $notrim ); + } + /** * Imports an associative array directly into the * internal property array of the bean as well as the @@ -2300,11 +2326,11 @@ class OODBBean implements\IteratorAggregate,\ArrayAccess,\Countable,Jsonable * Returns the ID of the bean. * If for some reason the ID has not been set, this method will * return NULL. This is actually the same as accessing the - * id property using $bean->id. The ID of a bean is it's primary + * id property using $bean->id. The ID of a bean is its primary * key and should always correspond with a table column named * 'id'. * - * @return string|null + * @return string|NULL */ public function getID() { @@ -2336,6 +2362,19 @@ class OODBBean implements\IteratorAggregate,\ArrayAccess,\Countable,Jsonable return; } + /** + * Returns the bean wrapped in an Either-instance. + * This allows the user to extract data from the bean using a chain + * of methods without any NULL checks, similar to the ?? operator but also + * in a way that is compatible with older versions of PHP. + * For more details consult the documentation of the Either class. + * + * @return Either + */ + public function either() { + return new Either( $this ); + } + /** * Adds WHERE clause conditions to ownList retrieval. * For instance to get the pages that belong to a book you would @@ -2566,13 +2605,14 @@ class OODBBean implements\IteratorAggregate,\ArrayAccess,\Countable,Jsonable $this->noLoad = FALSE; $this->all = FALSE; $this->via = NULL; + $this->castProperty = NULL; return $this; } /** * Determines whether a list is opened in exclusive mode or not. * If a list has been opened in exclusive mode this method will return TRUE, - * othwerwise it will return FALSE. + * otherwise it will return FALSE. * * @param string $listName name of the list to check * @@ -2667,7 +2707,12 @@ class OODBBean implements\IteratorAggregate,\ArrayAccess,\Countable,Jsonable //If exists and no list or exits and list not changed, bail out. if ( $exists && ((!$isOwn && !$isShared ) || (!$hasSQL && !$differentAlias && !$hasAll)) ) { + $castProperty = $this->castProperty; $this->clearModifiers(); + if (!is_null($castProperty)) { + $object = new $castProperty( $this->properties[$property] ); + return $object; + } return $this->properties[$property]; } @@ -2708,7 +2753,6 @@ class OODBBean implements\IteratorAggregate,\ArrayAccess,\Countable,Jsonable $this->properties[$property] = $beans; $this->__info["sys.shadow.$property"] = $beans; $this->__info['tainted'] = TRUE; - $this->clearModifiers(); return $this->properties[$property]; @@ -2800,8 +2844,8 @@ class OODBBean implements\IteratorAggregate,\ArrayAccess,\Countable,Jsonable $value = '0'; } elseif ( $value === TRUE ) { $value = '1'; - /* for some reason there is some kind of bug in xdebug so that it doesnt count this line otherwise... */ - } elseif ( $value instanceof \DateTime ) { $value = $value->format( 'Y-m-d H:i:s' ); } + /* for some reason there is some kind of bug in xdebug so that it doesn't count this line otherwise... */ + } elseif ( ( ( $value instanceof \DateTime ) or ( $value instanceof \DateTimeInterface ) ) ) { $value = $value->format( 'Y-m-d H:i:s' ); } $this->properties[$property] = $value; } @@ -2938,6 +2982,29 @@ class OODBBean implements\IteratorAggregate,\ArrayAccess,\Countable,Jsonable return $this; } + /** + * Captures a dynamic casting. + * Enables you to obtain a bean value as an object by type-hinting + * the desired return object using asX where X is the class you wish + * to use as a wrapper for the property. + * + * Usage: + * + * $dateTime = $bean->asDateTime()->date; + * + * @param string $method method (asXXX)... + * + * @return self|NULL + */ + public function captureDynamicCasting( $method ) + { + if ( strpos( $method, 'as' ) === 0 && ctype_upper( substr( $method, 2, 1) ) === TRUE ) { + $this->castProperty = substr( $method, 2 ); + return $this; + } + return NULL; + } + /** * Sends the call to the registered model. * This method can also be used to override bean behaviour. @@ -2963,7 +3030,7 @@ class OODBBean implements\IteratorAggregate,\ArrayAccess,\Countable,Jsonable public function __call( $method, $args ) { if ( empty( $this->__info['model'] ) ) { - return NULL; + return $this->captureDynamicCasting($method); } $overrideDontFail = FALSE; @@ -2974,6 +3041,9 @@ class OODBBean implements\IteratorAggregate,\ArrayAccess,\Countable,Jsonable if ( !is_callable( array( $this->__info['model'], $method ) ) ) { + $self = $this->captureDynamicCasting($method); + if ($self) return $self; + if ( self::$errorHandlingFUSE === FALSE || $overrideDontFail ) { return NULL; } @@ -3052,6 +3122,7 @@ class OODBBean implements\IteratorAggregate,\ArrayAccess,\Countable,Jsonable * * @return void */ + #[\ReturnTypeWillChange] public function offsetSet( $offset, $value ) { $this->__set( $offset, $value ); @@ -3069,6 +3140,7 @@ class OODBBean implements\IteratorAggregate,\ArrayAccess,\Countable,Jsonable * * @return boolean */ + #[\ReturnTypeWillChange] public function offsetExists( $offset ) { return $this->__isset( $offset ); @@ -3080,13 +3152,14 @@ class OODBBean implements\IteratorAggregate,\ArrayAccess,\Countable,Jsonable * Unsets a value from the array/bean. * * Array functions do not reveal x-own-lists and list-alias because - * you dont want duplicate entries in foreach-loops. + * you don't want duplicate entries in foreach-loops. * Also offers a slight performance improvement for array access. * * @param mixed $offset property * * @return void */ + #[\ReturnTypeWillChange] public function offsetUnset( $offset ) { $this->__unset( $offset ); @@ -3098,13 +3171,14 @@ class OODBBean implements\IteratorAggregate,\ArrayAccess,\Countable,Jsonable * Returns value of a property. * * Array functions do not reveal x-own-lists and list-alias because - * you dont want duplicate entries in foreach-loops. + * you don't want duplicate entries in foreach-loops. * Also offers a slight performance improvement for array access. * * @param mixed $offset property * * @return mixed */ + #[\ReturnTypeWillChange] public function &offsetGet( $offset ) { return $this->__get( $offset ); @@ -3182,7 +3256,7 @@ class OODBBean implements\IteratorAggregate,\ArrayAccess,\Countable,Jsonable * * @param string $property property * @param callable $function function - * @param integer $maxDepth maximum depth for traversal + * @param integer|NULL $maxDepth maximum depth for traversal * * @return OODBBean * @throws RedException @@ -3245,6 +3319,7 @@ class OODBBean implements\IteratorAggregate,\ArrayAccess,\Countable,Jsonable * * @return integer */ + #[\ReturnTypeWillChange] public function count() { return count( $this->properties ); @@ -3312,7 +3387,7 @@ class OODBBean implements\IteratorAggregate,\ArrayAccess,\Countable,Jsonable } /** - * Convience method. + * Convenience method. * Unsets all properties in the internal properties array. * * Usage: @@ -3395,7 +3470,7 @@ class OODBBean implements\IteratorAggregate,\ArrayAccess,\Countable,Jsonable * * Note that this method will return TRUE if applied to a loaded list. * Also note that this method keeps track of the bean's history regardless whether - * it has been stored or not. Storing a bean does not undo it's history, + * it has been stored or not. Storing a bean does not undo its history, * to clean the history of a bean use: clearHistory(). * * @param string $property name of the property you want the change-status of @@ -3760,9 +3835,9 @@ class OODBBean implements\IteratorAggregate,\ArrayAccess,\Countable,Jsonable * quest beans residing in the $questTarget->target properties * of each element in the xownQuestTargetList. * - * @param string $list the list you wish to process - * @param string $property the property to load - * @param string $type the type of bean residing in this property (optional) + * @param string $list the list you wish to process + * @param string $property the property to load + * @param string|NULL $type the type of bean residing in this property (optional) * * @return array */ @@ -3818,15 +3893,17 @@ class OODBBean implements\IteratorAggregate,\ArrayAccess,\Countable,Jsonable * * * The example above compares the flavour label 'mocca' with - * the flavour label attachec to the $coffee bean. This illustrates + * the flavour label attached to the $coffee bean. This illustrates * how to use equals() with RedBeanPHP-style enums. * - * @param OODBBean $bean other bean + * @param OODBBean|null $bean other bean * * @return boolean */ public function equals(OODBBean $bean) { + if ( is_null($bean) ) return false; + return (bool) ( ( (string) $this->properties['id'] === (string) $bean->properties['id'] ) && ( (string) $this->__info['type'] === (string) $bean->__info['type'] ) @@ -3850,6 +3927,7 @@ class OODBBean implements\IteratorAggregate,\ArrayAccess,\Countable,Jsonable * * @return array */ + #[\ReturnTypeWillChange] public function jsonSerialize() { $json = $this->__call( '@__jsonSerialize', array( ) ); @@ -4008,7 +4086,7 @@ interface Adapter * @param array $bindings array of values to bind to parameters in query string * @param boolean $noevent no event firing * - * @return void + * @return int */ public function exec( $sql, $bindings = array(), $noevent = FALSE ); @@ -4034,7 +4112,7 @@ interface Adapter * @param string $sql string containing SQL code for database * @param array $bindings array of values to bind to parameters in query string * - * @return array + * @return array|NULL */ public function getRow( $sql, $bindings = array() ); @@ -4060,7 +4138,7 @@ interface Adapter * @param string $sql string containing SQL code for database * @param array $bindings array of values to bind to parameters in query string * - * @return string + * @return string|NULL */ public function getCell( $sql, $bindings = array() ); @@ -4079,7 +4157,7 @@ interface Adapter * Executes the SQL query specified in $sql and returns * an associative array where the column names are the keys. * - * @param string $sql Sstring containing SQL code for databaseQL + * @param string $sql String containing SQL code for databaseQL * @param array $bindings values to bind * * @return array @@ -4117,7 +4195,7 @@ interface Adapter * adapter. RedBean will only access the adapter and never to talk * directly to the driver though. * - * @return mixed + * @return Driver */ public function getDatabase(); @@ -4477,7 +4555,7 @@ namespace RedBeanPHP { * Database Cursor Interface. * A cursor is used by Query Writers to fetch Query Result rows * one row at a time. This is useful if you expect the result set to - * be quite large. This interface dscribes the API of a database + * be quite large. This interface describes the API of a database * cursor. There can be multiple implementations of the Cursor, * by default RedBeanPHP offers the PDOCursor for drivers shipping * with RedBeanPHP and the NULLCursor. @@ -4497,7 +4575,7 @@ interface Cursor * Should retrieve the next row of the result set. * This method is used to iterate over the result set. * - * @return array + * @return array|NULL */ public function getNextItem(); @@ -4544,7 +4622,7 @@ use RedBeanPHP\Cursor as Cursor; class PDOCursor implements Cursor { /** - * @var PDOStatement + * @var \PDOStatement */ protected $res; @@ -4556,7 +4634,7 @@ class PDOCursor implements Cursor /** * Constructor, creates a new instance of a PDO Database Cursor. * - * @param PDOStatement $res the PDO statement + * @param \PDOStatement $res the PDO statement * @param string $fetchStyle fetch style constant to use * * @return void @@ -4687,20 +4765,27 @@ class BeanCollection */ protected $type = NULL; + /** + * @var string + */ + protected $mask = NULL; + /** * Constructor, creates a new instance of the BeanCollection. * * @param string $type type of beans in this collection * @param Repository $repository repository to use to generate bean objects * @param Cursor $cursor cursor object to use + * @param string $mask meta mask to apply (optional) * * @return void */ - public function __construct( $type, Repository $repository, Cursor $cursor ) + public function __construct( $type, Repository $repository, Cursor $cursor, $mask = '__meta' ) { $this->type = $type; $this->cursor = $cursor; $this->repository = $repository; + $this->mask = $mask; } /** @@ -4715,7 +4800,7 @@ class BeanCollection { $row = $this->cursor->getNextItem(); if ( $row ) { - $beans = $this->repository->convertToBeans( $this->type, array( $row ) ); + $beans = $this->repository->convertToBeans( $this->type, array( $row ), $this->mask ); return reset( $beans ); } return NULL; @@ -4849,7 +4934,7 @@ interface QueryWriter * @param boolean $firstOfChain is it the join of a chain (or the only join) * @param string $suffix suffix to add for aliasing tables (for joining same table multiple times) * - * @return string $joinSQLSnippet + * @return string */ public function writeJoin( $type, $targetType, $leftRight, $joinType, $firstOfChain, $suffix ); @@ -4879,8 +4964,8 @@ interface QueryWriter * @note A default implementation is available in AQueryWriter * unless a database uses very different SQL this should suffice. * - * @param string $sql SQL Snippet - * @param integer $glue the GLUE type - how to glue (C_GLUE_WHERE or C_GLUE_AND) + * @param string $sql SQL Snippet + * @param integer|NULL $glue the GLUE type - how to glue (C_GLUE_WHERE or C_GLUE_AND) * * @return string */ @@ -4945,7 +5030,7 @@ interface QueryWriter * C_DATA_TYPE_MANUAL (usually 99) which represents a user specified type. Although * no special treatment has been associated with the latter for now. * - * @param string $value value + * @param mixed $value value * @param boolean $alsoScanSpecialForTypes take special types into account * * @return integer @@ -4995,10 +5080,10 @@ interface QueryWriter * This methods selects the records from the database that match the specified * type, conditions (optional) and additional SQL snippet (optional). * - * @param string $type name of the table you want to query - * @param array $conditions criteria ( $column => array( $values ) ) - * @param string $addSql additional SQL snippet - * @param array $bindings bindings for SQL snippet + * @param string $type name of the table you want to query + * @param array $conditions criteria ( $column => array( $values ) ) + * @param string|NULL $addSql additional SQL snippet + * @param array $bindings bindings for SQL snippet * * @return array */ @@ -5009,10 +5094,10 @@ interface QueryWriter * This methods selects the records from the database that match the specified * type, conditions (optional) and additional SQL snippet (optional). * - * @param string $type name of the table you want to query - * @param array $conditions criteria ( $column => array( $values ) ) - * @param string $addSQL additional SQL snippet - * @param array $bindings bindings for SQL snippet + * @param string $type name of the table you want to query + * @param array $conditions criteria ( $column => array( $values ) ) + * @param string|NULL $addSql additional SQL snippet + * @param array $bindings bindings for SQL snippet * * @return Cursor */ @@ -5033,7 +5118,7 @@ interface QueryWriter public function queryRecordRelated( $sourceType, $destType, $linkID, $addSql = '', $bindings = array() ); /** - * Returns the row that links $sourceType $sourcID to $destType $destID in an N-M relation. + * Returns the row that links $sourceType $sourceID to $destType $destID in an N-M relation. * * @param string $sourceType source type, the first part of the link you're looking for * @param string $destType destination type, the second part of the link you're looking for @@ -5048,10 +5133,10 @@ interface QueryWriter * Counts the number of records in the database that match the * conditions and additional SQL. * - * @param string $type name of the table you want to query - * @param array $conditions criteria ( $column => array( $values ) ) - * @param string $addSQL additional SQL snippet - * @param array $bindings bindings for SQL snippet + * @param string $type name of the table you want to query + * @param array $conditions criteria ( $column => array( $values ) ) + * @param string|NULL $addSql additional SQL snippet + * @param array $bindings bindings for SQL snippet * * @return integer */ @@ -5111,12 +5196,12 @@ interface QueryWriter * (count rows) used for countParents and countChildren functions - or you can specify a * string yourself like 'count(distinct brand)'. * - * @param string $type the bean type you want to query rows for - * @param integer $id id of the reference row - * @param boolean $up TRUE to query parent rows, FALSE to query child rows - * @param string $addSql optional SQL snippet to embed in the query - * @param array $bindings parameter bindings for additional SQL snippet - * @param mixed $select Select Snippet to use when querying (optional) + * @param string $type the bean type you want to query rows for + * @param integer $id id of the reference row + * @param boolean $up TRUE to query parent rows, FALSE to query child rows + * @param string|NULL $addSql optional SQL snippet to embed in the query + * @param array $bindings parameter bindings for additional SQL snippet + * @param bool $select Select Snippet to use when querying (optional) * * @return array */ @@ -5130,9 +5215,9 @@ interface QueryWriter * Returns the new ID. * This methods accepts a type and infers the corresponding table name. * - * @param string $type name of the table to update - * @param array $updatevalues list of update values - * @param integer $id optional primary key ID value + * @param string $type name of the table to update + * @param array $updatevalues list of update values + * @param integer|NULL $id optional primary key ID value * * @return integer */ @@ -5147,7 +5232,7 @@ interface QueryWriter * @param string $addSql additional SQL * @param array $bindings bindings * - * @return void + * @return int */ public function deleteRecord( $type, $conditions = array(), $addSql = '', $bindings = array() ); @@ -5163,7 +5248,7 @@ interface QueryWriter public function deleteRelations( $sourceType, $destType, $sourceID ); /** - * @see QueryWriter::addUniqueConstaint + * @see QueryWriter::addUniqueConstraint */ public function addUniqueIndex( $type, $columns ); @@ -5219,7 +5304,7 @@ interface QueryWriter * @param string $targetType points to this type * @param string $property field that contains the foreign key value * @param string $targetProperty field where the fk points to - * @param string $isDep whether target is dependent and should cascade on update/delete + * @param bool $isDep whether target is dependent and should cascade on update/delete * * @return void */ @@ -5405,6 +5490,16 @@ abstract class AQueryWriter */ public $typeno_sqltype = array(); + /** + * @var array + */ + public $sqltype_typeno = array(); + + /** + * @var array + */ + public $encoding = array(); + /** * @var bool */ @@ -5417,8 +5512,10 @@ abstract class AQueryWriter * For instance to add ROW_FORMAT=DYNAMIC to all MySQL tables * upon creation: * + * * $sql = $writer->getDDLTemplate( 'createTable', '*' ); * $writer->setDDLTemplate( 'createTable', '*', $sql . ' ROW_FORMAT=DYNAMIC ' ); + * * * For property-specific templates set $beanType to: * account.username -- then the template will only be applied to SQL statements relating @@ -5440,9 +5537,9 @@ abstract class AQueryWriter * If no template can be found for the specified type, the template for * '*' will be returned instead. * - * @param string $type ( 'createTable' | 'widenColumn' | 'addColumn' ) - * @param string $beanType ( type of bean or '*' to apply to all types ) - * @param string $property specify if you're looking for a property-specific template + * @param string $type ( 'createTable' | 'widenColumn' | 'addColumn' ) + * @param string $beanType ( type of bean or '*' to apply to all types ) + * @param string|NULL $property specify if you're looking for a property-specific template * * @return string */ @@ -5553,7 +5650,7 @@ abstract class AQueryWriter * Globally available service method for RedBeanPHP. * Converts a camel cased string to a snake cased string. * - * @param string $camel camelCased string to converty to snake case + * @param string $camel camelCased string to convert to snake case * * @return string */ @@ -5562,6 +5659,25 @@ abstract class AQueryWriter return strtolower( preg_replace( '/(?<=[a-z])([A-Z])|([A-Z])(?=[a-z])/', '_$1$2', $camel ) ); } + /** + * Globally available service method for RedBeanPHP. + * Converts a snake cased string to a camel cased string. + * + * @param string $snake snake_cased string to convert to camelCase + * @param boolean $dolphin exception for Ids - (bookId -> bookID) + * too complicated for the human mind, only dolphins can understand this + * + * @return string + */ + public static function snakeCamel( $snake, $dolphinMode = false ) + { + $camel = lcfirst( str_replace(' ', '', ucwords( str_replace('_', ' ', $snake ) ) ) ); + if ( $dolphinMode ) { + $camel = preg_replace( '/(\w)Id$/', '$1ID', $camel ); + } + return $camel; + } + /** * Clears renames. * @@ -5719,9 +5835,9 @@ abstract class AQueryWriter * In previous versions you could only store one key-entry, I have changed this to * improve caching efficiency (issue #400). * - * @param string $cacheTag cache tag (secondary key) - * @param string $key key to store values under - * @param array $values content to be stored + * @param string $cacheTag cache tag (secondary key) + * @param string $key key to store values under + * @param array|int $values rows or count to be stored * * @return void */ @@ -5853,7 +5969,7 @@ abstract class AQueryWriter /** * Determines whether a string can be considered JSON or not. * This is used by writers that support JSON columns. However - * we dont want that code duplicated over all JSON supporting + * we don't want that code duplicated over all JSON supporting * Query Writers. * * @param string $value value to determine 'JSONness' of. @@ -6017,7 +6133,7 @@ abstract class AQueryWriter * Used for UUID support. * * @param integer $dataTypeID magic number constant assigned to this data type - * @param string $SQLDefinition SQL column definition (i.e. INT(11)) + * @param string $SQLDefinition SQL column definition (e.g. INT(11)) * * @return self */ @@ -6147,6 +6263,10 @@ abstract class AQueryWriter { static $snippetCache = array(); + if ( is_null( $sql ) ) { + return ''; + } + if ( trim( $sql ) === '' ) { return $sql; } @@ -7229,8 +7349,6 @@ class MySQL extends AQueryWriter implements QueryWriter */ public function scanType( $value, $flagSpecial = FALSE ) { - $this->svalue = $value; - if ( is_null( $value ) ) return MySQL::C_DATATYPE_BOOL; if ( $value === INF ) return MySQL::C_DATATYPE_TEXT7; @@ -7329,7 +7447,7 @@ class MySQL extends AQueryWriter implements QueryWriter ADD UNIQUE INDEX $name (" . implode( ',', $columns ) . ")"; $this->adapter->exec( $sql ); } catch ( SQLException $e ) { - //do nothing, dont use alter table ignore, this will delete duplicate records in 3-ways! + //do nothing, don't use alter table ignore, this will delete duplicate records in 3-ways! return FALSE; } return TRUE; @@ -7353,7 +7471,6 @@ class MySQL extends AQueryWriter implements QueryWriter /** * @see QueryWriter::addFK - * @return bool */ public function addFK( $type, $targetType, $property, $targetProperty, $isDependent = FALSE ) { @@ -7429,938 +7546,6 @@ class MySQL extends AQueryWriter implements QueryWriter } } -namespace RedBeanPHP\QueryWriter { - -use RedBeanPHP\QueryWriter\AQueryWriter as AQueryWriter; -use RedBeanPHP\QueryWriter as QueryWriter; -use RedBeanPHP\Adapter\DBAdapter as DBAdapter; -use RedBeanPHP\Adapter as Adapter; -use RedBeanPHP\RedException\SQL as SQLException; - -/** - * RedBeanPHP SQLiteWriter with support for SQLite types - * This is a QueryWriter class for RedBeanPHP. - * This QueryWriter provides support for the SQLite database platform. - * - * @file RedBeanPHP/QueryWriter/SQLiteT.php - * @author Gabor de Mooij and the RedBeanPHP Community - * @license BSD/GPLv2 - * - * @copyright - * (c) copyright G.J.G.T. (Gabor) de Mooij and the RedBeanPHP Community. - * This source file is subject to the BSD/GPLv2 License that is bundled - * with this source code in the file license.txt. - */ -class SQLiteT extends AQueryWriter implements QueryWriter -{ - /** - * Data types - */ - const C_DATATYPE_INTEGER = 0; - const C_DATATYPE_NUMERIC = 1; - const C_DATATYPE_TEXT = 2; - const C_DATATYPE_SPECIFIED = 99; - - /** - * @var DBAdapter - */ - protected $adapter; - - /** - * @var string - */ - protected $quoteCharacter = '`'; - - /** - * @var array - */ - protected $DDLTemplates = array( - 'addColumn' => array( - '*' => 'ALTER TABLE `%s` ADD `%s` %s' - ), - 'createTable' => array( - '*' => 'CREATE TABLE %s ( id INTEGER PRIMARY KEY AUTOINCREMENT )' - ), - 'widenColumn' => array( - '*' => ',`%s` %s ' - ) - ); - - /** - * Gets all information about a table (from a type). - * - * Format: - * array( - * name => name of the table - * columns => array( name => datatype ) - * indexes => array() raw index information rows from PRAGMA query - * keys => array() raw key information rows from PRAGMA query - * ) - * - * @param string $type type you want to get info of - * - * @return array - */ - protected function getTable( $type ) - { - $tableName = $this->esc( $type, TRUE ); - $columns = $this->getColumns( $type ); - $indexes = $this->getIndexes( $type ); - $keys = $this->getKeyMapForType( $type ); - - $table = array( - 'columns' => $columns, - 'indexes' => $indexes, - 'keys' => $keys, - 'name' => $tableName - ); - - $this->tableArchive[$tableName] = $table; - - return $table; - } - - /** - * Puts a table. Updates the table structure. - * In SQLite we can't change columns, drop columns, change or add foreign keys so we - * have a table-rebuild function. You simply load your table with getTable(), modify it and - * then store it with putTable()... - * - * @param array $tableMap information array - * - * @return void - */ - protected function putTable( $tableMap ) - { - $table = $tableMap['name']; - $q = array(); - $q[] = "DROP TABLE IF EXISTS tmp_backup;"; - - $oldColumnNames = array_keys( $this->getColumns( $table ) ); - - foreach ( $oldColumnNames as $k => $v ) $oldColumnNames[$k] = "`$v`"; - - $q[] = "CREATE TEMPORARY TABLE tmp_backup(" . implode( ",", $oldColumnNames ) . ");"; - $q[] = "INSERT INTO tmp_backup SELECT * FROM `$table`;"; - $q[] = "PRAGMA foreign_keys = 0 "; - $q[] = "DROP TABLE `$table`;"; - - $newTableDefStr = ''; - foreach ( $tableMap['columns'] as $column => $type ) { - if ( $column != 'id' ) { - $newTableDefStr .= sprintf( $this->getDDLTemplate( 'widenColumn', $table, $column ), $column, $type ); - } - } - - $fkDef = ''; - foreach ( $tableMap['keys'] as $key ) { - $fkDef .= ", FOREIGN KEY(`{$key['from']}`) - REFERENCES `{$key['table']}`(`{$key['to']}`) - ON DELETE {$key['on_delete']} ON UPDATE {$key['on_update']}"; - } - - $q[] = "CREATE TABLE `$table` ( `id` INTEGER PRIMARY KEY AUTOINCREMENT $newTableDefStr $fkDef );"; - - foreach ( $tableMap['indexes'] as $name => $index ) { - if ( strpos( $name, 'UQ_' ) === 0 ) { - $cols = explode( '__', substr( $name, strlen( 'UQ_' . $table ) ) ); - foreach ( $cols as $k => $v ) $cols[$k] = "`$v`"; - $q[] = "CREATE UNIQUE INDEX $name ON `$table` (" . implode( ',', $cols ) . ")"; - } else $q[] = "CREATE INDEX $name ON `$table` ({$index['name']}) "; - } - - $q[] = "INSERT INTO `$table` SELECT * FROM tmp_backup;"; - $q[] = "DROP TABLE tmp_backup;"; - $q[] = "PRAGMA foreign_keys = 1 "; - - foreach ( $q as $sq ) $this->adapter->exec( $sq ); - } - - /** - * Returns the an array describing the indexes for type $type. - * - * @param string $type type to describe indexes of - * - * @return array - */ - protected function getIndexes( $type ) - { - $table = $this->esc( $type, TRUE ); - $indexes = $this->adapter->get( "PRAGMA index_list('$table')" ); - - $indexInfoList = array(); - foreach ( $indexes as $i ) { - $indexInfoList[$i['name']] = $this->adapter->getRow( "PRAGMA index_info('{$i['name']}') " ); - - $indexInfoList[$i['name']]['unique'] = $i['unique']; - } - - return $indexInfoList; - } - - /** - * Adds a foreign key to a type. - * Note: cant put this in try-catch because that can hide the fact - * that database has been damaged. - * - * @param string $type type you want to modify table of - * @param string $targetType target type - * @param string $field field of the type that needs to get the fk - * @param string $targetField field where the fk needs to point to - * @param integer $buildopt 0 = NO ACTION, 1 = ON DELETE CASCADE - * - * @return boolean - */ - protected function buildFK( $type, $targetType, $property, $targetProperty, $constraint = FALSE ) - { - $table = $this->esc( $type, TRUE ); - $targetTable = $this->esc( $targetType, TRUE ); - $column = $this->esc( $property, TRUE ); - $targetColumn = $this->esc( $targetProperty, TRUE ); - - $tables = $this->getTables(); - if ( !in_array( $targetTable, $tables ) ) return FALSE; - - if ( !is_null( $this->getForeignKeyForTypeProperty( $table, $column ) ) ) return FALSE; - $t = $this->getTable( $table ); - $consSQL = ( $constraint ? 'CASCADE' : 'SET NULL' ); - $label = 'from_' . $column . '_to_table_' . $targetTable . '_col_' . $targetColumn; - $t['keys'][$label] = array( - 'table' => $targetTable, - 'from' => $column, - 'to' => $targetColumn, - 'on_update' => $consSQL, - 'on_delete' => $consSQL - ); - $this->putTable( $t ); - return TRUE; - } - - /** - * @see AQueryWriter::getKeyMapForType - */ - protected function getKeyMapForType( $type ) - { - $table = $this->esc( $type, TRUE ); - $keys = $this->adapter->get( "PRAGMA foreign_key_list('$table')" ); - $keyInfoList = array(); - foreach ( $keys as $k ) { - $label = $this->makeFKLabel( $k['from'], $k['table'], $k['to'] ); - $keyInfoList[$label] = array( - 'name' => $label, - 'from' => $k['from'], - 'table' => $k['table'], - 'to' => $k['to'], - 'on_update' => $k['on_update'], - 'on_delete' => $k['on_delete'] - ); - } - return $keyInfoList; - } - - /** - * Constructor - * Most of the time, you do not need to use this constructor, - * since the facade takes care of constructing and wiring the - * RedBeanPHP core objects. However if you would like to - * assemble an OODB instance yourself, this is how it works: - * - * Usage: - * - * - * $database = new RPDO( $dsn, $user, $pass ); - * $adapter = new DBAdapter( $database ); - * $writer = new PostgresWriter( $adapter ); - * $oodb = new OODB( $writer, FALSE ); - * $bean = $oodb->dispense( 'bean' ); - * $bean->name = 'coffeeBean'; - * $id = $oodb->store( $bean ); - * $bean = $oodb->load( 'bean', $id ); - * - * - * The example above creates the 3 RedBeanPHP core objects: - * the Adapter, the Query Writer and the OODB instance and - * wires them together. The example also demonstrates some of - * the methods that can be used with OODB, as you see, they - * closely resemble their facade counterparts. - * - * The wiring process: create an RPDO instance using your database - * connection parameters. Create a database adapter from the RPDO - * object and pass that to the constructor of the writer. Next, - * create an OODB instance from the writer. Now you have an OODB - * object. - * - * @param Adapter $adapter Database Adapter - */ - public function __construct( Adapter $adapter ) - { - $this->typeno_sqltype = array( - SQLiteT::C_DATATYPE_INTEGER => 'INTEGER', - SQLiteT::C_DATATYPE_NUMERIC => 'NUMERIC', - SQLiteT::C_DATATYPE_TEXT => 'TEXT', - ); - - $this->sqltype_typeno = array(); - - foreach ( $this->typeno_sqltype as $k => $v ) { - $this->sqltype_typeno[$v] = $k; - } - - $this->adapter = $adapter; - $this->adapter->setOption( 'setInitQuery', ' PRAGMA foreign_keys = 1 ' ); - } - - /** - * This method returns the datatype to be used for primary key IDS and - * foreign keys. Returns one if the data type constants. - * - * @return integer $const data type to be used for IDS. - */ - public function getTypeForID() - { - return self::C_DATATYPE_INTEGER; - } - - /** - * @see QueryWriter::scanType - */ - public function scanType( $value, $flagSpecial = FALSE ) - { - $this->svalue = $value; - - if ( $value === NULL ) return self::C_DATATYPE_INTEGER; - if ( $value === INF ) return self::C_DATATYPE_TEXT; - - if ( $this->startsWithZeros( $value ) ) return self::C_DATATYPE_TEXT; - - if ( $value === TRUE || $value === FALSE ) return self::C_DATATYPE_INTEGER; - - if ( is_numeric( $value ) && ( intval( $value ) == $value ) && $value < 2147483648 && $value > -2147483648 ) return self::C_DATATYPE_INTEGER; - - if ( ( is_numeric( $value ) && $value < 2147483648 && $value > -2147483648) - || preg_match( '/\d{4}\-\d\d\-\d\d/', $value ) - || preg_match( '/\d{4}\-\d\d\-\d\d\s\d\d:\d\d:\d\d/', $value ) - ) { - return self::C_DATATYPE_NUMERIC; - } - - return self::C_DATATYPE_TEXT; - } - - /** - * @see QueryWriter::addColumn - */ - public function addColumn( $table, $column, $type ) - { - $column = $this->check( $column ); - $table = $this->check( $table ); - $type = $this->typeno_sqltype[$type]; - - $this->adapter->exec( sprintf( $this->getDDLTemplate( 'addColumn', $table, $column ), $table, $column, $type ) ); - } - - /** - * @see QueryWriter::code - */ - public function code( $typedescription, $includeSpecials = FALSE ) - { - $r = ( ( isset( $this->sqltype_typeno[$typedescription] ) ) ? $this->sqltype_typeno[$typedescription] : 99 ); - - return $r; - } - - /** - * @see QueryWriter::widenColumn - */ - public function widenColumn( $type, $column, $datatype ) - { - $t = $this->getTable( $type ); - - $t['columns'][$column] = $this->typeno_sqltype[$datatype]; - - $this->putTable( $t ); - } - - /** - * @see QueryWriter::getTables(); - */ - public function getTables() - { - return $this->adapter->getCol( "SELECT name FROM sqlite_master - WHERE type='table' AND name!='sqlite_sequence';" ); - } - - /** - * @see QueryWriter::createTable - */ - public function createTable( $type ) - { - $table = $this->esc( $type ); - - $sql = sprintf( $this->getDDLTemplate( 'createTable', $type ), $table ); - - $this->adapter->exec( $sql ); - } - - /** - * @see QueryWriter::getColumns - */ - public function getColumns( $table ) - { - $table = $this->esc( $table, TRUE ); - - $columnsRaw = $this->adapter->get( "PRAGMA table_info('$table')" ); - - $columns = array(); - foreach ( $columnsRaw as $r ) $columns[$r['name']] = $r['type']; - - return $columns; - } - - /** - * @see QueryWriter::addUniqueIndex - */ - public function addUniqueConstraint( $type, $properties ) - { - $tableNoQ = $this->esc( $type, TRUE ); - $name = 'UQ_' . $this->esc( $type, TRUE ) . implode( '__', $properties ); - $t = $this->getTable( $type ); - $t['indexes'][$name] = array( 'name' => $name ); - try { - $this->putTable( $t ); - } catch( SQLException $e ) { - return FALSE; - } - return TRUE; - } - - /** - * @see QueryWriter::sqlStateIn - */ - public function sqlStateIn( $state, $list, $extraDriverDetails = array() ) - { - $stateMap = array( - '23000' => QueryWriter::C_SQLSTATE_INTEGRITY_CONSTRAINT_VIOLATION - ); - if ( $state == 'HY000' - && isset($extraDriverDetails[1]) - && $extraDriverDetails[1] == 1 - && ( in_array( QueryWriter::C_SQLSTATE_NO_SUCH_TABLE, $list ) - || in_array( QueryWriter::C_SQLSTATE_NO_SUCH_COLUMN, $list ) - )) { - return TRUE; - } - return in_array( ( isset( $stateMap[$state] ) ? $stateMap[$state] : '0' ), $list ); - } - - /** - * Sets an SQL snippet to be used for the next queryRecord() operation. - * SQLite has no SELECT-FOR-UPDATE and filters this. - * - * @param string $sql SQL snippet to use in SELECT statement. - * - * return self - */ - public function setSQLSelectSnippet( $sqlSelectSnippet = '' ) { - if ( $sqlSelectSnippet === AQueryWriter::C_SELECT_SNIPPET_FOR_UPDATE) $sqlSelectSnippet = ''; - $this->sqlSelectSnippet = $sqlSelectSnippet; - return $this; - } - - /** - * @see QueryWriter::addIndex - */ - public function addIndex( $type, $name, $column ) - { - $columns = $this->getColumns( $type ); - if ( !isset( $columns[$column] ) ) return FALSE; - - $table = $this->esc( $type ); - $name = preg_replace( '/\W/', '', $name ); - $column = $this->esc( $column, TRUE ); - - try { - $t = $this->getTable( $type ); - $t['indexes'][$name] = array( 'name' => $column ); - $this->putTable( $t ); - return TRUE; - } catch( SQLException $exception ) { - return FALSE; - } - } - - /** - * @see QueryWriter::wipe - */ - public function wipe( $type ) - { - $table = $this->esc( $type ); - - $this->adapter->exec( "DELETE FROM $table " ); - } - - /** - * @see QueryWriter::addFK - */ - public function addFK( $type, $targetType, $property, $targetProperty, $isDep = FALSE ) - { - return $this->buildFK( $type, $targetType, $property, $targetProperty, $isDep ); - } - - /** - * @see QueryWriter::wipeAll - */ - public function wipeAll() - { - if (AQueryWriter::$noNuke) throw new \Exception('The nuke() command has been disabled using noNuke() or R::feature(novice/...).'); - $this->adapter->exec( 'PRAGMA foreign_keys = 0 ' ); - - foreach ( $this->getTables() as $t ) { - try { $this->adapter->exec( "DROP TABLE IF EXISTS `$t`" ); } catch ( SQLException $e ) { ; } - try { $this->adapter->exec( "DROP TABLE IF EXISTS `$t`" ); } catch ( SQLException $e ) { ; } - } - - $this->adapter->exec( 'PRAGMA foreign_keys = 1 ' ); - } -} -} - -namespace RedBeanPHP\QueryWriter { - -use RedBeanPHP\QueryWriter\AQueryWriter as AQueryWriter; -use RedBeanPHP\QueryWriter as QueryWriter; -use RedBeanPHP\Adapter\DBAdapter as DBAdapter; -use RedBeanPHP\Adapter as Adapter; -use RedBeanPHP\RedException\SQL as SQLException; - -/** - * RedBeanPHP PostgreSQL Query Writer. - * This is a QueryWriter class for RedBeanPHP. - * This QueryWriter provides support for the PostgreSQL database platform. - * - * @file RedBeanPHP/QueryWriter/PostgreSQL.php - * @author Gabor de Mooij and the RedBeanPHP Community - * @license BSD/GPLv2 - * - * @copyright - * (c) copyright G.J.G.T. (Gabor) de Mooij and the RedBeanPHP Community. - * This source file is subject to the BSD/GPLv2 License that is bundled - * with this source code in the file license.txt. - */ -class PostgreSQL extends AQueryWriter implements QueryWriter -{ - /** - * Data types - */ - const C_DATATYPE_INTEGER = 0; - const C_DATATYPE_DOUBLE = 1; - const C_DATATYPE_TEXT = 3; - const C_DATATYPE_SPECIAL_DATE = 80; - const C_DATATYPE_SPECIAL_DATETIME = 81; - const C_DATATYPE_SPECIAL_TIME = 82; //TIME (no zone) only manual - const C_DATATYPE_SPECIAL_TIMEZ = 83; //TIME (plus zone) only manual - const C_DATATYPE_SPECIAL_POINT = 90; - const C_DATATYPE_SPECIAL_LSEG = 91; - const C_DATATYPE_SPECIAL_CIRCLE = 92; - const C_DATATYPE_SPECIAL_MONEY = 93; - const C_DATATYPE_SPECIAL_POLYGON = 94; - const C_DATATYPE_SPECIAL_MONEY2 = 95; //Numbers only money, i.e. fixed point numeric - const C_DATATYPE_SPECIAL_JSON = 96; //JSON support (only manual) - const C_DATATYPE_SPECIFIED = 99; - - /** - * @var DBAdapter - */ - protected $adapter; - - /** - * @var string - */ - protected $quoteCharacter = '"'; - - /** - * @var string - */ - protected $defaultValue = 'DEFAULT'; - - /** - * @var array - */ - protected $DDLTemplates = array( - 'addColumn' => array( - '*' => 'ALTER TABLE %s ADD %s %s ' - ), - 'createTable' => array( - '*' => 'CREATE TABLE %s (id SERIAL PRIMARY KEY) ' - ), - 'widenColumn' => array( - '*' => 'ALTER TABLE %s ALTER COLUMN %s TYPE %s' - ) - ); - - /** - * Returns the insert suffix SQL Snippet - * - * @param string $table table - * - * @return string $sql SQL Snippet - */ - protected function getInsertSuffix( $table ) - { - return 'RETURNING id '; - } - - /** - * @see AQueryWriter::getKeyMapForType - */ - protected function getKeyMapForType( $type ) - { - $table = $this->esc( $type, TRUE ); - $keys = $this->adapter->get( ' - SELECT - information_schema.key_column_usage.constraint_name AS "name", - information_schema.key_column_usage.column_name AS "from", - information_schema.constraint_table_usage.table_name AS "table", - information_schema.constraint_column_usage.column_name AS "to", - information_schema.referential_constraints.update_rule AS "on_update", - information_schema.referential_constraints.delete_rule AS "on_delete" - FROM information_schema.key_column_usage - INNER JOIN information_schema.constraint_table_usage - ON ( - information_schema.key_column_usage.constraint_name = information_schema.constraint_table_usage.constraint_name - AND information_schema.key_column_usage.constraint_schema = information_schema.constraint_table_usage.constraint_schema - AND information_schema.key_column_usage.constraint_catalog = information_schema.constraint_table_usage.constraint_catalog - ) - INNER JOIN information_schema.constraint_column_usage - ON ( - information_schema.key_column_usage.constraint_name = information_schema.constraint_column_usage.constraint_name - AND information_schema.key_column_usage.constraint_schema = information_schema.constraint_column_usage.constraint_schema - AND information_schema.key_column_usage.constraint_catalog = information_schema.constraint_column_usage.constraint_catalog - ) - INNER JOIN information_schema.referential_constraints - ON ( - information_schema.key_column_usage.constraint_name = information_schema.referential_constraints.constraint_name - AND information_schema.key_column_usage.constraint_schema = information_schema.referential_constraints.constraint_schema - AND information_schema.key_column_usage.constraint_catalog = information_schema.referential_constraints.constraint_catalog - ) - WHERE - information_schema.key_column_usage.table_catalog = current_database() - AND information_schema.key_column_usage.table_schema = ANY( current_schemas( FALSE ) ) - AND information_schema.key_column_usage.table_name = ? - ', array( $type ) ); - $keyInfoList = array(); - foreach ( $keys as $k ) { - $label = $this->makeFKLabel( $k['from'], $k['table'], $k['to'] ); - $keyInfoList[$label] = array( - 'name' => $k['name'], - 'from' => $k['from'], - 'table' => $k['table'], - 'to' => $k['to'], - 'on_update' => $k['on_update'], - 'on_delete' => $k['on_delete'] - ); - } - return $keyInfoList; - } - - /** - * Constructor - * Most of the time, you do not need to use this constructor, - * since the facade takes care of constructing and wiring the - * RedBeanPHP core objects. However if you would like to - * assemble an OODB instance yourself, this is how it works: - * - * Usage: - * - * - * $database = new RPDO( $dsn, $user, $pass ); - * $adapter = new DBAdapter( $database ); - * $writer = new PostgresWriter( $adapter ); - * $oodb = new OODB( $writer, FALSE ); - * $bean = $oodb->dispense( 'bean' ); - * $bean->name = 'coffeeBean'; - * $id = $oodb->store( $bean ); - * $bean = $oodb->load( 'bean', $id ); - * - * - * The example above creates the 3 RedBeanPHP core objects: - * the Adapter, the Query Writer and the OODB instance and - * wires them together. The example also demonstrates some of - * the methods that can be used with OODB, as you see, they - * closely resemble their facade counterparts. - * - * The wiring process: create an RPDO instance using your database - * connection parameters. Create a database adapter from the RPDO - * object and pass that to the constructor of the writer. Next, - * create an OODB instance from the writer. Now you have an OODB - * object. - * - * @param Adapter $adapter Database Adapter - */ - public function __construct( Adapter $adapter ) - { - $this->typeno_sqltype = array( - self::C_DATATYPE_INTEGER => ' integer ', - self::C_DATATYPE_DOUBLE => ' double precision ', - self::C_DATATYPE_TEXT => ' text ', - self::C_DATATYPE_SPECIAL_DATE => ' date ', - self::C_DATATYPE_SPECIAL_TIME => ' time ', - self::C_DATATYPE_SPECIAL_TIMEZ => ' time with time zone ', - self::C_DATATYPE_SPECIAL_DATETIME => ' timestamp without time zone ', - self::C_DATATYPE_SPECIAL_POINT => ' point ', - self::C_DATATYPE_SPECIAL_LSEG => ' lseg ', - self::C_DATATYPE_SPECIAL_CIRCLE => ' circle ', - self::C_DATATYPE_SPECIAL_MONEY => ' money ', - self::C_DATATYPE_SPECIAL_MONEY2 => ' numeric(10,2) ', - self::C_DATATYPE_SPECIAL_POLYGON => ' polygon ', - self::C_DATATYPE_SPECIAL_JSON => ' json ', - ); - - $this->sqltype_typeno = array(); - - foreach ( $this->typeno_sqltype as $k => $v ) { - $this->sqltype_typeno[trim( strtolower( $v ) )] = $k; - } - - $this->adapter = $adapter; - } - - /** - * This method returns the datatype to be used for primary key IDS and - * foreign keys. Returns one if the data type constants. - * - * @return integer - */ - public function getTypeForID() - { - return self::C_DATATYPE_INTEGER; - } - - /** - * @see QueryWriter::getTables - */ - public function getTables() - { - return $this->adapter->getCol( 'SELECT table_name FROM information_schema.tables WHERE table_schema = ANY( current_schemas( FALSE ) )' ); - } - - /** - * @see QueryWriter::createTable - */ - public function createTable( $type ) - { - $table = $this->esc( $type ); - - $this->adapter->exec( sprintf( $this->getDDLTemplate( 'createTable', $type ), $table ) ); - } - - /** - * @see QueryWriter::getColumns - */ - public function getColumns( $table ) - { - $table = $this->esc( $table, TRUE ); - - $columnsRaw = $this->adapter->get( "SELECT column_name, data_type FROM information_schema.columns WHERE table_name='$table' AND table_schema = ANY( current_schemas( FALSE ) )" ); - - $columns = array(); - foreach ( $columnsRaw as $r ) { - $columns[$r['column_name']] = $r['data_type']; - } - - return $columns; - } - - /** - * @see QueryWriter::scanType - */ - public function scanType( $value, $flagSpecial = FALSE ) - { - $this->svalue = $value; - - if ( $value === INF ) return self::C_DATATYPE_TEXT; - - if ( $flagSpecial && $value ) { - if ( preg_match( '/^\d{4}\-\d\d-\d\d$/', $value ) ) { - return PostgreSQL::C_DATATYPE_SPECIAL_DATE; - } - - if ( preg_match( '/^\d{4}\-\d\d-\d\d\s\d\d:\d\d:\d\d(\.\d{1,6})?$/', $value ) ) { - return PostgreSQL::C_DATATYPE_SPECIAL_DATETIME; - } - - if ( preg_match( '/^\([\d\.]+,[\d\.]+\)$/', $value ) ) { - return PostgreSQL::C_DATATYPE_SPECIAL_POINT; - } - - if ( preg_match( '/^\[\([\d\.]+,[\d\.]+\),\([\d\.]+,[\d\.]+\)\]$/', $value ) ) { - return PostgreSQL::C_DATATYPE_SPECIAL_LSEG; - } - - if ( preg_match( '/^\<\([\d\.]+,[\d\.]+\),[\d\.]+\>$/', $value ) ) { - return PostgreSQL::C_DATATYPE_SPECIAL_CIRCLE; - } - - if ( preg_match( '/^\((\([\d\.]+,[\d\.]+\),?)+\)$/', $value ) ) { - return PostgreSQL::C_DATATYPE_SPECIAL_POLYGON; - } - - if ( preg_match( '/^\-?(\$|€|¥|£)[\d,\.]+$/', $value ) ) { - return PostgreSQL::C_DATATYPE_SPECIAL_MONEY; - } - - if ( preg_match( '/^-?\d+\.\d{2}$/', $value ) ) { - return PostgreSQL::C_DATATYPE_SPECIAL_MONEY2; - } - if ( self::$flagUseJSONColumns && $this->isJSON( $value ) ) { - return self::C_DATATYPE_SPECIAL_JSON; - } - } - - if ( is_float( $value ) ) return self::C_DATATYPE_DOUBLE; - - if ( $this->startsWithZeros( $value ) ) return self::C_DATATYPE_TEXT; - - if ( $value === FALSE || $value === TRUE || $value === NULL || ( is_numeric( $value ) - && AQueryWriter::canBeTreatedAsInt( $value ) - && $value < 2147483648 - && $value > -2147483648 ) - ) { - return self::C_DATATYPE_INTEGER; - } elseif ( is_numeric( $value ) ) { - return self::C_DATATYPE_DOUBLE; - } else { - return self::C_DATATYPE_TEXT; - } - } - - /** - * @see QueryWriter::code - */ - public function code( $typedescription, $includeSpecials = FALSE ) - { - $r = ( isset( $this->sqltype_typeno[$typedescription] ) ) ? $this->sqltype_typeno[$typedescription] : 99; - - if ( $includeSpecials ) return $r; - - if ( $r >= QueryWriter::C_DATATYPE_RANGE_SPECIAL ) { - return self::C_DATATYPE_SPECIFIED; - } - - return $r; - } - - /** - * @see QueryWriter::widenColumn - */ - public function widenColumn( $beanType, $column, $datatype ) - { - $table = $beanType; - $type = $datatype; - - $table = $this->esc( $table ); - $column = $this->esc( $column ); - - $newtype = $this->typeno_sqltype[$type]; - - $this->adapter->exec( sprintf( $this->getDDLTemplate( 'widenColumn', $beanType, $column ), $table, $column, $newtype ) ); - - } - - /** - * @see QueryWriter::addUniqueIndex - */ - public function addUniqueConstraint( $type, $properties ) - { - $tableNoQ = $this->esc( $type, TRUE ); - $columns = array(); - foreach( $properties as $key => $column ) $columns[$key] = $this->esc( $column ); - $table = $this->esc( $type ); - sort( $columns ); //else we get multiple indexes due to order-effects - $name = "UQ_" . sha1( $table . implode( ',', $columns ) ); - $sql = "ALTER TABLE {$table} - ADD CONSTRAINT $name UNIQUE (" . implode( ',', $columns ) . ")"; - try { - $this->adapter->exec( $sql ); - } catch( SQLException $e ) { - return FALSE; - } - return TRUE; - } - - /** - * @see QueryWriter::sqlStateIn - */ - public function sqlStateIn( $state, $list, $extraDriverDetails = array() ) - { - $stateMap = array( - '42P01' => QueryWriter::C_SQLSTATE_NO_SUCH_TABLE, - '42703' => QueryWriter::C_SQLSTATE_NO_SUCH_COLUMN, - '23505' => QueryWriter::C_SQLSTATE_INTEGRITY_CONSTRAINT_VIOLATION, - '55P03' => QueryWriter::C_SQLSTATE_LOCK_TIMEOUT - ); - return in_array( ( isset( $stateMap[$state] ) ? $stateMap[$state] : '0' ), $list ); - } - - /** - * @see QueryWriter::addIndex - */ - public function addIndex( $type, $name, $property ) - { - $table = $this->esc( $type ); - $name = preg_replace( '/\W/', '', $name ); - $column = $this->esc( $property ); - - try { - $this->adapter->exec( "CREATE INDEX {$name} ON $table ({$column}) " ); - return TRUE; - } catch ( SQLException $e ) { - return FALSE; - } - } - - /** - * @see QueryWriter::addFK - */ - public function addFK( $type, $targetType, $property, $targetProperty, $isDep = FALSE ) - { - $table = $this->esc( $type ); - $targetTable = $this->esc( $targetType ); - $field = $this->esc( $property ); - $targetField = $this->esc( $targetProperty ); - $tableNoQ = $this->esc( $type, TRUE ); - $fieldNoQ = $this->esc( $property, TRUE ); - if ( !is_null( $this->getForeignKeyForTypeProperty( $tableNoQ, $fieldNoQ ) ) ) return FALSE; - try{ - $delRule = ( $isDep ? 'CASCADE' : 'SET NULL' ); - $this->adapter->exec( "ALTER TABLE {$table} - ADD FOREIGN KEY ( {$field} ) REFERENCES {$targetTable} - ({$targetField}) ON DELETE {$delRule} ON UPDATE {$delRule} DEFERRABLE ;" ); - return TRUE; - } catch ( SQLException $e ) { - return FALSE; - } - } - - /** - * @see QueryWriter::wipeAll - */ - public function wipeAll() - { - if (AQueryWriter::$noNuke) throw new \Exception('The nuke() command has been disabled using noNuke() or R::feature(novice/...).'); - $this->adapter->exec( 'SET CONSTRAINTS ALL DEFERRED' ); - - foreach ( $this->getTables() as $t ) { - $t = $this->esc( $t ); - //Some plugins (PostGIS have unremovable tables/views), avoid exceptions. - try { $this->adapter->exec( "DROP TABLE IF EXISTS $t CASCADE " ); }catch( \Exception $e ) {} - } - - $this->adapter->exec( 'SET CONSTRAINTS ALL IMMEDIATE' ); - } -} -} - namespace RedBeanPHP\QueryWriter { use RedBeanPHP\QueryWriter\AQueryWriter as AQueryWriter; use RedBeanPHP\QueryWriter as QueryWriter; @@ -8580,8 +7765,6 @@ class CUBRID extends AQueryWriter implements QueryWriter */ public function scanType( $value, $flagSpecial = FALSE ) { - $this->svalue = $value; - if ( is_null( $value ) ) { return self::C_DATATYPE_INTEGER; } @@ -8784,6 +7967,8 @@ class SQL extends RedException /** * @param array $driverDetails + * + * @return void */ public function setDriverDetails($driverDetails) { @@ -8840,7 +8025,7 @@ use RedBeanPHP\Cursor\NullCursor as NullCursor; * Abstract Repository. * * OODB manages two repositories, a fluid one that - * adjust the database schema on-the-fly to accomodate for + * adjust the database schema on-the-fly to accommodate for * new bean types (tables) and new properties (columns) and * a frozen one for use in a production environment. OODB * allows you to swap the repository instances using the freeze() @@ -8862,21 +8047,26 @@ abstract class Repository */ protected $stash = NULL; - /* + /** * @var integer */ protected $nesting = 0; /** - * @var DBAdapter + * @var QueryWriter */ protected $writer; /** - * @var boolean + * @var boolean|array */ protected $partialBeans = FALSE; + /** + * @var OODB + */ + public $oodb = NULL; + /** * Toggles 'partial bean mode'. If this mode has been * selected the repository will only update the fields of a bean that @@ -8889,7 +8079,7 @@ abstract class Repository * * @param boolean|array $yesNoBeans List of type names or 'all' * - * @return mixed + * @return boolean|array */ public function usePartialBeans( $yesNoBeans ) { @@ -8982,7 +8172,7 @@ abstract class Repository * A bean may contain lists. This * method handles shared addition lists; i.e. * the $bean->sharedObject properties. - * Shared beans will be associated with eachother using the + * Shared beans will be associated with each other using the * Association Manager. * * @param OODBBean $bean the bean @@ -9218,7 +8408,7 @@ abstract class Repository * @param int $number number of beans you would like to get * @param boolean $alwaysReturnArray if TRUE always returns the result as an array * - * @return OODBBean + * @return OODBBean|OODBBean[] */ public function dispense( $type, $number = 1, $alwaysReturnArray = FALSE ) { @@ -9398,7 +8588,7 @@ abstract class Repository * New in 4.3.2: meta mask. The meta mask is a special mask to send * data from raw result rows to the meta store of the bean. This is * useful for bundling additional information with custom queries. - * Values of every column whos name starts with $mask will be + * Values of every column who's name starts with $mask will be * transferred to the meta section of the bean under key 'data.bundle'. * * @param string $type type of beans you would like to have @@ -9477,10 +8667,6 @@ abstract class Repository public function count( $type, $addSQL = '', $bindings = array() ) { $type = AQueryWriter::camelsSnake( $type ); - if ( count( explode( '_', $type ) ) > 2 ) { - throw new RedException( 'Invalid type for count.' ); - } - try { $count = (int) $this->writer->queryRecordCount( $type, array(), $addSQL, $bindings ); } catch ( SQLException $exception ) { @@ -9497,7 +8683,7 @@ abstract class Repository * * @param OODBBean|SimpleModel $bean bean you want to remove from database * - * @return void + * @return int */ public function trash( $bean ) { @@ -9515,7 +8701,7 @@ abstract class Repository } } try { - $deleted = $this->writer->deleteRecord( $bean->getMeta( 'type' ), array( 'id' => array( $bean->id ) ), NULL ); + $deleted = $this->writer->deleteRecord( $bean->getMeta( 'type' ), array( 'id' => array( $bean->id ) ) ); } catch ( SQLException $exception ) { $this->handleException( $exception ); } @@ -9528,8 +8714,6 @@ abstract class Repository * Checks whether the specified table already exists in the database. * Not part of the Object Database interface! * - * @deprecated Use AQueryWriter::typeExists() instead. - * * @param string $table table name * * @return boolean @@ -9579,7 +8763,7 @@ use RedBeanPHP\Repository as Repository; /** * Fluid Repository. * OODB manages two repositories, a fluid one that - * adjust the database schema on-the-fly to accomodate for + * adjust the database schema on-the-fly to accommodate for * new bean types (tables) and new properties (columns) and * a frozen one for use in a production environment. OODB * allows you to swap the repository instances using the freeze() @@ -9654,9 +8838,10 @@ class Fluid extends Repository * * This method will also apply indexes, unique constraints and foreign keys. * - * @param OODBBean $bean bean to get cast data from and store meta in - * @param string $property property to store - * @param mixed $value value to store + * @param OODBBean $bean bean to get cast data from and store meta in + * @param string $property property to store + * @param mixed $value value to store + * @param array|NULL &$columns * * @return void */ @@ -9850,15 +9035,10 @@ class Fluid extends Repository * * @return OODBBean */ - public function xdispense( $type ) - { - return \R::getRedBean() -> dispense( $type ); - } - public function load( $type, $id ) { $rows = array(); - $bean = $this->xdispense( $type ); + $bean = $this->dispense( $type ); if ( isset( $this->stash[$this->nesting][$id] ) ) { $row = $this->stash[$this->nesting][$id]; } else { @@ -9907,7 +9087,7 @@ use RedBeanPHP\Repository as Repository; /** * Frozen Repository. * OODB manages two repositories, a fluid one that - * adjust the database schema on-the-fly to accomodate for + * adjust the database schema on-the-fly to accommodate for * new bean types (tables) and new properties (columns) and * a frozen one for use in a production environment. OODB * allows you to swap the repository instances using the freeze() @@ -10121,7 +9301,7 @@ class OODB extends Observable protected $nesting = 0; /** - * @var DBAdapter + * @var QueryWriter */ protected $writer; @@ -10131,12 +9311,12 @@ class OODB extends Observable protected $isFrozen = FALSE; /** - * @var FacadeBeanHelper + * @var BeanHelper|NULL */ protected $beanhelper = NULL; /** - * @var AssociationManager + * @var AssociationManager|NULL */ protected $assocManager = NULL; @@ -10146,12 +9326,12 @@ class OODB extends Observable protected $repository = NULL; /** - * @var FrozenRepo + * @var FrozenRepo|NULL */ protected $frozenRepository = NULL; /** - * @var FluidRepo + * @var FluidRepo|NULL */ protected $fluidRepository = NULL; @@ -10177,7 +9357,7 @@ class OODB extends Observable * Unboxes a bean from a FUSE model if needed and checks whether the bean is * an instance of OODBBean. * - * @param OODBBean $bean bean you wish to unbox + * @param OODBBean|SimpleModel $bean bean you wish to unbox * * @return OODBBean */ @@ -10239,11 +9419,11 @@ class OODB extends Observable /** * Toggles fluid or frozen mode. In fluid mode the database - * structure is adjusted to accomodate your objects. In frozen mode + * structure is adjusted to accommodate your objects. In frozen mode * this is not the case. * * You can also pass an array containing a selection of frozen types. - * Let's call this chilly mode, it's just like fluid mode except that + * Let's call this chill mode, it's just like fluid mode except that * certain types (i.e. tables) aren't touched. * * @param boolean|array $toggle TRUE if you want to use OODB instance in frozen mode @@ -10283,7 +9463,7 @@ class OODB extends Observable /** * Returns the current mode of operation of RedBean. * In fluid mode the database - * structure is adjusted to accomodate your objects. + * structure is adjusted to accommodate your objects. * In frozen mode * this is not the case. * @@ -10323,7 +9503,7 @@ class OODB extends Observable * @param string $number number of beans you would like to get * @param boolean $alwaysReturnArray if TRUE always returns the result as an array * - * @return OODBBean + * @return OODBBean|OODBBean[] */ public function dispense( $type, $number = 1, $alwaysReturnArray = FALSE ) { @@ -10352,7 +9532,7 @@ class OODB extends Observable * Returns the current bean helper. * Bean helpers assist beans in getting a reference to a toolbox. * - * @return BeanHelper + * @return BeanHelper|NULL */ public function getBeanHelper() { @@ -10374,7 +9554,7 @@ class OODB extends Observable } /** - * Searches the database for a bean that matches conditions $conditions and sql $addSQL + * Searches the database for a bean that matches conditions $conditions and sql $sql * and returns an array containing all the beans that have been found. * * Conditions need to take form: @@ -10392,10 +9572,10 @@ class OODB extends Observable * Note that you can use property names; the columns will be extracted using the * appropriate bean formatter. * - * @param string $type type of beans you are looking for - * @param array $conditions list of conditions - * @param string $sql SQL to be used in query - * @param array $bindings a list of values to bind to query parameters + * @param string $type type of beans you are looking for + * @param array $conditions list of conditions + * @param string|NULL $sql SQL to be used in query + * @param array $bindings a list of values to bind to query parameters * * @return array */ @@ -10407,9 +9587,9 @@ class OODB extends Observable /** * Same as find() but returns a BeanCollection. * - * @param string $type type of beans you are looking for - * @param string $sql SQL to be used in query - * @param array $bindings a list of values to bind to query parameters + * @param string $type type of beans you are looking for + * @param string|NULL $sql SQL to be used in query + * @param array $bindings a list of values to bind to query parameters * * @return BeanCollection */ @@ -10420,9 +9600,6 @@ class OODB extends Observable /** * Checks whether the specified table already exists in the database. - * Not part of the Object Database interface! - * - * @deprecated Use AQueryWriter::typeExists() instead. * * @param string $table table name * @@ -10497,7 +9674,7 @@ class OODB extends Observable * * @param OODBBean|SimpleModel $bean bean you want to remove from database * - * @return void + * @return int */ public function trash( $bean ) { @@ -10628,10 +9805,10 @@ class OODB extends Observable * MySQL spatial columns, because they need to be processed first using * the asText/GeomFromText functions. * - * @param string $mode mode to set function for, i.e. read or write - * @param string $field field (table.column) to bind SQL function to - * @param string $function SQL function to bind to field - * @param boolean $isTemplate TRUE if $function is an SQL string, FALSE for just a function name + * @param string $mode mode to set function for, i.e. read or write + * @param string $field field (table.column) to bind SQL function to + * @param string|NULL $function SQL function to bind to field + * @param boolean $isTemplate TRUE if $function is an SQL string, FALSE for just a function name * * @return void */ @@ -10987,7 +10164,7 @@ class Finder * R::genSlots( $users, * 'SELECT country.* FROM country WHERE id IN ( %s )' ), * array_column( $users, 'country_id' ), - * [Finder::onmap('country', $gebruikers)] + * [Finder::onmap('country', $users)] * ); * * @@ -11016,9 +10193,9 @@ class Finder * array parameter; you can either use the question mark notation * or the slot-notation (:keyname). * - * @param string $type type the type of bean you are looking for - * @param string $sql sql SQL query to find the desired bean, starting right after WHERE clause - * @param array $bindings values array of values to be bound to parameters in query + * @param string $type type the type of bean you are looking for + * @param string|NULL $sql sql SQL query to find the desired bean, starting right after WHERE clause + * @param array $bindings values array of values to be bound to parameters in query * * @return array */ @@ -11042,9 +10219,9 @@ class Finder * * @see Finder::find * - * @param string $type type the type of bean you are looking for - * @param string $sql sql SQL query to find the desired bean, starting right after WHERE clause - * @param array $bindings values array of values to be bound to parameters in query + * @param string $type type the type of bean you are looking for + * @param string|NULL $sql sql SQL query to find the desired bean, starting right after WHERE clause + * @param array $bindings values array of values to be bound to parameters in query * * @return array */ @@ -11065,9 +10242,9 @@ class Finder * * @see Finder::find * - * @param string $type type the type of bean you are looking for - * @param string $sql sql SQL query to find the desired bean, starting right after WHERE clause - * @param array $bindings values array of values to be bound to parameters in query + * @param string $type type the type of bean you are looking for + * @param string|NULL $sql sql SQL query to find the desired bean, starting right after WHERE clause + * @param array $bindings values array of values to be bound to parameters in query * * @return OODBBean|NULL */ @@ -11091,9 +10268,9 @@ class Finder * * @see Finder::find * - * @param string $type the type of bean you are looking for - * @param string $sql SQL query to find the desired bean, starting right after WHERE clause - * @param array $bindings values array of values to be bound to parameters in query + * @param string $type the type of bean you are looking for + * @param string|NULL $sql SQL query to find the desired bean, starting right after WHERE clause + * @param array $bindings values array of values to be bound to parameters in query * * @return OODBBean|NULL */ @@ -11115,9 +10292,9 @@ class Finder * * @see Finder::find * - * @param string $type the type of bean you are looking for - * @param string $sql SQL query to find the desired bean, starting right after WHERE clause - * @param array $bindings values array of values to be bound to parameters in query + * @param string $type the type of bean you are looking for + * @param string|NULL $sql SQL query to find the desired bean, starting right after WHERE clause + * @param array $bindings values array of values to be bound to parameters in query * * @return array */ @@ -11385,7 +10562,7 @@ class Finder } else { list($field1, $field2) = $matcher; foreach( $beans[$b] as $key => $bean ) { - $beans[$b][$key]->{$field1} = $beans[$a][$bean->{$field2}]; + $beans[$b][$key]->{$field1} = (isset($beans[$a][$bean->{$field2}]) ? $beans[$a][$bean->{$field2}] : NULL); } } } @@ -11434,6 +10611,11 @@ class AssociationManager extends Observable */ protected $writer; + /** + * @var ToolBox + */ + public $toolbox; + /** * Exception handler. * Fluid and Frozen mode have different ways of handling @@ -11612,7 +10794,7 @@ class AssociationManager extends Observable * * @param OODBBean|array $bean a bean object or an array of beans * @param string $type type of bean you're interested in - * @param string $sql SQL snippet (optional) + * @param string|NULL $sql SQL snippet (optional) * @param array $bindings bindings for your SQL string * * @return integer @@ -11731,7 +10913,7 @@ class AssociationManager extends Observable * Since 3.2, you can now also pass an array of beans instead just one * bean as the first parameter. * - * @param OODBBean|array $bean the bean you have + * @param OODBBean $bean the bean you have * @param string $type the type of beans you want * @param string $sql SQL snippet for extra filtering * @param array $bindings values to be inserted in SQL slots @@ -11769,7 +10951,7 @@ use RedBeanPHP\OODBBean as OODBBean; * Interface for Bean Helper. * A little bolt that glues the whole machinery together. * The Bean Helper is passed to the OODB RedBeanPHP Object to - * faciliatte the creation of beans and providing them with + * facilitate the creation of beans and providing them with * a toolbox. The Helper also facilitates the FUSE feature, * determining how beans relate to their models. By overriding * the getModelForBean method you can tune the FUSEing to @@ -11846,7 +11028,7 @@ class SimpleFacadeBeanHelper implements BeanHelper /** * Factory function to create instance of Simple Model, if any. * - * @var \Closure + * @var callable|NULL */ private static $factory = null; @@ -11868,7 +11050,7 @@ class SimpleFacadeBeanHelper implements BeanHelper * Sets the factory function to create the model when using FUSE * to connect a bean to a model. * - * @param \Closure $factory factory function + * @param callable|NULL $factory factory function * * @return void */ @@ -11893,6 +11075,28 @@ class SimpleFacadeBeanHelper implements BeanHelper $model = $bean->getMeta( 'type' ); $prefix = defined( 'REDBEAN_MODEL_PREFIX' ) ? REDBEAN_MODEL_PREFIX : '\\Model_'; + return $this->resolveModel($prefix, $model, $bean); + } + + /** + * Resolves the model associated with the bean using the model name (type), + * the prefix and the bean. + * + * @note + * If REDBEAN_CLASS_AUTOLOAD is defined this will be passed to class_exist as + * autoloading flag. + * + * @param string $prefix Prefix to use for resolution + * @param string $model Type name + * @param OODBBean $bean Bean to resolve model for + * + * @return SimpleModel|CustomModel|NULL + */ + protected function resolveModel($prefix, $model, $bean) { + + /* Determine autoloading preference */ + $autoloadFlag = ( defined( 'REDBEAN_CLASS_AUTOLOAD' ) ? REDBEAN_CLASS_AUTOLOAD : TRUE ); + if ( strpos( $model, '_' ) !== FALSE ) { $modelParts = explode( '_', $model ); $modelName = ''; @@ -11902,13 +11106,13 @@ class SimpleFacadeBeanHelper implements BeanHelper $modelName = $prefix . $modelName; if ( !class_exists( $modelName ) ) { $modelName = $prefix . ucfirst( $model ); - if ( !class_exists( $modelName ) ) { + if ( !class_exists( $modelName, $autoloadFlag ) ) { return NULL; } } } else { $modelName = $prefix . ucfirst( $model ); - if ( !class_exists( $modelName ) ) { + if ( !class_exists( $modelName, $autoloadFlag ) ) { return NULL; } } @@ -11927,6 +11131,63 @@ class SimpleFacadeBeanHelper implements BeanHelper } } +namespace RedBeanPHP\BeanHelper { + +use RedBeanPHP\BeanHelper as BeanHelper; +use RedBeanPHP\Facade as Facade; +use RedBeanPHP\OODBBean as OODBBean; +use RedBeanPHP\SimpleModelHelper as SimpleModelHelper; +use RedBeanPHP\BeanHelper\SimpleFacadeBeanHelper as SimpleFacadeBeanHelper; + +/** + * Dynamic Bean Helper. + * + * The dynamic bean helper allows you to use differently namespaced + * classes for models per database connection. + * + * @file RedBeanPHP/BeanHelper/DynamicBeanHelper.php + * @author Gabor de Mooij and the RedBeanPHP Community + * @license BSD/GPLv2 + * + * @copyright + * (c) copyright G.J.G.T. (Gabor) de Mooij and the RedBeanPHP Community + * This source file is subject to the BSD/GPLv2 License that is bundled + * with this source code in the file license.txt. + */ +class DynamicBeanHelper extends SimpleFacadeBeanHelper implements BeanHelper +{ + /** + * Model prefix to be used for the current database connection. + * + * @var string + */ + private $modelPrefix; + + /** + * Constructor + * + * Usage: + * + * + * R::addDatabase( ..., new DynamicBeanHelper('Prefix1_') ); + * + * + * @param string $modelPrefix prefix + */ + public function __construct( $modelPrefix ) { + $this->modelPrefix = $modelPrefix; + } + + /** + * @see BeanHelper::getModelForBean + */ + public function getModelForBean( OODBBean $bean ) + { + return $this->resolveModel( $this->modelPrefix, $bean->getMeta( 'type' ), $bean ); + } +} +} + namespace RedBeanPHP { use RedBeanPHP\OODBBean as OODBBean; @@ -12084,7 +11345,7 @@ class SimpleModelHelper implements Observer * invoke the corresponding method on the bean. * * @param string $eventName i.e. 'delete', 'after_delete' - * @param OODBean $bean affected bean + * @param OODBBean $bean affected bean * * @return void */ @@ -12162,7 +11423,7 @@ class TagManager protected $associationManager; /** - * @var OODBBean + * @var OODB */ protected $redbean; @@ -12171,7 +11432,7 @@ class TagManager * it will split the string into words and return an array instead. * In case of an array the argument will be returned 'as is'. * - * @param array|string $tagList list of tags + * @param array|string|false $tagList list of tags * * @return array */ @@ -12187,12 +11448,12 @@ class TagManager } /** - * Finds a tag bean by it's title. + * Finds a tag bean by its title. * Internal method. * * @param string $title title to search for * - * @return OODBBean + * @return OODBBean|NULL */ protected function findTagByTitle( $title ) { @@ -12223,7 +11484,7 @@ class TagManager } /** - * Tests whether a bean has been associated with one ore more + * Tests whether a bean has been associated with one or more * of the listed tags. If the third parameter is TRUE this method * will return TRUE only if all tags that have been specified are indeed * associated with the given bean, otherwise FALSE. @@ -12281,8 +11542,8 @@ class TagManager * In the example above, the $blog bean will no longer * be associated with the tags 'smart' and 'interesting'. * - * @param OODBBean $bean tagged bean - * @param array $tagList list of tags (names) + * @param OODBBean $bean tagged bean + * @param array|string $tagList list of tags (names) * * @return void */ @@ -12358,8 +11619,8 @@ class TagManager * The example adds the tag 'halloween' to the $blog * bean. * - * @param OODBBean $bean bean to tag - * @param array $tagList list of tags to add to bean + * @param OODBBean $bean bean to tag + * @param array|string|false $tagList list of tags to add to bean * * @return void */ @@ -12706,7 +11967,7 @@ use RedBeanPHP\Util\Feature; * RedBean Facade * * Version Information - * RedBean Version @version 5.6 + * RedBean Version @version 5.7 * * This class hides the object landscape of * RedBeanPHP behind a single letter class providing @@ -12726,7 +11987,7 @@ class Facade /** * RedBeanPHP version constant. */ - const C_REDBEANPHP_VERSION = '5.6'; + const C_REDBEANPHP_VERSION = '5.7'; /** * @var ToolBox @@ -12744,7 +12005,7 @@ class Facade private static $writer; /** - * @var DBAdapter + * @var Adapter */ private static $adapter; @@ -12784,7 +12045,7 @@ class Facade private static $logger; /** - * @var array + * @var callable[] */ private static $plugins = array(); @@ -12794,12 +12055,12 @@ class Facade private static $exportCaseStyle = 'default'; /** - * @var flag allows transactions through facade in fluid mode + * @var bool flag allows transactions through facade in fluid mode */ private static $allowFluidTransactions = FALSE; /** - * @var flag allows to unfreeze if needed with store(all) + * @var bool flag allows to unfreeze if needed with store(all) */ private static $allowHybridMode = FALSE; @@ -12814,7 +12075,7 @@ class Facade public static $currentDB = ''; /** - * @var array + * @var ToolBox[] */ public static $toolboxes = array(); @@ -12826,7 +12087,7 @@ class Facade * @param string $sql the sql you want to execute * @param array $bindings array of values to be bound to query statement * - * @return array + * @return array|int|Cursor|NULL */ private static function query( $method, $sql, $bindings ) { @@ -12861,6 +12122,8 @@ class Facade * flag. * * @param boolean $hybrid + * + * @return bool */ public static function setAllowHybridMode( $hybrid ) { @@ -12938,11 +12201,11 @@ class Facade * a connection is really required, for instance when attempting to load * a bean. * - * @param string $dsn Database connection string - * @param string $username Username for database - * @param string $password Password for database - * @param boolean $frozen TRUE if you want to setup in frozen mode - * @param boolean $partialBeans TRUE to enable partial bean updates + * @param string|\PDO|NULL $dsn Database connection string + * @param string|NULL $username Username for database + * @param string|NULL $password Password for database + * @param boolean|string[] $frozen TRUE if you want to setup in frozen mode + * @param boolean|string[] $partialBeans TRUE to enable partial bean updates * @param array $options Additional (PDO) options to pass * * @return ToolBox @@ -12993,7 +12256,7 @@ class Facade * Toggles fluid transactions. By default fluid transactions * are not active. Starting, committing or rolling back a transaction * through the facade in fluid mode will have no effect. If you wish - * to replace this standard portable behavor with behavior depending + * to replace this standard portable behavior with behavior depending * on how the used database platform handles fluid (DDL) transactions * set this flag to TRUE. * @@ -13056,6 +12319,7 @@ class Facade */ public static function transaction( $callback ) { + if ( !self::$allowFluidTransactions && !self::$redbean->isFrozen() ) return FALSE; return Transaction::transaction( self::$adapter, $callback ); } @@ -13073,28 +12337,35 @@ class Facade * This method allows you to dynamically add (and select) new databases * to the facade. Adding a database with the same key will cause an exception. * - * @param string $key ID for the database - * @param string $dsn DSN for the database - * @param string $user user for connection - * @param NULL|string $pass password for connection - * @param bool $frozen whether this database is frozen or not + * @param string $key ID for the database + * @param string|\PDO $dsn DSN for the database + * @param string|NULL $user user for connection + * @param string|NULL $pass password for connection + * @param bool|string[] $frozen whether this database is frozen or not + * @param bool|string[] $partialBeans should we load partial beans? + * @param array $options additional options for the query writer + * @param BeanHelper|NULL $beanHelper Beanhelper to use (use this for DB specific model prefixes) * * @return void */ - public static function addDatabase( $key, $dsn, $user = NULL, $pass = NULL, $frozen = FALSE, $partialBeans = FALSE, $options = array() ) + public static function addDatabase( $key, $dsn, $user = NULL, $pass = NULL, $frozen = FALSE, $partialBeans = FALSE, $options = array(), $beanHelper = NULL ) { if ( isset( self::$toolboxes[$key] ) ) { throw new RedException( 'A database has already been specified for this key.' ); } self::$toolboxes[$key] = self::createToolbox($dsn, $user, $pass, $frozen, $partialBeans, $options); + + if ( !is_null( $beanHelper ) ) { + self::$toolboxes[$key]->getRedBean()->setBeanHelper( $beanHelper ); + } } /** * Creates a toolbox. This method can be called if you want to use redbean non-static. - * It has the same interface as R::setup(). The createToolbx() method can be called - * without any arguments, in this case it will try to create a SQLite database in - * /tmp called red.db (this only works on UNIX-like systems). + * It has the same interface as R::setup(). The createToolbox() method can be called + * without any arguments, in this case it will try to create a SQLite database in + * /tmp called red.db (this only works on UNIX-like systems). * * Usage: * @@ -13116,15 +12387,17 @@ class Facade * Instead, it will prepare the connection and connect 'lazily', i.e. the moment * a connection is really required, for instance when attempting to load a bean. * - * @param string $dsn Database connection string + * @param string|\PDO $dsn Database connection string * @param string $username Username for database * @param string $password Password for database - * @param boolean $frozen TRUE if you want to setup in frozen mode + * @param boolean|string[] $frozen TRUE if you want to setup in frozen mode + * @param boolean|string[] $partialBeans TRUE to enable partial bean updates + * @param array $options * * @return ToolBox */ - public static function createToolbox( $dsn = NULL, $username = NULL, $password = NULL, $frozen = FALSE, $partialBeans = FALSE, $options = array() ) - { + public static function createToolbox( $dsn, $username = NULL, $password = NULL, $frozen = FALSE, $partialBeans = FALSE, $options = array() ) + { if ( is_object($dsn) ) { $db = new RPDO( $dsn ); $dbType = $db->getDatabaseType(); @@ -13149,6 +12422,7 @@ class Facade throw new RedException( 'Unsupported database ('.$wkey.').' ); } $writerClass = '\\RedBeanPHP\\QueryWriter\\'.$writers[$wkey]; + /** @var AQueryWriter $writer */ $writer = new $writerClass( $adapter ); $redbean = new OODB( $writer, $frozen ); @@ -13184,6 +12458,7 @@ class Facade * switched and FALSE otherwise (for instance if you already using the specified database). * * @param string $key Key of the database to select + * @param bool $force * * @return boolean */ @@ -13213,7 +12488,7 @@ class Facade * There are 2 debug styles: * * Classic: separate parameter bindings, explicit and complete but less readable - * Fancy: interpersed bindings, truncates large strings, highlighted schema changes + * Fancy: interspersed bindings, truncates large strings, highlighted schema changes * * Fancy style is more readable but sometimes incomplete. * @@ -13275,9 +12550,9 @@ class Facade * the column types used to store their values. * If no type is passed, this method returns a list of all tables in the database. * - * @param string $type Type of bean (i.e. table) you want to inspect + * @param string|NULL $type Type of bean (i.e. table) you want to inspect, or NULL for a list of all tables * - * @return array + * @return string[] */ public static function inspect( $type = NULL ) { @@ -13341,14 +12616,16 @@ class Facade /** * Toggles fluid or frozen mode. In fluid mode the database - * structure is adjusted to accomodate your objects. In frozen mode + * structure is adjusted to accommodate your objects. In frozen mode * this is not the case. * * You can also pass an array containing a selection of frozen types. * Let's call this chilly mode, it's just like fluid mode except that * certain types (i.e. tables) aren't touched. * - * @param boolean|array $tf mode of operation (TRUE means frozen) + * @param boolean|string[] $tf mode of operation (TRUE means frozen) + * + * @return void */ public static function freeze( $tf = TRUE ) { @@ -13369,10 +12646,10 @@ class Facade * list( $author, $bio ) = R::loadMulti( 'author, bio', $id ); * * - * @param string|array $types the set of types to load at once - * @param mixed $id the common ID + * @param string|string[] $types the set of types to load at once + * @param int $id the common ID * - * @return OODBBean + * @return OODBBean[] */ public static function loadMulti( $types, $id ) { @@ -13414,7 +12691,7 @@ class Facade * * @param string $type type of bean you want to load * @param integer $id ID of the bean you want to load - * @param string $snippet string to use after select (optional) + * @param string|NULL $snippet string to use after select (optional) * * @return OODBBean */ @@ -13468,10 +12745,10 @@ class Facade * * * @param string $type the type of bean you are looking for - * @param string $sql SQL query to find the desired bean, starting right after WHERE clause + * @param string|NULL $sql SQL query to find the desired bean, starting right after WHERE clause * @param array $bindings array of values to be bound to parameters in query * - * @return array + * @return OODBBean[] */ public static function findForUpdate( $type, $sql = NULL, $bindings = array() ) { @@ -13483,16 +12760,16 @@ class Facade * Same as findForUpdate but returns just one bean and adds LIMIT-clause. * * @param string $type the type of bean you are looking for - * @param string $sql SQL query to find the desired bean, starting right after WHERE clause + * @param string|NULL $sql SQL query to find the desired bean, starting right after WHERE clause * @param array $bindings array of values to be bound to parameters in query * - * @return array + * @return OODBBean|NULL */ public static function findOneForUpdate( $type, $sql = NULL, $bindings = array() ) { $sql = self::getWriter()->glueLimitOne( $sql ); $beans = self::findForUpdate($type, $sql, $bindings); - return !empty($beans) ? reset($beans) : NULL; + return empty($beans) ? NULL : reset($beans); } /** @@ -13523,7 +12800,7 @@ class Facade * @param string|OODBBean|SimpleModel $beanOrType bean you want to remove from database * @param integer $id ID if the bean to trash (optional, type-id variant only) * - * @return void + * @return int */ public static function trash( $beanOrType, $id = NULL ) { @@ -13571,11 +12848,11 @@ class Facade * ] ); * * - * @param string|array $typeOrBeanArray type or bean array to import + * @param string|OODBBean[] $typeOrBeanArray type or bean array to import * @param integer $num number of beans to dispense * @param boolean $alwaysReturnArray if TRUE always returns the result as an array * - * @return array|OODBBean + * @return OODBBean|OODBBean[] */ public static function dispense( $typeOrBeanArray, $num = 1, $alwaysReturnArray = FALSE ) { @@ -13616,15 +12893,15 @@ class Facade } /** - * Convience method. Tries to find beans of a certain type, + * Convenience method. Tries to find beans of a certain type, * if no beans are found, it dispenses a bean of that type. * Note that this function always returns an array. * - * @param string $type type of bean you are looking for - * @param string $sql SQL code for finding the bean - * @param array $bindings parameters to bind to SQL + * @param string $type type of bean you are looking for + * @param string|NULL $sql SQL code for finding the bean + * @param array $bindings parameters to bind to SQL * - * @return array + * @return OODBBean[] */ public static function findOrDispense( $type, $sql = NULL, $bindings = array() ) { @@ -13635,9 +12912,9 @@ class Facade /** * Same as findOrDispense but returns just one element. * - * @param string $type type of bean you are looking for - * @param string $sql SQL code for finding the bean - * @param array $bindings parameters to bind to SQL + * @param string $type type of bean you are looking for + * @param string|NULL $sql SQL code for finding the bean + * @param array $bindings parameters to bind to SQL * * @return OODBBean */ @@ -13657,12 +12934,15 @@ class Facade * * Your SQL does not have to start with a WHERE-clause condition. * - * @param string $type the type of bean you are looking for - * @param string $sql SQL query to find the desired bean, starting right after WHERE clause - * @param array $bindings array of values to be bound to parameters in query - * @param string $snippet SQL snippet to include in query (for example: FOR UPDATE) + * @param string $type the type of bean you are looking for + * @param string|NULL $sql SQL query to find the desired bean, starting right after WHERE clause + * @param array $bindings array of values to be bound to parameters in query + * @param string|NULL $snippet SQL snippet to include in query (for example: FOR UPDATE) * - * @return array + * @phpstan-param literal-string|null $sql + * @psalm-param literal-string|null $sql + * + * @return OODBBean[] */ public static function find( $type, $sql = NULL, $bindings = array(), $snippet = NULL ) { @@ -13673,11 +12953,11 @@ class Facade /** * Alias for find(). * - * @param string $type the type of bean you are looking for - * @param string $sql SQL query to find the desired bean, starting right after WHERE clause - * @param array $bindings array of values to be bound to parameters in query + * @param string $type the type of bean you are looking for + * @param string|NULL $sql SQL query to find the desired bean, starting right after WHERE clause + * @param array $bindings array of values to be bound to parameters in query * - * @return array + * @return OODBBean[] */ public static function findAll( $type, $sql = NULL, $bindings = array() ) { @@ -13693,9 +12973,9 @@ class Facade * * @see Finder::find * - * @param string $type type the type of bean you are looking for - * @param string $sql sql SQL query to find the desired bean, starting right after WHERE clause - * @param array $bindings values array of values to be bound to parameters in query + * @param string $type type the type of bean you are looking for + * @param string|NULL $sql sql SQL query to find the desired bean, starting right after WHERE clause + * @param array $bindings values array of values to be bound to parameters in query * * @return array */ @@ -13707,9 +12987,9 @@ class Facade /** * Like R::find() but returns the first bean only. * - * @param string $type the type of bean you are looking for - * @param string $sql SQL query to find the desired bean, starting right after WHERE clause - * @param array $bindings array of values to be bound to parameters in query + * @param string $type the type of bean you are looking for + * @param string|NULL $sql SQL query to find the desired bean, starting right after WHERE clause + * @param array $bindings array of values to be bound to parameters in query * * @return OODBBean|NULL */ @@ -13732,9 +13012,9 @@ class Facade * * @see Finder::find * - * @param string $type the type of bean you are looking for - * @param string $sql SQL query to find the desired bean, starting right after WHERE clause - * @param array $bindings values array of values to be bound to parameters in query + * @param string $type the type of bean you are looking for + * @param string|NULL $sql SQL query to find the desired bean, starting right after WHERE clause + * @param array $bindings values array of values to be bound to parameters in query * * @return OODBBean|NULL */ @@ -13749,9 +13029,9 @@ class Facade * cursors - this is useful for processing large datasets. A bean collection * will not load all beans into memory all at once, just one at a time. * - * @param string $type the type of bean you are looking for - * @param string $sql SQL query to find the desired bean, starting right after WHERE clause - * @param array $bindings values array of values to be bound to parameters in query + * @param string $type the type of bean you are looking for + * @param string|NULL $sql SQL query to find the desired bean, starting right after WHERE clause + * @param array $bindings values array of values to be bound to parameters in query * * @return BeanCollection */ @@ -13821,10 +13101,10 @@ class Facade * * @note instead of an SQL query you can pass a result array as well. * - * @param string|array $types a list of types (either array or comma separated string) - * @param string|array $sql an SQL query or an array of prefetched records - * @param array $bindings optional, bindings for SQL query - * @param array $remappings optional, an array of remapping arrays + * @param string|string[] $types a list of types (either array or comma separated string) + * @param string|array[]|NULL $sql an SQL query or an array of prefetched records + * @param array $bindings optional, bindings for SQL query + * @param array[] $remappings optional, an array of remapping arrays * * @return array */ @@ -13843,9 +13123,9 @@ class Facade * passed IDs as their keys. * * @param string $type type of beans - * @param array $ids ids to load + * @param int[] $ids ids to load * - * @return array + * @return OODBBean[] */ public static function batch( $type, $ids ) { @@ -13859,9 +13139,9 @@ class Facade * loadAll. * * @param string $type type of beans - * @param array $ids ids to load + * @param int[] $ids ids to load * - * @return array + * @return OODBBean[] */ public static function loadAll( $type, $ids ) { @@ -13893,7 +13173,7 @@ class Facade * @param string $sql SQL query to execute * @param array $bindings a list of values to be bound to query parameters * - * @return array + * @return string[][] */ public static function getAll( $sql, $bindings = array() ) { @@ -13910,7 +13190,7 @@ class Facade * @param string $sql SQL query to execute * @param array $bindings a list of values to be bound to query parameters * - * @return string + * @return string|NULL */ public static function getCell( $sql, $bindings = array() ) { @@ -13927,7 +13207,7 @@ class Facade * @param string $sql SQL query to execute * @param array $bindings a list of values to be bound to query parameters * - * @return RedBeanPHP\Cursor\PDOCursor + * @return Cursor */ public static function getCursor( $sql, $bindings = array() ) { @@ -13944,7 +13224,7 @@ class Facade * @param string $sql SQL query to execute * @param array $bindings a list of values to be bound to query parameters * - * @return array + * @return array|NULL */ public static function getRow( $sql, $bindings = array() ) { @@ -13961,7 +13241,7 @@ class Facade * @param string $sql SQL query to execute * @param array $bindings a list of values to be bound to query parameters * - * @return array + * @return string[] */ public static function getCol( $sql, $bindings = array() ) { @@ -13980,7 +13260,7 @@ class Facade * @param string $sql SQL query to execute * @param array $bindings a list of values to be bound to query parameters * - * @return array + * @return string[] */ public static function getAssoc( $sql, $bindings = array() ) { @@ -13988,7 +13268,7 @@ class Facade } /** - *Convenience function to fire an SQL query using the RedBeanPHP + * Convenience function to fire an SQL query using the RedBeanPHP * database adapter. This method allows you to directly query the * database without having to obtain an database adapter instance first. * Executes the specified SQL query together with the specified @@ -14010,7 +13290,7 @@ class Facade * Returns the insert ID for databases that support/require this * functionality. Alias for R::getAdapter()->getInsertID(). * - * @return mixed + * @return int */ public static function getInsertID() { @@ -14036,12 +13316,12 @@ class Facade * This function has a confusing method signature, the R::duplicate() function * only accepts two arguments: bean and filters. * - * @param OODBBean $bean bean to be copied - * @param array $trail for internal usage, pass array() - * @param boolean $pid for internal usage - * @param array $filters white list filter with bean types to duplicate + * @param OODBBean $bean bean to be copied + * @param OODBBean[] $trail for internal usage, pass array() + * @param boolean $pid for internal usage + * @param array $filters white list filter with bean types to duplicate * - * @return array + * @return OODBBean */ public static function dup( $bean, $trail = array(), $pid = FALSE, $filters = array() ) { @@ -14068,10 +13348,10 @@ class Facade * Note: * This is a simplified version of the deprecated R::dup() function. * - * @param OODBBean $bean bean to be copied - * @param array $white white list filter with bean types to duplicate + * @param OODBBean $bean bean to be copied + * @param array $filters white list filter with bean types to duplicate * - * @return array + * @return OODBBean */ public static function duplicate( $bean, $filters = array() ) { @@ -14087,12 +13367,12 @@ class Facade * * all own bean lists (recursively) * * all shared beans (not THEIR own lists) * - * @param array|OODBBean $beans beans to be exported - * @param boolean $parents whether you want parent beans to be exported - * @param array $filters whitelist of types - * @param boolean $meta export meta data as well + * @param OODBBean|OODBBean[] $beans beans to be exported + * @param boolean $parents whether you want parent beans to be exported + * @param array $filters whitelist of types + * @param boolean $meta export meta data as well * - * @return array + * @return array[] */ public static function exportAll( $beans, $parents = FALSE, $filters = array(), $meta = FALSE ) { @@ -14152,14 +13432,14 @@ class Facade * New in 4.3.2: meta mask. The meta mask is a special mask to send * data from raw result rows to the meta store of the bean. This is * useful for bundling additional information with custom queries. - * Values of every column whos name starts with $mask will be + * Values of every column who's name starts with $mask will be * transferred to the meta section of the bean under key 'data.bundle'. * - * @param string $type type of beans to produce - * @param array $rows must contain an array of array - * @param string $metamask meta mask to apply (optional) + * @param string $type type of beans to produce + * @param string[][] $rows must contain an array of array + * @param string|array|NULL $metamask meta mask to apply (optional) * - * @return array + * @return OODBBean[] */ public static function convertToBeans( $type, $rows, $metamask = NULL ) { @@ -14167,11 +13447,11 @@ class Facade } /** - * Just like converToBeans, but for one bean. + * Just like convertToBeans, but for one bean. * - * @param string $type type of bean to produce - * @param array $row one row from the database - * @param string $metamask metamask (see convertToBeans) + * @param string $type type of bean to produce + * @param string[] $row one row from the database + * @param string|array|NULL $metamask metamask (see convertToBeans) * * @return OODBBean|NULL */ @@ -14221,7 +13501,7 @@ class Facade * @param string $type Type of bean to produce * @param string $sql SQL query snippet to use * @param array $bindings bindings for query (optional) - * @param mixed $metamask meta mask (optional, defaults to 'extra_') + * @param string|array $metamask meta mask (optional, defaults to 'extra_') * @param boolean $autoExtract TRUE to return meta mask values as first item of array * * @return array @@ -14265,9 +13545,9 @@ class Facade * or 'horror' this operation will return FALSE because the third parameter * has been set to TRUE. * - * @param OODBBean $bean bean to check for tags - * @param array|string $tags list of tags - * @param boolean $all whether they must all match or just some + * @param OODBBean $bean bean to check for tags + * @param string|string[] $tags list of tags + * @param boolean $all whether they must all match or just some * * @return boolean */ @@ -14292,8 +13572,8 @@ class Facade * In the example above, the $blog bean will no longer * be associated with the tags 'smart' and 'interesting'. * - * @param OODBBean $bean tagged bean - * @param array $tagList list of tags (names) + * @param OODBBean $bean tagged bean + * @param string|string[] $tagList list of tags (names) * * @return void */ @@ -14321,10 +13601,10 @@ class Facade * as 'TexMex' and 'Mexican Cuisine'. The second line will * retrieve all tags attached to the meal object. * - * @param OODBBean $bean bean to tag - * @param mixed $tagList tags to attach to the specified bean + * @param OODBBean $bean bean to tag + * @param string[]|NULL $tagList tags to attach to the specified bean * - * @return string + * @return string[] */ public static function tag( OODBBean $bean, $tagList = NULL ) { @@ -14346,8 +13626,8 @@ class Facade * The example adds the tag 'halloween' to the $blog * bean. * - * @param OODBBean $bean bean to tag - * @param array $tagList list of tags to add to bean + * @param OODBBean $bean bean to tag + * @param string|string[] $tagList list of tags to add to bean * * @return void */ @@ -14378,12 +13658,12 @@ class Facade * tagged as 'horror' or 'gothic', order them by title and limit * the number of movies to be returned to 10. * - * @param string $beanType type of bean you are looking for - * @param array|string $tagList list of tags to match - * @param string $sql additional SQL (use only for pagination) - * @param array $bindings bindings + * @param string $beanType type of bean you are looking for + * @param string|string[] $tagList list of tags to match + * @param string $sql additional SQL (use only for pagination) + * @param array $bindings bindings * - * @return array + * @return OODBBean[] */ public static function tagged( $beanType, $tagList, $sql = '', $bindings = array() ) { @@ -14412,12 +13692,12 @@ class Facade * The example above returns at most 4 movies (due to the LIMIT clause in the SQL * Query Snippet) that have been tagged as BOTH 'short' AND 'gothic'. * - * @param string $beanType type of bean you are looking for - * @param array|string $tagList list of tags to match - * @param string $sql additional sql snippet - * @param array $bindings bindings + * @param string $beanType type of bean you are looking for + * @param string|string[] $tagList list of tags to match + * @param string $sql additional sql snippet + * @param array $bindings bindings * - * @return array + * @return OODBBean[] */ public static function taggedAll( $beanType, $tagList, $sql = '', $bindings = array() ) { @@ -14429,10 +13709,10 @@ class Facade * * @see R::taggedAll * - * @param string $beanType type of bean you are looking for - * @param array|string $tagList list of tags to match - * @param string $sql additional sql snippet - * @param array $bindings bindings + * @param string $beanType type of bean you are looking for + * @param string|string[] $tagList list of tags to match + * @param string $sql additional sql snippet + * @param array $bindings bindings * * @return integer */ @@ -14446,10 +13726,10 @@ class Facade * * @see R::tagged * - * @param string $beanType type of bean you are looking for - * @param array|string $tagList list of tags to match - * @param string $sql additional sql snippet - * @param array $bindings bindings + * @param string $beanType type of bean you are looking for + * @param string|string[] $tagList list of tags to match + * @param string $sql additional sql snippet + * @param array $bindings bindings * * @return integer */ @@ -14509,7 +13789,7 @@ class Facade self::$labelMaker = new LabelMaker( self::$toolbox ); $helper = new SimpleModelHelper(); $helper->attachEventListeners( self::$redbean ); - if (self::$redbean->getBeanHelper() == NULL) { + if (self::$redbean->getBeanHelper() === NULL) { self::$redbean->setBeanHelper( new SimpleFacadeBeanHelper ); } self::$duplicationManager = new DuplicationManager( self::$toolbox ); @@ -14518,7 +13798,7 @@ class Facade } /** - * Facade Convience method for adapter transaction system. + * Facade Convenience method for adapter transaction system. * Begins a transaction. * * Usage: @@ -14559,7 +13839,7 @@ class Facade } /** - * Facade Convience method for adapter transaction system. + * Facade Convenience method for adapter transaction system. * Commits a transaction. * * Usage: @@ -14600,7 +13880,7 @@ class Facade } /** - * Facade Convience method for adapter transaction system. + * Facade Convenience method for adapter transaction system. * Rolls back a transaction. * * Usage: @@ -14648,7 +13928,7 @@ class Facade * * @param string $table name of the table (not type) you want to get columns of * - * @return array + * @return string[] */ public static function getColumns( $table ) { @@ -14680,7 +13960,7 @@ class Facade * ' IN( ?,? ) '. * * @param array $array array to generate question mark slots for - * @param string $template template to use + * @param string|NULL $template template to use * * @return string */ @@ -14714,11 +13994,11 @@ class Facade * ); * * - * @param array $beans a list of OODBBeans - * @param string $type a type string - * @param string $sqlTemplate an SQL template string for the SELECT-query + * @param OODBBean[]|TypedModel[] $beans a list of OODBBeans + * @param string $type a type string + * @param string $sqlTemplate an SQL template string for the SELECT-query * - * @return array + * @return OODBBean[]|TypedModel[] */ public static function loadJoined( $beans, $type, $sqlTemplate = 'SELECT %s.* FROM %s WHERE id IN (%s)' ) { @@ -14800,10 +14080,10 @@ class Facade * will automatically temporarily switch to fluid mode to attempt to store the * bean in case of an SQLException. * - * @param array $beans list of beans to be stored - * @param boolean $unfreezeIfNeeded retries in fluid mode in hybrid mode + * @param OODBBean[] $beans list of beans to be stored + * @param boolean $unfreezeIfNeeded retries in fluid mode in hybrid mode * - * @return array + * @return int[] ids */ public static function storeAll( $beans, $unfreezeIfNeeded = FALSE ) { @@ -14819,9 +14099,9 @@ class Facade * For information please consult the R::trash() function. * A loop saver. * - * @param array $beans list of beans to be trashed + * @param OODBBean[] $beans list of beans to be trashed * - * @return void + * @return int */ public static function trashAll( $beans ) { @@ -14837,13 +14117,13 @@ class Facade * only IDs. This function combines trashAll and batch loading * in one call. Note that while this function accepts just * bean IDs, the beans will still be loaded first. This is because - * the function still respects all the FUSE hooks that may have beeb + * the function still respects all the FUSE hooks that may have been * associated with the domain logic associated with these beans. * If you really want to delete just records from the database use * a simple DELETE-FROM SQL query instead. * - * @param string type $type the bean type you wish to trash - * @param string array $ids list of bean IDs + * @param string $type the bean type you wish to trash + * @param int[] $ids list of bean IDs * * @return void */ @@ -14869,9 +14149,9 @@ class Facade * * Returns the number of beans deleted. * - * @param string $type bean type to look for in database - * @param string $sqlSnippet an SQL query snippet - * @param array $bindings SQL parameter bindings + * @param string $type bean type to look for in database + * @param string|NULL $sqlSnippet an SQL query snippet + * @param array $bindings SQL parameter bindings * * @return int */ @@ -14912,10 +14192,10 @@ class Facade * values of the array will be assigned to the name property of each * individual bean. * - * @param string $type type of beans you would like to have - * @param array $labels list of labels, names for each bean + * @param string $type type of beans you would like to have + * @param string[] $labels list of labels, names for each bean * - * @return array + * @return OODBBean[] */ public static function dispenseLabels( $type, $labels ) { @@ -14924,7 +14204,7 @@ class Facade /** * Generates and returns an ENUM value. This is how RedBeanPHP handles ENUMs. - * Either returns a (newly created) bean respresenting the desired ENUM + * Either returns a (newly created) bean representing the desired ENUM * value or returns a list of all enums for the type. * * To obtain (and add if necessary) an ENUM value: @@ -14951,7 +14231,7 @@ class Facade * * @param string $enum either type or type-value * - * @return array|OODBBean + * @return OODBBean|OODBBean[] */ public static function enum( $enum ) { @@ -14964,9 +14244,9 @@ class Facade * and stores the names in a new array. The array then gets sorted using the * default sort function of PHP (sort). * - * @param array $beans list of beans to loop + * @param OODBBean[] $beans list of beans to loop * - * @return array + * @return string[] */ public static function gatherLabels( $beans ) { @@ -15000,7 +14280,7 @@ class Facade * Simple convenience function, returns ISO date formatted representation * of $time. * - * @param mixed $time UNIX timestamp + * @param int|NULL $time UNIX timestamp * * @return string */ @@ -15018,7 +14298,7 @@ class Facade * formatted representation * of $time. * - * @param mixed $time UNIX timestamp + * @param int|NULL $time UNIX timestamp * * @return string */ @@ -15074,7 +14354,7 @@ class Facade * Optional accessor for neat code. * Sets the database adapter you want to use. * - * @return DBAdapter + * @return Adapter */ public static function getDatabaseAdapter() { @@ -15093,7 +14373,7 @@ class Facade * If the PDO object could not be found, for whatever reason, this method * will return NULL instead. * - * @return NULL|PDO + * @return NULL|\PDO */ public static function getPDO() { @@ -15102,6 +14382,8 @@ class Facade $database = $databaseAdapter->getDatabase(); if ( is_null( $database ) ) return NULL; if ( !method_exists( $database, 'getPDO' ) ) return NULL; + + /** @var RPDO $database */ return $database->getPDO(); } @@ -15173,8 +14455,8 @@ class Facade /** * Facade method for AQueryWriter::renameAssociation() * - * @param string|array $from - * @param string $to + * @param string|string[] $from + * @param string $to * * @return void */ @@ -15190,9 +14472,9 @@ class Facade * and shared lists, the beans are exported as-is, only loaded lists * are exported. * - * @param array $beans beans + * @param OODBBean[] $beans beans * - * @return array + * @return array[] */ public static function beansToArray( $beans ) { @@ -15252,9 +14534,9 @@ class Facade * to 35 characters to improve readability. Nested beans will * also be dumped. * - * @param OODBBean|array $data either a bean or an array of beans + * @param OODBBean|OODBBean[] $data either a bean or an array of beans * - * @return array + * @return string|string[] */ public static function dump( $data ) { @@ -15296,7 +14578,7 @@ class Facade * fetchAs but explicitly. For instance if you register * the alias 'cover' for 'page' a property containing a reference to a * page bean called 'cover' will correctly return the page bean and not - * a (non-existant) cover bean. + * a (non-existent) cover bean. * * * R::aliases( array( 'cover' => 'page' ) ); @@ -15320,7 +14602,7 @@ class Facade * From that point on, every bean reference to a cover * will return a 'page' bean. * - * @param array $list list of global aliases to use + * @param string[] $list list of global aliases to use * * @return void */ @@ -15339,13 +14621,13 @@ class Facade * * @param string $type type of bean to search for * @param array $like criteria set describing the bean to search for - * @param boolean $hasBeenCreated set to TRUE if bean has been created + * @param boolean &$hasBeenCreated set to TRUE if bean has been created * * @return OODBBean */ public static function findOrCreate( $type, $like = array(), $sql = '', &$hasBeenCreated = false ) { - return self::$finder->findOrCreate( $type, $like, $sql = '', $hasBeenCreated ); + return self::$finder->findOrCreate( $type, $like, $sql, $hasBeenCreated ); } /** @@ -15360,7 +14642,7 @@ class Facade * @param string $sql optional additional SQL for sorting * @param array $bindings bindings * - * @return array + * @return OODBBean[] */ public static function findLike( $type, $like = array(), $sql = '', $bindings = array() ) { @@ -15403,7 +14685,7 @@ class Facade /** * Stops logging and flushes the logs, - * convient method to stop logging of queries. + * convenient method to stop logging of queries. * Use this method to stop logging SQL queries being * executed by the adapter. Logging queries will not * print them on the screen. Use R::getLogs() to @@ -15478,7 +14760,7 @@ class Facade * Therefore, only stop logging AFTER you have obtained the * query logs using R::getLogs() * - * @return array + * @return string[] */ public static function getLogs() { @@ -15529,7 +14811,7 @@ class Facade * Returns the current logger instance being used by the * database object. * - * @return Logger + * @return Logger|NULL */ public static function getLogger() { @@ -15551,9 +14833,9 @@ class Facade * for some types. * This method will return the previous value. * - * @param boolean|array $yesNoBeans List of type names or 'all' + * @param boolean|string[] $yesNoBeans List of type names or 'all' * - * @return mixed + * @return boolean|string[] */ public static function usePartialBeans( $yesNoBeans ) { @@ -15625,7 +14907,7 @@ class Facade * @param array $onNotFoundDo task list to be considered on NOT finding the bean * @param OODBBean &$bean reference to obtain the found bean * - * @return mixed + * @return bool|NULL */ public static function matchUp( $type, $sql, $bindings = array(), $onFoundDo = NULL, $onNotFoundDo = NULL, &$bean = NULL ) { $matchUp = new MatchUp( self::$toolbox ); @@ -15670,7 +14952,7 @@ class Facade * 'strtoupper', * "\n" * ); - * + * * * The example above creates an HTML fragment like this: * @@ -15729,11 +15011,10 @@ class Facade * of property names that have to be skipped. By default this array is filled with * two strings: 'created' and 'modified'. * - * @param OODBBean|array $bean reference beans - * @param OODBBean|array $other beans to compare + * @param OODBBean|OODBBean[] $bean reference beans + * @param OODBBean|OODBBean[] $other beans to compare * @param array $filters names of properties of all beans to skip - * @param string $format the format of the key, defaults to '%s.%s.%s' - * @param string $type type/property of bean to use for key generation + * @param string $pattern the format of the key, defaults to '%s.%s.%s' * * @return array */ @@ -15785,7 +15066,6 @@ class Facade * Returns the toolbox associated with the specified key. * * @param string $key key to store toolbox instance under - * @param ToolBox $toolbox toolbox to register * * @return ToolBox|NULL */ @@ -15852,9 +15132,11 @@ class Facade * a warning mechanism in case your database does not support this * functionality. * - * @param OODBBean $bean bean to find children of - * @param string $sql optional SQL snippet - * @param array $bindings SQL snippet parameter bindings + * @param OODBBean $bean bean to find children of + * @param string|NULL $sql optional SQL snippet + * @param array $bindings SQL snippet parameter bindings + * + * @return OODBBean[] */ public static function children( OODBBean $bean, $sql = NULL, $bindings = array() ) { @@ -15885,9 +15167,11 @@ class Facade * it cannot 'predict' what or how you are trying to 'count'. * * @param OODBBean $bean bean to find children of - * @param string $sql optional SQL snippet + * @param string|NULL $sql optional SQL snippet * @param array $bindings SQL snippet parameter bindings * @param string|boolean $select select snippet to use (advanced, optional, see QueryWriter::queryRecursiveCommonTableExpression) + * + * @return int */ public static function countChildren( OODBBean $bean, $sql = NULL, $bindings = array(), $select = QueryWriter::C_CTE_SELECT_COUNT ) { @@ -15918,9 +15202,11 @@ class Facade * it cannot 'predict' what or how you are trying to 'count'. * * @param OODBBean $bean bean to find children of - * @param string $sql optional SQL snippet + * @param string|NULL $sql optional SQL snippet * @param array $bindings SQL snippet parameter bindings * @param string|boolean $select select snippet to use (advanced, optional, see QueryWriter::queryRecursiveCommonTableExpression) + * + * @return int */ public static function countParents( OODBBean $bean, $sql = NULL, $bindings = array(), $select = QueryWriter::C_CTE_SELECT_COUNT ) { @@ -15937,9 +15223,11 @@ class Facade * a warning mechanism in case your database does not support this * functionality. * - * @param OODBBean $bean bean to find parents of - * @param string $sql optional SQL snippet - * @param array $bindings SQL snippet parameter bindings + * @param OODBBean $bean bean to find parents of + * @param string|NULL $sql optional SQL snippet + * @param array $bindings SQL snippet parameter bindings + * + * @return OODBBean[] */ public static function parents( OODBBean $bean, $sql = NULL, $bindings = array() ) { @@ -15959,6 +15247,58 @@ class Facade return AQueryWriter::forbidNuke( $yesNo ); } + /** + * Globally available service method for RedBeanPHP. + * Converts a snake cased string to a camel cased string. + * If the parameter is an array, the keys will be converted. + * + * @param string|array $snake snake_cased string to convert to camelCase + * @param boolean $dolphin exception for Ids - (bookId -> bookID) + * too complicated for the human mind, only dolphins can understand this + * + * @return string|array + */ + public static function camelfy( $snake, $dolphin = false ) + { + if ( is_array( $snake ) ) { + $newArray = array(); + foreach( $snake as $key => $value ) { + $newKey = self::camelfy( $key, $dolphin ); + if ( is_array( $value ) ) { + $value = self::camelfy( $value, $dolphin ); + } + $newArray[ $newKey ] = $value; + } + return $newArray; + } + return AQueryWriter::snakeCamel( $snake, $dolphin ); + } + + /** + * Globally available service method for RedBeanPHP. + * Converts a camel cased string to a snake cased string. + * If the parameter is an array, the keys will be converted. + * + * @param string|array $camel camelCased string to convert to snake case + * + * @return string|array + */ + public static function uncamelfy( $camel ) + { + if ( is_array( $camel ) ) { + $newArray = array(); + foreach( $camel as $key => $value ) { + $newKey = self::uncamelfy( $key ); + if ( is_array( $value ) ) { + $value = self::uncamelfy( $value ); + } + $newArray[ $newKey ] = $value; + } + return $newArray; + } + return AQueryWriter::camelsSnake( $camel ); + } + /** * Selects the feature set you want as specified by * the label. @@ -16095,7 +15435,7 @@ class DuplicationManager protected $filters = array(); /** - * @var array + * @var boolean */ protected $cacheTables = FALSE; @@ -16305,7 +15645,7 @@ class DuplicationManager public function camelfy( $array, $dolphinMode = FALSE ) { $newArray = array(); foreach( $array as $key => $element ) { - $newKey = preg_replace_callback( '/_(\w)/', function( &$matches ){ + $newKey = preg_replace_callback( '/_(\w)/', function( $matches ){ return strtoupper( $matches[1] ); }, $key); @@ -16372,6 +15712,8 @@ class DuplicationManager * every time a duplication action is performed (dup()). * * @param boolean $yesNo TRUE to use caching, FALSE otherwise + * + * @return void */ public function setCacheTables( $yesNo ) { @@ -16549,8 +15891,8 @@ class ArrayTool * The statement in the example will produce the string: * ' IN( ?,? ) '. * - * @param array $array array to generate question mark slots for - * @param string $template template to use + * @param array $array array to generate question mark slots for + * @param string|NULL $template template to use * * @return string */ @@ -16590,6 +15932,7 @@ class ArrayTool namespace RedBeanPHP\Util { use RedBeanPHP\OODB as OODB; +use RedBeanPHP\OODBBean as OODBBean; use RedBeanPHP\RedException as RedException; /** @@ -16709,7 +16052,7 @@ class DispenseHelper * @param integer $num number of beans to dispense * @param boolean $alwaysReturnArray if TRUE always returns the result as an array * - * @return array|OODBBean + * @return OODBBean|OODBBean[] */ public static function dispense( OODB $oodb, $typeOrBeanArray, $num = 1, $alwaysReturnArray = FALSE ) { @@ -16869,6 +16212,7 @@ class Dump namespace RedBeanPHP\Util { use RedBeanPHP\OODB as OODB; +use RedBeanPHP\OODBBean as OODBBean; /** * Multi Bean Loader Helper @@ -16879,7 +16223,7 @@ use RedBeanPHP\OODB as OODB; * * This helper class offers limited support for one-to-one * relations by providing a service to load a set of beans - * with differnt types and a common ID. + * with different types and a common ID. * * @file RedBeanPHP/Util/MultiLoader.php * @author Gabor de Mooij and the RedBeanPHP Community @@ -16910,7 +16254,7 @@ class MultiLoader * @param string|array $types the set of types to load at once * @param mixed $id the common ID * - * @return OODBBean + * @return OODBBean[] */ public static function load( OODB $oodb, $types, $id ) { @@ -17026,7 +16370,7 @@ use RedBeanPHP\ToolBox as ToolBox; * The Quick Export Utility Class provides functionality to easily * expose the result of SQL queries as well-known formats like CSV. * - * @file RedBeanPHP/Util/QuickExporft.php + * @file RedBeanPHP/Util/QuickExport.php * @author Gabor de Mooij and the RedBeanPHP Community * @license BSD/GPLv2 * @@ -17038,12 +16382,12 @@ use RedBeanPHP\ToolBox as ToolBox; class QuickExport { /** - * @var Finder + * @var ToolBox */ protected $toolbox; /** - * @boolean + * @var boolean */ private static $test = FALSE; @@ -17060,7 +16404,13 @@ class QuickExport /** * Makes csv() testable. - */ + * + * @param string $name + * @param mixed $arg1 + * @param boolean $arg2 + * + * @return mixed + */ public static function operation( $name, $arg1, $arg2 = TRUE ) { $out = ''; switch( $name ) { @@ -17109,7 +16459,7 @@ class QuickExport * @param boolean $output TRUE to output CSV directly using readfile * @param array $options delimiter, quote and escape character respectively * - * @return void + * @return string|NULL */ public function csv( $sql = '', $bindings = array(), $columns = NULL, $path = '/tmp/redexport_%s.csv', $output = TRUE, $options = array(',','"','\\') ) { @@ -17219,11 +16569,11 @@ class MatchUp * @param string $type type of bean you're looking for * @param string $sql SQL snippet (starting at the WHERE clause, omit WHERE-keyword) * @param array $bindings array of parameter bindings for SQL snippet - * @param array $onFoundDo task list to be considered on finding the bean - * @param array $onNotFoundDo task list to be considered on NOT finding the bean - * @param OODBBean &$bean reference to obtain the found bean + * @param array|NULL $onFoundDo task list to be considered on finding the bean + * @param array|NULL $onNotFoundDo task list to be considered on NOT finding the bean + * @param OODBBean|NULL &$bean reference to obtain the found bean * - * @return mixed + * @return bool|NULL */ public function matchUp( $type, $sql, $bindings = array(), $onFoundDo = NULL, $onNotFoundDo = NULL, &$bean = NULL ) { @@ -17435,7 +16785,7 @@ class Diff * @param OODBBean|array $others beans to compare * @param array $filters names of properties of all beans to skip * @param string $format the format of the key, defaults to '%s.%s.%s' - * @param string $type type/property of bean to use for key generation + * @param string|NULL $type type/property of bean to use for key generation * * @return array */ @@ -17486,13 +16836,15 @@ class Diff namespace RedBeanPHP\Util { use RedBeanPHP\ToolBox; +use RedBeanPHP\OODB; use RedBeanPHP\OODBBean; +use RedBeanPHP\QueryWriter; /** * Tree * * Given a bean, finds it children or parents - * in a hierchical structure. + * in a hierarchical structure. * * @experimental feature * @@ -17540,7 +16892,7 @@ class Tree { * bean in a tree structure. * * @note this only works for databases that support - * recusrive common table expressions. + * recursive common table expressions. * * Usage: * @@ -17557,9 +16909,9 @@ class Tree { * parameter binding key ':slot0' is reserved for the ID of the bean * and used in the query. * - * @param OODBBean $bean reference bean to find children of - * @param string $sql optional SQL snippet - * @param array $bindings optional parameter bindings for SQL snippet + * @param OODBBean $bean reference bean to find children of + * @param string|NULL $sql optional SQL snippet + * @param array $bindings optional parameter bindings for SQL snippet * * @return array */ @@ -17578,7 +16930,7 @@ class Tree { * bean in a tree structure. * * @note this only works for databases that support - * recusrive common table expressions. + * recursive common table expressions. * * * $newsPages = R::parents( $newsArticle, ' ORDER BY title ASC ' ); @@ -17593,9 +16945,9 @@ class Tree { * parameter binding key ':slot0' is reserved for the ID of the bean * and used in the query. * - * @param OODBBean $bean reference bean to find parents of - * @param string $sql optional SQL snippet - * @param array $bindings optional parameter bindings for SQL snippet + * @param OODBBean $bean reference bean to find parents of + * @param string|NULL $sql optional SQL snippet + * @param array $bindings optional parameter bindings for SQL snippet * * @return array */ @@ -17614,7 +16966,7 @@ class Tree { * bean in a tree structure. * * @note this only works for databases that support - * recusrive common table expressions. + * recursive common table expressions. * * * $count = R::countChildren( $newsArticle ); @@ -17636,7 +16988,7 @@ class Tree { * it cannot 'predict' what or how you are trying to 'count'. * * @param OODBBean $bean reference bean to find children of - * @param string $sql optional SQL snippet + * @param string|NULL $sql optional SQL snippet * @param array $bindings optional parameter bindings for SQL snippet * @param string|boolean $select select snippet to use (advanced, optional, see QueryWriter::queryRecursiveCommonTableExpression) * @@ -17656,7 +17008,7 @@ class Tree { * bean in a tree structure. * * @note this only works for databases that support - * recusrive common table expressions. + * recursive common table expressions. * * * $count = R::countParents( $newsArticle ); @@ -17677,9 +17029,9 @@ class Tree { * this method assumes you take control of the resulting total yourself since * it cannot 'predict' what or how you are trying to 'count'. * - * @param OODBBean $bean reference bean to find parents of - * @param string $sql optional SQL snippet - * @param array $bindings optional parameter bindings for SQL snippet + * @param OODBBean $bean reference bean to find parents of + * @param string|NULL $sql optional SQL snippet + * @param array $bindings optional parameter bindings for SQL snippet * @param string|boolean $select select snippet to use (advanced, optional, see QueryWriter::queryRecursiveCommonTableExpression) * * @return integer @@ -17764,7 +17116,7 @@ class Feature case self::C_FEATURE_NOVICE_LATEST: case self::C_FEATURE_NOVICE_5_4: case self::C_FEATURE_NOVICE_5_5: - OODBBean::useFluidCount( FALSE ); + OODBBean::useFluidCount( TRUE ); R::noNuke( TRUE ); R::setAllowHybridMode( FALSE ); R::useISNULLConditions( TRUE ); @@ -17772,7 +17124,7 @@ class Feature case self::C_FEATURE_LATEST: case self::C_FEATURE_5_4: case self::C_FEATURE_5_5: - OODBBean::useFluidCount( FALSE ); + OODBBean::useFluidCount( TRUE ); R::noNuke( FALSE ); R::setAllowHybridMode( TRUE ); R::useISNULLConditions( TRUE ); @@ -17803,6 +17155,158 @@ class Feature } } +namespace RedBeanPHP\Util { + +/** + * Either Utility + * + * The Either Utility class provides an easy way to + * substitute the NULL coalesce operator in RedBeanPHP + * (since the lazy loading interface interferes with the ?? + * operator) in a way that can also be used in older PHP-versions. + * + * @file RedBeanPHP/Util/Either.php + * @author Gabor de Mooij and the RedBeanPHP Community + * @license BSD/GPLv2 + * + * @copyright + * copyright (c) G.J.G.T. (Gabor) de Mooij and the RedBeanPHP Community + * This source file is subject to the BSD/GPLv2 License that is bundled + * with this source code in the file license.txt. + */ +class Either { + + /** + * @var mixed + */ + private $result; + + /** + * Constructs a new Either-instance. + * + * Example usage: + * + * + * $author = $text + * ->either() + * ->page + * ->book + * ->autor + * ->name + * ->or('unknown'); + * + * + * The Either-class lets you access bean properties without having to do + * NULL-checks. The mechanism resembles the use of the ?? somewhat but + * offers backward compatibility with older PHP versions. The mechanism also works + * on arrays. + * + * + * $budget = $company + * ->either() + * ->sharedProject + * ->first() + * ->budget + * ->or(0); + * + */ + public function __construct($result) { + $this->result = $result; + } + + /** + * Extracts a value from the wrapped object and stores + * it in the internal result object. If the desired + * value cannot be found, the internal result object will be set + * to NULL. Chainable. + * + * @param string $something name of the property you wish to extract the value of + * + * @return self + */ + public function __get($something) { + if (is_object($this->result)) { + $this->result = $this->result->{$something}; + } else { + $this->result = NULL; + } + return $this; + } + + /** + * Extracts the first element of the array in the internal result + * object and stores it as the new value of the internal result object. + * Chainable. + * + * @return self + */ + public function first() { + if (is_array($this->result)) { + reset($this->result); + $key = key($this->result); + if (isset($this->result[$key])) { + $this->result = $this->result[$key]; + } else { + $this->result = NULL; + } + } + return $this; + } + + /** + * Extracts the last element of the array in the internal result + * object and stores it as the new value of the internal result object. + * Chainable. + * + * @return self + */ + public function last() { + if (is_array($this->result)) { + end($this->result); + $key = key($this->result); + if (isset($this->result[$key])) { + $this->result = $this->result[$key]; + } else { + $this->result = NULL; + } + } + return $this; + } + + /** + * Extracts the specified element of the array in the internal result + * object and stores it as the new value of the internal result object. + * Chainable. + * + * @return self + */ + public function index( $key = 0 ) { + if (is_array($this->result)) { + if (isset($this->result[$key])) { + $this->result = $this->result[$key]; + } else { + $this->result = NULL; + } + } + return $this; + } + + /** + * Resolves the Either-instance to a final value, either the value + * contained in the internal result object or the value specified + * in the or() function. + * + * @param mixed $value value to resolve to if internal result equals NULL + * + * @return mixed + */ + public function _or( $value ) { + $reference = (is_null($this->result)) ? $value : $this->result; + return $reference; + } +} +} + namespace RedBeanPHP { /** @@ -17916,5 +17420,61 @@ if ( !function_exists( 'array_flatten' ) ) { } } +/** + * Function pstr() generates [ $value, \PDO::PARAM_STR ] + * Ensures that your parameter is being treated as a string. + * + * Usage: + * + * + * R::find('book', 'title = ?', [ pstr('1') ]); + * + */ +if ( !function_exists( 'pstr' ) ) { + + function pstr( $value ) + { + return array( strval( $value ) , \PDO::PARAM_STR ); + } +} + + +/** + * Function pint() generates [ $value, \PDO::PARAM_INT ] + * Ensures that your parameter is being treated as an integer. + * + * Usage: + * + * + * R::find('book', ' pages > ? ', [ pint(2) ] ); + * + */ +if ( !function_exists( 'pint' ) ) { + + function pint( $value ) + { + return array( intval( $value ) , \PDO::PARAM_INT ); + } +} + +/** + * Function DBPrefix() is a simple function to allow you to + * quickly set a different namespace for FUSE model resolution + * per database connection. It works by creating a new DynamicBeanHelper + * with the specified string as model prefix. + * + * Usage: + * + * + * R::addDatabase( ..., DBPrefix( 'Prefix1_' ) ); + * + */ +if ( !function_exists( 'DBPrefix' ) ) { + + function DBPrefix( $prefix = '\\Model' ) { + return new \RedBeanPHP\BeanHelper\DynamicBeanHelper( $prefix ); + } +} + } diff --git a/templates/controls/alert-product-sets.php b/templates/controls/alert-product-sets.php new file mode 100644 index 0000000..487d58b --- /dev/null +++ b/templates/controls/alert-product-sets.php @@ -0,0 +1,59 @@ + + products ) ):?> +

    Dobierz inne produkty do kompletu

    + +
    + products ) ): foreach ( $this -> products as $product_id ): + $product = new \shop\Product( $product_id ); + + $product -> language['seo_link'] ? $url = '/' . $product -> language['seo_link'] : $url = '/p-' . $product['id'] . '-' . \S::seo( $product -> language['name'] ); + + if ( \S::get_session( 'current-lang' ) != \front\factory\Languages::default_language() and $url != '#' ) + $url = '/' . \S::get_session( 'current-lang' ) . $url; + ?> +
    + new_to_date and $product -> new_to_date >= date( 'Y-m-d' ) ):?> +
    + + +
    + images[0]['src'], 1 ) ) ):?> + class == 'item' ):?> + <?= $product -> images[0]['alt'];?> + + <?= $product -> images[0]['alt'];?> + images[1]['src'], 1 ) ) ):?> + <?= $product -> images[1]['alt'];?> + + <?= $product -> images[0]['alt'];?> + + + + + +
    +
    +
    +

    + + language['name'];?> + +

    +
    + price_brutto_promo ):?> +
    + price_brutto );?> +
    +
    + price_brutto_promo );?> +
    + +
    + price_brutto );?> +
    + +
    +
    +
    + +
    \ No newline at end of file diff --git a/templates/shop-basket/basket.php b/templates/shop-basket/basket.php index c4f678d..c39c0e4 100644 --- a/templates/shop-basket/basket.php +++ b/templates/shop-basket/basket.php @@ -6,7 +6,7 @@ Chcesz skorzystać z odroczonych płatności ? Wybierz jedną z form dostawy: odbiór osobisty, Paczkomaty InPost - przedpłata lub Kurier - przedpłata.
    Wartość zamówienia musi mieścić się w przedziale od 40 zł do 1000 zł. - basket ) and count( $this -> basket ) ):?> + basket ) and count( $this -> basket ) ):?>
    @@ -18,12 +18,6 @@
    - - -
    :
    @@ -44,7 +38,6 @@